PageRenderTime 73ms CodeModel.GetById 40ms app.highlight 17ms RepoModel.GetById 13ms app.codeStats 0ms

/examples/cowbell/cowbell.py

http://echo-nest-remix.googlecode.com/
Python | 113 lines | 109 code | 2 blank | 2 comment | 2 complexity | 01907b65806cc84b5a2361c1fdb6a786 MD5 | raw file
  1# By Rob Ochshorn and Adam Baratz.
  2# Slightly refactored by Joshua Lifton.
  3import numpy
  4import os
  5import random
  6import time
  7
  8import echonest.audio as audio
  9
 10usage = """
 11Usage: 
 12    python cowbell.py <inputFilename> <outputFilename> <cowbellIntensity> <walkenIntensity>
 13
 14Example:
 15    python cowbell.py YouCanCallMeAl.mp3 YouCanCallMeCow.mp3 0.2 0.5
 16
 17Reference:
 18    http://www.youtube.com/watch?v=ZhSkRHXTKlw
 19"""
 20
 21# constants
 22COWBELL_THRESHOLD = 0.85
 23COWBELL_OFFSET = -0.005
 24
 25# samples
 26soundsPath = "sounds/"
 27
 28cowbellSounds = map(lambda x: audio.AudioData(os.path.join(soundsPath, "cowbell%s.wav" % x), sampleRate=44100, numChannels=2), range(5))
 29walkenSounds = map(lambda x: audio.AudioData(os.path.join(soundsPath, "walken%s.wav" % x), sampleRate=44100, numChannels=2), range(16))
 30trill = audio.AudioData(os.path.join(soundsPath, "trill.wav"), sampleRate=44100, numChannels=2)
 31
 32def linear(input, in1, in2, out1, out2):
 33    return ((input-in1) / (in2-in1)) * (out2-out1) + out1
 34
 35def exp(input, in1, in2, out1, out2, coeff):
 36    if (input <= in1):
 37        return out1
 38    if (input >= in2):
 39        return out2
 40    return pow( ((input-in1) / (in2-in1)) , coeff ) * (out2-out1) + out1
 41
 42class Cowbell:
 43    def __init__(self, input_file):
 44        self.audiofile = audio.LocalAudioFile(input_file)
 45        self.audiofile.data *= linear(self.audiofile.analysis.loudness, -2, -12, 0.5, 1.5) * 0.75
 46
 47    def run(self, cowbell_intensity, walken_intensity, out):
 48        if cowbell_intensity != -1:
 49            self.cowbell_intensity = cowbell_intensity
 50            self.walken_intensity = walken_intensity
 51        t1 = time.time()
 52        sequence = self.sequence(cowbellSounds)
 53        print "Sequence and mixed in %g seconds" % (time.time() - t1)
 54        self.audiofile.encode(out)
 55
 56    def sequence(self, chops):
 57        # add cowbells on the beats
 58        for beat in self.audiofile.analysis.beats:
 59            volume = linear(self.cowbell_intensity, 0, 1, 0.1, 0.3)
 60            # mix in cowbell on beat
 61            if self.cowbell_intensity == 1:
 62                self.mix(beat.start+COWBELL_OFFSET, seg=cowbellSounds[random.randint(0,1)], volume=volume)
 63            else:
 64                self.mix(beat.start+COWBELL_OFFSET, seg=cowbellSounds[random.randint(2,4)], volume=volume)
 65            # divide beat into quarters
 66            quarters = (numpy.arange(1,4) * beat.duration) / 4. + beat.start
 67            # mix in cowbell on quarters
 68            for quarter in quarters:
 69                volume = exp(random.random(), 0.5, 0.1, 0, self.cowbell_intensity, 0.8) * 0.3
 70                pan = linear(random.random(), 0, 1, -self.cowbell_intensity, self.cowbell_intensity)
 71                if self.cowbell_intensity < COWBELL_THRESHOLD:
 72                    self.mix(quarter+COWBELL_OFFSET, seg=cowbellSounds[2], volume=volume)
 73                else:
 74                    randomCowbell = linear(random.random(), 0, 1, COWBELL_THRESHOLD, 1)
 75                    if randomCowbell < self.cowbell_intensity:
 76                        self.mix(start=quarter+COWBELL_OFFSET, seg=cowbellSounds[random.randint(0,1)], volume=volume)
 77                    else:
 78                        self.mix(start=quarter+COWBELL_OFFSET, seg=cowbellSounds[random.randint(2,4)], volume=volume)
 79        # add trills / walken on section changes
 80        for section in self.audiofile.analysis.sections[1:]:
 81            if random.random() > self.walken_intensity:
 82                sample = trill
 83                volume = 0.3
 84            else:
 85                sample = walkenSounds[random.randint(0, len(walkenSounds)-1)]
 86                volume = 1.5
 87            self.mix(start=section.start+COWBELL_OFFSET, seg=sample, volume=volume)
 88
 89    def mix(self, start=None, seg=None, volume=0.3, pan=0.):
 90        # this assumes that the audios have the same frequency/numchannels
 91        startsample = int(start * self.audiofile.sampleRate)
 92        seg = seg[0:]
 93        seg.data *= (volume-(pan*volume), volume+(pan*volume)) # pan + volume
 94        if self.audiofile.data.shape[0] - startsample > seg.data.shape[0]:
 95            self.audiofile.data[startsample:startsample+len(seg.data)] += seg.data[0:]
 96
 97
 98def main(inputFilename, outputFilename, cowbellIntensity, walkenIntensity ) :
 99    c = Cowbell(inputFilename)
100    print 'cowbelling...'
101    c.run(cowbellIntensity, walkenIntensity, outputFilename)
102
103if __name__ == '__main__':
104    import sys
105    try :
106        inputFilename = sys.argv[1]
107        outputFilename = sys.argv[2]
108        cowbellIntensity = float(sys.argv[3])
109        walkenIntensity = float(sys.argv[4])
110    except :
111        print usage
112        sys.exit(-1)
113    main(inputFilename, outputFilename, cowbellIntensity, walkenIntensity)