Commit 09298000 authored by Monty's avatar Monty
Browse files

Checkpoint ongoing work in the analysis interface

Monty 19990727

svn path=/trunk/vorbis/; revision=13
parent 264bbb24
# vorbis makefile configured for use with gcc on any platform
# $Id: Makefile.in,v 1.1 1999/07/13 07:48:14 mwhitson Exp $
# $Id: Makefile.in,v 1.2 1999/07/27 08:44:52 xiphmont Exp $
###############################################################################
# #
......@@ -42,8 +42,10 @@ profile:
selftest:
$(MAKE) clean
$(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST framing.c -o test_framing
$(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST analysis.c -o test_blocking
@echo
@./test_framing
@./test_blocking
target: $(TARGETFILES)
......
......@@ -14,11 +14,11 @@
function: PCM data vector blocking, windowing and dis/reassembly
author: Monty <xiphmont@mit.edu>
modifications by: Monty
last modification date: Jun 26 1999
last modification date: Jul 27 1999
Handle windowing, overlap-add, etc of the original (and synthesized)
PCM vectors. This is made more amusing by Vorbis' current two allowed
block sizes (512 and 2048 elements/channel).
Handle windowing, overlap-add, etc of the PCM vectors. This is made
more amusing by Vorbis' current two allowed block sizes (512 and 2048
elements/channel).
Vorbis manipulates the dynamic range of the incoming PCM data
envelope to minimise time-domain energy leakage from percussive and
......@@ -27,6 +27,8 @@
********************************************************************/
#include <stdlib.h>
#include <string.h>
#include "codec.h"
/* pcm accumulator and multipliers
examples (not exhaustive):
......@@ -70,49 +72,14 @@
mult[n]
*/
typedef struct vorbis_state{
int samples_per_envelope_step;
int block_size[2];
double *window[2][2][2]; /* windowsize, leadin, leadout */
double **pcm;
int pcm_storage;
int pcm_channels;
int pcm_current;
double **deltas;
int **multipliers;
int envelope_storage;
int envelope_channels;
int envelope_current;
int initflag;
long lW;
long W;
long Sl;
long Sr;
long beginW;
long endW;
long beginSl;
long endSl;
long beginSr;
long endSr;
long frame;
long samples;
} vorbis_state;
/* arbitrary settings and spec-mandated numbers get filled in here */
void vorbis_init_state(vorbis_state *v,int channels,int mode){
memset(v,0,sizeof(vorbis_state));
int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
memset(v,0,sizeof(vorbis_dsp_state));
v->samples_per_envelope_step=64;
v->block_size[0]=512;
v->block_size[1]=2048;
v->window[0][0][0]=vorbis_window(v->block_size[0],
/* v->window[0][0][0]=vorbis_window(v->block_size[0],
v->block_size[0]/2,v->block_size[0]/2);
v->window[1][0][0]=vorbis_window(v->block_size[1],
v->block_size[0]/2,v->block_size[0]/2);
......@@ -121,26 +88,27 @@ void vorbis_init_state(vorbis_state *v,int channels,int mode){
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->block_size[1]/2,v->block_size[1]/2);*/
/* initialize the storage vectors to a decent size greater than the
minimum */
v->pcm_storage=8192; /* 8k samples. we'll assume later that we have
a minimum of twice the blocksize (2k) of
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=channels;
v->pcm=malloc(channels*sizeof(double *));
v->pcm_channels=v->vi.channels=vi->channels;
v->pcm=malloc(vi->channels*sizeof(double *));
v->pcmret=malloc(vi->channels*sizeof(double *));
{
int i;
for(i=0;i<channels;i++)
for(i=0;i<vi->channels;i++)
v->pcm[i]=calloc(v->pcm_storage,sizeof(double));
}
/* Initialize the envelope multiplier storage */
v->envelope_storage=v->pcmstorage/v->samples_per_envelope_step+1;
v->envelope_channels=channels;
v->envelope_storage=v->pcm_storage/v->samples_per_envelope_step;
v->envelope_channels=vi->channels;
v->deltas=calloc(v->envelope_channels,sizeof(double *));
v->multipliers=calloc(v->envelope_channels,sizeof(int *));
{
......@@ -152,29 +120,19 @@ void vorbis_init_state(vorbis_state *v,int channels,int mode){
}
/* all 1 (large block) or 0 (small block) */
/*v->lW=0; previous window size */
/*v->W=0; determined during analysis */
/*v->Sl=0; previous Sr */
/*v->Sr=0; determined during analysis */
/* explicitly set for the sake of clarity */
v->lW=0; /* previous window size */
v->W=0; /* current window size */
/* all vector indexes; multiples of samples_per_envelope_step */
/*v->beginW=0; determined during analysis */
/*v->endW=0; determined during analysis */
v->beginSl=v->block_size[1]/4-v->block_size[0]/4;
v->endSl=v->beginSl+v->block_size[0]/2;
/*v->beginSr=0; determined during analysis */
/*v->endSr=0; determined during analysis */
/*v->frame=0;*/
/*v->samples=0;*/
v->pcm_current=v->endSl;
v->last_multiplier=v->endSl/v->samples_per_envelope_step+1;
v->centerW=v->block_size[1]/2;
v->initflag=1;
v->pcm_current=v->centerW;
v->envelope_current=v->centerW/v->samples_per_envelope_step;
return(0);
}
void vorbis_free_state(vorbis_state *v){
void vorbis_analysis_clear(vorbis_dsp_state *v){
int i,j,k;
if(v){
for(i=0;i<2;i++)
......@@ -185,6 +143,7 @@ void vorbis_free_state(vorbis_state *v){
for(i=0;i<v->pcm_channels;i++)
if(v->pcm[i])free(v->pcm[i]);
free(v->pcm);
free(v->pcmret);
}
if(v->deltas){
for(i=0;i<v->envelope_channels;i++)
......@@ -196,110 +155,228 @@ void vorbis_free_state(vorbis_state *v){
if(v->multipliers[i])free(v->multipliers[i]);
free(v->multipliers);
}
free(v);
memset(v,0,sizeof(vorbis_dsp_state));
}
}
int vorbis_analysis(vorbis_state *v, double **pcm, int vals){
/* call with val==0 to set eof */
double **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
int i;
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. */
v->eofflag=v->pcm_current;
v->pcm_current+=v->block_size[1]*2;
vals=0;
}
/* vorbis encode state initialization */
if(!v->initflag)
vorbis_init_settings(v);
/* first we need to handle incoming data (if any) */
if(vals>0){
/* Do we have enough storage space for the incoming data? If not,
expand the PCM storage */
/* 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;
for(i=0;i<v->pcm_channels;i++){
v->pcm[i]=realloc(v->pcm[i],v->pcm_storage*sizeof(double));
v->deltas[i]=realloc(v->deltas[i],v->envelope_storage*sizeof(double));
v->multipliers[i]=realloc(v->multipliers[i],
v->envelope_storage*sizeof(double));
if(v->pcm_current+vals>=pcm_storage){
for(i=0;i<v->pcm_channels;i++)
v->pcm[i]=realloc(v->pcm[i],
(v->pcm_current+vals*2)*sizeof(double));
v->pcm_storage=v->pcm_current+vals*2;
}
}
/* If we're encoding the end of the stream and we're handing in
padding, vals will be set, but the passed in buffer will be
NULL; just add in zeroes */
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. */
for(i=0;i<v->pcm_channels;i++)
if(pcm==NULL)
memset(v->pcm[i]+v->pcm_current,0,vals*sizeof(double));
else
memcpy(v->pcm[i]+v->pcm_current,pcm[i],vals*sizeof(double));
v->pcm_current+=vals;
memset(v->pcm[i]+v->eofflag,0,
(v->pcm_current-v->eofflag)*sizeof(double));
}
/* Do we definately have enough for a frame? We assume we have more
than actually necessary to encode the current block to make some
analysis easier. */
for(i=0;i<v->pcm_channels;i++)
v->pcmret[i]=v->pcm[i]+v->pcm_current;
return(v->pcmret);
}
if(v->pcm_current-v->endSl<v->blocksize[1]*2)
return(0);
int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
if(v->pcm_current+vals>v->pcm_storage)
return(-1);
/* we have enough. begin analysis */
/* complete the envelope analysis vectors */
v->pcm_current+=vals;
return(0);
}
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
int i;
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->pcm=malloc(vb->pcm_channels*sizeof(double *));
for(i=0;i<vb->pcm_channels;i++)
vb->pcm[i]=malloc(vb->pcm_storage*sizeof(double));
vb->mult=malloc(vb->mult_channels*sizeof(int *));
for(i=0;i<vb->mult_channels;i++)
vb->mult[i]=malloc(vb->mult_storage*sizeof(int));
return(0);
}
/* decide the blocksize of this frame */
int vorbis_block_clear(vorbis_block *vb){
int i;
if(vb->pcm){
for(i=0;i<vb->pcm_channels;i++)
free(vb->pcm[i]);
free(vb->pcm);
}
if(vb->mult){
for(i=0;i<vb->mult_channels;i++)
free(vb->mult[i]);
free(vb->mult);
}
memset(vb,0,sizeof(vorbis_block));
return(0);
}
/* do the deltas, envelope shaping, pre-echo and determine the size of
the next block on which to continue analysis */
int vorbis_analysis_block(vorbis_dsp_state *v,vorbis_block *vb){
int i;
long beginW=v->centerW-v->block_size[v->W]/2,centerNext;
long beginM=beginW/v->samples_per_envelope_step;
/* algebra to set the rest of the window alignment vectors; many are
just derived, but they make the process clearer for the time
being */
/* check to see if we're done... */
if(v->eofflag==-1)return(0);
/* 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){
_va_envelope_deltas(v);
_va_envelope_multipliers(v);
}
/* the real analysis begins; forward MDCT with window */
/* By our invariant, we have lW, W and centerW set. Search for
the next boundary so we can determine nW (the next window size)
which lets us compute the shape of the current block's window */
/* overconserve for now; any block with a non-placeholder multiplier
should be minimal size. We can be greedy and only look at nW size */
/* Noise floor, resolution floor */
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;
else
/* short window. Search from centerW */
i=v->centerW;
i/=v->samples_per_envelope_step;
for(;i<v->envelope_storage;i++)if(v->multipliers[i])break;
if(i<v->envelope_storage){
/* Ooo, we hit a multiplier. Is it beyond the boundary to make the
upcoming block large ? */
long largebound;
if(v->W)
largebound=v->centerW+v->block_size[1];
else
largebound=v->centerW+v->block_size[0]/4+v->block_size[1]*3/4;
largebound/=v->samples_per_envelope_step;
if(i>=largebound)
v->nW=1;
else
v->nW=0;
}else{
/* Assume maximum; if the block is incomplete given current
buffered data, this will be detected below */
v->nW=1;
}
/* encode the floor into LSP; get the actual floor back for quant */
/* Do we actually have enough data *now* for the next block? The
reason to check is that if we had no multipliers, that could
simply been due to running out of data. In that case, we don;t
know the size of the next block for sure and we need that now to
figure out the window shape of this block */
{
long blockbound=centerNext+v->block_size[v->nW]/2;
if(v->pcm_current<blockbound)return(0); /* not enough data yet */
}
/* use noise floor, res floor for culling, actual floor for quant */
/* fill in the block */
vb->lW=v->lW;
vb->W=v->W;
vb->nW=v->nW;
vb->vd=v;
/* encode residue */
vb->pcmend=v->block_size[v->W];
vb->multend=vb->pcmend / v->samples_per_envelope_step;
if(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);
}
/* 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(int));
vb->frameno=v->frame;
/* handle eof detection: eof==0 means that we've not yet received EOF
eof>0 marks the last 'real' sample in pcm[]
eof<0 'no more to do'; doesn't get here */
if(v->eofflag){
long endW=beginW+v->block_size[v->W];
if(endW>=v->eofflag){
v->eofflag=-1;
vb->eofflag=1;
}
}
/* advance storage vectors and clean up */
/* center the window leadout on blocksize[1]/4 */
{
int new_beginSr,new_endSr,movement,emove;
/* first do the pcm storage */
if(v->Sr){
new_beginSl=0;
new_endSl=v->blocksize[1]/2;
}else{
new_beginSl=v->blocksize[1]/4-v->blocksize[0]/4;
new_endSl=new_beginSr+v->blocksize[0]/2;
}
movement=v->beginSr-new_beginSl;
int new_centerNext=v->block_size[1]/2;
int movementW=centerNext-new_centerNext;
int movementM=movementW/v->samples_per_envelope_step;
for(i=0;i<v->pcm_channels;i++)
memmove(v->pcm[i],v->pcm[i]+movement,
(v->pcm_current-movement)*sizeof(double));
v->pcm_current-=movement;
v->lW=W;
v->Sl=v->Sr;
v->beginSl=new_beginSl;
v->endSl=new_endSl;
v->frame++;
v->samples+=movement;
/* now advance the multipliers */
emove=movement/samples_per_envelope_step;
memmove(v->pcm[i],v->pcm[i]+movementW,
(v->pcm_current-movementW)*sizeof(double));
for(i=0;i<v->envelope_channels;i++){
memmove(v->deltas[i],v->deltas[i]+emove,
(v->envelope_current-emove)*sizeof(double));
memmove(v->multipliers[i],v->multipliers[i]+emove,
(v->envelope_current-emove)*sizeof(int));
memmove(v->deltas[i],v->deltas[i]+movementM,
(v->envelope_current-movementM)*sizeof(double));
memmove(v->multipliers[i],v->multipliers[i]+movementM,
(v->envelope_current-movementM)*sizeof(int));
}
v->envelope_current-=emove;
v->pcm_current-=movementW;
v->envelope_current-=movementM;
v->lW=v->W;
v->W=v->nW;
v->centerW=new_centerNext;
v->frame++;
v->samples+=movementW;
}
/* done */
......@@ -309,3 +386,31 @@ int vorbis_analysis(vorbis_state *v, double **pcm, int vals){
int vorbis_analysis_packetout(vorbis_dsp_state *v, vorbis_block *vb,
ogg_packet *op){
/* find block's envelope vector and apply it */
/* the real analysis begins; forward MDCT with window */
/* Noise floor, resolution floor */
/* encode the floor into LSP; get the actual floor back for quant */
/* use noise floor, res floor for culling, actual floor for quant */
/* encode residue */
}
......@@ -11,10 +11,10 @@
* *
********************************************************************
function: PCM data vector blocking, windowing and dis/reassembly
function: codec headers
author: Monty <xiphmont@mit.edu>
modifications by: Monty
last modification date: Jul 13 1999
last modification date: Jul 25 1999
********************************************************************/
......@@ -31,41 +31,6 @@ typedef struct vorbis_info{
} vorbis_info;
typedef struct vorbis_dsp_state{
int samples_per_envelope_step;
int block_size[2];
double *window[2][2][2]; /* windowsize, leadin, leadout */
double **pcm;
int pcm_storage;
int pcm_channels;
int pcm_current;
double **deltas;
int **multipliers;
int envelope_storage;
int envelope_channels;
int envelope_current;
int initflag;
long lW;
long W;
long Sl;
long Sr;
long beginW;
long endW;
long beginSl;
long endSl;
long beginSr;
long endSr;
long frame;
long samples;
} vorbis_dsp_state;
typedef struct {
unsigned char *header;
long header_len;
......@@ -74,17 +39,6 @@ typedef struct {
} ogg_page;
typedef struct {
/* _________________________________________________
body_data: |_________________________________________________|
body_returned ----^ ^ ^ ^
body_processed------------' | |
body_fill ---------------------------------------' |
body_storage _______________________________________________'
the header is labelled the same way. Not all the pointers are
used by both encode and decode */
unsigned char *body_data; /* bytes from packet bodies */
long body_storage; /* storage elements allocated */
long body_fill; /* elements stored; fill mark */
......@@ -134,6 +88,63 @@ typedef struct {
int bodybytes;
} ogg_sync_state;
typedef struct {
int divisor;
double *window;
} _ve_lookup;
typedef struct vorbis_dsp_state{
int samples_per_envelope_step;
int block_size[2];
double *window[2][2][2]; /* windowsize, leadin, leadout */
_ve_lookup ve;
vorbis_info vi;
double **pcm;
double **pcmret;
int pcm_storage;
int pcm_channels;
int pcm_current;
double **deltas;
int **multipliers;
int envelope_storage;
int envelope_channels;
int envelope_current;
int eofflag;
long lW;
long W;
long nW;
long centerW;
long frame;
long samples;
} vorbis_dsp_state;
typedef struct vorbis_block{
double **pcm;
int **mult;
int pcm_channels; /* allocated, not used */
int pcm_storage; /* allocated, not used */
int mult_channels; /* allocated, not used */
int mult_storage; /* allocated, not used */