view cpp-qm-dsp/ConstantQ.cpp @ 30:39dddbb78d8b

Start on CQ process implementation
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 05 Nov 2013 16:44:12 +0000
parents
children 01a3e110bf8d
line wrap: on
line source

#include "ConstantQ.h"

#include "CQKernel.h"

#include "qm-dsp/dsp/rateconversion/Resampler.h"
#include "qm-dsp/maths/MathUtilities.h"
#include "qm-dsp/dsp/transforms/FFT.h"

#include <algorithm>
#include <complex>
#include <iostream>
#include <stdexcept>

using std::vector;
using std::complex;
using std::cerr;
using std::endl;

ConstantQ::ConstantQ(double sampleRate,
		     double minFreq,
		     double maxFreq,
		     int binsPerOctave) :
    m_sampleRate(sampleRate),
    m_maxFrequency(maxFreq),
    m_minFrequency(minFreq),
    m_binsPerOctave(binsPerOctave),
    m_fft(0)
{
    if (minFreq <= 0.0 || maxFreq <= 0.0) {
	throw std::invalid_argument("Frequency extents must be positive");
    }

    initialise();
}

ConstantQ::~ConstantQ()
{
    delete m_fft;
    for (int i = 0; i < m_decimators.size(); ++i) {
	delete m_decimators[i];
    }
}

void
ConstantQ::initialise()
{
    m_octaves = int(ceil(log2(m_maxFrequency / m_minFrequency)));
    double actualMinFreq =
	(m_maxFrequency / pow(2.0, m_octaves)) * pow(2.0, 1.0/m_binsPerOctave);

    cerr << "actual min freq = " << actualMinFreq << endl;

    m_kernel = new CQKernel(m_sampleRate, m_maxFrequency, m_binsPerOctave);
    m_p = m_kernel->getProperties();
    
    // use exact powers of two for resampling rates. They don't have
    // to be related to our actual samplerate, the resampler only
    // cares about the ratio

    int sourceRate = pow(2, m_octaves);
    vector<int> latencies;
    for (int oct = 1; oct < m_octaves; ++oct) {
	Resampler *r = new Resampler(sourceRate, sourceRate / pow(2, oct));
	latencies.push_back(r->getLatency());
	m_decimators.push_back(r);
    }

    //!!! should be multiple of the kernel fft size?
    int maxLatency = *std::max_element(latencies.begin(), latencies.end());
    m_totalLatency = MathUtilities::nextPowerOfTwo(maxLatency);
    cerr << "total latency = " << m_totalLatency << endl;
    for (int i = 0; i < latencies.size(); ++i) {
	m_extraLatencies.push_back(m_totalLatency - latencies[i]);
	cerr << "extra latency " << i << " = " << m_extraLatencies[i] << endl;
	m_octaveBuffers.push_back(new vector<double>(m_extraLatencies[i], 0.0));
    }

    m_fft = new FFT(m_p.fftSize);
    m_bigBlockSize = m_p.fftSize * pow(2, m_octaves) / 2;

    cerr << "m_bigBlockSize = " << m_bigBlockSize << " for " << m_octaves << " octaves" << endl;
}

vector<vector<double> > 
ConstantQ::process(vector<double> td)
{
    for (int i = 1; i < m_octaves; ++i) {
	vector<double> dec = m_decimators[i]->process(td.data(), td.size());
	m_octaveBuffers[i].insert(m_octaveBuffers[i].end(), dec);
    }

    //!!! do the work!

    vector<vector<double> > out;
    return out;
}