normalizing audio volume on movies

The last time I asked this I didn't get any practical answers, but that was a year ago, so I might as well ask again:

Dear Lazyweb,

How do I normalize the audio volume of a bunch of MOV and MP4 files?

The "Sound Check" option in iTunes works passably well for MP3 files, but doesn't do anything for videos. This makes it annoying to use a playlist full of music videos as a source of ambient entertainment, since the volume fluctuates wildly.

I think that a solution involving manually pulling the audio out of the movie files, normalizing it as a WAV, and re-inserting it into the movie is probably doomed to synchronization errors. So let's not.

I have tried using the "Get Info / Options / Volume Adjustment" slider manually on a few videos, but that is far too manual and annoying to do for all of them. Perhaps an approach would be to compute the volume boost desired of each movie, then set whatever ID3 tag corresponds to that slider? Or failing that, do it with Applescript?

Update: I kinda got something working with Applescript here. It fails if any video requires a volume increase of more than 100% (~6dB), but I only have a few videos of which that is true.

Tags: , , , ,

26 Responses:

  1. edouardp says:

    OK - so assuming there is no simply and easy solution, then I guess this is where I would start with the sticky tape solution; Applescript and shell utilities.

    I'm pretty sure you can get iTunes iterate through a playlist (a smart playlist of movies?) and open each movie in Quicktime Player 7. There are bound to be some examples that are sufficiently similar at http://dougscripts.com/itunes/

    Then you can extract the audio as a WAVE file from Quicktime Player 7 with

    tell application "QuickTime Player 7" to export document 1 to "test.wav" as wave

    Then you can invoke lame on the wav file from inside Applescript (somehow - I'm sure I've seen this done)

    lame test.wav  2>&1  | grep ReplayGain

    that will spit out the replaygain adjustment as "ReplayGain: +1.2dB"

    Then extract the dB value and convert it to an iTunes volume adjustment setting. I think the iVolume page used to have some information about the conversion, but trial and error would also work.

    Finally set the volume adjustment in iTunes for the original movie file with something like (just some random applescript from the net)

    tell application "iTunes" set (volume adjustment of someTrack) to 51

    A few hours work to get it all going? And then a run overnight (or several nights) to do the adjustment?

    • edouardp says:

      Got another few minutes to play around. This kinds works for me, and writes the values back into .mov files via Quicktime Player scripting (rather than the iTunes playback volume adjustment, which of course is something completely different).

      Doesn't work on .mp4 files, since Quicktime Player is only pretending to be able to read and write their metadata.

      Yes, a world a suck.

      do shell script "rm -f /tmp/vol.wav"
      tell application "QuickTime Player 7" to export document 1 to "/tmp/vol.wav" as wave
      set db_string to do shell script "lame /tmp/vol.wav 2>&1 | grep ReplayGain | cut -d ':' -f 2 | c -d '+' -f 2 | cut -d 'd' -f 1"
      set db to db_string as number
      set adjustment to (256 + db * 42) as integer -- This is a very bad approximation
      if adjustment > 512 then
      set adjustment to 512
      end if
      if adjustment < 0 then
      set adjustment to 0
      end if
      tell application "QuickTime Player 7"
      set thetracks to tracks of document 1
      repeat with thetrack in thetracks
      if the kind of thetrack is "Sound" then
      set sound volume of thetrack to adjustment
      end if
      end repeat
      save document 1
      end tell

      • lionsphil says:

        Given that you're only using LAME to calculate the ReplayGain of the input data (default, desirable here), you could probably speed that up a fair bit with -f to make the encoding quick-and-dirty.

      • jwz says:

        Since Quicktime Player can't re-write mp4 files, it seems to me that it would be better to just set the "volume" slider in iTunes than to overwrite data in the audio track in the file itself. But that slider goes from -100% to +100%. How do I convert the ReplayGain dB float value to the -100:100 range?

      • jwz says:

        I think maybe this is it, except for that fact that about one in every couple hundred MOVs I have are ones that ffmpeg can't extract the audio from (despite playing fine in iTunes):

        to movie_volume(m)
           
            set TMPFILE to "/tmp/vol.wav"
            do shell script "rm -f " & TMPFILE
           
            -- Extract the first 2 minutes of the video to the tmp WAV file, as 8 bit mono.
            set CMD to "/opt/local/bin/ffmpeg -t 120 -vn -acodec pcm_u8 " & TMPFILE
            set CMD to CMD & " -i " & {quoted form of m} & " 2>&- <&-"
            do shell script CMD
           
            -- Find the volume adjustement for that tmp WAV file. We can't do this with a pipe instead of a tmp file because ffmpeg writes bogus WAVs to stdout.
            set CMD to "lame -f " & TMPFILE & " /dev/null 2>&1"
            set CMD to CMD & " | sed -n 's/^ReplayGain: \\+*\\(-*[0-9.]*\\)dB$/\\1/p'"
            set db to do shell script CMD
           
            do shell script "rm -f " & TMPFILE
           
            -- For relative volume x, dB value is 20*log[10](x)
            -- if y=log[b](x) then x=b^y
            -- so db=20*log[10](x)
            -- and x=10^(db/20)

            set db to db as number
            set PCT to 100 * (10 ^ (db / 20.0)) - 100
           
            return PCT
        end movie_volume

        tell application "iTunes"
            if selection is {} then
                display dialog "Select some videos first" buttons {"Cancel"} default button 1 with icon 2 giving up after 10
            end if
            repeat with V in selection as list
                tell V
                    set F to POSIX path of {location}
                    set OLD to {volume adjustment}
                    tell me to set NEW to movie_volume(F)
                    set {volume adjustment} to {NEW}
                    log {name} & ": gain " & OLD & " => " & NEW
                end tell
               
            end repeat
        end tell

        • jwz says:

          Also, a bunch of these videos require volume increases of >200%, and iTunes caps the volume adjustment value at 100%. Sigh...

          • edouardp says:

            You could re-adjust everything with a lower base volume to give you extra headroom.

            Hmmm, thinking about that for a second, it's an excellent technical solution, and a terrible practical one.

            Never mind.

        • edouardp says:

          Looking very good - I think 99.5% of the videos being able to be adjusted should be counted as a good result!

  2. cacepi says:

    You could try mp4track (source code here) where you edit the volume atom for the audio track:

    mp4track --track-id # --volume # $file

    Although I don't know if it iTunes would normalize the audio or simply boost the volume by a percentage you set (e.g. 1.5 = 50% louder).

    • jwz says:

      Unfortunately, half my videos are mp4 and half are mov.

      That's another awesome thing about the current state of the world: you can never find a single tool that lets you manipulate both mp4 and mov containers, and the tools all have dramatically disjoint sets of capabilities.

  3. lionsphil says:

    Maybe AACgain? It lists MP4, so and works by twiddling metadata, so might manage to tweak the audio stream without breaking the video one. (Regardless, ReplayGain seems to be a good algorithm for perceived loudness—I've used MP3Gain before now on a wide range of samples and it's done a great job.)

    • jwz says:

      Maybe... it appears to do something. However, it only works on mp4 files, not mov (even though that web page defines "AAC" as "mp4/m4a/Quicktime"), and it makes extensive changes throughout the file. It's not just adding some tag to the header, it's changing bits all over the place. Since I have no tools for examining the structure of these files, I can't tell what it's doing, but it's doing a lot, which means it's probably modifying every frame in the audio track.

      • lionsphil says:

        The library it uses for metadata tweaking claims to support MOV. Or do you mean you tried it, and "supports MOV" is hilarious open-source speak for "we recognise MOV and give a nice little `unimplemented' error, send patches please"?

        MP3Gain, and this it appears, work by setting the gain metadata for each frame of the stream. In MP3's case, I think this is due to a lack of an overall gain metadata field (only the ReplayGain-suggested non-standard one, which naturally plenty of players are ignorant of)—I guess this is just inertia for MP4/MOV formats. (Absolute worst case, there's source.) This approach doesn't change the sample data at all, which is why they claim it's reversible (by default it will refuse to saturate values, and saves the adjustment for undo as a metadata field), and thus shouldn't affect quality or sync.

        That said, I wouldn't let it run riot with your only copy of anything.

        The AppleScript solution above might be better if MP4/MOV have a global volume metadata field that players actually use.

        • jwz says:
          % aacgain -s c tst1.mov
          Error: In SVQ3 atom, extra 4 bytes at end of atom
          ReadAtom: invalid atom size, extends outside parent atom - skipping to end of "meta" "" 1761967686 vs 10556144
          ReadAtom: invalid atom size, extends outside parent atom - skipping to end of "©ART" "Feli" 11670320 vs 10556247
          ReadAtom: invalid atom size, extends outside parent atom - skipping to end of "©gen" "New " 11080631 vs 10556355
          Error opening file: tst1.mov
          tst1.mov is not a valid mp4/m4a file.

          So maybe that means it doesn't support .mov, or maybe that means it tries but it's just crap at it. Who can tell.

  4. toolmaker says:

    From friend:

    http://www.mltframework.org/twiki/bin/view/MLT/Services

    Adjust an audio stream's volume level
    - based on the 'normalize' utility

    • jwz says:

      I can barely tell what that is or whether it will do what I want. I did download it, and predictably, it doesn't compile on MacOS. So tell me why I shouldn't just ignore this?

      • toolmaker says:

        Sorry, that was from a friend who's been fiddling with audio taken from conference videos. I don't do video/audio stuff, and didn't realize the page wasn't sensical. He doesn't use OSX either. Given all of the above, you should ignore it.

      • osx user: "I could get normalize to compile,"

        http://normalize.nongnu.org/ readme "I've tried to make the code as portable as possible, so I'd appreciate hearing whether normalize works on other platforms."

        I was happy with normalize, but didn't like having to demux, tweak, mux.. so then I looked to melt which does all sorts of wonderful and is being actively developed.

        So if you can't find something that just works, one of these may be the next best thing.

  5. behem says:

    Have you tried VLC? It can play both MOV and MP4 and also has a handy option for normalizing audio playback using the audio/filters/volume normalizer option.

    • jwz says:

      I hate VLC. My music videos are in iTunes with my music, where they belong.

      • taskboy3000 says:

        I really surprised to hear that you use iTunes. This isn't an open source v. Apple thing. It's just that iTunes is so, so awful to use. I dropped it awhile ago favoring anything else in its place. Do I have iPods? Sure. Those are fine. But that horrid software dongle know as iTunes is an aborted fetus.

        But, I suppose, your mileage will vary.

        Also, I use VLC, but may painfully aware of its limitations.

        • edouardp says:

          VLC used to suck (a long time ago), but my opinion is that it's now an excellent video player. But iTunes is a very good music/video/podcast organiser, which VLC isn't.

          iTunes and/or Quicktime Player with Perian installed is pretty close to VLC for straight forward playback...

  6. patrock says:

    give this thing a try http://www.squared5.com/ MPEG Streamclip

    I think it will do what you need it to do. I've had good luck with it

    • jwz says:

      I've used MPEG Streamclip, and as far as I can tell, it doesn't do anything even remotely like what I need. Why do you think it does?

      • patrock says:

        well, then i misread your request. it will strip audio and convert files.

        you could just burn them all to dvd or image with Toast and use the limit/compression