]> granicus.if.org Git - handbrake/commitdiff
Add audio gain adjustment to libhb and CLI
authorjstebbins <jstebbins.hb@gmail.com>
Tue, 5 Apr 2011 20:42:40 +0000 (20:42 +0000)
committerjstebbins <jstebbins.hb@gmail.com>
Tue, 5 Apr 2011 20:42:40 +0000 (20:42 +0000)
New CLI option is --gain <float>.  Value is measured in dB.  Negative values are
quieter, positive values are louder.

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3902 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/common.c
libhb/common.h
libhb/sync.c
libhb/work.c
test/test.c

index 2387aa4ef85900f06190606a26b81c1e367bf33b..4c382e57cdd1b218078d9893b1687c0634854a72 100644 (file)
@@ -1222,6 +1222,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg)
         audio->config.out.bitrate = audiocfg->out.bitrate;
         audio->config.out.dynamic_range_compression = audiocfg->out.dynamic_range_compression;
         audio->config.out.mixdown = audiocfg->out.mixdown;
+        audio->config.out.gain = audiocfg->out.gain;
     }
 
     hb_list_add(job->list_audio, audio);
index a3461e864ffd511548ccfc4c16be37c78d6f62a2..bb0c219cbd0bb9dffc20e95a7225419c1abb7ab0 100644 (file)
@@ -399,6 +399,7 @@ struct hb_audio_config_s
             int bitrate;    /* Output bitrate (kbps) */
             int mixdown;    /* The mixdown format to be used for this audio track (see HB_AMIXDOWN_*) */
             double dynamic_range_compression; /* Amount of DRC that gets applied to this track */
+            double gain;    /* Gain in dB. negative is quieter */
             char * name;    /* Output track name */
     } out;
 
index 7061aa1dafaa3aea81e5b0b311f8f318ee0351a5..19ee605f028542e739f9da0c998582a27db6664f 100644 (file)
@@ -47,6 +47,8 @@ typedef struct
     /* AC-3 */
     int          ac3_size;
     uint8_t    * ac3_buf;
+
+    double       gain_factor;
 } hb_sync_audio_t;
 
 typedef struct
@@ -1024,6 +1026,8 @@ hb_work_object_t hb_sync_audio =
     syncAudioClose
 };
 
+#define LVL_PLUS1DB 1.122462048
+
 static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
 {
     hb_work_object_t  * w;
@@ -1101,6 +1105,9 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
                 w->audio->config.out.mixdown), &error );
         sync->data.end_of_input = 0;
     }
+
+    sync->gain_factor = pow(LVL_PLUS1DB, w->audio->config.out.gain);
+
     hb_list_add( job->list_work, w );
 }
 
@@ -1110,54 +1117,81 @@ static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf,
     int64_t start = (int64_t)sync->next_start;
     double duration = buf->stop - buf->start;
 
-    if( audio->config.in.samplerate == audio->config.out.samplerate ||
-        audio->config.out.codec == HB_ACODEC_AC3_PASS ||
-        audio->config.out.codec == HB_ACODEC_DCA_PASS )
-    {
-        /*
-         * If we don't have to do sample rate conversion or this audio is 
-         * pass-thru just send the input buffer downstream after adjusting
-         * its timestamps to make the output stream continuous.
-         */
-    }
-    else
+    if ( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) )
     {
-        /* Not pass-thru - do sample rate conversion */
-        int count_in, count_out;
-        hb_buffer_t * buf_raw = buf;
-        int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown) *
-                            sizeof( float );
+        // Audio is not passthru.  Check if we need to modify the audio
+        // in any way.
+        if( audio->config.in.samplerate != audio->config.out.samplerate )
+        {
+            /* do sample rate conversion */
+            int count_in, count_out;
+            hb_buffer_t * buf_raw = buf;
+            int channel_count = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown) *
+                                sizeof( float );
 
-        count_in  = buf_raw->size / channel_count;
-        /*
-         * When using stupid rates like 44.1 there will always be some
-         * truncation error. E.g., a 1536 sample AC3 frame will turn into a
-         * 1536*44.1/48.0 = 1411.2 sample frame. If we just truncate the .2
-         * the error will build up over time and eventually the audio will
-         * substantially lag the video. libsamplerate will keep track of the
-         * fractional sample & give it to us when appropriate if we give it
-         * an extra sample of space in the output buffer.
-         */
-        count_out = ( duration * audio->config.out.samplerate ) / 90000 + 1;
+            count_in  = buf_raw->size / channel_count;
+            /*
+             * When using stupid rates like 44.1 there will always be some
+             * truncation error. E.g., a 1536 sample AC3 frame will turn into a
+             * 1536*44.1/48.0 = 1411.2 sample frame. If we just truncate the .2
+             * the error will build up over time and eventually the audio will
+             * substantially lag the video. libsamplerate will keep track of the
+             * fractional sample & give it to us when appropriate if we give it
+             * an extra sample of space in the output buffer.
+             */
+            count_out = ( duration * audio->config.out.samplerate ) / 90000 + 1;
 
-        sync->data.input_frames = count_in;
-        sync->data.output_frames = count_out;
-        sync->data.src_ratio = (double)audio->config.out.samplerate /
-                               (double)audio->config.in.samplerate;
+            sync->data.input_frames = count_in;
+            sync->data.output_frames = count_out;
+            sync->data.src_ratio = (double)audio->config.out.samplerate /
+                                   (double)audio->config.in.samplerate;
 
-        buf = hb_buffer_init( count_out * channel_count );
-        sync->data.data_in  = (float *) buf_raw->data;
-        sync->data.data_out = (float *) buf->data;
-        if( src_process( sync->state, &sync->data ) )
+            buf = hb_buffer_init( count_out * channel_count );
+            sync->data.data_in  = (float *) buf_raw->data;
+            sync->data.data_out = (float *) buf->data;
+            if( src_process( sync->state, &sync->data ) )
+            {
+                /* XXX If this happens, we're screwed */
+                hb_log( "sync: audio 0x%x src_process failed", audio->id );
+            }
+            hb_buffer_close( &buf_raw );
+
+            buf->size = sync->data.output_frames_gen * channel_count;
+            duration = (double)( sync->data.output_frames_gen * 90000 ) /
+                       audio->config.out.samplerate;
+        }
+        if( audio->config.out.gain > 0.0 )
         {
-            /* XXX If this happens, we're screwed */
-            hb_log( "sync: audio 0x%x src_process failed", audio->id );
+            int count, ii;
+
+            count  = buf->size / sizeof(float);
+            for ( ii = 0; ii < count; ii++ )
+            {
+                double sample;
+
+                sample = (double)*(((float*)buf->data)+ii);
+                sample *= sync->gain_factor;
+                if (sample > 0)
+                    sample = MIN(sample, 32767.0);
+                else
+                    sample = MAX(sample, -32768.0);
+                *(((float*)buf->data)+ii) = sample;
+            }
         }
-        hb_buffer_close( &buf_raw );
+        else if( audio->config.out.gain < 0.0 )
+        {
+            int count, ii;
 
-        buf->size = sync->data.output_frames_gen * channel_count;
-        duration = (double)( sync->data.output_frames_gen * 90000 ) /
-                   audio->config.out.samplerate;
+            count  = buf->size / sizeof(float);
+            for ( ii = 0; ii < count; ii++ )
+            {
+                double sample;
+
+                sample = (double)*(((float*)buf->data)+ii);
+                sample *= sync->gain_factor;
+                *(((float*)buf->data)+ii) = sample;
+            }
+        }
     }
     buf->frametype = HB_FRAME_AUDIO;
     buf->start = start;
index 11b8d27c4fc511d224271a81a0053dd3318fdfc7..8c182fa66edda8a21b9c961cadf1782d9e33cb51 100644 (file)
@@ -347,6 +347,10 @@ void hb_display_job_info( hb_job_t * job )
                         break;
                     }
                 }
+                if ( audio->config.out.gain != 0.0 )
+                {
+                    hb_log( "   + gain: %.fdB", audio->config.out.gain );
+                }
             }
 
             if ( audio->config.out.dynamic_range_compression && (audio->config.out.codec != HB_ACODEC_AC3_PASS) && (audio->config.out.codec != HB_ACODEC_DCA_PASS))
index 97ecfd3e9fa9a79a5e3f39c57a77f0f5ff5590b0..33cc9e7e8f9a7570cb95c4941e497b8c75010ae2 100644 (file)
@@ -67,6 +67,7 @@ static hb_audio_config_t * audio = NULL;
 static int    num_audio_tracks = 0;
 static char * mixdowns    = NULL;
 static char * dynamic_range_compression = NULL;
+static char * audio_gain  = NULL;
 static char * atracks     = NULL;
 static char * arates      = NULL;
 static char * abitrates   = NULL;
@@ -346,6 +347,7 @@ int main( int argc, char ** argv )
     }
     if( mixdowns ) free( mixdowns );
     if( dynamic_range_compression ) free( dynamic_range_compression );
+    if( audio_gain ) free( audio_gain );
     if( atracks ) free( atracks );
     if( arates ) free( arates );
     if( abitrates ) free( abitrates );
@@ -1864,6 +1866,33 @@ static int HandleEvents( hb_handle_t * h )
             }
             /* Audio DRC */
 
+            /* Audio Gain */
+            i = 0;
+            if ( audio_gain )
+            {
+                double gain;
+                char * token = strtok(audio_gain, ",");
+                if (token == NULL)
+                    token = audio_gain;
+                while ( token != NULL )
+                {
+                    gain = atof(token);
+                    audio = hb_list_audio_config_item(job->list_audio, i);
+                    if( audio != NULL )
+                    {
+                        audio->out.gain = gain;
+                        if( (++i) >= num_audio_tracks )
+                            break;  /* We have more inputs than audio tracks, oops */
+                    } 
+                    else
+                    {
+                        fprintf(stderr, "Ignoring gain, no audio tracks\n");
+                    }
+                    token = strtok(NULL, ",");
+                }
+            }
+            /* Audio Gain */
+
             /* Audio Track Names */
             i = 0;
             if ( anames )
@@ -2543,6 +2572,10 @@ static void ShowHelp()
     "                            making soft sounds louder. Range is 1.0 to 4.0\n"
     "                            (too loud), with 1.5 - 2.5 being a useful range.\n"
     "                            Separated by commas for more than one audio track.\n"
+    "        --gain <float>      Amplify or attenuate audio before encoding.  Does\n"
+    "                            NOT work with audio passthru (copy). Values are in\n"
+    "                            dB.  Negative values attenuate, positive values\n"
+    "                            amplify. A 1 dB difference is barely audible.\n"
     "    -A, --aname <string>    Audio track name(s),\n"
     "                            Separated by commas for more than one audio track.\n"
     "\n"
@@ -2787,6 +2820,7 @@ static int ParseOptions( int argc, char ** argv )
     #define SCAN_ONLY           276
     #define MAIN_FEATURE        277
     #define MIN_DURATION        278
+    #define AUDIO_GAIN          279
     
     for( ;; )
     {
@@ -2814,6 +2848,7 @@ static int ParseOptions( int argc, char ** argv )
             { "audio",       required_argument, NULL,    'a' },
             { "mixdown",     required_argument, NULL,    '6' },
             { "drc",         required_argument, NULL,    'D' },
+            { "gain",        required_argument, NULL,    AUDIO_GAIN },
             { "subtitle",    required_argument, NULL,    's' },
             { "subtitle-forced", optional_argument,   NULL,    'F' },
             { "subtitle-burned", optional_argument,   NULL,    SUB_BURNED },
@@ -3016,6 +3051,12 @@ static int ParseOptions( int argc, char ** argv )
                     dynamic_range_compression = strdup( optarg );
                 }
                 break;
+            case AUDIO_GAIN:
+                if( optarg != NULL )
+                {
+                    audio_gain = strdup( optarg );
+                }
+                break;
             case 's':
                 subtracks = str_split( optarg, ',' );
                 break;