Example #1
0
    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;
    }
Example #3
0
 const SignalBank& Model::getOutput(const string& outputName) const
 {
     auto search = outputModules_.find(outputName);
     LOUDNESS_ASSERT(search != outputModules_.end());
     return search -> second -> getOutput();
 }
Example #4
0
    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;
    }
Example #5
0
    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;
    }
Example #6
0
    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;
    }