def EncodeSingleChannel(data, codingParams): """Encodes a single-channel block of signed-fraction data based on the parameters in a PACFile object""" # prepare various constants halfN = codingParams.nMDCTLines # print halfN # N = 2*halfN # print N nScaleBits = codingParams.nScaleBits maxMantBits = ( 1 << codingParams.nMantSizeBits ) # 1 isn't an allowed bit allocation so n size bits counts up to 2^n if maxMantBits > 16: maxMantBits = 16 # to make sure we don't ever overflow mantissa holders sfBands = codingParams.sfBands # vectorizing the Mantissa function call # vMantissa = np.vectorize(Mantissa) # compute target mantissa bit budget for this block of halfN MDCT mantissas bitBudget = codingParams.targetBitsPerSample * halfN # this is overall target bit rate bitBudget -= nScaleBits * ( sfBands.nBands + 1 ) # less scale factor bits (including overall scale factor) bitBudget -= codingParams.nMantSizeBits * sfBands.nBands # less mantissa bit allocation bits # window data for side chain FFT and also window and compute MDCT timeSamples = data mdctTimeSamples = SineWindow(data) mdctLines = MDCT(mdctTimeSamples, halfN, halfN)[:halfN] # compute overall scale factor for this block and boost mdctLines using it maxLine = np.max(np.abs(mdctLines)) overallScale = ScaleFactor( maxLine, nScaleBits) #leading zeroes don't depend on nMantBits mdctLines *= (1 << overallScale) # # compute SPLs # bandPeaks=np.zeros(25) # for i in np.arange(sfBands.nBands): # bandPeaks[i]=np.amax(mdctLines[sfBands.lowerLine[i]:sfBands.upperLine[i]]) # from psychoac import SPL # bandPeaks=SPL(bandPeaks) # compute the mantissa bit allocations # compute SMRs in side chain FFT SMRs = CalcSMRs(timeSamples, mdctLines, overallScale, codingParams.sampleRate, sfBands) # perform bit allocation using SMR results bitAlloc = BitAlloc(bitBudget, maxMantBits, sfBands.nBands, sfBands.nLines, SMRs) # bitAlloc = BitAllocUniform(bitBudget, maxMantBits, sfBands.nBands, sfBands.nLines) # bitAlloc = BitAllocConstSNR(bitBudget, maxMantBits, sfBands.nBands, sfBands.nLines, bandPeaks) # bitAlloc = BitAllocConstMNR(bitBudget, maxMantBits, sfBands.nBands, sfBands.nLines, SMRs) # given the bit allocations, quantize the mdct lines in each band scaleFactor = np.empty(sfBands.nBands, dtype=np.int32) nMant = halfN # print nMant for iBand in range(sfBands.nBands): if not bitAlloc[iBand]: nMant -= sfBands.nLines[ iBand] # account for mantissas not being transmitted # print nMant mantissa = np.empty(nMant, dtype=np.int32) iMant = 0 for iBand in range(sfBands.nBands): lowLine = sfBands.lowerLine[iBand] highLine = sfBands.upperLine[ iBand] + 1 # extra value is because slices don't include last value nLines = sfBands.nLines[iBand] scaleLine = np.max(np.abs(mdctLines[lowLine:highLine])) scaleFactor[iBand] = ScaleFactor(scaleLine, nScaleBits, bitAlloc[iBand]) if bitAlloc[iBand]: # print len(mdctLines[lowLine:highLine]) # print scaleFactor[iBand] # print nScaleBits # print bitAlloc[iBand] # print len(mantissa[iMant:iMant+nLines]) # output = vMantissa(mdctLines[lowLine:highLine],scaleFactor[iBand], nScaleBits, bitAlloc[iBand]) # print len(output) # print iMant # print nMant # print nLines # print '\n' mantissa[iMant:iMant + nLines] = vMantissa( mdctLines[lowLine:highLine], scaleFactor[iBand], nScaleBits, bitAlloc[iBand]) iMant += nLines # end of loop over scale factor bands # return results return (scaleFactor, bitAlloc, mantissa, overallScale)
def EncodeSingleChannel(data, codingParams): """Encodes a single-channel block of signed-fraction data based on the parameters in a PACFile object""" # prepare various constants """----------------------------------------EDIT--------------------------------------------------""" # compute the actual window and half window lengths N = codingParams.a + codingParams.b halfN = (codingParams.a + codingParams.b) / 2. """------------------------------------END-EDIT--------------------------------------------------""" nScaleBits = codingParams.nScaleBits maxMantBits = ( 1 << codingParams.nMantSizeBits ) # 1 isn't an allowed bit allocation so n size bits counts up to 2^n if maxMantBits > 16: maxMantBits = 16 # to make sure we don't ever overflow mantissa holders sfBands = codingParams.sfBands # vectorizing the Mantissa function call # vMantissa = np.vectorize(Mantissa) # compute target mantissa bit budget for this block of halfN MDCT mantissas bitBudget = codingParams.targetBitsPerSample * halfN # this is overall target bit rate bitBudget -= nScaleBits * ( sfBands.nBands + 1 ) # less scale factor bits (including overall scale factor) bitBudget -= codingParams.nMantSizeBits * sfBands.nBands # less mantissa bit allocation bits """----------------------------------------EDIT--------------------------------------------------""" # account for (binary) block length bits bitBudget -= codingParams.blkswBitA bitBudget -= codingParams.blkswBitB # add bit reservoir bitBudget += codingParams.bitReservoir """------------------------------------END-EDIT--------------------------------------------------""" # window data for side chain FFT and also window and compute MDCT timeSamples = data """----------------------------------------EDIT--------------------------------------------------""" # use TransitionWindow instead of SineWindow # send MDCT and TransitionWindow the actual block lengths mdctTimeSamples = TransitionWindow(data, codingParams.a, codingParams.b) mdctLines = MDCT(mdctTimeSamples, codingParams.a, codingParams.b)[:halfN] """------------------------------------END-EDIT--------------------------------------------------""" # compute overall scale factor for this block and boost mdctLines using it maxLine = np.max(np.abs(mdctLines)) overallScale = ScaleFactor( maxLine, nScaleBits) #leading zeroes don't depend on nMantBits mdctLines *= (1 << overallScale) # compute the mantissa bit allocations # compute SMRs in side chain FFT SMRs = CalcSMRs(timeSamples, mdctLines, overallScale, codingParams.sampleRate, sfBands) # perform bit allocation using SMR results (bitAlloc, remaining_bits) = BitAlloc(bitBudget, maxMantBits, sfBands.nBands, sfBands.nLines, SMRs) bitAlloc = bitAlloc.astype(int) """----------------------------------------EDIT--------------------------------------------------""" codingParams.bitReservoir = int(remaining_bits) """--------------------------------------END-EDIT--------------------------------------------------""" # given the bit allocations, quantize the mdct lines in each band scaleFactor = np.empty(sfBands.nBands, dtype=np.int32) nMant = halfN for iBand in range(sfBands.nBands): if not bitAlloc[iBand]: nMant -= sfBands.nLines[ iBand] # account for mantissas not being transmitted mantissa = np.empty(nMant, dtype=np.int32) iMant = 0 for iBand in range(sfBands.nBands): lowLine = sfBands.lowerLine[iBand] highLine = sfBands.upperLine[ iBand] + 1 # extra value is because slices don't include last value nLines = sfBands.nLines[iBand] scaleLine = np.max(np.abs(mdctLines[lowLine:highLine])) scaleFactor[iBand] = ScaleFactor(scaleLine, nScaleBits, bitAlloc[iBand]) if bitAlloc[iBand]: mantissa[iMant:iMant + nLines] = vMantissa( mdctLines[lowLine:highLine], scaleFactor[iBand], nScaleBits, bitAlloc[iBand]) iMant += nLines # end of loop over scale factor bands # return results return (scaleFactor, bitAlloc, mantissa, overallScale)
def JointEncodeChannels(dataLeft, dataRight, codingParams): """Encodes a single-channel block of signed-fraction data based on the parameters in a PACFile object""" #calculate the mid channel and the side channel dataMid = (dataLeft + dataRight) / 2.0 dataSide = (dataLeft - dataRight) / 2.0 """----------------------------------------EDIT--------------------------------------------------""" # compute the actual window and half window lengths N = codingParams.a + codingParams.b halfN = (codingParams.a + codingParams.b) / 2. """------------------------------------END-EDIT--------------------------------------------------""" nScaleBits = codingParams.nScaleBits maxMantBits = ( 1 << codingParams.nMantSizeBits ) # 1 isn't an allowed bit allocation so n size bits counts up to 2^n if maxMantBits > 16: maxMantBits = 16 # to make sure we don't ever overflow mantissa holders sfBands = codingParams.sfBands # vectorizing the Mantissa function call # vMantissa = np.vectorize(Mantissa) # compute target mantissa bit budget for this block of halfN MDCT mantissas bitBudget = codingParams.targetBitsPerSample * halfN # this is overall target bit rate bitBudget -= nScaleBits * ( sfBands.nBands ) # less scale factor bits (including overall scale factor) bitBudget -= codingParams.nMantSizeBits * sfBands.nBands # less mantissa bit allocation bits ### need to also factor in subtracting the scale factor bands for a bit determining m/s code bitBudget += bitBudget bitBudget -= sfBands.nBands bitBudget -= nScaleBits * 4 bitBudget += codingParams.bitReservoir """----------------------------------------EDIT--------------------------------------------------""" # account for (binary) block length bits bitBudget -= codingParams.blkswBitA bitBudget -= codingParams.blkswBitB """------------------------------------END-EDIT--------------------------------------------------""" ### Compute all of the MDCTs For the Left, Right, Mid, Side # window data for side chain FFT and also window and compute MDCT timeSamples_Left = dataLeft """----------------------------------------EDIT--------------------------------------------------""" # use TransitionWindow instead of SineWindow # send MDCT and TransitionWindow the actual block lengths mdctTimeSamples_Left = TransitionWindow(dataLeft, codingParams.a, codingParams.b) mdctLinesLeft = MDCT(mdctTimeSamples_Left, codingParams.a, codingParams.b)[:halfN] """------------------------------------END-EDIT--------------------------------------------------""" timeSamples_Right = dataRight """----------------------------------------EDIT--------------------------------------------------""" # use TransitionWindow instead of SineWindow # send MDCT and TransitionWindow the actual block lengths mdctTimeSamples_Right = TransitionWindow(dataRight, codingParams.a, codingParams.b) mdctLinesRight = MDCT(mdctTimeSamples_Right, codingParams.a, codingParams.b)[:halfN] """------------------------------------END-EDIT--------------------------------------------------""" timeSamples_Mid = dataMid """----------------------------------------EDIT--------------------------------------------------""" # use TransitionWindow instead of SineWindow # send MDCT and TransitionWindow the actual block lengths mdctTimeSamples_Mid = TransitionWindow(dataMid, codingParams.a, codingParams.b) mdctLinesMid = MDCT(mdctTimeSamples_Mid, codingParams.a, codingParams.b)[:halfN] """------------------------------------END-EDIT--------------------------------------------------""" timeSamples_Side = dataSide """----------------------------------------EDIT--------------------------------------------------""" # use TransitionWindow instead of SineWindow # send MDCT and TransitionWindow the actual block lengths mdctTimeSamples_Side = TransitionWindow(dataSide, codingParams.a, codingParams.b) mdctLinesSide = MDCT(mdctTimeSamples_Side, codingParams.a, codingParams.b)[:halfN] """------------------------------------END-EDIT--------------------------------------------------""" ### # determine which bands to enable ms coding ms_switch = MSSwitchSFBands(mdctLinesLeft, mdctLinesRight, sfBands) ### compute scale factors for lr ms: this is the normalization stuff # compute overall scale factor for this block and boost mdctLines using it maxLine_Left = np.max(np.abs(mdctLinesLeft)) overallScale_Left = ScaleFactor( maxLine_Left, nScaleBits) #leading zeroes don't depend on nMantBits mdctLinesLeft *= (1 << overallScale_Left) maxLine_Right = np.max(np.abs(mdctLinesRight)) overallScale_Right = ScaleFactor( maxLine_Right, nScaleBits) #leading zeroes don't depend on nMantBits mdctLinesRight *= (1 << overallScale_Right) maxLine_Mid = np.max(np.abs(mdctLinesMid)) overallScale_Mid = ScaleFactor( maxLine_Mid, nScaleBits) #leading zeroes don't depend on nMantBits mdctLinesMid *= (1 << overallScale_Mid) maxLine_Side = np.max(np.abs(mdctLinesSide)) overallScale_Side = ScaleFactor( maxLine_Side, nScaleBits) #leading zeroes don't depend on nMantBits mdctLinesSide *= (1 << overallScale_Side) scaleFactorsPack = [] scaleFactorsPack.append(overallScale_Left) scaleFactorsPack.append(overallScale_Right) scaleFactorsPack.append(overallScale_Mid) scaleFactorsPack.append(overallScale_Side) ### ### Calculate the new thresholds for mid and side with the masking factors midThresh = getMaskedThreshold(timeSamples_Mid, mdctLinesMid, overallScale_Mid, codingParams.sampleRate, sfBands) sideThresh = getMaskedThreshold(timeSamples_Side, mdctLinesSide, overallScale_Side, codingParams.sampleRate, sfBands) lin = np.linspace(0, N - 1, N) freq = np.add(lin, 0.5) freq = np.multiply(freq, (codingParams.sampleRate) / N) freqtest = freq[0:N / 2] zVec = Bark(freqtest) new_threshs = StereoMaskingFactor(midThresh, sideThresh, sfBands, zVec) new_midThresh = new_threshs[0] new_sideThresh = new_threshs[1] ### Calculate all of the SMRs for all SMRs_Left = CalcSMRs(timeSamples_Left, mdctLinesLeft, overallScale_Left, codingParams.sampleRate, sfBands) SMRs_Right = CalcSMRs(timeSamples_Right, mdctLinesRight, overallScale_Right, codingParams.sampleRate, sfBands) SMRs_Mid = CalcSMRs(timeSamples_Mid, mdctLinesMid, overallScale_Mid, codingParams.sampleRate, sfBands, 1, new_midThresh) SMRs_Side = CalcSMRs(timeSamples_Side, mdctLinesSide, overallScale_Side, codingParams.sampleRate, sfBands, 1, new_sideThresh) (SMR1, SMR2) = OverallSMRs(SMRs_Left, SMRs_Right, SMRs_Mid, SMRs_Side, sfBands, ms_switch) ### # perform bit allocation using SMR results #need to concatenate together, then split appart once the allocations have been made back into 2 channels nLines1 = sfBands.nLines nLinesPass = np.append(nLines1, nLines1) SMRsConcat = SMR1 SMRsPass = np.append(SMRsConcat, SMR2) (bitAlloc, remaining_bits) = BitAlloc(bitBudget, maxMantBits, 2 * sfBands.nBands, nLinesPass, SMRsPass) bitAlloc = bitAlloc.astype(int) bitAlloc1 = bitAlloc[0:sfBands.nBands] bitAlloc2 = bitAlloc[sfBands.nBands:] codingParams.bitReservoir = int(remaining_bits) # given the bit allocations, quantize the mdct lines in each band scaleFactor1 = np.empty(sfBands.nBands, dtype=np.int32) scaleFactor2 = np.empty(sfBands.nBands, dtype=np.int32) nMant = halfN #for the first bit allocation of the left and mid signals for iBand in range(sfBands.nBands): if not bitAlloc1[iBand]: nMant -= sfBands.nLines[ iBand] # account for mantissas not being transmitted mantissa1 = np.empty(nMant, dtype=np.int32) iMant = 0 for iBand in range(sfBands.nBands): ms_band = ms_switch[iBand] lowLine = sfBands.lowerLine[iBand] highLine = sfBands.upperLine[ iBand] + 1 # extra value is because slices don't include last value nLines = sfBands.nLines[iBand] if ms_band == 1: mdctLines = mdctLinesMid else: mdctLines = mdctLinesLeft scaleLine = np.max(np.abs(mdctLines[lowLine:highLine])) scaleFactor1[iBand] = ScaleFactor(scaleLine, nScaleBits, bitAlloc1[iBand]) if bitAlloc1[iBand]: mantissa1[iMant:iMant + nLines] = vMantissa( mdctLines[lowLine:highLine], scaleFactor1[iBand], nScaleBits, bitAlloc1[iBand]) iMant += nLines # end of loop over scale factor bands nMant = halfN #for the second bit allocation of the right and side signals for iBand in range(sfBands.nBands): if not bitAlloc2[iBand]: nMant -= sfBands.nLines[ iBand] # account for mantissas not being transmitted mantissa2 = np.empty(nMant, dtype=np.int32) iMant = 0 for iBand in range(sfBands.nBands): ms_band = ms_switch[iBand] lowLine = sfBands.lowerLine[iBand] highLine = sfBands.upperLine[ iBand] + 1 # extra value is because slices don't include last value nLines = sfBands.nLines[iBand] if ms_band == 1: mdctLines = mdctLinesSide else: mdctLines = mdctLinesRight scaleLine = np.max(np.abs(mdctLines[lowLine:highLine])) scaleFactor2[iBand] = ScaleFactor(scaleLine, nScaleBits, bitAlloc2[iBand]) if bitAlloc2[iBand]: mantissa2[iMant:iMant + nLines] = vMantissa( mdctLines[lowLine:highLine], scaleFactor2[iBand], nScaleBits, bitAlloc2[iBand]) iMant += nLines # end of loop over scale factor bands # return results scaleFactors = [] bitAlloc = [] mantissa = [] scaleFactors.append(scaleFactor1) scaleFactors.append(scaleFactor2) bitAlloc.append(bitAlloc1) bitAlloc.append(bitAlloc2) mantissa.append(mantissa1) mantissa.append(mantissa2) return (scaleFactors, bitAlloc, mantissa, scaleFactorsPack, ms_switch)
def EncodeDualChannel(data,codingParams,LRMS,huffman): """Encodes a single-channel block of signed-fraction data based on the parameters in a PACFile object""" # prepare various constants halfN = codingParams.nMDCTLines nScaleBits = codingParams.nScaleBits maxMantBits = (1<<codingParams.nMantSizeBits) # 1 isn't an allowed bit allocation so n size bits counts up to 2^n if maxMantBits>16: maxMantBits = 16 # to make sure we don't ever overflow mantissa holders sfBands = codingParams.sfBands # compute target mantissa bit budget for this block of halfN MDCT mantissas bitBudget = codingParams.targetBitsPerSample * halfN # this is overall target bit rate bitBudget -= nScaleBits*(sfBands.nBands +1) # less scale factor bits (including overall scale factor) bitBudget -= codingParams.nMantSizeBits*sfBands.nBands # less mantissa bit allocation bits '''Subtract the bits needed for the table ID''' bitBudget -= codingParams.nTableIDBits '''Get extra bits saved from Huffman encoding to do bit alloc''' codingParams.extraBits += huffman.withdrawBits() timeSamples=[] mdctTimeSamples=[] mdctLines=[] maxLine=[] overallScale=[] for iCh in range(codingParams.nChannels): # window data for side chain FFT and also window and compute MDCT timeSamples.append(data[iCh]) mdctTimeSamples.append(SineWindow(data[iCh])) mdctLines.append(MDCT(mdctTimeSamples[iCh], halfN, halfN)[:halfN]) # compute overall scale factor for this block and boost mdctLines using it maxLine.append(np.max( np.abs(mdctLines[iCh]) ) ) overallScale.append(ScaleFactor(maxLine[iCh],nScaleBits) ) #leading zeroes don't depend on nMantBits mdctLines[iCh] *= (1<<overallScale[iCh]) # compute the mantissa bit allocations # compute SMRs in side chain FFT (SMRs,LRMSmdctLines) = getStereoMaskThreshold(timeSamples, mdctLines, overallScale, codingParams.sampleRate, sfBands, LRMS, codingParams) bitAlloc=[] scaleFactor=[] mantissa=[] # perform bit allocation using SMR results for iCh in range(codingParams.nChannels): ba,bitDifference=BitAlloc(bitBudget, codingParams.extraBits, maxMantBits, sfBands.nBands, sfBands.nLines, SMRs[iCh], LRMS) bitAlloc.append(ba) codingParams.extraBits+=bitDifference # given the bit allocations, quantize the mdct lines in each band scaleFactor.append(np.empty(sfBands.nBands,dtype=np.int32)) nMant=halfN for iBand in range(sfBands.nBands): if not bitAlloc[iCh][iBand]: nMant-= sfBands.nLines[iBand] # account for mantissas not being transmitted mantissa.append(np.empty(nMant,dtype=np.int32)) iMant=0 for iBand in range(sfBands.nBands): lowLine = sfBands.lowerLine[iBand] highLine = sfBands.upperLine[iBand] + 1 # extra value is because slices don't include last value nLines= sfBands.nLines[iBand] scaleLine = np.max(np.abs( LRMSmdctLines[iCh][lowLine:highLine] ) ) scaleFactor[iCh][iBand] = ScaleFactor(scaleLine, nScaleBits, bitAlloc[iCh][iBand]) if bitAlloc[iCh][iBand]: mantissa[iCh][iMant:iMant+nLines] = vMantissa(LRMSmdctLines[iCh][lowLine:highLine],scaleFactor[iCh][iBand], nScaleBits, bitAlloc[iCh][iBand]) iMant += nLines # end of loop over scale factor bands # return results return (scaleFactor, bitAlloc, mantissa, overallScale)