#!/usr/bin/python
#
# Stereonorm: Normalize a wav file's channels independently.
#
# usage: Stereonorm file.wav
#
# Ugly code warning:
#
# This script eats up disk space rapidly, you need 2X the size of the
# source wav file to run it.  The output file is called
# tmp2.wav, when the process is done, check out tmp2.wav and
# use it to replace the original wav file.  Manually remove tmp1.wav.
#
# 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)
