def main(input_filename, output_filename, tatums, beats, bars): audiofile = audio.LocalAudioFile(input_filename) num_channels = audiofile.numChannels sample_rate = audiofile.sampleRate # mono files have a shape of (len,) out_shape = list(audiofile.data.shape) out_shape[0] = len(audiofile) out = audio.AudioData(shape=out_shape, sampleRate=sample_rate,numChannels=num_channels) # same hack to change shape: we want blip_files[0] as a short, silent blip null_shape = list(audiofile.data.shape) null_shape[0] = 2 null_audio = audio.AudioData(shape=null_shape) null_audio.endindex = len(null_audio) low_blip = audio.AudioData(blip_filenames[0]) med_blip = audio.AudioData(blip_filenames[1]) high_blip = audio.AudioData(blip_filenames[2]) all_tatums = audiofile.analysis.tatums all_beats = audiofile.analysis.beats all_bars = audiofile.analysis.bars if not all_tatums: print "Didn't find any tatums in this analysis!" print "No output." sys.exit(-1) print "going to add blips..." for tatum in all_tatums: mix_list = [audiofile[tatum], null_audio, null_audio, null_audio] if tatums: print "match! tatum start time:" + str(tatum.start) mix_list[1] = low_blip if beats: for beat in all_beats: if beat.start == tatum.start: print "match! beat start time: " + str(beat.start) mix_list[2] = med_blip break if bars: for bar in all_bars: if bar.start == tatum.start: print "match! bar start time: " + str(bar.start) mix_list[3] = high_blip break out_data = audio.megamix(mix_list) out.append(out_data) del(out_data) print "blips added, going to encode", output_filename, "..." out.encode(output_filename) print "Finito, Benito!"
def mashComponents(localAudioFiles, loudnessMarkers): instSegments = localAudioFiles[0].analysis.segments# This is the base track vocalSegments = localAudioFiles[1].analysis.segments# This is the overlay track instBeats = localAudioFiles[0].analysis.beats[loudnessMarkers[0][0]: loudnessMarkers[0][1]] vocalBeats = localAudioFiles[1].analysis.beats[loudnessMarkers[1][0]: loudnessMarkers[1][1]] pitches = meanPitches(instSegments,instBeats) timbre = meanTimbre(instSegments,instBeats) sections = localAudioFiles[1].analysis.sections #This is the new lead vocal layer sections = sections.that(selection.are_contained_by_range( vocalBeats[0].start, vocalBeats[-1].start+vocalBeats[-1].duration)) if(len(sections)==0):sections = localAudioFiles[1].analysis.sections[2:-2] pyplot.figure(0,(16,9)) image = numpy.array(pitches) image = numpy.concatenate((image,numpy.array(timbre)),axis = 1) image = numpy.concatenate((image,numpy.array(meanLoudness(instSegments,instBeats))), axis = 1) """ Now image contains chromatic, timbral, and loudness information""" sectBeats = getSectBeats(sections[0]) # get beats that comprise a specific section template = numpy.array(meanPitches(vocalSegments,sectBeats)) template = numpy.concatenate((template,numpy.array( meanTimbre(vocalSegments,sectBeats))),axis=1) template = numpy.concatenate((template,numpy.array( meanLoudness(vocalSegments,sectBeats))),axis = 1) im = feature.match_template(image,template,pad_input=True) maxValues = [] #tuples of x coord, y coord, correlation, and section len(in secs) ij = numpy.unravel_index(numpy.argmax(im), im.shape) x, y = ij[::-1] maxValues.append((numpy.argmax(im),x,y,sections[0].duration)) for i in range(len(sections)-1): sectBeats = getSectBeats(sections[i+1]) template = numpy.array(meanPitches(vocalSegments,sectBeats)) template = numpy.concatenate((template,numpy.array( meanTimbre(vocalSegments,sectBeats))), axis=1) template = numpy.concatenate((template,numpy.array( meanLoudness(vocalSegments,sectBeats))),axis = 1) match = feature.match_template(image,template,pad_input=True) ij = numpy.unravel_index(numpy.argmax(match), match.shape) x, y = ij[::-1] maxValues.append((numpy.argmax(match), TEMPLATE_WIDTH*i+x,y,sections[i+1].duration)) im = numpy.concatenate((im,match),axis = 1) maxValues.sort() maxValues.reverse() try: count = 0 while(maxValues[count][3] < 10.0): # choose a section longer than 10 secs count += 1 x = maxValues[count][1] y = maxValues[count][2] except: print "exception in mashComponents..." ij = numpy.unravel_index(numpy.argmax(im), im.shape) x, y = ij[::-1] pyplot.imshow(im, cmap = pyplot.get_cmap('gray'), aspect = 'auto') pyplot.plot(x,y,'o',markeredgecolor='r',markerfacecolor='none',markersize=15) pyplot.show() sectionBeats = getSectBeats(sections[x/TEMPLATE_WIDTH]) print "len(sectionBeats): ", len(sectionBeats) print "len(instBeats): ", len(instBeats) print "y: ", y y = instBeats[y].absolute_context()[0] instBeats = localAudioFiles[0].analysis.beats matchingBeats = instBeats[(y-len(sectionBeats)/2):(y+len(sectionBeats)/2)] print"len(matchingBeats): ", len(matchingBeats) matchingBeats = matchingBeats[-len(sectionBeats):] print"len(matchingBeats): ", len(matchingBeats) """ Check to make sure lengths of beat lists are equal... """ if len(matchingBeats) != len(sectionBeats): print "len(matchingBeats) != len(sectionBeats). For now, I will just truncate..." print "len(matchingBeats): ", len(matchingBeats) print "len(sectionBeats): ", len(sectionBeats) if len(matchingBeats) > len(sectionBeats):matchingBeats = matchingBeats[ :len(sectionBeats)] else: sectionBeats = sectionBeats[:len(matchingBeats)] """ I have to make sure sectionBeats and matchingBeats are similarly aligned within their group, aka bar of four beats. I will add a beat to the beginning of matchingBeats until that condition is met. I re-initialize instBeats and vocalBeats, because now I want to include the areas outside of those marked off by AutomaticDJ for fade ins and fade outs.""" vocalBeats = localAudioFiles[1].analysis.beats while(matchingBeats[0].local_context()[0] != sectionBeats[0].local_context()[0]): matchingBeats.insert(0,instBeats[matchingBeats[0].absolute_context()[0]-1]) sectionBeats.append(vocalBeats[sectionBeats[-1].absolute_context()[0]+1]) """ Check to make sure lengths of beat lists are equal... """ if len(matchingBeats) != len(sectionBeats): print "len(matchingBeats) != len(sectionBeats) at the second checkpoint." print "This should not be the case. The while loop must not be adding beats" print "to both lists equally." print "len(matchingBeats): ", len(matchingBeats) print "len(sectionBeats): ", len(sectionBeats) sys.exit() """ Next, I will use the beats around the designated beats above to transition into and out of the mashup. """ XLEN = 4 # number of beats in crossmatch if(matchingBeats[0].absolute_context()[0] < XLEN or len(instBeats) - matchingBeats[-1].absolute_context()[0] - 1 < XLEN or sectionBeats[0].absolute_context()[0] < XLEN or len(vocalBeats) - sectionBeats[-1].absolute_context()[0] - 1 < XLEN): XLEN -= 1 BUFFERLEN = 12 # number of beats before and after crossmatches while(matchingBeats[0].absolute_context()[0] < BUFFERLEN+XLEN or len(instBeats) - matchingBeats[-1].absolute_context()[0] - 1 < BUFFERLEN+XLEN or sectionBeats[0].absolute_context()[0] < BUFFERLEN+XLEN or len(vocalBeats) - sectionBeats[-1].absolute_context()[0] - 1 < BUFFERLEN+XLEN): BUFFERLEN -= 1 try: """ These are the 4 beats before matchingBeats. These are the four beats of the instrumental track that preclude the mashed section. """ b4beatsI = instBeats[matchingBeats[0].absolute_context()[0]-XLEN: matchingBeats[0].absolute_context()[0]] """ These are the 4 beats after matchingBeats. These are the four beats of the instrumental track that follow the mashed section. """ afterbeatsI = instBeats[matchingBeats[-1].absolute_context()[0]+1: matchingBeats[-1].absolute_context()[0]+1+XLEN] if(len(b4beatsI) != len(afterbeatsI)): print "The lengths of b4beatsI and afterbeatsI are not equal." """ These are the 16 beats before the 4-beat crossmatch into matchingBeats. """ preBufferBeats = instBeats[matchingBeats[0].absolute_context()[0]-BUFFERLEN-XLEN: matchingBeats[0].absolute_context()[0]-XLEN] """ These are the 16 beats before the 4-beat crossmatch into matchingBeats. """ postBufferBeats = instBeats[matchingBeats[-1].absolute_context()[0]+1+XLEN: matchingBeats[-1].absolute_context()[0]+1+XLEN+BUFFERLEN] if(len(preBufferBeats) != len(postBufferBeats)): print "The lengths of preBufferBeats and postBufferBeats are not equal." print "len(preBufferBeats): ", len(preBufferBeats) print "len(postBufferBeats): ", len(postBufferBeats) print matchingBeats[-1].absolute_context()[0] print len(instBeats) sys.exit() """ These are the 4 beats before matchingBeats. These are the four beats of the new vocal track that preclude the mashed section. """ b4beatsV = vocalBeats[sectionBeats[0].absolute_context()[0]-XLEN: sectionBeats[0].absolute_context()[0]] """ These are the 4 beats after matchingBeats. These are the four beats of the new vocal track that follow the mashed section. """ afterbeatsV = vocalBeats[sectionBeats[-1].absolute_context()[0]+1: sectionBeats[-1].absolute_context()[0]+1+XLEN] if(len(b4beatsV) != len(afterbeatsV)): print "The lengths of b4beatsI and afterbeatsI are not equal." sys.exit() except: print "exception in 4 beat try block." sys.exit() """ vocData: An AudioData object for the new vocal data that will be overlaid. instData: An AudioData object for the base instrumental track. originalVocData: An AudioData object of the original vocal to accompany the new one. vocalMix: An AudioData of both vocal tracks mixed together, in order to keep the overall vocal loudness approximately constant. mix: An AudioData of the instrumental track and combined vocals mixed together. """ vocData = audio.getpieces(localAudioFiles[3],b4beatsV+sectionBeats+afterbeatsV) instData = audio.getpieces(localAudioFiles[2],b4beatsI+matchingBeats+afterbeatsI) if instData.data.shape[0] >= vocData.data.shape[0]: mix = audio.megamix([instData, vocData]) else: mix = audio.megamix([vocData, instData]) # the longer data set has to go first. mix.encode('mix.mp3') vocData.encode('vocData.mp3') """ Now, make a similar mix for before the mashed sections...""" instData = audio.getpieces(localAudioFiles[2], preBufferBeats + b4beatsI) vocData = audio.getpieces(localAudioFiles[4], preBufferBeats + b4beatsI) premix = audio.megamix([instData, vocData]) """ ...and another mix for after the mashed sections.""" instData = audio.getpieces(localAudioFiles[2], afterbeatsI + postBufferBeats) vocData = audio.getpieces(localAudioFiles[4], afterbeatsI + postBufferBeats) postmix = audio.megamix([instData, vocData]) """ Now, I have three AudioData objects, mix, premix, and postmix, that overlap by four beats. I will build Crossmatch objects from the overlapping regions, and three Playback objects for the areas that are not in transition. """ action.make_stereo(premix) action.make_stereo(mix) action.make_stereo(postmix) preBuffdur = sum([p.duration for p in preBufferBeats]) # duration of preBufferBeats playback1 = action.Playback(premix,0.0,preBuffdur) b4dur = sum([p.duration for p in b4beatsI]) # duration of b4beatsI crossfade1 = action.Crossfade((premix,mix),(preBuffdur,0.0),b4dur) abdur = sum([p.duration for p in afterbeatsI]) playback2 = action.Playback(mix,b4dur,mix.duration - b4dur - abdur) crossfade2 = action.Crossfade((mix,postmix),(mix.duration - abdur,0.0),abdur) playback3 = action.Playback(postmix,abdur,sum([p.duration for p in postBufferBeats])) action.render([playback1,crossfade1,playback2,crossfade2,playback3], 'mashup.mp3')
# 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 segment_data_list.append(segment_data) # mix the original and the remix #mixed_data = audio.mix(segment_data,reference_data,mix=mix) mixed_data = audio.megamix(segment_data_list) out.append(mixed_data) # redner output out.encode(outputFilename)
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 segment_data_list.append(segment_data) # mix the original and the remix #mixed_data = audio.mix(segment_data,reference_data,mix=mix) mixed_data = audio.megamix(segment_data_list) out.append(mixed_data) # redner output out.encode(outputFilename)