Commit 0024760a authored by Monty's avatar Monty
Browse files

OK, libvorbis encodes and decodes bitstreams (not complete Vorbis
bitstreams, but they work).  Lib and examples debugged.  Lib does not
yet do *any* backend compression and it's slow as hell.  We address
both next.

Monty

svn path=/trunk/vorbis/; revision=143
parent 321b01cb
# vorbis makefile configured for use with gcc on any platform
# $Id: Makefile.in,v 1.10 1999/10/05 15:34:56 xiphmont Exp $
# $Id: Makefile.in,v 1.11 1999/10/10 20:32:17 xiphmont Exp $
###############################################################################
# #
......@@ -31,7 +31,8 @@ HFILES = mdct.h codec.h bitwise.h envelope.h lpc.h lsp.h modes.h\
psy.h smallft.h window.h xlogmap.h
LFILES = framing.o mdct.o smallft.o block.o envelope.o window.o\
lsp.o lpc.o analysis.o synthesis.o psy.o info.o bitwise.o
lsp.o lpc.o analysis.o synthesis.o psy.o info.o bitwise.o\
spectrum.o
EFILES = encoder_example.o decoder_example.o
......
......@@ -14,7 +14,7 @@
function: single-block PCM analysis
author: Monty <xiphmont@mit.edu>
modifications by: Monty
last modification date: Oct 4 1999
last modification date: Oct 7 1999
********************************************************************/
......@@ -27,31 +27,104 @@
#include "envelope.h"
#include "mdct.h"
#include "psy.h"
#include "bitwise.h"
#include "spectrum.h"
/* this code is still seriously abbreviated. I'm filling in pieces as
we go... --Monty 19991004 */
int vorbis_analysis(vorbis_block *vb,ogg_packet *op){
static int frameno=0;
int i;
double *window=vb->vd->window[vb->W][vb->lW][vb->nW];
lpc_lookup *vl=&vb->vd->vl[vb->W];
vorbis_dsp_state *vd=vi->vd;
vorbis_dsp_state *vd=vb->vd;
vorbis_info *vi=vd->vi;
oggpack_buffer *opb=&vb->opb;
int n=vb->pcmend;
int spectral_order=vi->floororder[vb->W];
/*lpc_lookup *vbal=&vb->vd->vbal[vb->W];
double balance_v[vbal->m];
double balance_amp;*/
/* we have the preecho metrics; decie what to do with them */
_ve_envelope_sparsify(vb);
_ve_envelope_apply(vb,0);
/* first things first. Make sure encode is ready*/
_oggpack_reset(opb);
/* Encode the packet type */
_oggpack_write(opb,0,1);
/* Encode the block size */
_oggpack_write(opb,vb->W,1);
/* we have the preecho metrics; decide what to do with them */
/*_ve_envelope_sparsify(vb);
_ve_envelope_apply(vb,0);*/
/* Encode the envelope */
/*if(_ve_envelope_encode(vb))return(-1);*/
/* time domain PCM -> MDCT domain */
for(i=0;i<vi->channels;i++)
mdct_forward(&vd->vm[vb->W],vb->pcm[i],vb->pcm[i],window);
/* no balance yet */
/* extract the spectral envelope and residue */
/* just do by channel. No coupling yet */
{
for(i=0;i<vi->channels;i++){
double floor[n/2];
double curve[n/2];
double *lpc=vb->lpc[i];
double *lsp=vb->lsp[i];
memset(floor,0,sizeof(double)*n/2);
_vp_noise_floor(vb->pcm[i],floor,n/2);
_vp_mask_floor(vb->pcm[i],floor,n/2);
/* Convert our floor to a set of lpc coefficients */
vb->amp[i]=sqrt(vorbis_curve_to_lpc(floor,lpc,vl));
/* LSP <-> LPC is orthogonal and LSP quantizes more stably */
vorbis_lpc_to_lsp(lpc,lsp,vl->m);
/* code the spectral envelope; mutates the lsp coeffs to reflect
what was actually encoded */
_vs_spectrum_encode(vb,vb->amp[i],lsp);
/* Generate residue from the decoded envelope, which will be
slightly different to the pre-encoding floor due to
quantization. Slow, yes, but perhaps more accurate */
vorbis_lsp_to_lpc(lsp,lpc,vl->m);
vorbis_lpc_to_curve(curve,lpc,vb->amp[i],vl);
/* this may do various interesting massaging too...*/
_vs_residue_quantize(vb->pcm[i],curve,vi,n/2);
/* encode the residue */
_vs_residue_encode(vb,vb->pcm[i]);
}
}
/* set up the packet wrapper */
op->packet=opb->buffer;
op->bytes=_oggpack_bytes(opb);
op->b_o_s=0;
op->e_o_s=vb->eofflag;
op->frameno=vb->frameno;
return(0);
}
/* no balance or channel coupling yet */
/* commented out, relocated balance stuff */
/*{
double *C=vb->pcm[0];
double *D=vb->pcm[1];
......@@ -115,103 +188,3 @@ int vorbis_analysis(vorbis_block *vb,ogg_packet *op){
}
}*/
/* extract the spectral envelope and residue */
/* just do by channel. No coupling yet */
{
for(i=0;i<vi->channels;vi++){
double floor[n/2];
double curve[n/2];
double *lpc=vb->lpc[i];
double *lsp=vb->lsp[i];
memset(floor,0,sizeof(double)*n/2);
_vp_noise_floor(vb->pcm[i],floor,n/2);
_vp_mask_floor(vb->pcm[i],floor,n/2);
vb->amp[i]=sqrt(vorbis_curve_to_lpc(floor,lpc,vl));
vorbis_lpc_to_lsp(lpc,lsp,vl->m);
{
/* make this scale configurable */
int scale=1020;
int last=0;
for(i=0;i<vl->m;i++){
double q=lsp[i]/M_PI*scale;
int val=rint(q-last);
last+=val;
lsp[i]=val;
}
}
/* make residue. Get the floor curve back from LPC (do we want
to recover all the way from LSP in the future? Yes, once the
residue massaging is smarter) */
vorbis_lpc_to_curve(work,lpc1,amp1,vl);
_vp_psy_quantize(C,work,n/2);
_vp_psy_quantize(D,work,n/2);
_vp_psy_unquantize(C,work,n/2);
_vp_psy_unquantize(D,work,n/2);
{
FILE *out;
char buffer[80];
/*sprintf(buffer,"qC%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<n/2;i++)
fprintf(out,"%g\n",fabs(C[i]));
fclose(out);
sprintf(buffer,"qD%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<n/2;i++)
fprintf(out,"%g\n",fabs(D[i]));
fclose(out);
sprintf(buffer,"floor%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<n/2;i++)
fprintf(out,"%g\n",floor1[i]);
fclose(out);
sprintf(buffer,"lpc%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<n/2;i++)
fprintf(out,"%g\n",work[i]);
fclose(out);
sprintf(buffer,"curve%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<n/2;i++)
fprintf(out,"%g\n",curve[i]);
fclose(out);
sprintf(buffer,"lsp%d.m",frameno);
out=fopen(buffer,"w+");
for(i=0;i<30;i++){
fprintf(out,"%g 0.\n",lsp1[i]);
fprintf(out,"%g .1\n",lsp1[i]);
fprintf(out,"\n");
fprintf(out,"\n");
}
fclose(out);*/
frameno++;
}
}
/* unmix */
_vp_balance_apply(D,C,balance_v,balance_amp,vbal,0);
}
return(0);
}
......@@ -48,7 +48,7 @@ void _oggpack_reset(oggpack_buffer *b){
b->endbit=b->endbyte=0;
}
void _oggpack_writefree(oggpack_buffer *b){
void _oggpack_writeclear(oggpack_buffer *b){
free(b->buffer);
memset(b,0,sizeof(oggpack_buffer));
}
......
......@@ -22,7 +22,7 @@
extern void _oggpack_writeinit(oggpack_buffer *b);
extern void _oggpack_reset(oggpack_buffer *b);
extern void _oggpack_writefree(oggpack_buffer *b);
extern void _oggpack_writeclear(oggpack_buffer *b);
extern void _oggpack_readinit(oggpack_buffer *b,char *buf,int bytes);
extern void _oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
extern long _oggpack_look(oggpack_buffer *b,int bits);
......
......@@ -75,15 +75,16 @@
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
int i;
vorbis_info *vi=v->vi;
memset(vb,0,sizeof(vorbis_block));
vb->vd=v;
vb->pcm_storage=v->block_size[1];
vb->pcm_channels=v->pcm_channels;
vb->mult_storage=v->block_size[1]/v->samples_per_envelope_step;
vb->mult_channels=v->envelope_channels;
vb->floor_channels=v->vi.floorch;
vb->floor_storage=v->vi.floororder;
vb->pcm_storage=vi->blocksize[1];
vb->pcm_channels=vi->channels;
vb->mult_storage=vi->blocksize[1]/vi->envelopesa;
vb->mult_channels=vi->envelopech;
vb->floor_channels=vi->floorch;
vb->floor_storage=max(vi->floororder[0],vi->floororder[1]);
vb->pcm=malloc(vb->pcm_channels*sizeof(double *));
for(i=0;i<vb->pcm_channels;i++)
......@@ -100,6 +101,8 @@ int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
vb->lsp[i]=malloc(vb->floor_storage*sizeof(double));
vb->lpc[i]=malloc(vb->floor_storage*sizeof(double));
}
if(v->analysisp)
_oggpack_writeinit(&vb->opb);
return(0);
}
......@@ -116,6 +119,9 @@ int vorbis_block_clear(vorbis_block *vb){
free(vb->mult[i]);
free(vb->mult);
}
if(vb->vd->analysisp)
_oggpack_writeclear(&vb->opb);
memset(vb,0,sizeof(vorbis_block));
return(0);
}
......@@ -127,29 +133,25 @@ int vorbis_block_clear(vorbis_block *vb){
static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
memset(v,0,sizeof(vorbis_dsp_state));
memcpy(&v->vi,vi,sizeof(vorbis_info));
v->vi=vi;
_ve_envelope_init(&v->ve,vi->envelopesa);
mdct_init(&v->vm[0],vi->smallblock);
mdct_init(&v->vm[1],vi->largeblock);
mdct_init(&v->vm[0],vi->blocksize[0]);
mdct_init(&v->vm[1],vi->blocksize[1]);
v->samples_per_envelope_step=vi->envelopesa;
v->block_size[0]=vi->smallblock;
v->block_size[1]=vi->largeblock;
v->window[0][0][0]=_vorbis_window(v->block_size[0],
v->block_size[0]/2,v->block_size[0]/2);
v->window[0][0][0]=_vorbis_window(vi->blocksize[0],
vi->blocksize[0]/2,vi->blocksize[0]/2);
v->window[0][0][1]=v->window[0][0][0];
v->window[0][1][0]=v->window[0][0][0];
v->window[0][1][1]=v->window[0][0][0];
v->window[1][0][0]=_vorbis_window(v->block_size[1],
v->block_size[0]/2,v->block_size[0]/2);
v->window[1][0][1]=_vorbis_window(v->block_size[1],
v->block_size[0]/2,v->block_size[1]/2);
v->window[1][1][0]=_vorbis_window(v->block_size[1],
v->block_size[1]/2,v->block_size[0]/2);
v->window[1][1][1]=_vorbis_window(v->block_size[1],
v->block_size[1]/2,v->block_size[1]/2);
v->window[1][0][0]=_vorbis_window(vi->blocksize[1],
vi->blocksize[0]/2,vi->blocksize[0]/2);
v->window[1][0][1]=_vorbis_window(vi->blocksize[1],
vi->blocksize[0]/2,vi->blocksize[1]/2);
v->window[1][1][0]=_vorbis_window(vi->blocksize[1],
vi->blocksize[1]/2,vi->blocksize[0]/2);
v->window[1][1][1]=_vorbis_window(vi->blocksize[1],
vi->blocksize[1]/2,vi->blocksize[1]/2);
/* initialize the storage vectors to a decent size greater than the
minimum */
......@@ -157,7 +159,6 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
v->pcm_storage=8192; /* we'll assume later that we have
a minimum of twice the blocksize of
accumulated samples in analysis */
v->pcm_channels=v->vi.channels=vi->channels;
v->pcm=malloc(vi->channels*sizeof(double *));
v->pcmret=malloc(vi->channels*sizeof(double *));
{
......@@ -169,12 +170,11 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
/* Initialize the envelope multiplier storage */
if(vi->envelopech){
v->envelope_storage=v->pcm_storage/v->samples_per_envelope_step;
v->envelope_channels=vi->envelopech;
v->multipliers=calloc(v->envelope_channels,sizeof(double *));
v->envelope_storage=v->pcm_storage/vi->envelopesa;
v->multipliers=calloc(vi->envelopech,sizeof(double *));
{
int i;
for(i=0;i<v->envelope_channels;i++){
for(i=0;i<vi->envelopech;i++){
v->multipliers[i]=calloc(v->envelope_storage,sizeof(double));
}
}
......@@ -186,10 +186,10 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
v->W=0; /* current window size */
/* all vector indexes; multiples of samples_per_envelope_step */
v->centerW=v->block_size[1]/2;
v->centerW=vi->blocksize[1]/2;
v->pcm_current=v->centerW;
v->envelope_current=v->centerW/v->samples_per_envelope_step;
v->envelope_current=v->centerW/vi->envelopesa;
return(0);
}
......@@ -197,17 +197,20 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
_vds_shared_init(v,vi);
/* the coder init is different for read/write */
v->analysisp=1;
/* Yes, wasteful to have four lookups. This will get collapsed once
things crystallize */
lpc_init(&v->vl[0],vi->smallblock/2,vi->smallblock/2,
vi->floororder,vi->flooroctaves,1);
lpc_init(&v->vl[1],vi->largeblock/2,vi->largeblock/2,
vi->floororder,vi->flooroctaves,1);
lpc_init(&v->vl[0],vi->blocksize[0]/2,vi->blocksize[0]/2,
vi->floororder[0],vi->flooroctaves[0],1);
lpc_init(&v->vl[1],vi->blocksize[1]/2,vi->blocksize[1]/2,
vi->floororder[0],vi->flooroctaves[0],1);
lpc_init(&v->vbal[0],vi->smallblock/2,256,
vi->balanceorder,vi->balanceoctaves,1);
lpc_init(&v->vbal[1],vi->largeblock/2,256,
/*lpc_init(&v->vbal[0],vi->blocksize[0]/2,256,
vi->balanceorder,vi->balanceoctaves,1);
lpc_init(&v->vbal[1],vi->blocksize[1]/2,256,
vi->balanceorder,vi->balanceoctaves,1);*/
return(0);
}
......@@ -215,19 +218,20 @@ int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
void vorbis_dsp_clear(vorbis_dsp_state *v){
int i,j,k;
if(v){
vorbis_info *vi=v->vi;
if(v->window[0][0][0])free(v->window[0][0][0]);
for(j=0;j<2;j++)
for(k=0;k<2;k++)
if(v->window[1][j][k])free(v->window[1][j][k]);
if(v->pcm){
for(i=0;i<v->pcm_channels;i++)
for(i=0;i<vi->channels;i++)
if(v->pcm[i])free(v->pcm[i]);
free(v->pcm);
if(v->pcmret)free(v->pcmret);
}
if(v->multipliers){
for(i=0;i<v->envelope_channels;i++)
for(i=0;i<vi->envelopech;i++)
if(v->multipliers[i])free(v->multipliers[i]);
free(v->multipliers);
}
......@@ -236,32 +240,33 @@ void vorbis_dsp_clear(vorbis_dsp_state *v){
mdct_clear(&v->vm[1]);
lpc_clear(&v->vl[0]);
lpc_clear(&v->vl[1]);
lpc_clear(&v->vbal[0]);
lpc_clear(&v->vbal[1]);
/*lpc_clear(&v->vbal[0]);
lpc_clear(&v->vbal[1]);*/
memset(v,0,sizeof(vorbis_dsp_state));
}
}
double **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
int i;
vorbis_info *vi=v->vi;
/* Do we have enough storage space for the requested buffer? If not,
expand the PCM (and envelope) storage */
if(v->pcm_current+vals>=v->pcm_storage){
v->pcm_storage=v->pcm_current+vals*2;
v->envelope_storage=v->pcm_storage/v->samples_per_envelope_step;
v->envelope_storage=v->pcm_storage/v->vi->envelopesa;
for(i=0;i<v->pcm_channels;i++){
for(i=0;i<vi->channels;i++){
v->pcm[i]=realloc(v->pcm[i],v->pcm_storage*sizeof(double));
}
for(i=0;i<v->envelope_channels;i++){
for(i=0;i<vi->envelopech;i++){
v->multipliers[i]=realloc(v->multipliers[i],
v->envelope_storage*sizeof(double));
}
}
for(i=0;i<v->pcm_channels;i++)
for(i=0;i<vi->channels;i++)
v->pcmret[i]=v->pcm[i]+v->pcm_current;
return(v->pcmret);
......@@ -270,15 +275,16 @@ double **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
/* call with val<=0 to set eof */
int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
vorbis_info *vi=v->vi;
if(vals<=0){
/* We're encoding the end of the stream. Just make sure we have
[at least] a full block of zeroes at the end. */
int i;
vorbis_analysis_buffer(v,v->block_size[1]*2);
vorbis_analysis_buffer(v,v->vi->blocksize[1]*2);
v->eofflag=v->pcm_current;
v->pcm_current+=v->block_size[1]*2;
for(i=0;i<v->pcm_channels;i++)
v->pcm_current+=v->vi->blocksize[1]*2;
for(i=0;i<vi->channels;i++)
memset(v->pcm[i]+v->eofflag,0,
(v->pcm_current-v->eofflag)*sizeof(double));
}else{
......@@ -295,8 +301,9 @@ int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
the next block on which to continue analysis */
int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
int i,j;
long beginW=v->centerW-v->block_size[v->W]/2,centerNext;
long beginM=beginW/v->samples_per_envelope_step;
vorbis_info *vi=v->vi;
long beginW=v->centerW-vi->blocksize[v->W]/2,centerNext;
long beginM=beginW/vi->envelopesa;
/* check to see if we're done... */
if(v->eofflag==-1)return(0);
......@@ -304,7 +311,7 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
/* if we have any unfilled envelope blocks for which we have PCM
data, fill them up in before proceeding. */
if(v->pcm_current/v->samples_per_envelope_step>v->envelope_current){
if(v->pcm_current/vi->envelopesa>v->envelope_current){
/* This generates the multipliers, but does not sparsify the vector.
That's done by block before coding */
_ve_envelope_multipliers(v);
......@@ -317,22 +324,22 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
/* overconserve for now; any block with a non-placeholder multiplier
should be minimal size. We can be greedy and only look at nW size */
if(v->vi.smallblock<v->vi.largeblock){
if(vi->blocksize[0]<vi->blocksize[1]){
if(v->W)
/* this is a long window; we start the search forward of centerW
because that's the fastest we could react anyway */
i=v->centerW+v->block_size[1]/4-v->block_size[0]/4;
i=v->centerW+vi->blocksize[1]/4-vi->blocksize[0]/4;
else
/* short window. Search from centerW */
i=v->centerW;
i/=v->samples_per_envelope_step;
i/=vi->envelopesa;
for(;i<v->envelope_current;i++){
for(j=0;j<v->envelope_channels;j++)
if(v->multipliers[j][i-1]*v->vi.preecho_thresh<
for(j=0;j<vi->envelopech;j++)
if(v->multipliers[j][i-1]*vi->preecho_thresh<
v->multipliers[j][i])break;
if(j<v->envelope_channels)break;
if(j<vi->envelopech)break;
}
if(i<v->envelope_current){
......@@ -340,10 +347,10 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
upcoming block large ? */
long largebound;
if(v->W)
largebound=v->centerW+v->block_size[1];
largebound=v->centerW+vi->blocksize[1];
else
largebound=v->centerW+v->block_size[0]/4+v->block_size[1]*3/4;
largebound/=v->samples_per_envelope_step;
largebound=v->centerW+vi->blocksize[0]/4+vi->blocksize[1]*3/4;
largebound/=vi->envelopesa;
if(i>=largebound)
v->nW=1;
......@@ -365,10 +372,10 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
know the size of the next block for sure and we need that now to
figure out the window shape of this block */
centerNext=v->centerW+v->block_size[v->W]/4+v->block_size[v->nW]/4;
centerNext=v->centerW+vi->blocksize[v->W]/4+vi->blocksize[v->nW]/4;
{
long blockbound=centerNext+v->block_size[v->nW]/2;
long blockbound=centerNext+vi->blocksize[v->nW]/2;
if(v->pcm_current<blockbound)return(0); /* not enough data yet */
}
......@@ -378,28 +385,15 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
vb->nW=v->nW;
vb->vd=v;
vb->pcmend=v->block_size[v->W];
vb->multend=vb->pcmend / v->samples_per_envelope_step;
if(vb->floor_channels!=v->vi.floorch ||
vb->floor_storage!=v->vi.floororder ||
v->pcm_channels!=vb->pcm_channels ||
v->block_size[1]!=vb->pcm_storage ||
v->envelope_channels!=vb->mult_channels){
/* Storage not initialized or initilized for some other codec
instance with different settings */
vorbis_block_clear(vb);
vorbis_block_init(v,vb);
}
vb->pcmend=vi->blocksize[v->W];
vb->multend=vb->pcmend / vi->envelopesa;
/* copy the vectors */
for(i=0;i<v->pcm_channels;i++)
memcpy(vb->pcm[i],v->pcm[i]+beginW,v->block_size[v->W]*sizeof(double));
for(i=0;i<v->envelope_channels;i++)
memcpy(vb->mult[i],v->multipliers[i]+beginM,v->block_size[v->W]/
v->samples_per_envelope_step*sizeof(double));
for(i=0;i<vi->channels;i++)
memcpy(vb->pcm[i],v->pcm[i]+beginW,vi->blocksize[v->W]*sizeof(double));
for(i=0;i<vi->envelopech;i++)
memcpy(vb->mult[i],v->multipliers[i]+beginM,vi->blocksize[v->W]/
vi->envelopesa*sizeof(double));
vb->frameno=v->frame;
......@@ -416,19 +410,19 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
/* advance storage vectors and clean up */
{
int new_centerNext=v->block_size[1]/2;
int new_centerNext=vi->blocksize[1]/2;
int movementW=centerNext-new_centerNext;
int movementM=movementW/v->samples_per_envelope_step;
int movementM=movementW/vi->e