[vorbis-dev] replaygain support

Paul Martin pm at nowster.zetnet.co.uk
Wed Nov 26 13:47:28 PST 2003



On Wed, Nov 26, 2003 at 08:18:33PM +0300, Jack Pavlovsky wrote:

> So, is there any consensus among libvorbisfile developers as what to do 
> with replaygain?

Just adding gain support to libvorbisfile would help. Not hard:

/* ov_read_gain

   input values: buffer) a buffer to hold packed PCM data for return
                 length) the byte length requested to be placed into buffer
                 gain) gain adjustment to be applied, in decibels
                 bigendianp) should the data be packed LSB first (0) or
                             MSB first (1)
                 word) word size for output.  currently 1 (byte) or 
                       2 (16 bit short)

   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
                   0) EOF
                   n) number of bytes of PCM actually returned.  The
                   below works on a packet-by-packet basis, so the
                   return length is not related to the 'length' passed
                   in, just guaranteed to fit.

            *section) set to the logical bitstream number */

<p>long ov_read_gain(OggVorbis_File *vf,char *buffer,int length, float gain,
                    int bigendianp,int word,int sgned,int *bitstream){
  int i,j;
  int host_endian = host_is_big_endian();

  float **pcm;
  long samples;

  if(vf->ready_state<OPENED)return(OV_EINVAL);

  while(1){
    if(vf->ready_state>=STREAMSET){
      samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
      if(samples)break;
    }

    /* suck in another packet */
    {
      int ret=_fetch_and_process_packet(vf,NULL,1);
      if(ret==OV_EOF)return(0);
      if(ret<=0)return(ret);
    }

  }

  if(samples>0){
  
    /* yay! proceed to pack data into the byte buffer */
    
    long channels=ov_info(vf,-1)->channels;
    long bytespersample=word * channels;
    vorbis_fpu_control fpu;
    if(samples>length/bytespersample)samples=length/bytespersample;

    if(samples <= 0)
      return OV_EINVAL;
    
    /* a tight loop to pack each size */
    {
      int val;
      if(word==1){
        float scale = 128.0f * powf(10.0f,gain/20.0f);
        int off=(sgned?0:128);
        vorbis_fpu_setround(&fpu);
        for(j=0;j<samples;j++)
          for(i=0;i<channels;i++){
            val=vorbis_ftoi(pcm[i][j]*scale);
            if(val>127)val=127;
            else if(val<-128)val=-128;
            *buffer++=val+off;
          }
        vorbis_fpu_restore(fpu);
      }else{
        int off=(sgned?0:32768);
        float scale = 32768.0f * powf(10.0f,gain/20.0f);
        
        if(host_endian==bigendianp){
          if(sgned){
            
            vorbis_fpu_setround(&fpu);
            for(i=0;i<channels;i++) { /* It's faster in this order */
              float *src=pcm[i];
              short *dest=((short *)buffer)+i;
              for(j=0;j<samples;j++) {
                val=vorbis_ftoi(src[j]*scale);
                if(val>32767)val=32767;
                else if(val<-32768)val=-32768;
                *dest=val;
                dest+=channels;
              }
            }
            vorbis_fpu_restore(fpu);
            
          }else{
            
            vorbis_fpu_setround(&fpu);
            for(i=0;i<channels;i++) {
              float *src=pcm[i];
              short *dest=((short *)buffer)+i;
              for(j=0;j<samples;j++) {
                val=vorbis_ftoi(src[j]*scale);
                if(val>32767)val=32767;
                else if(val<-32768)val=-32768;
                *dest=val+off;
                dest+=channels;
              }
            }
            vorbis_fpu_restore(fpu);
            
          }
        }else if(bigendianp){
          
          vorbis_fpu_setround(&fpu);
          for(j=0;j<samples;j++)
            for(i=0;i<channels;i++){
              val=vorbis_ftoi(pcm[i][j]*scale);
              if(val>32767)val=32767;
              else if(val<-32768)val=-32768;
              val+=off;
              *buffer++=(val>>8);
              *buffer++=(val&0xff);
            }
          vorbis_fpu_restore(fpu);
          
        }else{
          int val;
          vorbis_fpu_setround(&fpu);
          for(j=0;j<samples;j++)
            for(i=0;i<channels;i++){
              val=vorbis_ftoi(pcm[i][j]*scale);
              if(val>32767)val=32767;
              else if(val<-32768)val=-32768;
              val+=off;
              *buffer++=(val&0xff);
              *buffer++=(val>>8);
                }
          vorbis_fpu_restore(fpu);  
          
        }
      }
    }
    
    vorbis_synthesis_read(&vf->vd,samples);
    vf->pcm_offset+=samples;
    if(bitstream)*bitstream=vf->current_link;
    return(samples*bytespersample);
  }else{
    return(samples);
  }
}

<p><p>ov_read then can be a lot shorter:

long ov_read(OggVorbis_File *vf,char *buffer,int length,
                    int bigendianp,int word,int sgned,int *bitstream){

  return ov_read_gain(vf, buffer, length, 0.0f,
                    bigendianp, word, sgned, bitstream){

}

<p>
-- 
Paul Martin <pm at zetnet.net> (work)
  <pm at nowster.zetnet.co.uk> (home)
--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'vorbis-dev-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.




More information about the Vorbis-dev mailing list