bool Window::initializeInternal(const SignalBank &input) { LOUDNESS_ASSERT(input.getNSamples() == length_[0], name_ << ": Number of input samples does not equal the largest window size!"); //number of windows nWindows_ = (int)length_.size(); LOUDNESS_DEBUG(name_ << ": Number of windows = " << nWindows_); window_.resize(nWindows_); //Largest window should be the first largestWindowSize_ = length_[0]; LOUDNESS_DEBUG(name_ << ": Largest window size = " << largestWindowSize_); //first window (largest) does not require a shift windowOffset_.push_back(0); //check if we are using multi windows on one input channel int nOutputChannels = input.getNChannels(); if((input.getNChannels()==1) && (nWindows_>1)) { LOUDNESS_DEBUG(name_ << ": Using parallel windows"); parallelWindows_ = true; nOutputChannels = nWindows_; //if so, calculate the delay int alignmentSample = largestWindowSize_ / 2; LOUDNESS_DEBUG(name_ << ": Alignment sample = " << alignmentSample); for(int w=1; w<nWindows_; w++) { int thisCentreSample = length_[w] / 2; int thisWindowOffset = alignmentSample - thisCentreSample; windowOffset_.push_back(thisWindowOffset); LOUDNESS_DEBUG(name_ << ": Centre sample for window " << w << " = " << thisCentreSample); LOUDNESS_DEBUG(name_ << ": Offset for window " << w << " = " << thisWindowOffset); } } else { LOUDNESS_ASSERT(input.getNChannels() == nWindows_, "Multiple channels but incorrect window specification."); } //generate the normalised window functions for (int w=0; w<nWindows_; w++) { window_[w].assign(length_[w],0.0); generateWindow(window_[w], windowType_, periodic_); normaliseWindow(window_[w], normalisation_); LOUDNESS_DEBUG(name_ << ": Length of window " << w << " = " << window_[w].size()); } //initialise the output signal output_.initialize(input.getNEars(), nOutputChannels, largestWindowSize_, input.getFs()); output_.setFrameRate(input.getFrameRate()); return 1; }
bool SpecificLoudnessANSIS342007::initializeInternal(const SignalBank &input) { LOUDNESS_ASSERT(input.getNChannels() > 1, name_ << ": Insufficient number of input channels."); //c value from ANSI 2007 parameterC_ = 0.046871; if (updateParameterCForBinauralInhibition_) { parameterC_ /= 0.75; LOUDNESS_DEBUG(name_ << ": Scaling parameter C for binaural inhibition model: " << parameterC_); } //Number of filters below 500Hz nFiltersLT500_ = 0; Real eThrqdB500Hz = internalExcitation(500); //fill loudness parameter vectors for (int i = 0; i < input.getNChannels(); i++) { Real fc = input.getCentreFreq(i); if (fc < 500) { Real eThrqdB = internalExcitation(fc); eThrqParam_.push_back(pow(10, eThrqdB/10.0)); Real gdB = eThrqdB500Hz - eThrqdB; parameterG_.push_back(pow(10, gdB/10.0)); parameterA_.push_back(gdBToA(gdB)); parameterAlpha_.push_back(gdBToAlpha(gdB)); nFiltersLT500_++; } } LOUDNESS_DEBUG(name_ << ": number of filters <500 Hz: " << nFiltersLT500_); //output SignalBank output_.initialize(input); return 1; }
const SignalBank& Model::getOutput(const string& outputName) const { auto search = outputModules_.find(outputName); LOUDNESS_ASSERT(search != outputModules_.end()); return search -> second -> getOutput(); }
bool Biquad::initializeInternal(const SignalBank &input) { if (type_ == "RLB") { RealVec bCoefs = {1.0, -2.0, 1.0}; RealVec aCoefs = {1.0, -1.99004745483398, 0.99007225036621}; setBCoefs (bCoefs); setACoefs (aCoefs); setCoefficientFs (48000); } else if (type_ == "prefilter") { RealVec bCoefs = {1.53512485958697, -2.69169618940638, 1.19839281085285}; RealVec aCoefs = {1.0, -1.69065929318241, 0.73248077421585}; setBCoefs (bCoefs); setACoefs (aCoefs); setCoefficientFs (48000); } LOUDNESS_ASSERT( bCoefs_.size() == 3 && aCoefs_.size() == 3, "Filter coefficients do not satisfy filter order"); //normalise by a[0] normaliseCoefs(); //Transform coefficients if sampling frequency is different from //the one used in origin filter design //See: Parameter Quantization in Direct-Form Recursive Audio Filters //by Neunaber (2008) if((coefficientFs_ != 0) && (coefficientFs_ != input.getFs())) { double fc = (coefficientFs_/PI) * atan( sqrt( (1+aCoefs_[1]+aCoefs_[2]) / (1-aCoefs_[1]+aCoefs_[2]))); double Q = sqrt((aCoefs_[2]+1)*(aCoefs_[2]+1) - aCoefs_[1]*aCoefs_[1]) / (2*fabs(1-aCoefs_[2])); double Vl = (bCoefs_[0]+bCoefs_[1]+bCoefs_[2]) / (1+aCoefs_[1]+aCoefs_[2]); double Vb = (bCoefs_[0] - bCoefs_[2]) / (1-aCoefs_[2]); double Vh = (bCoefs_[0]-bCoefs_[1]+bCoefs_[2]) / (1-aCoefs_[1]+aCoefs_[2]); double omega = tan(PI*fc/input.getFs()); double omegaSqrd = omega*omega; double denom = omegaSqrd + omega/Q + 1; aCoefs_[0] = 1.0; aCoefs_[1] = 2*(omegaSqrd - 1) / denom; aCoefs_[2] = (omegaSqrd - (omega/Q) + 1)/ denom; bCoefs_[0] = (Vl * omegaSqrd + Vb * (omega/Q) + Vh) / denom; bCoefs_[1] = 2*(Vl*omegaSqrd - Vh) / denom; bCoefs_[2] = (Vl*omegaSqrd - (Vb*omega/Q) + Vh) / denom; } /* std::cout << "A" << std::endl; for (int i = 0; i < 3; ++i) std::cout << aCoefs_[i] << std::endl; std::cout << "B" << std::endl; for (int i = 0; i < 3; ++i) std::cout << bCoefs_[i] << std::endl; */ delayLine_.initialize(input.getNSources(), input.getNEars(), input.getNChannels(), 2, input.getFs()); //output SignalBank output_.initialize(input); return 1; }
bool CompressSpectrum::initializeInternal(const SignalBank &input) { LOUDNESS_ASSERT(input.getNChannels() > 1, name_ << ": Insufficient number of channels."); /* * This code is sloppy due to along time spent figuring how * to implement the damn thing. * It's currently in two parts, one that searches for the limits of each * summation range in order to satisfy summation criterion. * The other that finds the average Centre frequencies per compressed band. */ int nChannels = input.getNChannels(); int i=0, binIdxPrev = 0; Real dif = hertzToCam(input.getCentreFreq(1)) - hertzToCam(input.getCentreFreq(0)); int groupSize = max(2.0, std::floor(alpha_/(dif))); int groupSizePrev = groupSize; vector<int> groupSizeStore, binIdx; while(i < nChannels-1) { //compute different between adjacent bins on Cam scale dif = hertzToCam(input.getCentreFreq(i+1)) - hertzToCam(input.getCentreFreq(i)); //Check if we can sum bins in group size if(dif < (alpha_/double(groupSize))) { /* * from here we can group bins in groupSize * whilst maintaining alpha spacing */ //Check we have zero idx if((binIdx.size() < 1) && (i>0)) { binIdx.push_back(0); groupSizeStore.push_back(1); } /* * This line ensures the next group starts at the next multiple of the previous * groupSize above the previous starting position. * This is why you sometimes get finer resolution than the criterion */ int store = ceil((i-binIdxPrev)/double(groupSizePrev))*groupSizePrev+binIdxPrev; /* * This line is cheeky; it re-evaluates the groupSize at the new multiple * in attempt to maintain alpha spacing, I'm not 100% but the algorithm * seems to satisfy various criteria */ if((store > 0) && (store < nChannels)) { dif = hertzToCam(input.getCentreFreq(store)) - hertzToCam(input.getCentreFreq(store-1)); groupSize = max((double)groupSize, std::floor(alpha_/dif)); } //fill variables groupSizePrev = groupSize; binIdxPrev = store; //storage binIdx.push_back(store); groupSizeStore.push_back(groupSize); //print "Bin: %d, Binnew: %d, composite bin size: %d" % (i, store, groupSize) //Move i along i = store+groupSize; //increment groupSize for wider group groupSize += 1; } else i += 1; } //add the final frequency if(binIdx[binIdx.size()-1] < nChannels) binIdx.push_back(nChannels); //PART 2 //compressed spectrum RealVec cfs; Real fa = 0; int count = 0; int j = 0; i = 0; while(i < nChannels) { //bounds check out? if(i<binIdx[j+1]) { fa += input.getCentreFreq(i); count++; if (count==groupSizeStore[j]) { //upper limit upperBandIdx_.push_back(i+1); //+1 for < conditional //set the output frequency cfs.push_back(fa/count); count = 0; fa = 0; } i++; } else j++; } //add the final component if it didn't make it if (count>0) { cfs.push_back(fa/count); upperBandIdx_.push_back(i); } //check #if defined(DEBUG) Real freqLimit = 0.0; for(unsigned int i=0; i<cfs.size()-1; i++) { if((hertzToCam(cfs[i+1]) - hertzToCam(cfs[i])) > alpha_) freqLimit = cfs[i]; } LOUDNESS_DEBUG("CompressSpectrum: Criterion satisfied above " << freqLimit << " Hz."); #endif //set output SignalBank output_.initialize(input.getNSources(), input.getNEars(), cfs.size(), 1, input.getFs()); output_.setCentreFreqs(cfs); output_.setFrameRate(input.getFrameRate()); LOUDNESS_DEBUG(name_ << ": Number of bins comprising the compressed spectrum: " << output_.getNChannels()); return 1; }
bool PowerSpectrum::initializeInternal(const SignalBank &input) { ffts_.clear(); //number of windows int nWindows = (int)windowSizes_.size(); LOUDNESS_ASSERT(input.getNChannels() == nWindows, name_ << ": Number of channels do not match number of windows"); LOUDNESS_ASSERT((int)bandFreqsHz_.size() == (nWindows + 1), name_ << ": Number of frequency bands should equal number of input channels + 1."); LOUDNESS_ASSERT(!anyAscendingValues(windowSizes_), name_ << ": Window lengths must be in descending order."); //work out FFT configuration (constrain to power of 2) int largestWindowSize = input.getNSamples(); vector<int> fftSize(nWindows, nextPowerOfTwo(largestWindowSize)); if(sampleSpectrumUniformly_) { ffts_.push_back(unique_ptr<FFT> (new FFT(fftSize[0]))); ffts_[0] -> initialize(); } else { for(int w=0; w<nWindows; w++) { fftSize[w] = nextPowerOfTwo(windowSizes_[w]); ffts_.push_back(unique_ptr<FFT> (new FFT(fftSize[w]))); ffts_[w] -> initialize(); } } //desired bins indices (lo and hi) per band bandBinIndices_.resize(nWindows); normFactor_.resize(nWindows); int fs = input.getFs(); int nBins = 0; for(int i=0; i<nWindows; i++) { //bin indices to use for compiled spectrum bandBinIndices_[i].resize(2); //These are NOT the nearest components but satisfies f_k in [f_lo, f_hi) bandBinIndices_[i][0] = ceil(bandFreqsHz_[i]*fftSize[i]/fs); // use < bandBinIndices_[i][1] to exclude upper bin bandBinIndices_[i][1] = ceil(bandFreqsHz_[i+1]*fftSize[i]/fs); LOUDNESS_ASSERT(bandBinIndices_[i][1]>0, name_ << ": No components found in band number " << i); //exclude DC and Nyquist if found int nyqIdx = (fftSize[i]/2) + (fftSize[i]%2); if(bandBinIndices_[i][0]==0) { LOUDNESS_WARNING(name_ << ": DC found...excluding."); bandBinIndices_[i][0] = 1; } if((bandBinIndices_[i][1]-1) >= nyqIdx) { LOUDNESS_WARNING(name_ << ": Bin is >= nyquist...excluding."); bandBinIndices_[i][1] = nyqIdx; } nBins += bandBinIndices_[i][1]-bandBinIndices_[i][0]; //Power spectrum normalisation Real refSquared = referenceValue_ * referenceValue_; switch (normalisation_) { case NONE: normFactor_[i] = 1.0 / refSquared; break; case ENERGY: normFactor_[i] = 2.0/(fftSize[i] * refSquared); break; case AVERAGE_POWER: normFactor_[i] = 2.0/(fftSize[i] * windowSizes_[i] * refSquared); break; default: normFactor_[i] = 2.0/(fftSize[i] * refSquared); } LOUDNESS_DEBUG(name_ << ": Normalisation factor : " << normFactor_[i]); } //total number of bins in the output spectrum LOUDNESS_DEBUG(name_ << ": Total number of bins comprising the output spectrum: " << nBins); //initialize the output SignalBank output_.initialize(input.getNEars(), nBins, 1, fs); output_.setFrameRate(input.getFrameRate()); //output frequencies in Hz int j = 0, k = 0; for(int i=0; i<nWindows; i++) { j = bandBinIndices_[i][0]; while(j < bandBinIndices_[i][1]) output_.setCentreFreq(k++, (j++)*fs/(Real)fftSize[i]); LOUDNESS_DEBUG(name_ << ": Included freq Hz (band low): " << fs * bandBinIndices_[i][0] / float(fftSize[i]) << ": Included freq Hz (band high): " << fs * (bandBinIndices_[i][1] - 1) / float(fftSize[i])); } return 1; }