void rebuilder::rebuild_id_header(
  int channels, int rate, int blocksize_short, int blocksize_long, 
  ogg_packet_holder & packet) {
  
  // Identification header
  oggpack_buffer opb;
  oggpack_writeinit(&opb);

  // Preamble
  oggpack_write(&opb, 0x01, 8);
  oggpack_write_string(&opb, "vorbis");

  // Basic information about the stream.
  oggpack_write(&opb, 0x00, 32);
  oggpack_write(&opb, channels, 8);
  oggpack_write(&opb, rate, 32);

  // Bitrate upper, nominal and lower.
  // All are optional and we do not provide them.
  oggpack_write(&opb, 0, 32);
  oggpack_write(&opb, 0, 32);
  oggpack_write(&opb, 0, 32);

  oggpack_write(&opb, ilog2(blocksize_short), 4);
  oggpack_write(&opb, ilog2(blocksize_long), 4);
  oggpack_write(&opb, 1, 1);

  CHECK(oggpack_writecheck(&opb) == 0);
  
  packet.assign(opb.buffer, oggpack_bytes(&opb));
  packet->b_o_s = 1;
  packet->e_o_s = 0;
  packet->granulepos = 0;
  packet->packetno = 0;
  
  oggpack_writeclear(&opb);
}
Beispiel #2
0
static void floor1_pack ( vorbis_info_floor *i, oggpack_buffer *opb )
{
    vorbis_info_floor1 *info = ( vorbis_info_floor1 * )i;
    int j, k;
    int count = 0;
    int rangebits;
    int maxposit = info->postlist[1];
    int maxclass = -1;

    /* save out partitions */
    oggpack_write( opb, info->partitions, 5 ); /* only 0 to 31 legal */
    for ( j = 0;j < info->partitions;j++ )
    {
        oggpack_write( opb, info->partitionclass[j], 4 ); /* only 0 to 15 legal */
        if ( maxclass < info->partitionclass[j] )
            maxclass = info->partitionclass[j];
    }

    /* save out partition classes */
    for ( j = 0;j < maxclass + 1;j++ )
    {
        oggpack_write( opb, info->class_dim[j] - 1, 3 ); /* 1 to 8 */
        oggpack_write( opb, info->class_subs[j], 2 ); /* 0 to 3 */
        if ( info->class_subs[j] )
            oggpack_write( opb, info->class_book[j], 8 );
        for ( k = 0;k < ( 1 << info->class_subs[j] );k++ )
            oggpack_write( opb, info->class_subbook[j][k] + 1, 8 );
    }

    /* save out the post list */
    oggpack_write( opb, info->mult - 1, 2 );     /* only 1,2,3,4 legal now */
    oggpack_write( opb, ilog2( maxposit ), 4 );
    rangebits = ilog2( maxposit );

    for ( j = 0, k = 0;j < info->partitions;j++ )
    {
        count += info->class_dim[info->partitionclass[j]];
        for ( ;k < count;k++ )
            oggpack_write( opb, info->postlist[k+2], rangebits );
    }
}
Beispiel #3
0
static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi)
{
    codec_setup_info     *ci=vi->codec_setup;
    if(!ci) { return(OV_EFAULT); }

    /* preamble */
    oggpack_write(opb,0x01,8);
    _v_writestring(opb,"vorbis", 6);

    /* basic information about the stream */
    oggpack_write(opb,0x00,32);
    oggpack_write(opb,vi->channels,8);
    oggpack_write(opb,vi->rate,32);

    oggpack_write(opb,vi->bitrate_upper,32);
    oggpack_write(opb,vi->bitrate_nominal,32);
    oggpack_write(opb,vi->bitrate_lower,32);

    oggpack_write(opb,ilog2(ci->blocksizes[0]),4);
    oggpack_write(opb,ilog2(ci->blocksizes[1]),4);
    oggpack_write(opb,1,1);

    return(0);
}
Beispiel #4
0
static int
_tarkin_pack_layer_desc (oggpack_buffer * opb, TarkinInfo * vi)
{
  int i;
  TarkinVideoLayer *layer;

#ifdef DBG_OGG
  printf ("dbg_ogg: Putting out layers description:\n");
#endif

  oggpack_write (opb, 0x05, 8);
  _v_writestring (opb, "tarkin", 6);

  for (i = 0; i < vi->n_layers; i++) {
    layer = vi->layer + i;
    oggpack_write (opb, layer->desc.width, 32);
    oggpack_write (opb, layer->desc.height, 32);
    oggpack_write (opb, layer->desc.a_moments, 32);
    oggpack_write (opb, layer->desc.s_moments, 32);
    oggpack_write (opb, layer->desc.frames_per_buf, 32);
    oggpack_write (opb, layer->desc.bitstream_len, 32);
    oggpack_write (opb, layer->desc.format, 32);

#ifdef DBG_OGG
    printf ("       res. %dx%d, format %d, a_m %d, s_m %d, fpb %d\n",
        layer->desc.width, layer->desc.height, layer->desc.format,
        layer->desc.a_moments, layer->desc.s_moments,
        layer->desc.frames_per_buf);
#endif

  }
  oggpack_write (opb, 1, 1);

#ifdef DBG_OGG
  printf ("      wrote %ld bytes.\n", oggpack_bytes (opb));
#endif

  return (0);
}
Beispiel #5
0
static int _tarkin_pack_info(oggpack_buffer *opb,TarkinInfo *vi){

  /* preamble */  
  oggpack_write(opb,0x01,8);
  _v_writestring(opb,"tarkin", 6);

  /* basic information about the stream */
  oggpack_write(opb,0x00,32);
  oggpack_write(opb,vi->n_layers,8);
  oggpack_write(opb,vi->inter.numerator,32);
  oggpack_write(opb,vi->inter.denominator,32);

  oggpack_write(opb,vi->bitrate_upper,32);
  oggpack_write(opb,vi->bitrate_nominal,32);
  oggpack_write(opb,vi->bitrate_lower,32);

  oggpack_write(opb,1,1);

#ifdef DBG_OGG
  printf("dbg_ogg: Putting out info, inter %d/%d, n_layers %d\n",
               vi->inter.numerator,vi->inter.denominator,vi->n_layers);
#endif
  return(0);
}
Beispiel #6
0
static int _commentheader_out(vcedit_state *state, ogg_packet *op)
{
    vorbis_comment *vc = state->vc;
    char           *vendor = state->vendor;
    oggpack_buffer opb;

    oggpack_writeinit(&opb);

    if (state->oggtype == VCEDIT_IS_OGGVORBIS)
    {
        /* preamble */
        oggpack_write(&opb,0x03,8);
        _v_writestring(&opb,"vorbis", 6);
    }

    /* vendor */
    oggpack_write(&opb,strlen(vendor),32);
    _v_writestring(&opb,vendor, strlen(vendor));

    /* comments */
    oggpack_write(&opb,vc->comments,32);
    if(vc->comments){
        int i;
        for(i=0;i<vc->comments;i++){
            if(vc->user_comments[i]){
                oggpack_write(&opb,vc->comment_lengths[i],32);
                _v_writestring(&opb,vc->user_comments[i],
                               vc->comment_lengths[i]);
            }else{
                oggpack_write(&opb,0,32);
            }
        }
    }
    oggpack_write(&opb,1,1);

    op->packet = _ogg_malloc(oggpack_bytes(&opb));
    memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));

    op->bytes=oggpack_bytes(&opb);
    op->b_o_s=0;
    op->e_o_s=0;
    op->granulepos=0;
    if (state->oggtype == VCEDIT_IS_OGGVORBIS)
    {
        op->packetno = 1;
    }

    oggpack_writeclear(&opb);
    return 0;
}
static bool
write_comments (vcedit_state *s, ogg_packet *packet)
{
	oggpack_buffer opb;
	size_t len;
	int i;

	ogg_packet_init (packet, NULL, 0);

	oggpack_writeinit (&opb);

	/* preamble */
	oggpack_write (&opb, 0x03, 8);
	_v_writestring (&opb, "vorbis", 6);

	/* vendor */
	len = strlen (s->vendor);
	oggpack_write (&opb, len, 32);
	_v_writestring (&opb, s->vendor, len);

	/* comments */
	oggpack_write (&opb, s->vc.comments, 32);

	for (i = 0; i < s->vc.comments; i++)
		if (!s->vc.user_comments[i])
			oggpack_write (&opb, 0, 32);
		else {
			oggpack_write (&opb, s->vc.comment_lengths[i], 32);
			_v_writestring (&opb, s->vc.user_comments[i],
			                s->vc.comment_lengths[i]);
		}

	oggpack_write (&opb, 1, 1);

	packet->bytes = oggpack_bytes (&opb);

	packet->packet = _ogg_malloc (packet->bytes);
	if (!packet->packet)
		return false;

	memcpy (packet->packet, opb.buffer, packet->bytes);

	oggpack_writeclear (&opb);

	return true;
}
Beispiel #8
0
void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){
  vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
  int j,acc=0;
  oggpack_write(opb,info->begin,24);
  oggpack_write(opb,info->end,24);

  oggpack_write(opb,info->grouping-1,24);  /* residue vectors to group and
                                             code with a partitioned book */
  oggpack_write(opb,info->partitions-1,6); /* possible partition choices */
  oggpack_write(opb,info->groupbook,8);  /* group huffman book */

  /* secondstages is a bitmask; as encoding progresses pass by pass, a
     bitmask of one indicates this partition class has bits to write
     this pass */
  for(j=0;j<info->partitions;j++){
    if(ov_ilog(info->secondstages[j])>3){
      /* yes, this is a minor hack due to not thinking ahead */
      oggpack_write(opb,info->secondstages[j],3);
      oggpack_write(opb,1,1);
      oggpack_write(opb,info->secondstages[j]>>3,5);
    }else
Beispiel #9
0
int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
  long i,j;
  int ordered=0;

  /* first the basic parameters */
  oggpack_write(opb,0x564342,24);
  oggpack_write(opb,c->dim,16);
  oggpack_write(opb,c->entries,24);

  /* pack the codewords.  There are two packings; length ordered and
     length random.  Decide between the two now. */

  for(i=1;i<c->entries;i++)
    if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
  if(i==c->entries)ordered=1;

  if(ordered){
    /* length ordered.  We only need to say how many codewords of
       each length.  The actual codewords are generated
       deterministically */

    long count=0;
    oggpack_write(opb,1,1);  /* ordered */
    oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */

    for(i=1;i<c->entries;i++){
      long this=c->lengthlist[i];
      long last=c->lengthlist[i-1];
      if(this>last){
        for(j=last;j<this;j++){
          oggpack_write(opb,i-count,_ilog(c->entries-count));
          count=i;
        }
      }
    }
    oggpack_write(opb,i-count,_ilog(c->entries-count));

  }else{
Beispiel #10
0
static int
_commentheader_out(vorbis_comment * vc, char *vendor, ogg_packet * op)
{
    oggpack_buffer opb;

    oggpack_writeinit(&opb);

    /* preamble */
    oggpack_write(&opb, 0x03, 8);
    _v_writestring(&opb, "vorbis", 6);

    /* vendor */
    oggpack_write(&opb, strlen(vendor), 32);
    _v_writestring(&opb, vendor, strlen(vendor));

    /* comments */
    oggpack_write(&opb, vc->comments, 32);
    if (vc->comments) {
        int i;
        for (i = 0; i < vc->comments; i++) {
            if (vc->user_comments[i]) {
                oggpack_write(&opb, vc->comment_lengths[i], 32);
                _v_writestring(&opb, vc->user_comments[i],
                               vc->comment_lengths[i]);
            }
            else {
                oggpack_write(&opb, 0, 32);
            }
        }
    }
    oggpack_write(&opb, 1, 1);

    op->packet = _ogg_malloc(oggpack_bytes(&opb));
    memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));

    op->bytes = oggpack_bytes(&opb);
    op->b_o_s = 0;
    op->e_o_s = 0;
    op->granulepos = 0;

    return 0;
}
Beispiel #11
0
static int
_tarkin_pack_comment (oggpack_buffer * opb, TarkinComment * vc)
{
  char temp[] = "libTarkin debugging edition 20011104";
  int bytes = strlen (temp);

  /* preamble */
  oggpack_write (opb, 0x03, 8);
  _v_writestring (opb, "tarkin", 6);

  /* vendor */
  oggpack_write (opb, bytes, 32);
  _v_writestring (opb, temp, bytes);

  /* comments */

  oggpack_write (opb, vc->comments, 32);
  if (vc->comments) {
    int i;

    for (i = 0; i < vc->comments; i++) {
      if (vc->user_comments[i]) {
        oggpack_write (opb, vc->comment_lengths[i], 32);
        _v_writestring (opb, vc->user_comments[i], vc->comment_lengths[i]);
      } else {
        oggpack_write (opb, 0, 32);
      }
    }
  }
  oggpack_write (opb, 1, 1);

#ifdef DBG_OGG
  printf ("dbg_ogg: Putting out %d comments\n", vc->comments);
#endif

  return (0);
}
Beispiel #12
0
static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc)
{
    char temp[]="Xiph.Org libVorbis I 20030909";
    int bytes = strlen(temp);

    /* preamble */
    oggpack_write(opb,0x03,8);
    _v_writestring(opb,"vorbis", 6);

    /* vendor */
    oggpack_write(opb,bytes,32);
    _v_writestring(opb,temp, bytes);

    /* comments */

    oggpack_write(opb,vc->comments,32);
    if(vc->comments)
    {
        int i;
        for(i=0; i<vc->comments; i++)
        {
            if(vc->user_comments[i])
            {
                oggpack_write(opb,vc->comment_lengths[i],32);
                _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
            }
            else
            {
                oggpack_write(opb,0,32);
            }
        }
    }
    oggpack_write(opb,1,1);

    return(0);
}
Beispiel #13
0
void oggpack_writealign(oggpack_buffer *b){
  int bits=8-b->endbit;
  if(bits<8)
    oggpack_write(b,0,bits);
}
Beispiel #14
0
static int BURGERCALL _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
  codec_setup_info     *ci=static_cast<codec_setup_info *>(vi->codec_setup);
  int i;
  if(!ci)return(OV_EFAULT);

  oggpack_write(opb,0x05,8);
  _v_writestring(opb,"vorbis", 6);

  /* books */
  oggpack_write(opb,ci->books-1,8);
  for(i=0;i<ci->books;i++)
    if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;

  /* times */
  oggpack_write(opb,ci->times-1,6);
  for(i=0;i<ci->times;i++){
    oggpack_write(opb,ci->time_type[i],16);
    _time_P[ci->time_type[i]]->pack(ci->time_param[i],opb);
  }

  /* floors */
  oggpack_write(opb,ci->floors-1,6);
  for(i=0;i<ci->floors;i++){
    oggpack_write(opb,ci->floor_type[i],16);
    _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
  }

  /* residues */
  oggpack_write(opb,ci->residues-1,6);
  for(i=0;i<ci->residues;i++){
    oggpack_write(opb,ci->residue_type[i],16);
    _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
  }

  /* maps */
  oggpack_write(opb,ci->maps-1,6);
  for(i=0;i<ci->maps;i++){
    oggpack_write(opb,ci->map_type[i],16);
    _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
  }

  /* modes */
  oggpack_write(opb,ci->modes-1,6);
  for(i=0;i<ci->modes;i++){
    oggpack_write(opb,ci->mode_param[i]->blockflag,1);
    oggpack_write(opb,ci->mode_param[i]->windowtype,16);
    oggpack_write(opb,ci->mode_param[i]->transformtype,16);
    oggpack_write(opb,ci->mode_param[i]->mapping,8);
  }
  oggpack_write(opb,1,1);

  return(0);
err_out:
  return(-1);
} 
Beispiel #15
0
static void BURGERCALL _v_writestring(oggpack_buffer *o,char *s, int bytes)
{
	while(bytes--){
		oggpack_write(o,*s++,8);
	}
}
Beispiel #16
0
static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){

  while(bytes--){
    oggpack_write(o,*s++,8);
  }
}
Beispiel #17
0
/* returns the number of bits ************************************************/
int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
  oggpack_write(b,book->codelist[a],book->c->lengthlist[a]);
  return(book->c->lengthlist[a]);
}
Beispiel #18
0
static void _v_writestring(oggpack_buffer *o,char *s){
  while(*s){
    oggpack_write(o,*s++,8);
  }
}
Beispiel #19
0
static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm,
			  oggpack_buffer *opb){
  int i;
  vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm;

  /* another 'we meant to do it this way' hack...  up to beta 4, we
     packed 4 binary zeros here to signify one submapping in use.  We
     now redefine that to mean four bitflags that indicate use of
     deeper features; bit0:submappings, bit1:coupling,
     bit2,3:reserved. This is backward compatable with all actual uses
     of the beta code. */

  if(info->submaps>1){
    oggpack_write(opb,1,1);
    oggpack_write(opb,info->submaps-1,4);
  }else
    oggpack_write(opb,0,1);

  if(info->coupling_steps>0){
    oggpack_write(opb,1,1);
    oggpack_write(opb,info->coupling_steps-1,8);
    
    for(i=0;i<info->coupling_steps;i++){
      oggpack_write(opb,info->coupling_mag[i],ilog(vi->channels));
      oggpack_write(opb,info->coupling_ang[i],ilog(vi->channels));
    }
  }else
    oggpack_write(opb,0,1);
  
  oggpack_write(opb,0,2); /* 2,3:reserved */

  /* we don't write the channel submappings if we only have one... */
  if(info->submaps>1){
    for(i=0;i<vi->channels;i++)
      oggpack_write(opb,info->chmuxlist[i],4);
  }
  for(i=0;i<info->submaps;i++){
    oggpack_write(opb,0,8); /* time submap unused */
    oggpack_write(opb,info->floorsubmap[i],8);
    oggpack_write(opb,info->residuesubmap[i],8);
  }
}
Beispiel #20
0
static int mapping0_forward(vorbis_block *vb){
  vorbis_dsp_state      *vd=vb->vd;
  vorbis_info           *vi=vd->vi;
  codec_setup_info      *ci=vi->codec_setup;
  private_state         *b=vb->vd->backend_state;
  vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
  int                    n=vb->pcmend;
  int i,j,k;

  int    *nonzero    = alloca(sizeof(*nonzero)*vi->channels);
  float  **gmdct     = _vorbis_block_alloc(vb,vi->channels*sizeof(*gmdct));
  int    **ilogmaskch= _vorbis_block_alloc(vb,vi->channels*sizeof(*ilogmaskch));
  int ***floor_posts = _vorbis_block_alloc(vb,vi->channels*sizeof(*floor_posts));
  
  float global_ampmax=vbi->ampmax;
  float *local_ampmax=alloca(sizeof(*local_ampmax)*vi->channels);
  int blocktype=vbi->blocktype;

  int modenumber=vb->W;
  vorbis_info_mapping0 *info=ci->map_param[modenumber];
  vorbis_look_psy *psy_look=
    b->psy+blocktype+(vb->W?2:0);

  vb->mode=modenumber;

  for(i=0;i<vi->channels;i++){
    float scale=4.f/n;
    float scale_dB;

    float *pcm     =vb->pcm[i]; 
    float *logfft  =pcm;

    gmdct[i]=_vorbis_block_alloc(vb,n/2*sizeof(**gmdct));

    scale_dB=todB(&scale) + .345; /* + .345 is a hack; the original
                                     todB estimation used on IEEE 754
                                     compliant machines had a bug that
                                     returned dB values about a third
                                     of a decibel too high.  The bug
                                     was harmless because tunings
                                     implicitly took that into
                                     account.  However, fixing the bug
                                     in the estimator requires
                                     changing all the tunings as well.
                                     For now, it's easier to sync
                                     things back up here, and
                                     recalibrate the tunings in the
                                     next major model upgrade. */

#if 0
    if(vi->channels==2)
      if(i==0)
	_analysis_output("pcmL",seq,pcm,n,0,0,total-n/2);
      else
	_analysis_output("pcmR",seq,pcm,n,0,0,total-n/2);
#endif
  
    /* window the PCM data */
    _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW);

#if 0
    if(vi->channels==2)
      if(i==0)
	_analysis_output("windowedL",seq,pcm,n,0,0,total-n/2);
      else
	_analysis_output("windowedR",seq,pcm,n,0,0,total-n/2);
#endif

    /* transform the PCM data */
    /* only MDCT right now.... */
    mdct_forward(b->transform[vb->W][0],pcm,gmdct[i]);
    
    /* FFT yields more accurate tonal estimation (not phase sensitive) */
    drft_forward(&b->fft_look[vb->W],pcm);
    logfft[0]=scale_dB+todB(pcm)  + .345; /* + .345 is a hack; the
                                     original todB estimation used on
                                     IEEE 754 compliant machines had a
                                     bug that returned dB values about
                                     a third of a decibel too high.
                                     The bug was harmless because
                                     tunings implicitly took that into
                                     account.  However, fixing the bug
                                     in the estimator requires
                                     changing all the tunings as well.
                                     For now, it's easier to sync
                                     things back up here, and
                                     recalibrate the tunings in the
                                     next major model upgrade. */
    local_ampmax[i]=logfft[0];
    for(j=1;j<n-1;j+=2){
      float temp=pcm[j]*pcm[j]+pcm[j+1]*pcm[j+1];
      temp=logfft[(j+1)>>1]=scale_dB+.5f*todB(&temp)  + .345; /* +
                                     .345 is a hack; the original todB
                                     estimation used on IEEE 754
                                     compliant machines had a bug that
                                     returned dB values about a third
                                     of a decibel too high.  The bug
                                     was harmless because tunings
                                     implicitly took that into
                                     account.  However, fixing the bug
                                     in the estimator requires
                                     changing all the tunings as well.
                                     For now, it's easier to sync
                                     things back up here, and
                                     recalibrate the tunings in the
                                     next major model upgrade. */
      if(temp>local_ampmax[i])local_ampmax[i]=temp;
    }

    if(local_ampmax[i]>0.f)local_ampmax[i]=0.f;
    if(local_ampmax[i]>global_ampmax)global_ampmax=local_ampmax[i];

#if 0
    if(vi->channels==2){
      if(i==0){
	_analysis_output("fftL",seq,logfft,n/2,1,0,0);
      }else{
	_analysis_output("fftR",seq,logfft,n/2,1,0,0);
      }
    }
#endif

  }
  
  {
    float   *noise        = _vorbis_block_alloc(vb,n/2*sizeof(*noise));
    float   *tone         = _vorbis_block_alloc(vb,n/2*sizeof(*tone));
    
    for(i=0;i<vi->channels;i++){
      /* the encoder setup assumes that all the modes used by any
	 specific bitrate tweaking use the same floor */
      
      int submap=info->chmuxlist[i];
      
      /* the following makes things clearer to *me* anyway */
      float *mdct    =gmdct[i];
      float *logfft  =vb->pcm[i];
      
      float *logmdct =logfft+n/2;
      float *logmask =logfft;

      vb->mode=modenumber;

      floor_posts[i]=_vorbis_block_alloc(vb,PACKETBLOBS*sizeof(**floor_posts));
      memset(floor_posts[i],0,sizeof(**floor_posts)*PACKETBLOBS);
      
      for(j=0;j<n/2;j++)
	logmdct[j]=todB(mdct+j)  + .345; /* + .345 is a hack; the original
                                     todB estimation used on IEEE 754
                                     compliant machines had a bug that
                                     returned dB values about a third
                                     of a decibel too high.  The bug
                                     was harmless because tunings
                                     implicitly took that into
                                     account.  However, fixing the bug
                                     in the estimator requires
                                     changing all the tunings as well.
                                     For now, it's easier to sync
                                     things back up here, and
                                     recalibrate the tunings in the
                                     next major model upgrade. */

#if 0
      if(vi->channels==2){
	if(i==0)
	  _analysis_output("mdctL",seq,logmdct,n/2,1,0,0);
	else
	  _analysis_output("mdctR",seq,logmdct,n/2,1,0,0);
      }else{
	_analysis_output("mdct",seq,logmdct,n/2,1,0,0);
      }
#endif 
      
      /* first step; noise masking.  Not only does 'noise masking'
         give us curves from which we can decide how much resolution
         to give noise parts of the spectrum, it also implicitly hands
         us a tonality estimate (the larger the value in the
         'noise_depth' vector, the more tonal that area is) */

      _vp_noisemask(psy_look,
		    logmdct,
		    noise); /* noise does not have by-frequency offset
                               bias applied yet */
#if 0
      if(vi->channels==2){
	if(i==0)
	  _analysis_output("noiseL",seq,noise,n/2,1,0,0);
	else
	  _analysis_output("noiseR",seq,noise,n/2,1,0,0);
      }
#endif

      /* second step: 'all the other crap'; all the stuff that isn't
         computed/fit for bitrate management goes in the second psy
         vector.  This includes tone masking, peak limiting and ATH */

      _vp_tonemask(psy_look,
		   logfft,
		   tone,
		   global_ampmax,
		   local_ampmax[i]);

#if 0
      if(vi->channels==2){
	if(i==0)
	  _analysis_output("toneL",seq,tone,n/2,1,0,0);
	else
	  _analysis_output("toneR",seq,tone,n/2,1,0,0);
      }
#endif

      /* third step; we offset the noise vectors, overlay tone
	 masking.  We then do a floor1-specific line fit.  If we're
	 performing bitrate management, the line fit is performed
	 multiple times for up/down tweakage on demand. */

#if 0
      {
      float aotuv[psy_look->n];
#endif

	_vp_offset_and_mix(psy_look,
			   noise,
			   tone,
			   1,
			   logmask,
			   mdct,
			   logmdct);
	
#if 0
	if(vi->channels==2){
	  if(i==0)
	    _analysis_output("aotuvM1_L",seq,aotuv,psy_look->n,1,1,0);
	  else
	    _analysis_output("aotuvM1_R",seq,aotuv,psy_look->n,1,1,0);
	}
      }
#endif


#if 0
      if(vi->channels==2){
	if(i==0)
	  _analysis_output("mask1L",seq,logmask,n/2,1,0,0);
	else
	  _analysis_output("mask1R",seq,logmask,n/2,1,0,0);
      }
#endif

      /* this algorithm is hardwired to floor 1 for now; abort out if
         we're *not* floor1.  This won't happen unless someone has
         broken the encode setup lib.  Guard it anyway. */
      if(ci->floor_type[info->floorsubmap[submap]]!=1)return(-1);

      floor_posts[i][PACKETBLOBS/2]=
	floor1_fit(vb,b->flr[info->floorsubmap[submap]],
		   logmdct,
		   logmask);
      
      /* are we managing bitrate?  If so, perform two more fits for
         later rate tweaking (fits represent hi/lo) */
      if(vorbis_bitrate_managed(vb) && floor_posts[i][PACKETBLOBS/2]){
	/* higher rate by way of lower noise curve */

	_vp_offset_and_mix(psy_look,
			   noise,
			   tone,
			   2,
			   logmask,
			   mdct,
			   logmdct);

#if 0
	if(vi->channels==2){
	  if(i==0)
	    _analysis_output("mask2L",seq,logmask,n/2,1,0,0);
	  else
	    _analysis_output("mask2R",seq,logmask,n/2,1,0,0);
	}
#endif
	
	floor_posts[i][PACKETBLOBS-1]=
	  floor1_fit(vb,b->flr[info->floorsubmap[submap]],
		     logmdct,
		     logmask);
      
	/* lower rate by way of higher noise curve */
	_vp_offset_and_mix(psy_look,
			   noise,
			   tone,
			   0,
			   logmask,
			   mdct,
			   logmdct);

#if 0
	if(vi->channels==2)
	  if(i==0)
	    _analysis_output("mask0L",seq,logmask,n/2,1,0,0);
	  else
	    _analysis_output("mask0R",seq,logmask,n/2,1,0,0);
#endif

	floor_posts[i][0]=
	  floor1_fit(vb,b->flr[info->floorsubmap[submap]],
		     logmdct,
		     logmask);
	
	/* we also interpolate a range of intermediate curves for
           intermediate rates */
	for(k=1;k<PACKETBLOBS/2;k++)
	  floor_posts[i][k]=
	    floor1_interpolate_fit(vb,b->flr[info->floorsubmap[submap]],
				   floor_posts[i][0],
				   floor_posts[i][PACKETBLOBS/2],
				   k*65536/(PACKETBLOBS/2));
	for(k=PACKETBLOBS/2+1;k<PACKETBLOBS-1;k++)
	  floor_posts[i][k]=
	    floor1_interpolate_fit(vb,b->flr[info->floorsubmap[submap]],
				   floor_posts[i][PACKETBLOBS/2],
				   floor_posts[i][PACKETBLOBS-1],
				   (k-PACKETBLOBS/2)*65536/(PACKETBLOBS/2));
      }
    }
  }
  vbi->ampmax=global_ampmax;

  /*
    the next phases are performed once for vbr-only and PACKETBLOB
    times for bitrate managed modes.
    
    1) encode actual mode being used
    2) encode the floor for each channel, compute coded mask curve/res
    3) normalize and couple.
    4) encode residue
    5) save packet bytes to the packetblob vector
    
  */

  /* iterate over the many masking curve fits we've created */

  {
    float **res_bundle=alloca(sizeof(*res_bundle)*vi->channels);
    float **couple_bundle=alloca(sizeof(*couple_bundle)*vi->channels);
    int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels);
    int **sortindex=alloca(sizeof(*sortindex)*vi->channels);
    float **mag_memo;
    int **mag_sort;

    if(info->coupling_steps){
      mag_memo=_vp_quantize_couple_memo(vb,
					&ci->psy_g_param,
					psy_look,
					info,
					gmdct);    
      
      mag_sort=_vp_quantize_couple_sort(vb,
					psy_look,
					info,
					mag_memo);    

      hf_reduction(&ci->psy_g_param,
		   psy_look,
		   info,
		   mag_memo);
    }

    memset(sortindex,0,sizeof(*sortindex)*vi->channels);
    if(psy_look->vi->normal_channel_p){
      for(i=0;i<vi->channels;i++){
	float *mdct    =gmdct[i];
	sortindex[i]=alloca(sizeof(**sortindex)*n/2);
	_vp_noise_normalize_sort(psy_look,mdct,sortindex[i]);
      }
    }

    for(k=(vorbis_bitrate_managed(vb)?0:PACKETBLOBS/2);
	k<=(vorbis_bitrate_managed(vb)?PACKETBLOBS-1:PACKETBLOBS/2);
	k++){
      oggpack_buffer *opb=vbi->packetblob[k];

      /* start out our new packet blob with packet type and mode */
      /* Encode the packet type */
      oggpack_write(opb,0,1);
      /* Encode the modenumber */
      /* Encode frame mode, pre,post windowsize, then dispatch */
      oggpack_write(opb,modenumber,b->modebits);
      if(vb->W){
	oggpack_write(opb,vb->lW,1);
	oggpack_write(opb,vb->nW,1);
      }

      /* encode floor, compute masking curve, sep out residue */
      for(i=0;i<vi->channels;i++){
	int submap=info->chmuxlist[i];
	float *mdct    =gmdct[i];
	float *res     =vb->pcm[i];
	int   *ilogmask=ilogmaskch[i]=
	  _vorbis_block_alloc(vb,n/2*sizeof(**gmdct));
      
	nonzero[i]=floor1_encode(opb,vb,b->flr[info->floorsubmap[submap]],
				 floor_posts[i][k],
				 ilogmask);
#if 0
	{
	  char buf[80];
	  sprintf(buf,"maskI%c%d",i?'R':'L',k);
	  float work[n/2];
	  for(j=0;j<n/2;j++)
	    work[j]=FLOOR1_fromdB_LOOKUP[ilogmask[j]];
	  _analysis_output(buf,seq,work,n/2,1,1,0);
	}
#endif
	_vp_remove_floor(psy_look,
			 mdct,
			 ilogmask,
			 res,
			 ci->psy_g_param.sliding_lowpass[vb->W][k]);

	_vp_noise_normalize(psy_look,res,res+n/2,sortindex[i]);

	
#if 0
	{
	  char buf[80];
	  float work[n/2];
	  for(j=0;j<n/2;j++)
	    work[j]=FLOOR1_fromdB_LOOKUP[ilogmask[j]]*(res+n/2)[j];
	  sprintf(buf,"resI%c%d",i?'R':'L',k);
	  _analysis_output(buf,seq,work,n/2,1,1,0);

	}
#endif
      }
      
      /* our iteration is now based on masking curve, not prequant and
	 coupling.  Only one prequant/coupling step */
      
      /* quantize/couple */
      /* incomplete implementation that assumes the tree is all depth
         one, or no tree at all */
      if(info->coupling_steps){
	_vp_couple(k,
		   &ci->psy_g_param,
		   psy_look,
		   info,
		   vb->pcm,
		   mag_memo,
		   mag_sort,
		   ilogmaskch,
		   nonzero,
		   ci->psy_g_param.sliding_lowpass[vb->W][k]);
      }
      
      /* classify and encode by submap */
      for(i=0;i<info->submaps;i++){
	int ch_in_bundle=0;
	long **classifications;
	int resnum=info->residuesubmap[i];

	for(j=0;j<vi->channels;j++){
	  if(info->chmuxlist[j]==i){
	    zerobundle[ch_in_bundle]=0;
	    if(nonzero[j])zerobundle[ch_in_bundle]=1;
	    res_bundle[ch_in_bundle]=vb->pcm[j];
	    couple_bundle[ch_in_bundle++]=vb->pcm[j]+n/2;
	  }
	}
	
	classifications=_residue_P[ci->residue_type[resnum]]->
	  class(vb,b->residue[resnum],couple_bundle,zerobundle,ch_in_bundle);
	
	_residue_P[ci->residue_type[resnum]]->
	  forward(opb,vb,b->residue[resnum],
		  couple_bundle,NULL,zerobundle,ch_in_bundle,classifications);
      }
      
      /* ok, done encoding.  Next protopacket. */
    }
    
  }

#if 0
  seq++;
  total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4;
#endif
  return(0);
}
Beispiel #21
0
int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){
  long i,j;
  int ordered=0;

  /* first the basic parameters */
  oggpack_write(opb,0x564342,24);
  oggpack_write(opb,c->dim,16);
  oggpack_write(opb,c->entries,24);

  /* pack the codewords.  There are two packings; length ordered and
     length random.  Decide between the two now. */

  for(i=1;i<c->entries;i++)
    if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break;
  if(i==c->entries)ordered=1;

  if(ordered){
    /* length ordered.  We only need to say how many codewords of
       each length.  The actual codewords are generated
       deterministically */

    long count=0;
    oggpack_write(opb,1,1);  /* ordered */
    oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */

    for(i=1;i<c->entries;i++){
      long thisx=c->lengthlist[i];
      long last=c->lengthlist[i-1];
      if(thisx>last){
	for(j=last;j<thisx;j++){
	  oggpack_write(opb,i-count,_ilog(c->entries-count));
	  count=i;
	}
      }
    }
    oggpack_write(opb,i-count,_ilog(c->entries-count));

  }else{
    /* length random.  Again, we don't code the codeword itself, just
       the length.  This time, though, we have to encode each length */
    oggpack_write(opb,0,1);   /* unordered */

    /* algortihmic mapping has use for 'unused entries', which we tag
       here.  The algorithmic mapping happens as usual, but the unused
       entry has no codeword. */
    for(i=0;i<c->entries;i++)
      if(c->lengthlist[i]==0)break;

    if(i==c->entries){
      oggpack_write(opb,0,1); /* no unused entries */
      for(i=0;i<c->entries;i++)
	oggpack_write(opb,c->lengthlist[i]-1,5);
    }else{
      oggpack_write(opb,1,1); /* we have unused entries; thus we tag */
      for(i=0;i<c->entries;i++){
	if(c->lengthlist[i]==0){
	  oggpack_write(opb,0,1);
	}else{
	  oggpack_write(opb,1,1);
	  oggpack_write(opb,c->lengthlist[i]-1,5);
	}
      }
    }
  }

  /* is the entry number the desired return value, or do we have a
     mapping? If we have a mapping, what type? */
  oggpack_write(opb,c->maptype,4);
  switch(c->maptype){
  case 0:
    /* no mapping */
    break;
  case 1:case 2:
    /* implicitly populated value mapping */
    /* explicitly populated value mapping */

    if(!c->quantlist){
      /* no quantlist?  error */
      return(-1);
    }

    /* values that define the dequantization */
    oggpack_write(opb,c->q_min,32);
    oggpack_write(opb,c->q_delta,32);
    oggpack_write(opb,c->q_quant-1,4);
    oggpack_write(opb,c->q_sequencep,1);

    {
      int quantvals;
      switch(c->maptype){
      case 1:
	/* a single column of (c->entries/c->dim) quantized values for
	   building a full value list algorithmically (square lattice) */
	quantvals=_book_maptype1_quantvals(c);
	break;
      case 2:
	/* every value (c->entries*c->dim total) specified explicitly */
	quantvals=c->entries*c->dim;
	break;
      default: /* NOT_REACHABLE */
	quantvals=-1;
      }

      /* quantized values */
      for(i=0;i<quantvals;i++)
	oggpack_write(opb,labs(c->quantlist[i]),c->q_quant);

    }
    break;
  default:
    /* error case; we don't have any other map types now */
    return(-1);
  }

  return(0);
}
JNIEXPORT void JNICALL Java_org_echocat_jogg_OggPackBufferJNI_write
    (JNIEnv *env, jclass thisClass, jlong handle, jlong value, jint bits) {

    oggpack_write((oggpack_buffer*) handle, value, bits);
}
/* Next two functions pulled straight from libvorbis, apart from one change
 * - we don't want to overwrite the vendor string.
 */
static void
_v_writestring (oggpack_buffer *o, const char *s, int len)
{
	while (len--)
		oggpack_write (o, *s++, 8);
}
Beispiel #24
0
static int floor1_forward(vorbis_block *vb,vorbis_look_floor *in,
			  float *mdct, const float *logmdct,   /* in */
			  const float *logmask, const float *logmax, /* in */
			  float *codedflr){          /* out */
  static int seq=0;
  long i,j,k,l;
  vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
  vorbis_info_floor1 *info=look->vi;
  long n=info->n;
  long posts=look->posts;
  long nonzero=0;
  lsfit_acc fits[VIF_POSIT+1];
  int fit_valueA[VIF_POSIT+2]; /* index by range list position */
  int fit_valueB[VIF_POSIT+2]; /* index by range list position */
  int fit_flag[VIF_POSIT+2];

  int loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */
  int hineighbor[VIF_POSIT+2]; 
  int memo[VIF_POSIT+2];
  codec_setup_info *ci=vb->vd->vi->codec_setup;
  static_codebook **sbooks=ci->book_param;
  codebook *books=NULL;
  int writeflag=0;

  if(vb->vd->backend_state){
    books=((backend_lookup_state *)(vb->vd->backend_state))->
      fullbooks;   
    writeflag=1;
  }

  memset(fit_flag,0,sizeof(fit_flag));
  for(i=0;i<posts;i++)loneighbor[i]=0; /* 0 for the implicit 0 post */
  for(i=0;i<posts;i++)hineighbor[i]=1; /* 1 for the implicit post at n */
  for(i=0;i<posts;i++)memo[i]=-1;      /* no neighbor yet */

  /* Scan back from high edge to first 'used' frequency */
  for(;n>info->unusedmin_n;n--)
    if(logmdct[n-1]>-floor1_rangedB && 
       logmdct[n-1]+info->twofitatten>logmask[n-1])break;

  /* quantize the relevant floor points and collect them into line fit
     structures (one per minimal division) at the same time */
  if(posts==0){
    nonzero+=accumulate_fit(logmask,logmax,0,n,fits,n,info);
  }else{
    for(i=0;i<posts-1;i++)
      nonzero+=accumulate_fit(logmask,logmax,look->sorted_index[i],
			      look->sorted_index[i+1],fits+i,
			      n,info);
  }
  
  if(nonzero){
    /* start by fitting the implicit base case.... */
    int y0=-200;
    int y1=-200;
    int mse=fit_line(fits,posts-1,&y0,&y1);
    if(mse<0){
      /* Only a single nonzero point */
      y0=-200;
      y1=0;
      fit_line(fits,posts-1,&y0,&y1);
    }

    fit_flag[0]=1;
    fit_flag[1]=1;
    fit_valueA[0]=y0;
    fit_valueB[0]=y0;
    fit_valueB[1]=y1;
    fit_valueA[1]=y1;

    if(mse>=0){
      /* Non degenerate case */
      /* start progressive splitting.  This is a greedy, non-optimal
	 algorithm, but simple and close enough to the best
	 answer. */
      for(i=2;i<posts;i++){
	int sortpos=look->reverse_index[i];
	int ln=loneighbor[sortpos];
	int hn=hineighbor[sortpos];

	/* eliminate repeat searches of a particular range with a memo */
	if(memo[ln]!=hn){
	  /* haven't performed this error search yet */
	  int lsortpos=look->reverse_index[ln];
	  int hsortpos=look->reverse_index[hn];
	  memo[ln]=hn;

	  /* if this is an empty segment, its endpoints don't matter.
	     Mark as such */
	  for(j=lsortpos;j<hsortpos;j++)
	    if(fits[j].un)break;
	  if(j==hsortpos){
	    /* empty segment; important to note that this does not
               break 0/n post case */
	    fit_valueB[ln]=-200;
	    if(fit_valueA[ln]<0)
	      fit_flag[ln]=0;
	    fit_valueA[hn]=-200;
	    if(fit_valueB[hn]<0)
	      fit_flag[hn]=0;
 
	  }else{
	    /* A note: we want to bound/minimize *local*, not global, error */
	    int lx=info->postlist[ln];
	    int hx=info->postlist[hn];	  
	    int ly=post_Y(fit_valueA,fit_valueB,ln);
	    int hy=post_Y(fit_valueA,fit_valueB,hn);
	    
	    if(inspect_error(lx,hx,ly,hy,logmask,logmdct,info)){
	      /* outside error bounds/begin search area.  Split it. */
	      int ly0=-200;
	      int ly1=-200;
	      int hy0=-200;
	      int hy1=-200;
	      int lmse=fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1);
	      int hmse=fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1);
	      
	      /* the boundary/sparsity cases are the hard part.  They
                 don't happen often given that we use the full mask
                 curve (weighted) now, but when they do happen they
                 can go boom. Pay them detailed attention */
	      /* cases for a segment:
		 >=0) normal fit (>=2 unique points)
		 -1) one point on x0;
		 one point on x1; <-- disallowed by fit_line
		 -2) one point in between x0 and x1
		 -3) no points */

	      switch(lmse){ 
	      case -2:  
		/* no points in the low segment */
		break;
	      case -1:
		ly0=fits[lsortpos].edgey0;
		break;
		/*default:
		  break;*/
	      }

	      switch(hmse){ 
	      case -2:  
		/* no points in the hi segment */
		break;
	      case -1:
		hy0=fits[sortpos].edgey0;
		break;
	      }

	      /* store new edge values */
	      fit_valueB[ln]=ly0;
	      if(ln==0 && ly0>=0)fit_valueA[ln]=ly0;
	      fit_valueA[i]=ly1;
	      fit_valueB[i]=hy0;
	      fit_valueA[hn]=hy1;
	      if(hn==1 && hy1>=0)fit_valueB[hn]=hy1;

	      if(ly0<0 && fit_valueA[ln]<0)
		fit_flag[ln]=0;
	      if(hy1<0 && fit_valueB[hn]<0)
		fit_flag[hn]=0;

	      if(ly1>=0 || hy0>=0){
		/* store new neighbor values */
		for(j=sortpos-1;j>=0;j--)
		  if(hineighbor[j]==hn)
		  hineighbor[j]=i;
		  else
		    break;
		for(j=sortpos+1;j<posts;j++)
		  if(loneighbor[j]==ln)
		    loneighbor[j]=i;
		  else
		    break;
		
		/* store flag (set) */
		fit_flag[i]=1;
	      }
	    }
	  }
	}
      }
    }

    /* quantize values to multiplier spec */
    switch(info->mult){
    case 1: /* 1024 -> 256 */
      for(i=0;i<posts;i++)
	if(fit_flag[i])
	  fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>2;
      break;
    case 2: /* 1024 -> 128 */
      for(i=0;i<posts;i++)
	if(fit_flag[i])
	  fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>3;
      break;
    case 3: /* 1024 -> 86 */
      for(i=0;i<posts;i++)
	if(fit_flag[i])
	  fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)/12;
      break;
    case 4: /* 1024 -> 64 */
      for(i=0;i<posts;i++)
	if(fit_flag[i])
	  fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>4;
      break;
    }

    /* find prediction values for each post and subtract them */
    for(i=2;i<posts;i++){
      int sp=look->reverse_index[i];
      int ln=look->loneighbor[i-2];
      int hn=look->hineighbor[i-2];
      int x0=info->postlist[ln];
      int x1=info->postlist[hn];
      int y0=fit_valueA[ln];
      int y1=fit_valueA[hn];
	
      int predicted=render_point(x0,x1,y0,y1,info->postlist[i]);
	
      if(fit_flag[i]){
	int headroom=(look->quant_q-predicted<predicted?
		      look->quant_q-predicted:predicted);
	
	int val=fit_valueA[i]-predicted;
	
	/* at this point the 'deviation' value is in the range +/- max
	   range, but the real, unique range can always be mapped to
	   only [0-maxrange).  So we want to wrap the deviation into
	   this limited range, but do it in the way that least screws
	   an essentially gaussian probability distribution. */
	
	if(val<0)
	  if(val<-headroom)
	    val=headroom-val-1;
	  else
	    val=-1-(val<<1);
	else
	  if(val>=headroom)
	    val= val+headroom;
	  else
	    val<<=1;
	
	fit_valueB[i]=val;
	
	/* unroll the neighbor arrays */
	for(j=sp+1;j<posts;j++)
	  if(loneighbor[j]==i)
	    loneighbor[j]=loneighbor[sp];
	  else
	    break;
	for(j=sp-1;j>=0;j--)
	  if(hineighbor[j]==i)
	    hineighbor[j]=hineighbor[sp];
	  else
	    break;
	
      }else{
	fit_valueA[i]=predicted;
	fit_valueB[i]=0;
      }
      if(fit_valueB[i]==0)
	fit_valueA[i]|=0x8000;
      else{
	fit_valueA[look->loneighbor[i-2]]&=0x7fff;
	fit_valueA[look->hineighbor[i-2]]&=0x7fff;
      }
    }

    /* we have everything we need. pack it out */
    /* mark nontrivial floor */
    if(writeflag){
      oggpack_write(&vb->opb,1,1);
      
      /* beginning/end post */
      look->frames++;
      look->postbits+=ilog(look->quant_q-1)*2;
      oggpack_write(&vb->opb,fit_valueA[0],ilog(look->quant_q-1));
      oggpack_write(&vb->opb,fit_valueA[1],ilog(look->quant_q-1));
      
      
      /* partition by partition */
      for(i=0,j=2;i<info->partitions;i++){
	int class=info->partitionclass[i];
	int cdim=info->class_dim[class];
	int csubbits=info->class_subs[class];
	int csub=1<<csubbits;
	int bookas[8]={0,0,0,0,0,0,0,0};
	int cval=0;
	int cshift=0;
	
	/* generate the partition's first stage cascade value */
	if(csubbits){
	  int maxval[8];
	  for(k=0;k<csub;k++){
	    int booknum=info->class_subbook[class][k];
	    if(booknum<0){
	      maxval[k]=1;
	    }else{
	      maxval[k]=sbooks[info->class_subbook[class][k]]->entries;
	    }
	  }
	  for(k=0;k<cdim;k++){
	    for(l=0;l<csub;l++){
	      int val=fit_valueB[j+k];
	      if(val<maxval[l]){
		bookas[k]=l;
		break;
	      }
	    }
	    cval|= bookas[k]<<cshift;
	    cshift+=csubbits;
	  }
	  /* write it */
	  look->phrasebits+=
	  vorbis_book_encode(books+info->class_book[class],cval,&vb->opb);
	  
#ifdef TRAIN_FLOOR1
	  {
	    FILE *of;
	    char buffer[80];
	    sprintf(buffer,"line_%ldx%ld_class%d.vqd",
		    vb->pcmend/2,posts-2,class);
	    of=fopen(buffer,"a");
	    fprintf(of,"%d\n",cval);
	    fclose(of);
	  }
#endif
	}
	
	/* write post values */
	for(k=0;k<cdim;k++){
	  int book=info->class_subbook[class][bookas[k]];
	  if(book>=0){
	    /* hack to allow training with 'bad' books */
	    if(fit_valueB[j+k]<(books+book)->entries)
	      look->postbits+=vorbis_book_encode(books+book,
						 fit_valueB[j+k],&vb->opb);
	    /*else
	      fprintf(stderr,"+!");*/

#ifdef TRAIN_FLOOR1
	    {
	      FILE *of;
	      char buffer[80];
	      sprintf(buffer,"line_%ldx%ld_%dsub%d.vqd",
		      vb->pcmend/2,posts-2,class,bookas[k]);
	      of=fopen(buffer,"a");
	      fprintf(of,"%d\n",fit_valueB[j+k]);
	      fclose(of);
	    }
#endif
	  }
	}
	j+=cdim;
      }
    }

    {
      /* generate quantized floor equivalent to what we'd unpack in decode */
      int hx;
      int lx=0;
      int ly=fit_valueA[0]*info->mult;

      for(j=1;j<posts;j++){
	int current=look->forward_index[j];
	if(!(fit_valueA[current]&0x8000)){
	  int hy=(fit_valueA[current]&0x7fff)*info->mult;
	  hx=info->postlist[current];
	  
	  render_line0(lx,hx,ly,hy,codedflr);
	  
	  lx=hx;
	  ly=hy;
	}
      }
      for(j=lx;j<vb->pcmend/2;j++)codedflr[j]=codedflr[j-1]; /* be certain */

      /* use it to create residue vector.  Eliminate mdct elements
         that were below the error training attenuation relative to
         the original mask.  This avoids portions of the floor fit
         that were considered 'unused' in fitting from being used in
         coding residue if the unfit values are significantly below
         the original input mask */

      for(j=0;j<n;j++)
	if(logmdct[j]+info->twofitatten<logmask[j])
	  mdct[j]=0.f;
      for(j=n;j<vb->pcmend/2;j++)mdct[j]=0.f;

    }    

  }else{
    if(writeflag)oggpack_write(&vb->opb,0,1);