[vorbis-dev] Peak value

Paul Martin pm at nowster.zetnet.co.uk
Tue Jan 22 10:14:46 PST 2002



On Tue, Jan 22, 2002 at 01:22:22PM +0100, Magnus Holmgren wrote:

> While testing ReplayGain (so it could be related to a bug), I noticed
> the following gain comments for a file:
> 
> RG_PEAK=1.71580

That's fairly high, but not unusual.

I regularly get peak values of 1.2 on recently released tracks (which
are heavily multi-band compressed). This happens with both ogg and mp3,
and is why the replay gain specification says that in calculating the
replay gain you must allow for overshoots without clipping.

I've suggested to the creator of replay gain that the peak value should
not be stored as a "fraction of maximum" but as the gain in dB that you
should use to get a normalised (maximum without clipping) output.

normalise_gain = - log10 (fabs (peak)) * 20.0;

Then you can use the same units (dB) in instructing your playback
engine, and choosing a gain value to use can become as simple as
min(radio_gain,normalise_gain).

Note that ogg123 and libvorbisfile's ov_read both will happily clip on
these files without reporting the fact.

<p>Suggested addition for libvorbisfile:

<p><p><p>/* gain is in decibels, and clipped is a boolean which indicates
   whether this block has any samples which have been clipped */

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

  float **pcm;
  float scale;
  long samples;

  *clipped = 0;
  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=_process_packet(vf,1);
      if(ret==OV_EOF)return(0);
      if(ret<=0)return(ret);
    }

  }

  if (word == 1) {
    scale = 128.f * pow(10.0,gain/20.0);
  } else {
    scale = 32768.f * pow(10.0,gain/20.0);
  }

  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;
    
    /* a tight loop to pack each size */
    {
      int val;
      if(word==1){
        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; *clipped=1;}
            else if(val<-128){val=-128; *clipped=1;}
            *buffer++=val+off;
          }
        vorbis_fpu_restore(fpu);
      }else{
        int off=(sgned?0:32768);
        
        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; *clipped=1;}
                else if(val<-32768){val=-32768; *clipped=1;}
                *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; *clipped=1;}
                else if(val<-32768){val=-32768; *clipped=1;}
                *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; *clipped=1;}
              else if(val<-32768){val=-32768; *clipped=1;}
              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; *clipped=1;}
              else if(val<-32768){val=-32768; *clipped=1;}
              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><p><p><p><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