def sortFiles(self): # Get list of wav files, recursively fileList = utility.getFiles(self.snippetDirectory, '.wav') # Array of per-file, per-note tonalities. Each file gets a score for each pitch tonalities = np.zeros((len(fileList), self.nNotes)) print "Getting tonalities..." for n in np.arange(len(fileList)): # Get audio data audioData, fs = utility.getWavData(fileList[n]) # Make sure the sampling rate matches... assert fs == self.fs # Get the tonality scores for all notes for this file tonalities[n] = self.getTonality(audioData) # Hash for the fundamental frequencies of each file fileFrequencies = {} # Find the best file for each note print "Finding best candidates for notes" for n in np.arange(self.nNotes): # Get the tonality scores tonalitiesForThisNote = tonalities[:, n] # Get the sorted indices of tonality scores tonalitiesSort = np.argsort(tonalitiesForThisNote)[::-1] # Keep track of which sorted array index we're getting the frequency for sortedIndex = 0 # What frequency is the note we're looking for? targetHz = utility.midiToHz(self.baseNote + n) # What's the detected Hz of the note? detectedHz = 1.0 # Until we find an audio file whose YIN detected pitch is sufficiently close while ( (targetHz / detectedHz) < (1 - PITCH_TOLERANCE) or (targetHz / detectedHz) > (1 + PITCH_TOLERANCE)) and sortedIndex < tonalitiesSort.shape[ 0] and sortedIndex < PITCHES_TO_RUN: # If this file has not been YIN analyzed yet, analyze it if not fileFrequencies.has_key(tonalitiesSort[sortedIndex]): audioData, fs = utility.getWavData( fileList[tonalitiesSort[sortedIndex]]) # ... and store it so that you don't have to calculate it next time fileFrequencies[tonalitiesSort[ sortedIndex]] = self.yinPitchDetect(audioData) detectedHz = fileFrequencies[tonalitiesSort[sortedIndex]] # Check the next file next time sortedIndex += 1 # If we didn't run out of files, copy out the file that we found (with the closest pitch) if sortedIndex < len(fileList): shutil.copy( fileList[tonalitiesSort[sortedIndex - 1]], os.path.join(self.destinationDirectory, str(n + self.baseNote) + ".wav")) else: shutil.copy( fileList[tonalitiesSort[0]], os.path.join(self.destinationDirectory, str(n + self.baseNote) + ".wav"))
def createMask( self, N, baseFrequency ): # Number of bins in the mask nBins = N/2 - 1 # Maximum frequency that we want to create a mask for maxFrequency = utility.midiToHz( self.baseNote + self.nNotes + 24 ) # Make sure it's not out of range... above nyquist or so if maxFrequency > (self.fs*.9)/2.0: maxFrequency = (self.fs*.9)/2.0 # Create the mask mask = np.zeros( nBins ) # Over all harmonic frequencies for harmonic in baseFrequency*(2**np.arange( 4 )): if harmonic > maxFrequency: break # Set bins near this harmonic to 1 mask[utility.hzToBins( harmonic, N, self.fs )] = 1 return mask
def createMask(self, N, baseFrequency): # Number of bins in the mask nBins = N / 2 - 1 # Maximum frequency that we want to create a mask for maxFrequency = utility.midiToHz(self.baseNote + self.nNotes + 24) # Make sure it's not out of range... above nyquist or so if maxFrequency > (self.fs * .9) / 2.0: maxFrequency = (self.fs * .9) / 2.0 # Create the mask mask = np.zeros(nBins) # Over all harmonic frequencies for harmonic in baseFrequency * (2**np.arange(4)): if harmonic > maxFrequency: break # Set bins near this harmonic to 1 mask[utility.hzToBins(harmonic, N, self.fs)] = 1 return mask
def getTonality( self, audioData ): # Number of samples in the audio data N = audioData.shape[0] # Tonality scores for each note tonalityScores = np.zeros( self.nNotes ) # Get magnitude spectrum for this audio data AudioData = np.abs( np.fft.rfft( audioData ) ) # Calculate spectral crest factor and RMS... not sure if we should use these spectralCrestFactor = np.max( AudioData )/np.mean( AudioData ) RMS = np.sqrt( np.sum( audioData**2.0 ) )/(N*1.0) # For each note for note in np.arange( self.nNotes ): # Create a mask for only bins which are harmonics of the note in question mask = self.createMask( N, utility.midiToHz( self.baseNote + note ) ) # Calculate "monophonic tonality" - max of bins corresponding to harmonics/spectral mean monophonicTonality = np.max( AudioData[mask == 1] )/np.mean( AudioData[mask == 0] ) # Write out tonality score tonalityScores[note] = monophonicTonality*RMS return tonalityScores
def sortFiles( self ): # Get list of wav files, recursively fileList = utility.getFiles( self.snippetDirectory, '.wav' ) # Array of per-file, per-note tonalities. Each file gets a score for each pitch tonalities = np.zeros( ( len( fileList ), self.nNotes ) ) print "Getting tonalities..." for n in np.arange( len( fileList ) ): # Get audio data audioData, fs = utility.getWavData( fileList[n] ) # Make sure the sampling rate matches... assert fs == self.fs # Get the tonality scores for all notes for this file tonalities[n] = self.getTonality( audioData ) # Hash for the fundamental frequencies of each file fileFrequencies = {} # Find the best file for each note print "Finding best candidates for notes" for n in np.arange( self.nNotes ): # Get the tonality scores tonalitiesForThisNote = tonalities[:,n] # Get the sorted indices of tonality scores tonalitiesSort = np.argsort( tonalitiesForThisNote )[::-1] # Keep track of which sorted array index we're getting the frequency for sortedIndex = 0 # What frequency is the note we're looking for? targetHz = utility.midiToHz( self.baseNote + n ) # What's the detected Hz of the note? detectedHz = 1.0 # Until we find an audio file whose YIN detected pitch is sufficiently close while ((targetHz/detectedHz) < (1 - PITCH_TOLERANCE) or (targetHz/detectedHz) > (1 + PITCH_TOLERANCE)) and sortedIndex < tonalitiesSort.shape[0] and sortedIndex < PITCHES_TO_RUN: # If this file has not been YIN analyzed yet, analyze it if not fileFrequencies.has_key( tonalitiesSort[sortedIndex] ): audioData, fs = utility.getWavData( fileList[tonalitiesSort[sortedIndex]] ) # ... and store it so that you don't have to calculate it next time fileFrequencies[tonalitiesSort[sortedIndex]] = self.yinPitchDetect( audioData ) detectedHz = fileFrequencies[tonalitiesSort[sortedIndex]] # Check the next file next time sortedIndex += 1 # If we didn't run out of files, copy out the file that we found (with the closest pitch) if sortedIndex < len( fileList ): shutil.copy( fileList[tonalitiesSort[sortedIndex-1]], os.path.join( self.destinationDirectory, str(n + self.baseNote) + ".wav" ) ) else: shutil.copy( fileList[tonalitiesSort[0]], os.path.join( self.destinationDirectory, str(n + self.baseNote) + ".wav" ) )
def getTonality(self, audioData): # Number of samples in the audio data N = audioData.shape[0] # Tonality scores for each note tonalityScores = np.zeros(self.nNotes) # Get magnitude spectrum for this audio data AudioData = np.abs(np.fft.rfft(audioData)) # Calculate spectral crest factor and RMS... not sure if we should use these spectralCrestFactor = np.max(AudioData) / np.mean(AudioData) RMS = np.sqrt(np.sum(audioData**2.0)) / (N * 1.0) # For each note for note in np.arange(self.nNotes): # Create a mask for only bins which are harmonics of the note in question mask = self.createMask(N, utility.midiToHz(self.baseNote + note)) # Calculate "monophonic tonality" - max of bins corresponding to harmonics/spectral mean monophonicTonality = np.max(AudioData[mask == 1]) / np.mean( AudioData[mask == 0]) # Write out tonality score tonalityScores[note] = monophonicTonality * RMS return tonalityScores