def main(): try: in_filename = sys.argv[1] except Exception: print USAGE sys.exit(-1) afile = audio.LocalAudioFile(in_filename) vecin = afile.data # ------------------------------------------------------------------------------------ # Single time-stretch # ------------------------------------------------------------------------------------ rate = 1.25 # 25% slower quality = 0 # fast processing print "Time Stretching with single rate", rate # arguments are: # 1) a numpy array of size N x C, where N is a number of samples, and C the number of channels (1 or 2) # 2) a float representing the time-stretching rate, e.g. 0.5 for twice as short, and 2.0 for twice as long # 3) an integer representing the sample rate of the input signal, e.g. 44100 # 4) an optional integer representing the processing quality and speed between the default 0 (fastest, lowest quality) and 2 (slowest, highest quality) vecout = dirac.timeScale(vecin, rate, afile.sampleRate, quality) # output audio out = audio.AudioData(ndarray=vecout, shape=vecout.shape, sampleRate=afile.sampleRate, numChannels=vecout.shape[1]) out_filename = 'out_single_rate.wav' print "Writing file", out_filename out.encode(out_filename) # ------------------------------------------------------------------------------------ # Varying time-stretch # ------------------------------------------------------------------------------------ # This example will linearly change the speed from 'rate' to 1.0 in 'numChunks' chunks numChunks = 16 # divide the signal into 16 chunks sizeChunk = int(vecin.shape[0] / numChunks) incRate = (1.0-rate) / (numChunks-1) # first tuple must start at index 0 index = 0 rates = [(index, rate)] for i in xrange(numChunks-1): index += sizeChunk rate += incRate rates.append((index, rate)) print "Time Stretching with list of rates", rates # arguments are: # 1) a numpy array of size N x C, where N is a number of samples, and C the number of channels (1 or 2) # 2) a list of tuples each representing (a sample index, a rate). First index must be 0. # 3) an integer representing the sample rate of the input signal, e.g. 44100 # 4) an optional integer representing the processing quality and speed between the default 0 (fastest, lowest quality) and 2 (slowest, highest quality) vecout = dirac.timeScale(vecin, rates, afile.sampleRate, quality) out = audio.AudioData(ndarray=vecout, shape=vecout.shape, sampleRate=afile.sampleRate, numChannels=vecout.shape[1]) out_filename = 'out_list_rates.wav' print "Writing file", out_filename out.encode(out_filename)
def split_break(breakfile, n): drum_data = [] start = 0 for i in range(n): start = int((len(breakfile) * (i)) / n) end = int((len(breakfile) * (i + 1)) / n) ndarray = breakfile.data[start:end] new_data = audio.AudioData(ndarray=ndarray, sampleRate=breakfile.sampleRate, numChannels=breakfile.numChannels) drum_data.append(new_data) return drum_data
def main(inputFilename, outputFilename, windowing): print "HERE WE GO!!!!" print inputFilename print "\n" print outputFilename print "\n" song = audio.LocalAudioFile(inputFilename) print "Cool, we loaded the song" sample_rate = song.sampleRate num_channels = song.numChannels out_shape = list(song.data.shape) out_shape[0] = 2 out = audio.AudioData(shape=out_shape, sampleRate=sample_rate, numChannels=num_channels) chunks = [] for section in song.analysis.sections: segs = song.analysis.segments.that(are_contained_by(section)) seglen = len(segs) print seglen for i in range(0, seglen): if i % 2: seg = song[segs[i]] if windowing: seg.data = window(seg.data) out.append(seg) else: seg = song[segs[seglen - i - 1]] try: seg.data = seg.data[::-1] if windowing: seg.data = window(seg.data) out.append(seg) del (seg.data) del (seg) except: print "fuckkkkk" seg = song[segs[i]] if windowing: seg.data = window(seg.data) out.append(seg) #newAudio = audio.getpieces(song, chunks) out.encode(outputFilename)
outputFilename = sys.argv[3] # how many different groups will we cluster our data into? num_clusters = int(sys.argv[4]) # how many different groups will we cluster our data into? mix = float(sys.argv[5]) song = audio.LocalAudioFile(inputFilename) song2 = audio.LocalAudioFile(inputFilename2) sample_rate = song.sampleRate num_channels = song.numChannels out_shape = list(song.data.shape) out_shape[0] = 2 out = audio.AudioData(shape=out_shape, sampleRate=sample_rate, numChannels=num_channels) """ outs = [None]*2 for n in range(0,num_clusters): outs[n] = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) """ # for each section in song1 for sectionnumber in range(0, len(song.analysis.bars)): # song1 section section = song.analysis.bars[sectionnumber] # song2 section. If too many sections, it loops back to beginning sectionnumber2 = sectionnumber % len(song2.analysis.sections) section2 = song2.analysis.sections[sectionnumber2]
Example: python cowbell.py YouCanCallMeAl.mp3 YouCanCallMeCow.mp3 0.2 0.5 Reference: http://www.youtube.com/watch?v=ZhSkRHXTKlw """ # constants COWBELL_THRESHOLD = 0.85 COWBELL_OFFSET = -0.005 # samples soundsPath = "sounds/" cowbellSounds = map(lambda x: audio.AudioData(os.path.join(soundsPath, "cowbell%s.wav" % x), sampleRate=44100, numChannels=2), range(5)) walkenSounds = map(lambda x: audio.AudioData(os.path.join(soundsPath, "walken%s.wav" % x), sampleRate=44100, numChannels=2), range(16)) trill = audio.AudioData(os.path.join(soundsPath, "trill.wav"), sampleRate=44100, numChannels=2) def linear(input, in1, in2, out1, out2): return ((input-in1) / (in2-in1)) * (out2-out1) + out1 def exp(input, in1, in2, out1, out2, coeff): if (input <= in1): return out1 if (input >= in2): return out2 return pow( ((input-in1) / (in2-in1)) , coeff ) * (out2-out1) + out1 class Cowbell: def __init__(self, input_file):
def main(input_filename, output_filename, break_filename, break_parts, measures, mix): # This takes the input tracks, sends them to the analyzer, and returns the results. audiofile = audio.LocalAudioFile(input_filename) sample_rate = audiofile.sampleRate breakfile = audio.LocalAudioFile(break_filename) # This converts the break to stereo, if it is mono if breakfile.numChannels == 1: breakfile = mono_to_stereo(breakfile) # This gets the number of channels in the main file num_channels = audiofile.numChannels # This splits the break into each beat drum_data = split_break(breakfile, break_parts) hits_per_beat = int(break_parts / (4 * measures)) # This gets the bars from the input track bars = audiofile.analysis.bars # This creates the 'shape' of new array. # (Shape is a tuple (x, y) that indicates the length per channel of the audio file) out_shape = (len(audiofile) + 100000, num_channels) # This creates a new AudioData array to write data to out = audio.AudioData(shape=out_shape, sampleRate=sample_rate, numChannels=num_channels) if not bars: # If the analysis can't find any bars, stop! # (This might happen with really ambient music) print "Didn't find any bars in this analysis!" print "No output." sys.exit(-1) # This is where the magic happens: # For every beat in every bar except the last bar, # map the tatums of the break to the tatums of the beat for bar in bars[:-1]: # This gets the beats in the bar, and loops over them beats = bar.children() for i in range(len(beats)): # This gets the index of matching beat in the break try: break_index = ((bar.local_context()[0] %\ measures) * 4) + (i % 4) except ValueError: break_index = i % 4 # This gets the tatums from the beat of the break tats = range((break_index) * hits_per_beat, (break_index + 1) * hits_per_beat) # This gets the number of samples in each tatum drum_samps = sum([len(drum_data[x]) for x in tats]) # This gets the number of sample and the shape of the beat from the original track beat_samps = len(audiofile[beats[i]]) beat_shape = (beat_samps, num_channels) # This get the shape of each tatum tat_shape = (float(beat_samps / hits_per_beat), num_channels) # This creates the new AudioData that will be filled with chunks of the drum break beat_data = audio.AudioData(shape=beat_shape, sampleRate=sample_rate, numChannels=num_channels) for j in tats: # This creates an audioData for each tatum tat_data = audio.AudioData(shape=tat_shape, sampleRate=sample_rate, numChannels=num_channels) # This corrects for length / timing: # If the original is shorter than the break, truncate drum hits to fit beat length if drum_samps > beat_samps / hits_per_beat: tat_data.data = drum_data[j].data[:len(tat_data)] # If the original is longer, space out drum hits to fit beat length elif drum_samps < beat_samps / hits_per_beat: tat_data.append(drum_data[j]) # This adds each new tatum to the new beat. tat_data.endindex = len(tat_data) beat_data.append(tat_data) del (tat_data) # This corrects for rounding errors beat_data.endindex = len(beat_data) # This mixes the new beat data with the input data, and appends it to the final file mixed_beat = audio.mix(beat_data, audiofile[beats[i]], mix=mix) del (beat_data) out.append(mixed_beat) # This works out the last beat and appends it to the final file finale = bars[-1].start + bars[-1].duration last = audio.AudioQuantum( audiofile.analysis.bars[-1].start, audiofile.analysis.duration - audiofile.analysis.bars[-1].start) last_data = audio.getpieces(audiofile, [last]) out.append(last_data) # This writes the newly created audio to the given file. out.encode(output_filename)
def remix(self): """ Wub wub wub wub wub wub wub wub wub wub wub wub wub wub wub wub wub wub. """ self.log("Looking up track...", 5) self.getTag() self.processArt() self.log( "Listening to %s..." % ('"%s"' % self.tag['title'] if 'title' in self.tag else 'song'), 5) self.original = audio.LocalAudioFile(self.infile, False) if not 'title' in self.tag: self.detectSong(self.original) self.st = FastModify() self.log("Choosing key and tempo...", 10) self.tonic = self.original.analysis.key['value'] self.tempo = self.original.analysis.tempo['value'] self.bars = self.original.analysis.bars self.beats = self.original.analysis.beats self.sections = self.original.analysis.sections self.tag['key'] = self.keys[ self.tonic] if self.tonic >= 0 and self.tonic < 12 else '?' self.tag['tempo'] = self.template['tempo'] self.log("Arranging intro...", 40.0 / (len(self.sections) + 1)) self.partialEncode(self.compileIntro()) past_progress = 0 hats = audio.AudioData(self.sample_path + self.template['hats'], sampleRate=44100, numChannels=2, verbose=False) i = 0 # Required if there are no sections for i, section in enumerate(self.sections): self.log( "Arranging section %s of %s..." % (i + 1, len(self.sections)), 40.0 / (len(self.sections) + 1)) a, b = self.compileSection(i, section, hats) self.partialEncode(a) self.partialEncode(b) del a, b del hats self.original.unload() self.log("Adding ending...", 5) self.partialEncode( audio.AudioData(self.sample_path + self.template['splash_ends'][ (i + 1) % len(self.template['splash_ends'])], sampleRate=44100, numChannels=2, verbose=False)) self.log("Mixing...", 5) self.mixwav(self.tempfile) if self.deleteOriginal: try: unlink(self.infile) except: pass # File could have been deleted by an eager cleanup script self.log("Mastering...", 5) self.lame(self.tempfile, self.outfile) unlink(self.tempfile) self.log("Adding artwork...", 20) self.updateTags(titleSuffix=" (Wub Machine Remix)") return self.outfile
def compileSection(self, j, section, hats): """ Compiles one "section" of dubstep - that is, one section (verse/chorus) of the original song, but appropriately remixed as dubstep. Chooses appropriate samples from the section of the original song in three keys (P1, m3, m7) then plays them back in order in the generic "dubstep" pattern (all 8th notes): | | :| |: 1 1 1 1 1 1 1 1 | m3 m3 m3 m3 m7 m7 m7 m7 :| x2 | | :| On the first iteration, the dubstep bar is mixed with a "splash" sound - high-passed percussion or whatnot. On the second iteration, hats are mixed in on the offbeats and the wubs break on the last beat to let the original song's samples shine through for a second, before dropping back down in the next section. If samples are missing of one pitch, the searchSamples algorithm tries to find samples a fifth from that pitch that will sound good. (If none exist, it keeps trying, in fifths up the scale.) If the song is not 4/4, the resulting remix is sped up or slowed down by the appropriate amount. (That can get really wonky, but sounds cool sometimes, and fixes a handful of edge cases.) """ onebar = audio.AudioQuantumList() s1 = self.searchSamples(j, self.tonic) s2 = self.searchSamples(j, (self.tonic + 3) % 12) s3 = self.searchSamples(j, (self.tonic + 9) % 12) biggest = max([s1, s2, s3]) #for music that's barely tonal if not biggest: for i in xrange(0, 12): biggest = self.searchSamples(j, self.tonic + i) if biggest: break if not biggest: raise Exception('Missing samples in section %s of the song!' % j + 1) if not s1: s1 = biggest if not s2: s2 = biggest if not s3: s3 = biggest if self.template['target'] == "tatums": f = 4 r = 2 elif self.template['target'] == "beats": f = 2 r = 2 elif self.template['target'] == "bars": f = 1 r = 1 for k in xrange(0, r): for i in xrange(0, 4 * f): onebar.append(s1[i % len(s1)]) for i in xrange(4 * f, 6 * f): onebar.append(s2[i % len(s2)]) for i in xrange(6 * f, 8 * f): onebar.append(s3[i % len(s3)]) if self.original.analysis.time_signature == 4: orig_bar = self.st.shiftTempo( audio.getpieces(self.original, onebar), self.template['tempo'] / self.tempo) else: orig_bar = audio.getpieces(self.original, onebar) orig_bar = self.st.shiftTempo( orig_bar, len(orig_bar) / ((44100 * 16 * 2 * 60.0) / self.template['tempo'])) if orig_bar.numChannels == 1: orig_bar = self.mono_to_stereo(orig_bar) mixfactor = self.mixfactor(onebar) a = self.truncatemix( audio.mix( audio.AudioData(self.sample_path + self.template['wubs'][self.tonic], sampleRate=44100, numChannels=2, verbose=False), audio.AudioData( self.sample_path + self.template['splashes'][(j + 1) % len(self.template['splashes'])], sampleRate=44100, numChannels=2, verbose=False)), orig_bar, mixfactor) b = self.truncatemix( audio.mix( audio.AudioData(self.sample_path + self.template['wub_breaks'][self.tonic], sampleRate=44100, numChannels=2, verbose=False), hats), orig_bar, mixfactor) return (a, b)
def compileIntro(self): """ Compiles the dubstep introduction. Returns an AudioData of the first 8 bars. (8 bars at 140 bpm = ~13.71 seconds of audio) If song is not 4/4, tries to even things out by speeding it up by the appropriate amount. Pattern: first 4 bars of song first beat of 1st bar x 4 (quarter notes) first beat of 2nd bar x 4 (quarter notes) first beat of 3rd bar x 8 (eighth notes) first beat of 4th bar x 8 (sixteenth notes) third beat of 4th bar x 8 (sixteenth notes) """ out = audio.AudioQuantumList() intro = audio.AudioData(self.sample_path + self.template['intro'], sampleRate=44100, numChannels=2, verbose=False) # First 4 bars of song custom_bars = [] if not self.beats or len(self.beats) < 16: # Song is not long or identifiable enough # Take our best shot at making something self.tempo = 60.0 * 16.0 / self.original.duration for i in xrange(0, 4): bar = [] for j in xrange(0, 4): length = self.original.duration / 16.0 start = ((i * 4) + j) * length bar.append( audio.AudioQuantum(start, length, None, 0, self.original.source)) custom_bars.append(bar) else: for i in xrange(0, 4): custom_bars.append(self.beats[i * 4:(i * 4) + 4]) out.extend([x for bar in custom_bars for x in bar]) # First beat of first bar x 4 for i in xrange(0, 4): out.append(custom_bars[0][0]) # First beat of second bar x 4 for i in xrange(0, 4): out.append(custom_bars[1][0]) beatone = custom_bars[2][0] beattwo = custom_bars[3][0] beatthree = custom_bars[3][2] # First beat of third bar x 8 for x in xrange(0, 8): out.append( audio.AudioQuantum(beatone.start, beatone.duration / 2, None, beatone.confidence, beatone.source)) # First beat of fourth bar x 8 for x in xrange(0, 8): out.append( audio.AudioQuantum(beattwo.start, beattwo.duration / 4, None, beattwo.confidence, beattwo.source)) # Third beat of fourth bar x 8 for x in xrange(0, 8): out.append( audio.AudioQuantum(beatthree.start, beatthree.duration / 4, None, beatthree.confidence, beatthree.source)) if self.original.analysis.time_signature == 4: shifted = self.st.shiftTempo(audio.getpieces(self.original, out), self.template['tempo'] / self.tempo) else: shifted1 = audio.getpieces(self.original, out) shifted = self.st.shiftTempo( shifted1, len(shifted1) / ((44100 * 16 * 2 * 60.0) / self.template['tempo'])) shifted1.unload() if shifted.numChannels == 1: shifted = self.mono_to_stereo(shifted) return self.truncatemix(intro, shifted, self.mixfactor(out))
def dnbify(randombeat): print "dnbify" dnbfile = "mp3/breaks/RC4_Breakbeat_175 (%i).mp3" % randombeat dnbloop = audio.LocalAudioFile(dnbfile) # how many different groups will we cluster our data into? num_clusters = 5 mix = 1.0 dnbouts = [] for layer in range(0, 2): # best_match = 1 # slower, less varied version. Good for b's which are percussion loops # best_match = 0 # faster, more varied version, picks a random segment from that cluster. Good for b's which are sample salads. best_match = layer print "layer" print layer song1 = dnbloop song2 = song dnbout = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) # here we just grab the segments that overlap the section sectionsegments = song1.analysis.segments #for _ in range(3): # sectionsegments.extend(song1.analysis.segments) sectionsegments2 = song2.analysis.segments #.that(overlap(section)); # this is just too easy # song.analysis.segments.timbre is a list of all 12-valued timbre vectors. # must be converted to a numpy.array() so that kmeans(data, n) is happy data = array(sectionsegments.timbre) data2 = array(sectionsegments2.timbre) """ # grab timbre data # must be converted to a numpy.array() so that kmeans(data, n) is happy data = array(song1.analysis.segments.timbre) data2 = array(song2.analysis.segments.timbre) """ # computing K-Means with k = num_clusters centroids,_ = kmeans(data,num_clusters) centroids2,_ = kmeans(data2,num_clusters) # assign each sample to a cluster idx,_ = vq(data,centroids) idx2,_ = vq(data2,centroids2) collection = [] for c in range(0, num_clusters): ccount = 0 for i in idx: if i==c: ccount += 1 collection.append([ccount, c]) collection.sort() # list of cluster indices from largest to smallest centroid_pairs = [] for _,c in collection: centroid1 = array(centroids[c]) min_distance = [9999999999,0] for ci in range(0,len(centroids2)): if ci in [li[1] for li in centroid_pairs]: continue centroid2 = array(centroids2[ci]) euclidian_distance = norm(centroid1-centroid2) if euclidian_distance < min_distance[0]: min_distance = [euclidian_distance, ci] centroid_pairs.append([c,min_distance[1]]) print centroid_pairs # now we have a list of paired up cluster indices. Cool. # Just so we're clear, we're rebuilding the structure of song1 with segments from song2 # prepare song2 clusters, segclusters2 = [audio.AudioQuantumList()]*len(centroids2) for s2 in range(0,len(idx2)): segment2 = song2.analysis.segments[s2] cluster2 = idx2[s2] segment2.numpytimbre = array(segment2.timbre) segclusters2[cluster2].append(segment2) # for each segment1 in song1, find the timbrely closest segment2 in song2 belonging to the cluster2 with which segment1's cluster1 is paired. for s in range(0,len(idx)): segment1 = song1.analysis.segments[s] cluster1 = idx[s] cluster2 = [li[1] for li in centroid_pairs if li[0]==cluster1][0] if(best_match>0): # slower, less varied version. Good for b's which are percussion loops """ # there's already a function for this, use that instead: timbre_distance_from timbre1 = array(segment1.timbre) min_distance = [9999999999999,0] for seg in segclusters2[cluster2]: timbre2 = seg.numpytimbre euclidian_distance = norm(timbre2-timbre1) if euclidian_distance < min_distance[0]: min_distance = [euclidian_distance, seg] bestmatchsegment2 = min_distance[1] # we found the segment2 in song2 that best matches segment1 """ bestmatches = segclusters2[cluster2].ordered_by(timbre_distance_from(segment1)) if(best_match > 1): # if best_match > 1, it randomly grabs from the top best_matches. maxmatches = max(best_match, len(bestmatches)) bestmatchsegment2 = choice(bestmatches[0:maxmatches]) else: # if best_match == 1, it grabs the exact best match bestmatchsegment2 = bestmatches[0] else: # faster, more varied version, picks a random segment from that cluster. Good for sample salads. bestmatchsegment2 = choice(segclusters2[cluster2]) reference_data = song1[segment1] segment_data = song2[bestmatchsegment2] # what to do when segments lengths aren't equal? (almost always) # do we add silence? or do we stretch the samples? add_silence = True # This is the add silence solution: if add_silence: if reference_data.endindex > segment_data.endindex: # we need to add silence, because segment1 is longer if num_channels > 1: silence_shape = (reference_data.endindex,num_channels) else: silence_shape = (reference_data.endindex,) new_segment = audio.AudioData(shape=silence_shape, sampleRate=out.sampleRate, numChannels=segment_data.numChannels) new_segment.append(segment_data) new_segment.endindex = len(new_segment) segment_data = new_segment elif reference_data.endindex < segment_data.endindex: # we need to cut segment2 shorter, because segment2 is shorter index = slice(0, int(reference_data.endindex), 1) segment_data = audio.AudioData(None, segment_data.data[index], sampleRate=segment_data.sampleRate) else: # TODO: stretch samples to fit. # haven't written this part yet. segment_data = segment_data # mix the original and the remix mixed_data = audio.mix(segment_data,reference_data,mix=mix) dnbout.append(mixed_data) dnbouts.append(dnbout) print "YEA" mixed_dnbouts = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) print len(dnbouts[0]) print len(dnbouts[1]) #for s in range(0,len(dnbouts[0])): # print s # print dnbouts[0] # print dnbouts[1] mixed_data = audio.mix(dnbouts[0], dnbouts[1], 0.5) mixed_dnbouts.append(mixed_data) print "woah" dnbrepeatout = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) for _ in range(4): dnbrepeatout.append(mixed_dnbouts) print "oh okay" return dnbrepeatout
# take an input song input_filename = "mp3/vaetxh-unfolding.mp3"; output_filename = "mp3/qup-creation.mp3"; input_filename = sys.argv[1] output_filename = sys.argv[2] song = audio.LocalAudioFile(input_filename) # set sample_rate = song.sampleRate num_channels = song.numChannels out_shape = list(song.data.shape) out_shape[0] = 2 out = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) secs = song.analysis.sections num_sections = len(secs) ### ZEPTO -> DNB -> ZEPTO -> DNB ?? def loudness(section): segs = song.analysis.segments.that(overlap(section)) num_segs = len(segs) loudness_total = 0 for seg in segs: loudness_total += seg.loudness_max avg_loudness = loudness_total / num_segs return avg_loudness
def run(self, mix=0.5, envelope=False): # This chunk creates a new array of AudioData to put the resulting resynthesis in: # Add two seconds to the length, just in case dur = len(self.input_a.data) + 100000 # This determines the 'shape' of new array. # (Shape is a tuple (x, y) that indicates the length per channel of the audio file) # If we have a stereo shape, copy that shape if len(self.input_a.data.shape) > 1: new_shape = (dur, self.input_a.data.shape[1]) new_channels = self.input_a.data.shape[1] # If not, make a mono shape else: new_shape = (dur, ) new_channels = 1 # This creates the new AudioData array, based on the new shape out = audio.AudioData(shape=new_shape, sampleRate=self.input_b.sampleRate, numChannels=new_channels) # Now that we have a properly formed array to put chunks of audio in, # we can start deciding what chunks to put in! # This loops over each segment in file A and finds the best matching segment from file B for a in self.segs_a: seg_index = a.absolute_context()[0] # This works out the distances distance_matrix = self.calculate_distances(a) distances = [ numpy.sqrt(x[0] + x[1] + x[2]) for x in distance_matrix ] # This gets the best match match = self.segs_b[distances.index(min(distances))] segment_data = self.input_b[match] reference_data = self.input_a[a] # This corrects for length: if our new segment is shorter, we add silence if segment_data.endindex < reference_data.endindex: if new_channels > 1: silence_shape = (reference_data.endindex, new_channels) else: silence_shape = (reference_data.endindex, ) new_segment = audio.AudioData( shape=silence_shape, sampleRate=out.sampleRate, numChannels=segment_data.numChannels) new_segment.append(segment_data) new_segment.endindex = len(new_segment) segment_data = new_segment # Or, if our new segment is too long, we make it shorter elif segment_data.endindex > reference_data.endindex: index = slice(0, int(reference_data.endindex), 1) segment_data = audio.AudioData( None, segment_data.data[index], sampleRate=segment_data.sampleRate) # This applies the volume envelopes from each segment of A to the segment from B. if envelope: # This gets the maximum volume and starting volume for the segment from A: # db -> voltage ratio http://www.mogami.com/e/cad/db.html linear_max_volume = pow(10.0, a.loudness_max / 20.0) linear_start_volume = pow(10.0, a.loudness_begin / 20.0) # This gets the starting volume for the next segment if (seg_index == len(self.segs_a) - 1 ): # If this is the last segment, the next volume is zero linear_next_start_volume = 0 else: linear_next_start_volume = pow( 10.0, self.segs_a[seg_index + 1].loudness_begin / 20.0) pass # This gets when the maximum volume occurs in A when_max_volume = a.time_loudness_max # Count # of ticks I wait doing volume ramp so I can fix up rounding errors later. ss = 0 # This sets the starting volume volume of this segment. cur_vol = float(linear_start_volume) # This ramps up to the maximum volume from start samps_to_max_loudness_from_here = int(segment_data.sampleRate * when_max_volume) if (samps_to_max_loudness_from_here > 0): how_much_volume_to_increase_per_samp = float( linear_max_volume - linear_start_volume) / float( samps_to_max_loudness_from_here) for samps in xrange(samps_to_max_loudness_from_here): try: # This actally applies the volume modification segment_data.data[ss] *= cur_vol except IndexError: pass cur_vol = cur_vol + how_much_volume_to_increase_per_samp ss = ss + 1 # This ramp down to the volume for the start of the next segent samps_to_next_segment_from_here = int( segment_data.sampleRate * (a.duration - when_max_volume)) if (samps_to_next_segment_from_here > 0): how_much_volume_to_decrease_per_samp = float( linear_max_volume - linear_next_start_volume) / float( samps_to_next_segment_from_here) for samps in xrange(samps_to_next_segment_from_here): cur_vol = cur_vol - how_much_volume_to_decrease_per_samp try: # This actally applies the volume modification segment_data.data[ss] *= cur_vol except IndexError: pass ss = ss + 1 # This mixes the segment from B with the segment from A, and adds it to the output mixed_data = audio.mix(segment_data, reference_data, mix=mix) out.append(mixed_data) # This writes the newly created audio to the given file. Phew! out.encode(self.output_filename)