shithub: opusfile

Download patch

ref: 2bb99f3cf0119a43884cb7c04fb5dc8c3aec61fc
parent: 661459b4aad3511e28976d8dfd84e02b36cc3d63
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Tue Dec 29 09:36:25 EST 2015

Add support for R128_ALBUM_GAIN tag.

This includes convenience routines specifying the album gain should
 be applied and for parsing the tag.

--- a/include/opusfile.h
+++ b/include/opusfile.h
@@ -531,6 +531,24 @@
 int opus_tags_query_count(const OpusTags *_tags,const char *_tag)
  OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
 
+/**Get the album gain from an R128_ALBUM_GAIN tag, if one was specified.
+   This searches for the first R128_ALBUM_GAIN tag with a valid signed,
+    16-bit decimal integer value and returns the value.
+   This routine is exposed merely for convenience for applications which wish
+    to do something special with the album gain (i.e., display it).
+   If you simply wish to apply the album gain instead of the header gain, you
+    can use op_set_gain_offset() with an #OP_ALBUM_GAIN type and no offset.
+   \param      _tags    An initialized #OpusTags structure.
+   \param[out] _gain_q8 The album gain, in 1/256ths of a dB.
+                        This will lie in the range [-32768,32767], and should
+                         be applied in <em>addition</em> to the header gain.
+                        On error, no value is returned, and the previous
+                         contents remain unchanged.
+   \return 0 on success, or a negative value on error.
+   \retval #OP_FALSE There was no album gain available in the given tags.*/
+int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
 /**Get the track gain from an R128_TRACK_GAIN tag, if one was specified.
    This searches for the first R128_TRACK_GAIN tag with a valid signed,
     16-bit decimal integer value and returns the value.
@@ -1763,6 +1781,10 @@
 #define OP_HEADER_GAIN   (0)
 
 /**Gain offset type that indicates that the provided offset is relative to the
+    R128_ALBUM_GAIN value (if any), in addition to the header gain.*/
+#define OP_ALBUM_GAIN    (3007)
+
+/**Gain offset type that indicates that the provided offset is relative to the
     R128_TRACK_GAIN value (if any), in addition to the header gain.*/
 #define OP_TRACK_GAIN    (3008)
 
@@ -1782,8 +1804,8 @@
    It is meant for setting a target volume level, rather than applying smooth
     fades, etc.
    \param _of             The \c OggOpusFile on which to set the gain offset.
-   \param _gain_type      One of #OP_HEADER_GAIN, #OP_TRACK_GAIN, or
-                           #OP_ABSOLUTE_GAIN.
+   \param _gain_type      One of #OP_HEADER_GAIN, #OP_ALBUM_GAIN,
+                           #OP_TRACK_GAIN, or #OP_ABSOLUTE_GAIN.
    \param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB.
    \return 0 on success or a negative value on error.
    \retval #OP_EINVAL The \a _gain_type was unrecognized.*/
--- a/src/info.c
+++ b/src/info.c
@@ -332,19 +332,20 @@
   return found;
 }
 
-int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
+static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
+ const char *_tag_name,size_t _tag_len){
   char **comments;
   int    ncomments;
   int    ci;
   comments=_tags->user_comments;
   ncomments=_tags->comments;
-  /*Look for the first valid R128_TRACK_GAIN tag and use that.*/
+  /*Look for the first valid tag with the name _tag_name and use that.*/
   for(ci=0;ci<ncomments;ci++){
-    if(opus_tagncompare("R128_TRACK_GAIN",15,comments[ci])==0){
+    if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){
       char       *p;
       opus_int32  gain_q8;
       int         negative;
-      p=comments[ci]+16;
+      p=comments[ci]+_tag_len+1;
       negative=0;
       if(*p=='-'){
         negative=-1;
@@ -358,7 +359,7 @@
         p++;
       }
       /*This didn't look like a signed 16-bit decimal integer.
-        Not a valid R128_TRACK_GAIN tag.*/
+        Not a valid gain tag.*/
       if(*p!='\0')continue;
       *_gain_q8=(int)(gain_q8+negative^negative);
       return 0;
@@ -365,6 +366,14 @@
     }
   }
   return OP_FALSE;
+}
+
+int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){
+  return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15);
+}
+
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
+  return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15);
 }
 
 static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -1307,13 +1307,20 @@
      track gain must lie in the range [-32768,32767], and the user-supplied
      offset has been pre-clamped to [-98302,98303].*/
   switch(_of->gain_type){
+    case OP_ALBUM_GAIN:{
+      int album_gain_q8;
+      album_gain_q8=0;
+      opus_tags_get_album_gain(&_of->links[li].tags,&album_gain_q8);
+      gain_q8+=album_gain_q8;
+      gain_q8+=head->output_gain;
+    }break;
     case OP_TRACK_GAIN:{
       int track_gain_q8;
       track_gain_q8=0;
       opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8);
       gain_q8+=track_gain_q8;
-    }
-    /*Fall through.*/
+      gain_q8+=head->output_gain;
+    }break;
     case OP_HEADER_GAIN:gain_q8+=head->output_gain;break;
     case OP_ABSOLUTE_GAIN:break;
     default:OP_ASSERT(0);
@@ -2666,8 +2673,8 @@
 
 int op_set_gain_offset(OggOpusFile *_of,
  int _gain_type,opus_int32 _gain_offset_q8){
-  if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_TRACK_GAIN
-   &&_gain_type!=OP_ABSOLUTE_GAIN){
+  if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_ALBUM_GAIN
+   &&_gain_type!=OP_TRACK_GAIN&&_gain_type!=OP_ABSOLUTE_GAIN){
     return OP_EINVAL;
   }
   _of->gain_type=_gain_type;