You are here: Home Radio Resources Libradio Ogg Vorbis Patch
Document Actions

Libradio Ogg Vorbis Patch

Click here to get the file

Size 10.7 kB - File type text/x-patch

File contents

Index: ChangeLog
===================================================================
RCS file: /home/cvs/srl/libradio/ChangeLog,v
retrieving revision 1.366
diff -u -B -b -w -r1.366 ChangeLog
--- ChangeLog	15 Dec 2006 21:04:13 -0000	1.366
+++ ChangeLog	27 Dec 2006 00:01:46 -0000
@@ -1372,3 +1372,8 @@
 2006-12-15 Fred Gleason <fredg@salemradiolabs.com>
 	* Added a BNV_HAVE_QT macro in 'autoinclude.m4'.
 	* Modified the build system to autodetect the presence of Qt.
+2006-12-18 Darrick Servis <darrick@dcn.org>
+	* Added Stefans patch to handle energy data cache files for oggvorbis
+	encoding.
+2006-12-26
+        * Added error checking to ReadEnergyFile() in radio/rwavefile.cpp.
Index: radio/rwavefile.cpp
===================================================================
RCS file: /home/cvs/srl/libradio/radio/rwavefile.cpp,v
retrieving revision 1.58
diff -u -B -b -w -r1.58 rwavefile.cpp
--- radio/rwavefile.cpp	20 Oct 2006 17:12:31 -0000	1.58
+++ radio/rwavefile.cpp	27 Dec 2006 00:01:46 -0000
@@ -52,6 +52,8 @@
   recordable=false;
   format_chunk=false;
   format_tag=0;
+  energy_tag=0;
+  normalize_level=1.0;
   channels=0;
   samples_per_sec=0;
   avg_bytes_per_sec=0;
@@ -287,7 +289,9 @@
 	time_length=(unsigned)ov_time_total(&vorbis_file,-1);
 	data_chunk=true;
 	format_chunk=true;
+	ReadEnergyFile(wave_file.name());
 	wave_type=RWaveFile::Ogg;
+	ReadOggMetadata();
 	return true;
 #else
 	return false;
@@ -432,6 +436,10 @@
 
       case WAVE_FORMAT_VORBIS:
 #ifdef HAVE_VORBIS
+	energy_data.clear();
+	for(int i=0;i<channels;i++) {
+	  energy_data.push_back(0);
+	}
 	avg_bytes_per_sec=2*channels*samples_per_sec;
 	vorbis_info_init(&vorbis_inf);
 	if(vorbis_encode_init_vbr(&vorbis_inf,channels,samples_per_sec,
@@ -491,8 +499,54 @@
   unsigned csize;
   unsigned lsize=0;
   unsigned cptr;
+  QFile energy_file;
+  QString str;
+  mode_t prev_mask;
+  bool rc;
+
 
   if(recordable) {
+     if(energy_tag==1) {
+        // Calculate peak amplitude.  
+        //
+        // The way sox does this:
+        // - Find the sample with the highest value.  
+        // Should be looking at minimum values too and take the absolute value.
+        double peak_level = 0;
+        for(unsigned i=0;i<energy_data.size();i++) {
+           if(energy_data[i] > peak_level) {
+               peak_level = energy_data[i]; 
+           }
+        }
+        // - Then we need a ratio to multiple all our samples by.  i.e.
+        // vol_scale * sample will never be greater then SIGNED_SHORT_MAX.
+        double vol_scale = 32768.0f/peak_level; 
+        // - Then we want to allow for adjusting the volume so it's not so full on loud.  
+        // Like set it 13db below the max.  This is where the user selectable level comes in.
+        normalize_level = normalize_level*vol_scale;
+        if( normalize_level==0){
+           normalize_level=1.0f;
+        }else{
+           for(unsigned i=0;i<energy_data.size();i++) {
+              energy_data[i] *= normalize_level;
+           }
+        }
+        // I Propose the normalize_level here is the same as sent to rd_import_file.
+        // i.e. normal=pow(10.0,(double)(library_conf->ripperLevel())/20.0);
+        // failing that change it to a int and set the normalize_level to ripperLevel() and 
+        // keep the gory details of converting that to double within this library.
+        str=str.sprintf("%f\n",normalize_level);
+        energy_file.setName(wave_file.name()+".energy");
+        energy_file.remove();
+        prev_mask = umask(0113);      // Set umask so files are user and group writable.
+        rc=energy_file.open(IO_ReadWrite);
+        umask(prev_mask);
+        if(rc) {
+           write(energy_file.handle(),(const char*)str,strlen(str));
+           write(energy_file.handle(),&(energy_data[0]),2*energy_data.size());
+           energy_file.close();
+        }
+     }
     switch(wave_type) {
 	case RWaveFile::Wave:
 	  //
@@ -632,6 +686,8 @@
   time_length=0;
   format_chunk=false;
   format_tag=0;
+  energy_tag=0;
+  normalize_level=1.0;
   channels=0;
   samples_per_sec=0;
   avg_bytes_per_sec=0;
@@ -816,11 +872,23 @@
   int stream;
   int n;
   unsigned int pos;
+  int16_t *sample;
 
   switch(wave_type) {
       case RWaveFile::Ogg:
 #ifdef HAVE_VORBIS
-	n=ov_read(&vorbis_file,(char *)buf,count,0,2,1,&stream);
+	      n = 0;
+	      while(n!=count){
+		    int ret = ov_read(&vorbis_file,(char *)buf+n,count-n,0,2,1,&stream);
+		    if (!ret) break;
+		    n+=ret;
+	      }
+           if(normalize_level != 1.0f){
+	      for (int i=0;i<n/2;i++) {
+             sample=(int16_t *)buf+i;
+            *sample=(int16_t)(normalize_level*(double)*sample);
+	      }
+           }
 	return n;
 #endif  // HAVE_VORBIS
 	return 0;
@@ -951,6 +1019,55 @@
 	return write(wave_file.handle(),buf,count);
 
       case WAVE_FORMAT_VORBIS:
+	  for(int i=0;i<count;i++) {
+	    switch(levl_istate) {
+		case 0:   // Left Channel, LSB
+		  levl_accum=((char *)buf)[i]&0xff;
+		  levl_istate=1;
+		  break;
+
+		case 1:   // Left Channel, MSB
+		  levl_accum|=((((char *)buf)[i]&0xff)<<8);
+		  switch(channels) {
+		      case 1:
+			if(levl_accum>energy_data[energy_data.size()-1]) {
+			  energy_data[energy_data.size()-1]=levl_accum;
+			}
+			if(++levl_block_ptr==1152) {
+			  energy_data.push_back(0);
+			  levl_block_ptr=0;
+			}
+			levl_istate=0;
+			break;
+
+		      case 2:
+			if(levl_accum>energy_data[energy_data.size()-2]) {
+			  energy_data[energy_data.size()-2]=levl_accum;
+			}
+			levl_istate=2;
+			break;
+		  }
+		  break;
+
+		case 2:   // Right Channel, LSB
+		  levl_accum=((char *)buf)[i]&0xff;
+		  levl_istate=3;
+		  break;
+
+		case 3:   // Right Channel, MSB
+		  levl_accum|=((((char *)buf)[i]&0xff)<<8);
+		  if(levl_accum>energy_data[energy_data.size()-1]) {
+		    energy_data[energy_data.size()-1]=levl_accum;
+		  }
+		  if(++levl_block_ptr==1152) {
+		    energy_data.push_back(0);
+		    energy_data.push_back(0);
+		    levl_block_ptr=0;
+		  }
+		  levl_istate=0;
+		  break;
+	    }
+	  }
 	WriteOggBuffer((char *)buf,count);
 	break;
   }
@@ -1130,6 +1247,30 @@
 }
 
 
+void RWaveFile::setEnergyTag(int format)
+{
+  energy_tag=format;
+}
+
+
+int RWaveFile::getEnergyTag() const
+{
+  return energy_tag;
+}
+
+
+double RWaveFile::getNormalizeLevel() const
+{
+  return normalize_level;
+}
+
+
+void RWaveFile::setNormalizeLevel(double level)
+{
+  normalize_level=level;
+}
+
+
 unsigned short RWaveFile::getChannels() const
 {
   return channels;
@@ -2322,6 +2463,35 @@
 }
 
 
+
+bool RWaveFile::ReadEnergyFile(QString wave_file_name)
+{
+   if(has_energy && energy_loaded) return true;
+  QFile energy_file;
+  QString str;
+  unsigned char frame[50];
+
+  energy_file.setName(wave_file_name+".energy");
+  if(!energy_file.open(IO_ReadOnly)) 
+    return false;
+  if(energy_file.readLine(str,20) <= 0)
+     return false;
+  normalize_level=str.toDouble();
+  energy_file.close();
+  if(!energy_file.open(IO_ReadOnly)) 
+    return false;
+  read(energy_file.handle(),frame,str.length());
+  for(unsigned i=1;i<((getSampleLength()*getChannels()/1152));i++) {
+    if(read(energy_file.handle(),frame,2) != 2) return false;
+    energy_data.push_back(frame[0]+256*frame[1]);
+  }
+  energy_file.close();
+  energy_loaded=true;
+  has_energy=true;
+  return true;
+}
+
+
 bool RWaveFile::GetLevl(int fd)
 {
   unsigned size=LEVL_CHUNK_SIZE;
@@ -2587,6 +2757,23 @@
 }
 
 
+void RWaveFile::ReadOggMetadata()
+{
+ /* if(wave_data==NULL) {
+    return;
+  }
+  TagLib::FileRef f(wave_file.name());
+  if(!f.isNull() && f.tag()){
+    TagLib::Tag *tag=f.tag();
+    wave_data->setTitle(TStringToQString(tag->title()));
+    wave_data->setArtist(TStringToQString(tag->artist()));
+    wave_data->setAlbum(TStringToQString(tag->album()));
+    wave_data->setReleaseYear((int)tag->year());
+    wave_data->setMetadataFound(true);
+  } */
+}
+
+
 void RWaveFile::ReadId3Metadata()
 {
   if(wave_data==NULL) {
@@ -3652,6 +3839,29 @@
 	return i;
 	break;
 
+      case WAVE_FORMAT_VORBIS:
+	block_size=2304*channels;
+	while(i<energy_size) {
+	  if(readWave(pcm,block_size)!=block_size) {
+	    has_energy=true;
+	    return i;
+	  }
+	  for(int j=0;j<channels;j++) {
+	    max=0;
+	    energy_data.push_back(0);
+	    for(int k=0;k<1152;k++) {
+	      offset=2*k*channels+2*j;
+	      if((pcm[offset]+256*pcm[offset+1])>energy_data[i]) {
+		energy_data[i]=pcm[offset]+256*pcm[offset+1];
+	      }
+	    }
+	    i++;
+	  }
+	}
+	has_energy=true;
+	return i;
+	break;
+
       default:
 	has_energy=false;
 	return 0;
@@ -3697,9 +3907,13 @@
 	high=buffer[j][i];
       }
 */
+	    buffer[j][i] = ((buf[i*2*channels + 2*j + 1]<<8) |
+			    (buf[i*2*channels + 2*j] & 0xff))/32768.0f;
+            /* My compilier doesn't like these casts.
       buffer[j][i]=
 	((float)(buf[2*channels*i+2*j]&0xff)+
 	 (256.0f*(float)(buf[2*channels*i+2*j+1]&0xff)))/32768.0f;
+         */
     }
 //    printf("HIGH: %5.3f\n",high);
   }
Index: radio/rwavefile.h
===================================================================
RCS file: /home/cvs/srl/libradio/radio/rwavefile.h,v
retrieving revision 1.31
diff -u -B -b -w -r1.31 rwavefile.h
--- radio/rwavefile.h	19 Oct 2006 12:40:52 -0000	1.31
+++ radio/rwavefile.h	27 Dec 2006 00:01:46 -0000
@@ -311,6 +311,18 @@
    **/
    void setFormatTag(unsigned short format);
 
+   void setEnergyTag(int format);
+   int getEnergyTag() const;
+
+   /**
+    * <level> = Normalization level, expressed as linear ratio (0 = No normalization)
+    */
+   double getNormalizeLevel() const;
+
+
+   void setNormalizeLevel(double level);
+
+
   /**
    * Returns the number of audio channels recorded in the WAV file, as 
    * represented by the 'FMT chunk.
@@ -1031,12 +1043,14 @@
    bool GetBext(int);
    bool GetMext(int);
    bool GetLevl(int);
+   bool ReadEnergyFile (QString);
    bool GetList(int);
    bool ReadListElement(unsigned char *buffer,unsigned *offset,unsigned size);
    bool ReadTmcMetadata(int);
    void ReadTmcTag(const QString tag,const QString value);
    bool GetLine(int fd,char *buffer,int max_len);
    void ReadId3Metadata();
+   void ReadOggMetadata();
    bool GetMpegHeader(int fd,int offset);
    int GetAtxOffset(int fd);
    bool GetFlacStreamInfo();
@@ -1064,6 +1078,7 @@
    unsigned ext_time_length;       // Audio length in msec
    bool format_chunk;              // Does 'fmt ' chunk exist?
    unsigned short format_tag;      // Encoding Format
+   int energy_tag;	           // 0: Include Energy Data 1: Extra File
    unsigned short channels;        // Number of channels
    unsigned samples_per_sec;       // Samples/sec/channel
    unsigned avg_bytes_per_sec;     // Average bytes/sec overall
@@ -1173,6 +1188,7 @@
    float encode_quality;
    int serial_number;
    int atx_offset;
+   double normalize_level;
 #ifdef HAVE_VORBIS
    OggVorbis_File vorbis_file;
    vorbis_info vorbis_inf;

© 2005 KDRT 101.5 FM • Davis, California