def calculateRMSForData(inputData, byteWidth): maxValueForInputData = 2**((byteWidth*8)-1) sampleData = [] for i in range(0,len(inputData), byteWidth): try: sampleData.append(les24toles32Value(inputData[i:i+byteWidth]) * 1.0/maxValueForInputData) except Exception as e: print e.message signalPower = np.sum(np.power(sampleData,2)) rms = math.sqrt(signalPower/(len(inputData)/byteWidth)) return dbRepresentation(rms)
def ultimateFreqAndPowerForData(inputData, byteWidth, sampleRate): ### this must be refactored for the appropiate type of data ### for signed data maxValueForInputData = 2**((byteWidth*8)-1) sampleData = [] for i in range(0,len(inputData), byteWidth): try: sampleData.append(les24toles32Value(inputData[i:i+byteWidth]) * 1.0/maxValueForInputData) except Exception as e: print e.message signal = np.array(sampleData) signalPower = np.sum(np.power(signal,2)) rms = math.sqrt(signalPower/(len(inputData)/byteWidth)) highestdbRep = dbRepresentation(rms) # Compute Fourier transform of windowed signal windowed = signal * blackmanharris(len(signal)) f = np.fft.rfft(windowed) # Find the peak and interpolate to get a more accurate peak i = np.argmax(abs(f)) # Just use this for less-accurate, naive version try: #defensive code around divide by zero issue, basically creating noise np.seterr(all='ignore') a = np.arange(len(f), dtype=np.float) a.fill(10**-10) nf = np.where(f == 0., a, f) i = i if i != 0. else 10**-10 if i > len(nf)-2: i = len(nf) -2 true_i = parabolic(np.log(abs(nf)), i)[0] # Convert to equivalent frequency freqHz = (sampleRate * true_i / len(windowed)) except ValueError: freqHz = 0.0 return {"mainFreq":{"freqHz":freqHz, "dbRep":highestdbRep}, "nextFreq":{"freqHz":"0", "dbRep":"0"}}
def analyzeTrackCorrelations(filePath): wavefile = None if os.path.exists(filePath): wavefile = PCWaveFile(filePath) else: return if wavefile == None or wavefile.isValidWaveFile() == False: return {"status":"fail", "resultString":"file is not a wavefile", "layout":"Unknown"} sampleRate = wavefile.fmtChunkInfoDict['nSamplesPerSec'] channelByteWidth = wavefile.fmtChunkInfoDict['wBitsPerSample'] / 8 bitsPerSample = wavefile.fmtChunkInfoDict['wBitsPerSample'] numberOfChannels = wavefile.fmtChunkInfoDict['nChannels'] packetByteWidth = channelByteWidth * numberOfChannels if numberOfChannels != 6: if numberOfChannels == 2: return {"status":"pass", "resultString":"File contains {} audio channels".format(numberOfChannels), "layout":"STEREO"} else: return {"status":"pass", "resultString":"File contains {} audio channels".format(numberOfChannels), "layout":"Unknown"} isSigned = True if channelByteWidth == 1: isSigned = False chunkPosition = wavefile.getDataChunk()['chunkPosition'] numberOfSamples = wavefile.getDataChunk()['chunkSize'] / packetByteWidth #open the file, read through the packets and do a running mean of each track in the file #what this does do is ASSUME that the input file is 24 bit signed data, otherwise 16 bit would be signed, but 8 bit wouldn't #not that 8 bit is an issue with open(filePath, 'rb') as f: f.seek(chunkPosition) blockWidthInSeconds = 1 samplesToReadBlockSize = (sampleRate * blockWidthInSeconds)/2 numberOfSamplesRemaining = numberOfSamples bufferAmount = samplesToReadBlockSize if numberOfSamples > samplesToReadBlockSize else numberOfSamples totalBlocksInFile = numberOfSamplesRemaining // samplesToReadBlockSize shouldReadEntireFile = False analysisSpacing = 0 numberOfAnalyses = 34 initialAnalyses = 0 if totalBlocksInFile < (2 * numberOfAnalyses): shouldReadEntireFile = True else: analysisSpacing = totalBlocksInFile / numberOfAnalyses startTime = datetime.datetime.now() constantBitDepth16 = pow(2,15) constantBitDepth24 = pow(2,23) #totalsCounter = RunningTotalCounter(pow(2,(bitsPerSample-1)), samplesToReadBlockSize, numberOfChannels) totalsCounter = RunningTotalCounter(constantBitDepth16, samplesToReadBlockSize, numberOfChannels) # you need to constrain the size of the input as we will be calculating RMS values which require exponential math while numberOfSamplesRemaining > 0: #read a buffer's amount of samples if numberOfSamplesRemaining > bufferAmount: bytesToRead = packetByteWidth * bufferAmount data = f.read(bytesToRead) numberOfSamplesRemaining -= (len(data)/packetByteWidth) if len(data) != bytesToRead: logging.error("IO Error: bytes returned do not match bytes asked for") #read a buffer's amount of samples analysis = {} for i in range(0,numberOfChannels): analysis[str(i)] = [] # read the file or current analysis into memory and sum all of the samples and raise to the 2nd pow if shouldReadEntireFile == True or (initialAnalyses % analysisSpacing == 0): for i in range(0, bytesToRead, packetByteWidth): subdata = data[i:(i+packetByteWidth)] for chPos in range(0, numberOfChannels): trackoffset = chPos * channelByteWidth extendedValue = les24toles32Value(''.join(subdata[trackoffset:trackoffset+channelByteWidth])) extendedValue = int(((1.0 * extendedValue) / constantBitDepth24) * constantBitDepth16) analysis[str(chPos)].append(extendedValue) maxValue = 0 track = 0 srcTrack = '0' for i in [0,1,2,3,4,5]: if int(srcTrack) == i: continue result = np.cov(analysis[srcTrack], analysis[str(i)])[0,1] if result > maxValue: maxValue = result track = i print srcTrack, "matches", track, "with", maxValue initialAnalyses += 1 else: data = f.read(packetByteWidth * numberOfSamplesRemaining) numberOfSamplesRemaining = 0 return {"OK":"OK"}
def analyzeLevels(filePath): wavefile = None if os.path.exists(filePath): wavefile = PCWaveFile(filePath) else: return if wavefile == None or wavefile.isValidWaveFile() == False: return {"status":"fail", "resultString":"file is not a wavefile", "layout":"Unknown", "warningString":""} sampleRate = wavefile.fmtChunkInfoDict['nSamplesPerSec'] channelByteWidth = wavefile.fmtChunkInfoDict['wBitsPerSample'] / 8 bitsPerSample = wavefile.fmtChunkInfoDict['wBitsPerSample'] numberOfChannels = wavefile.fmtChunkInfoDict['nChannels'] packetByteWidth = channelByteWidth * numberOfChannels for title in ['MEHELP']: if title.lower() in filePath.lower(): layout = 'MONO' if numberOfChannels == 1 else 'MULTI-MONO' return {"status":"pass", "resultString":"The file contains {} in its file name and will not be analyzed.".format(title), "layout":layout, "warningString":""} if numberOfChannels != 6: if numberOfChannels == 2: return {"status":"pass", "resultString":"File contains {} audio channels".format(numberOfChannels), "layout":"STEREO", "warningString":""} else: return {"status":"pass", "resultString":"File contains {} audio channels".format(numberOfChannels), "layout":"Unknown", "warningString":""} isSigned = True if channelByteWidth == 1: isSigned = False chunkPosition = wavefile.getDataChunk()['chunkPosition'] numberOfSamples = wavefile.getDataChunk()['chunkSize'] / packetByteWidth #open the file, read through the packets and do a running mean of each track in the file #what this does do is ASSUME that the input file is 24 bit signed data, otherwise 16 bit would be signed, but 8 bit wouldn't #not that 8 bit is an issue with open(filePath, 'rb') as f: f.seek(chunkPosition) blockWidthInSeconds = 4 samplesToReadBlockSize = (sampleRate * blockWidthInSeconds) numberOfSamplesRemaining = numberOfSamples bufferAmount = samplesToReadBlockSize if numberOfSamples > samplesToReadBlockSize else numberOfSamples totalBlocksInFile = numberOfSamplesRemaining // samplesToReadBlockSize shouldReadEntireFile = False analysisSpacing = 0 numberOfAnalyses = 34 initialAnalyses = 0 if totalBlocksInFile < (2 * numberOfAnalyses): shouldReadEntireFile = True else: analysisSpacing = totalBlocksInFile / numberOfAnalyses startTime = datetime.datetime.now() constantBitDepth16 = pow(2,15) constantBitDepth24 = pow(2,23) #totalsCounter = RunningTotalCounter(pow(2,(bitsPerSample-1)), samplesToReadBlockSize, numberOfChannels) totalsCounter = RunningTotalCounter(constantBitDepth16, samplesToReadBlockSize, numberOfChannels) # you need to constrain the size of the input as we will be calculating RMS values which require exponential math while numberOfSamplesRemaining > 0: #read a buffer's amount of samples if numberOfSamplesRemaining > bufferAmount: bytesToRead = packetByteWidth * bufferAmount data = f.read(bytesToRead) numberOfSamplesRemaining -= (len(data)/packetByteWidth) if len(data) != bytesToRead: logging.error("IO Error: bytes returned do not match bytes asked for") #read a buffer's amount of samples analysis = totalsCounter.emptyAnalysisDictionary() # read the file or current analysis into memory and sum all of the samples and raise to the 2nd pow if shouldReadEntireFile == True or (initialAnalyses % analysisSpacing == 0): for i in range(0, bytesToRead, packetByteWidth): subdata = data[i:(i+packetByteWidth)] for chPos in range(0, numberOfChannels): trackoffset = chPos * channelByteWidth extendedValue = les24toles32Value(''.join(subdata[trackoffset:trackoffset+channelByteWidth])) extendedValue = int(((1.0 * extendedValue) / constantBitDepth24) * constantBitDepth16) analysis[str(chPos)] += (extendedValue**2) totalsCounter.addAnalysis(analysis) initialAnalyses += 1 else: data = f.read(packetByteWidth * numberOfSamplesRemaining) numberOfSamplesRemaining = 0 return totalsCounter.performAnalysis()
def highestAndNextHighestFreqAndPowerForData(inputData, byteWidth, sampleRate): ### this must be refactored for the appropiate type of data ### for signed data maxValueForInputData = 2**((byteWidth*8)-1) sampleData = [] for i in range(0,len(inputData), byteWidth): try: sampleData.append(les24toles32Value(inputData[i:i+byteWidth]) * 1.0/maxValueForInputData) except Exception as e: print e.message ### take sample data and make numpy array from which we take the fft and keep the lower half of the data ### I am not applying a window data = np.array(sampleData) p = np.fft.fft(data) uniquePts = math.ceil(len(data)/2.0) + 1.0 p = p[0:uniquePts] freqs = np.fft.fftfreq(len(data)) #### Find the peak in the coefficients idx = np.argmax(np.abs(p)**2) freq = freqs[idx] freqHz = abs(freq*sampleRate) ### Find the next highest peak which should exclude a nice band around the frequency of interest ### high end ### since we can be certain that each frequency band has a resolution of 1 Hz ### I can calculate the 1/3 octave frequency by using the idx upperBand = idx * pow(2,1.0/6) safeIdx = upperBand if upperBand < len(p) else idx pNext = p[safeIdx:len(p)-safeIdx] if len(pNext) > 0: idxNext = np.argmax(np.abs(pNext)**2) idxNext += safeIdx nextHighest = idxNext else: nextHighest = 0 ### low end lowerBand = idx / pow(2,1.0/6) safeIdx = lowerBand if lowerBand > 1 else idx pNext = p[0:safeIdx] if len(pNext) > 0: idxNext = np.argmax(np.abs(pNext)**2) else: idxNext = 0 if abs(p[idxNext]) > abs(p[nextHighest]): nextHighest = idxNext nextHighestFreq = freqs[nextHighest] nextHighestFreqHz = abs(nextHighestFreq*sampleRate) ### normalize fft length p = np.divide(p,float(len(data))) p = np.abs(p) p = np.power(p,2) ### make up for the power loss we deleted the the right side of the fft if len(data) % 2 > 0: p[1:len(p)] = np.multiply(p[1:len(p)], 2) else: p[1:len(p) - 1] = np.multiply(p[1:len(p) -1], 2) ### calculate the power of the highest frequency index rms = math.sqrt(p[idx]) dataLength = (len(inputData)/byteWidth) hightestdbRep = dbRepresentation(rms) highestFreqDict = {"freqHz":freqHz, "dbRep":hightestdbRep} ### calculate the power of the next highest frequency index rmsNext = math.sqrt(p[nextHighest]) dataLength = (len(inputData)/byteWidth) nextHighestdbRep = dbRepresentation(rmsNext) nextHighestFreqDict = {"freqHz":nextHighestFreqHz, "dbRep":nextHighestdbRep} return {"mainFreq":highestFreqDict, "nextFreq":nextHighestFreqDict}
def analyzeTrackCorrelations(filePath): wavefile = None if os.path.exists(filePath): wavefile = PCWaveFile(filePath) else: return if wavefile == None or wavefile.isValidWaveFile() == False: return { "status": "fail", "resultString": "file is not a wavefile", "layout": "Unknown" } sampleRate = wavefile.fmtChunkInfoDict['nSamplesPerSec'] channelByteWidth = wavefile.fmtChunkInfoDict['wBitsPerSample'] / 8 bitsPerSample = wavefile.fmtChunkInfoDict['wBitsPerSample'] numberOfChannels = wavefile.fmtChunkInfoDict['nChannels'] packetByteWidth = channelByteWidth * numberOfChannels if numberOfChannels != 6: if numberOfChannels == 2: return { "status": "pass", "resultString": "File contains {} audio channels".format(numberOfChannels), "layout": "STEREO" } else: return { "status": "pass", "resultString": "File contains {} audio channels".format(numberOfChannels), "layout": "Unknown" } isSigned = True if channelByteWidth == 1: isSigned = False chunkPosition = wavefile.getDataChunk()['chunkPosition'] numberOfSamples = wavefile.getDataChunk()['chunkSize'] / packetByteWidth #open the file, read through the packets and do a running mean of each track in the file #what this does do is ASSUME that the input file is 24 bit signed data, otherwise 16 bit would be signed, but 8 bit wouldn't #not that 8 bit is an issue with open(filePath, 'rb') as f: f.seek(chunkPosition) blockWidthInSeconds = 1 samplesToReadBlockSize = (sampleRate * blockWidthInSeconds) / 2 numberOfSamplesRemaining = numberOfSamples bufferAmount = samplesToReadBlockSize if numberOfSamples > samplesToReadBlockSize else numberOfSamples totalBlocksInFile = numberOfSamplesRemaining // samplesToReadBlockSize shouldReadEntireFile = False analysisSpacing = 0 numberOfAnalyses = 34 initialAnalyses = 0 if totalBlocksInFile < (2 * numberOfAnalyses): shouldReadEntireFile = True else: analysisSpacing = totalBlocksInFile / numberOfAnalyses startTime = datetime.datetime.now() constantBitDepth16 = pow(2, 15) constantBitDepth24 = pow(2, 23) #totalsCounter = RunningTotalCounter(pow(2,(bitsPerSample-1)), samplesToReadBlockSize, numberOfChannels) totalsCounter = RunningTotalCounter(constantBitDepth16, samplesToReadBlockSize, numberOfChannels) # you need to constrain the size of the input as we will be calculating RMS values which require exponential math while numberOfSamplesRemaining > 0: #read a buffer's amount of samples if numberOfSamplesRemaining > bufferAmount: bytesToRead = packetByteWidth * bufferAmount data = f.read(bytesToRead) numberOfSamplesRemaining -= (len(data) / packetByteWidth) if len(data) != bytesToRead: logging.error( "IO Error: bytes returned do not match bytes asked for" ) #read a buffer's amount of samples analysis = {} for i in range(0, numberOfChannels): analysis[str(i)] = [] # read the file or current analysis into memory and sum all of the samples and raise to the 2nd pow if shouldReadEntireFile == True or (initialAnalyses % analysisSpacing == 0): for i in range(0, bytesToRead, packetByteWidth): subdata = data[i:(i + packetByteWidth)] for chPos in range(0, numberOfChannels): trackoffset = chPos * channelByteWidth extendedValue = les24toles32Value(''.join( subdata[trackoffset:trackoffset + channelByteWidth])) extendedValue = int( ((1.0 * extendedValue) / constantBitDepth24) * constantBitDepth16) analysis[str(chPos)].append(extendedValue) maxValue = 0 track = 0 srcTrack = '0' for i in [0, 1, 2, 3, 4, 5]: if int(srcTrack) == i: continue result = np.cov(analysis[srcTrack], analysis[str(i)])[0, 1] if result > maxValue: maxValue = result track = i print srcTrack, "matches", track, "with", maxValue initialAnalyses += 1 else: data = f.read(packetByteWidth * numberOfSamplesRemaining) numberOfSamplesRemaining = 0 return {"OK": "OK"}