def add_wave(self, path): """Reads a wave file at `path` and imports its structure into a pattern dictionary.""" # ********************************************************************** # STEP 1: Open waveform from argv and get mono audio samples wav = waveform.from_file(path) wav.setchannelcount(1) samples = np.fromstring(wav.getsamples(), dtype='Int16').tolist() # ********************************************************************** # STEP 2: Run STFT on samples matrix = stft.STFT_Matrix(samples, c_size=2**10) matrix.amplitudes = stft.triangular_smoothing(matrix.amplitudes, 3) matrix.smooth_amps_2() matrix.blip_filter_2() #matrix.spectrogram() # ********************************************************************** # STEP 3: Convert the STFT to PatternDictionary self.pattern_dictionary.import_stft(matrix)
waveform-test.py - tests the waveform class Copyright EJM Software 2016 Usage: python waveform-test.py PATH """ # ****************************************************************************** # Add the parent directory to Python's list of paths to search for modules import sys sys.path.append("../") # ****************************************************************************** import waveform if __name__=="__main__": if len(sys.argv) > 1: # LOAD A WAVEFORM FROM FILE wav = waveform.from_file(sys.argv[1]) originalsamplewidth = wav.getsamplewidth() originalchannelcount = wav.getchannelcount() originalsize = len(wav.getsamples()) # TEST ONE: LOADING AND WRITING # write the data to a file waveform.to_file('readertest.wav', wav) # check that the files are identical, ie. the data was read and processed properly import filecmp assert filecmp.cmp(sys.argv[1], 'readertest.wav') # delete the created test file from os import remove remove('readertest.wav') # TEST TWO: CHANGING THE CHANNEL COUNT
def add_template(self, filename): """Adds a song to the music generator's knowledge base""" # STEP 1: Read the waveform music file at the given path wave = waveform.from_file(filename) print "Setting channel count" wave.setchannelcount(1) print "Making samples" samples = stft.np.fromstring(wave.getsamples(), dtype='Int16').tolist() print "Done" # STEP 2: Parse the waveform music into a music note format using STFT matrix = stft.STFT_Matrix(samples, c_size=2**10) matrix.amplitudes = stft.triangular_smoothing(matrix.amplitudes, 5) matrix.smooth_amps_2() matrix.filter(31000) matrix.spectrogram() # STEP 3: Create an array with all the patterns found in the music # Notes about the self.patterns dictionary: # "Next" - an array # Parse the data into songsmith format # Then, place each note into the patterns dictionary song = matrix.to_song() #print len(song.chords) song.debug() # Note: In "next" array, the 0 index is the newest self.patterns.append({"name":"", "frequency":"", "durations":[0], "next":[[] for i in range(self.search_depth)], "chords":[]}) lastindices = [[0] for i in range(self.search_depth)] for chord in song.chords: currentindices = [] # Skip notes shorter than 25 bps, its probably trash data if chord.notes[0].duration < 0.04: continue # Add the notes from the chord for note in chord.notes: name = songsmith.freqtoname(note.frequency)[:-1] currentindex = next((i for i,v in enumerate(self.patterns) if v["name"]==name), None) if currentindex==None: currentindex = len(self.patterns) self.patterns.append({"name":name, "frequency":note.frequency, "durations":[], "next":[[] for i in range(self.search_depth)], "chords":[]}) self.patterns[currentindex]["durations"].append(note.duration) for other in currentindices: if other != note: self.patterns[currentindex]["chords"].append(other) # Pack the next note data into the patterns dictionary for depth, indices in enumerate(lastindices): for index in indices: self.patterns[index]["next"][depth].append(currentindex) currentindices.append(currentindex) # Update the lastindices for the next loop lastindices.pop() lastindices.insert(0, currentindices) # last2indices = last1indices # last1indices = currentindices # Add the blank notes to the end of the song # for last1index in last1indices: # self.patterns[last1index]["nexts"].append(0) # for last2index in last2indices: # self.patterns[last2index]["next2"].append(0) # Add as many empty notes to the end of the patterns as the search_depth for depth, indices in enumerate(lastindices): for index in indices: for i in range(depth, self.search_depth): self.patterns[index]["next"][i].append(0)