if its too loud, turn it down

Thursday, December 31, 2009

Applescript to apply mp3gain to iTunes playlists from the Script Menu

First off, if you use iTunes "Sound Check" and like it you may not need this. I disabled it because with iTunes 9, because I had alot of problems importing large mp3 files. It would often hang when determing the mp3's volume. Also, I was never able to tell the difference one way or the other. Playlists with songs from different albums still sounded un-even when Sound Check was enabled. If you love Sound Check and don't have any problems with it, this tip is not for you.

There are a couple other options for "normalizing" MP3 volume on OS X. One is iVolume which I've never tried. I read good things about it...but it costs money. Another is what I am going to focus on here: MacMP3Gain which is a port of the open source command-line program mp3gain for OS X (they also added a GUI).

mp3gain does more than just normalization, it does analysis to determine how quiet or loud an mp3 will sound to the human ear. If you really want to get technical, mp3gain does its analysis based on the Replay Gain algorithm. mp3gain applies lossless adjustment - it does not re-encode the mp3. However, MacMP3Gain offers this caveat about mp3gain, "MacMP3Gain modifies MP3 and unprotected AAC files with no provision provided to undo the changes." I haven't had any trouble after using extensively.

The MacMP3Gain application does have a GUI, which allows you to process by folder or by iTunes playlist. However, in the spirit of efficiency, I wanted a way to be able to normalize playlists right from iTunes. So I wrote this script which can be run right from the iTunes script menu. The other advantages of this script vs. the MacMP3Gain GUI is that it gives you a proper progress bar (important because it can take a long time to process), and it shows you the output when its done (so you can see exactly what changes were made to each file).

Prerequisites

MacMP3Gain - Install MacMP3Gain on your Mac. To use this applescript, you'll need to create a symlink from the command-line binary to somewhere in your path. This can be done with this command:
sudo ln -s /Applications/MacMP3Gain.app/Contents/Resources/aacgain /usr/bin/mp3gain
You can now use mp3gain on the command line. For a complete list of switches, open up Terminal and type:
mp3gain -?
mp3gain is also available via MacPorts, if you use that. Though at the time of writing, the newest version was 1.7.0 while the version rolled into the Intel MacMP3Gain is 1.8.0. To install via ports do this:
sudo port install aacgain
sudo ln -s /opt/local/bin/aacgain /usr/bin/mp3gain
Note: if you don't want to use any symlinks then just update the "mp3gain" reference in the applescript to point to the full path of your installed aacgain program.

BP Progress Bar - mp3gain takes roughly 30 seconds to process each mp3. Therefore, it can take a while to process an entire playlist. So, I've configured this script with a handy progress indicator. Applescript has no "native" progress indicator method, but you can access an external app to do this for you. Download BP Progress Bar (download link), unzip it and mount the disk image. Then, copy the app "BP Progress Bar" to your "Applications" folder, and the "BP Progress Bar Controller.scpt" to your Scripts folder /Users/YOU/Library/Scripts/ (create if it doesn't exist) and you're all good to go!

Please Note: The first time you run this script, you might get the rainbow wheel for 10-20 seconds, and you'll probably get the "BP Progress Bar was downloaded from the internet" security warning. Both of these things happen only the first time.

Now, copy the script below to Script Editor, and save it as "normalize_playlist.scpt" in your iTunes scripts directory /Users/YOU/Library/iTunes/Scripts/ (create if it doesn't exist). This will allow you to run it from the iTunes script menu like below:

iTunes Script Menu

Upon launch, you're prompted to enter a playlist to normalize.

Enter Playlist

As long as you enter a good one, you should see a progress bar come up.

Progress Bar

Upon completion you can view the log, which is written to /tmp/mp3gain_output.log.

MP3Gain Log

Enjoy!

(* 

Normalize Playlist

Accepts an itunes playlist as text input,
and normalizes all mp3 files on the playlist
with mp3gain -r (mp3gain itself decides how 
best to normalize).

Prerequisities:

* mp3gain on command-line
* http://homepage.mac.com/beryrinaldo/AudioTron/MacMP3Gain/
* BP Progress Bar
* http://scriptbuilders.net/files/bpprogressbar1.0.html

*)

--Ask the use for the playlist
set myList to the text returned of (display dialog "Enter playlist to normalize " default answer "")

--exit if they didn't enter anyting
if the myList is "" then
 display dialog "No playlist entered" giving up after 2
 return
end if

--make sure itunes is running
--SHOULD BE if it's run from the itunes script menu
--but it could be executed directly
set itunesOK to my itunes_is_running()
if itunesOK is false then
 tell application "iTunes"
  activate
 end tell
end if

tell application "iTunes"
 set oldfi to fixed indexing
 set fixed indexing to true
 
 --see if the playlist exists
 if exists user playlist myList then
  --do nothing for now
 else
  --show error if the playlist doesn't exist
  display dialog "Playlist does not exist" giving up after 2
  return
 end if
 set currentList to playlist myList
 
 --initialize progress bar
 set ProgressBar to load script alias (((path to scripts folder) as text) & "BP Progress Bar Controller.scpt")
 set myTitle to "Normalizing " & myList & " - may take several minutes"
 tell ProgressBar to initialize(myTitle) -- title of progress bar
 -- Start of Script to use ProgressBar Controller
 tell ProgressBar
  barberPole(true)
  setStatusTop to "Initializing Volume Adjustment"
  setStatusBottom to ""
 end tell
 
 --get the number of items on the playlist
 set eop to index of last track of currentList
 
 -- Stop the barber pole, set up for the progress bar
 tell ProgressBar
  barberPole(false)
  setMax to eop -- to match the items to be processed below
  setStatusTop to "Examining playlist"
 end tell
 
 --add a little progress so it doesn't start at 0
 tell ProgressBar to increase by 1
 
 with timeout of 10800 seconds --avoid "event timed out" error
  
  --delete the logfile if it already exists
  do shell script "if [ -e /tmp/mp3gain_output.log ]; then rm -f /tmp/mp3gain_output.log; fi;"
  
  repeat with i from 1 to eop
   
   --write current track to log
   do shell script "echo \"------------ Track " & i & " of " & eop & " ------------\" >> /tmp/mp3gain_output.log"
   
   --get the mac path to the mp3 file, name of the track, and extension
   set i_location to (get location of track i of currentList)
   set i_name to (get name of track i of currentList)
   set theFileInfo to info for i_location
   set ext to name extension of theFileInfo as string
   
   --only do this if it's an mp3
   if ext is "mp3" then
    
    --convert mac path to POSIX path, quote it so we
    --can use it on the cmd line
    set mypath to POSIX path of i_location
    set posixpath to quoted form of mypath
    
    --create our command
    --mp3gain is CPU-intensive, so pass thru nice
    --write output of mp3gain to log
    --this will allow us to report on what changes were made
    set myCmd to "nice mp3gain -r -k -c -q " & posixpath & " >> /tmp/mp3gain_output.log"
    
    --update progress window with status
    tell ProgressBar
     setStatusTop to "Processing file " & i & " of " & eop & " : " & i_name
     setStatusBottom to "Full path: " & mypath
    end tell
    
    --execute the shell command
    do shell script myCmd
   else
    --if track is not an mp3, don't process it
    do shell script "echo \"Track " & posixpath & "is not an mp3...not processing\" >> /tmp/mp3gain_output.log"
    
   end if --end if for is an mp3
   
   tell ProgressBar to increase by 1
   
  end repeat
 end timeout
 
 set fixed indexing to oldfi
end tell

tell ProgressBar to quit

--tell them we're done and ask if they want to see log
set seeLog to (display dialog ¬
 "Done. Would you like to see the log? " with title ¬
 "Normalization Complete" buttons {"Yes", "No"} ¬
 default button "Yes")
set button_name to button returned of seeLog
if button_name is "Yes" then
 --open log in textedit
 tell application "TextEdit"
  activate
  open "/tmp/mp3gain_output.log"
 end tell
end if

--be nice and clean up
do shell script "if [ -e /tmp/mp3gain_output.log ]; then rm -f /tmp/mp3gain_output.log; fi;"

return

--subroutine checks if itunes is running
on itunes_is_running()
 tell application "System Events" to return (exists process "iTunes")
end itunes_is_running

1 comment:

  1. I am tackling this problem right now and was glad when I came across your script and explanation. I created the symlink and installed the two software apps including your scripts to their respective places but I get this error after the progress bar appears: "The variable posixpath is not defined". I am running Snow Leopard perhaps it is an Applescript issue with the new OS. I would appreciate your help.
    Thanks - Loren

    ReplyDelete