#!/usr/bin/python # # Stereonorm: Normalize a wav file's channels independently. # usage: Stereonorm file.wav # # Version date: December 23, 2008 # G. Forrest Cook # Released under the GNU General Public License Version 3 (GPLv3). # # Warning: # This script eats up disk space rapidly, it can make two copies of the # original wav file while processing. The script tries to be smart # about equalizing, if a track's channel is already at 100% volume, it # skips the lengthy processing step for that channel. # # Based on an email from ecasound (http://eca.cx/) author Kai Vehmanen: # To use ecasound for a stereo normalization: # There is an apparent channel name reversal with the query/change steps. # Channel 1 is right, 2 is left. # Its a good idea to normalize slightly lower than the max gain. #ecasound returns: (audiofx) Max gain without clipping, all: 1.85371. # # for channel 1: #ecasound -i X.wav -o null -eac:0,2 -ev | grep clipping # for channel 2: #ecasound -i X.wav -o null -eac:0,1 -ev | grep clipping # #normalize channel 1 up by a factor of 185% #ecasound -i Y.wav -o Z.wav -eac:185,1 # #normalize channel 2 up by a factor of 110% #ecasound -i X.wav -o Y.wav -eac:110,2 # import sys import os import string if len(sys.argv) != 2: print 'usage: %s file.wav' % sys.argv[0] sys.exit (1) changed1 = 0 changed2 = 0 # # Get some file names. # wavfile = sys.argv[1] tmp2 = "tmp2.wav" print "Stereo Normalizing: " + wavfile print "This will take a while..." # # Get Channel 1 gain change info. # Build a command to run ecasound # The channel numbers are flipped on purpose. # cmd = "ecasound -i " + wavfile + " -o null -eac:0,2 -ev | grep clipping" #print "Command: " + cmd ecafd = os.popen (cmd) line = ecafd.readline () ecafd.close () # Break up the return values sline = string.split (line) # Get rid of the tailing . on the returned number, scale and make int. gain1 = (int) (100 * string.atof (sline[6][0:-1])) print "gain1 change: ", gain1 # # Get Channel 2 gain change info. # cmd = "ecasound -i " + wavfile + " -o null -eac:0,1 -ev | grep clipping" #print "Command: " + cmd ecafd = os.popen (cmd) line = ecafd.readline () ecafd.close () # Break up the return values sline = string.split (line) # # Get rid of the tailing . on the returned number, scale and make int. # Rounding down is the desired behavior. # gain2 = (int) (100 * string.atof (sline[6][0:-1])) print "gain2 change: ", gain2 if (gain1 != 100): print "Normalizing channel 1" changed1 = 1 tmp1 = "tmp1.wav" # # Change Channel 1 gain # cmd = "ecasound -i " + wavfile + " -o " + tmp1 + " -eac:%d" % gain1 + ",1 > /dev/null" #print "cmd: ", cmd os.system (cmd) else: tmp1 = wavfile if (gain2 != 100): print "Normalizing channel 2" changed2 = 1 # # Change Channel 2 gain # cmd = "ecasound -i " + tmp1 + " -o " + tmp2 + " -eac:%d" % gain2 + ",2 > /dev/null" #print "cmd: ", cmd os.system (cmd) # # We're done with tmp1. # if (changed1 == 1): cmd = "/bin/rm " + tmp1 + " > /dev/null" #print "cmd: ", cmd os.system (cmd) # # Clean up and deal with cases where only one channel was changed. # if (changed2 == 1): cmd = "/bin/mv " + tmp2 + " " + wavfile + " > /dev/null" #print "cmd: ", cmd os.system (cmd) else: if (changed1 == 1): cmd = "/bin/mv " + tmp1 + " " + wavfile + " > /dev/null" #print "cmd: ", cmd os.system (cmd) sys.exit (0)