Chris@0: /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: A waveform viewer and audio annotation editor. Chris@2: Chris Cannam, Queen Mary University of London, 2005-2006 Chris@0: Chris@0: This is experimental software. Not for distribution. Chris@0: */ Chris@0: Chris@0: #include "BeatDetectionFunctionTransform.h" Chris@0: Chris@0: #include "model/DenseTimeValueModel.h" Chris@0: #include "model/SparseTimeValueModel.h" Chris@0: Chris@0: #include Chris@0: #include "dsp/onsets/DetectionFunction.h" Chris@0: #include "dsp/tempotracking/TempoTrack.h" Chris@0: Chris@0: Chris@0: BeatDetectionFunctionTransform::BeatDetectionFunctionTransform(Model *inputModel) : Chris@0: Transform(inputModel) Chris@0: { Chris@0: m_output = new SparseTimeValueModel(inputModel->getSampleRate(), 1, Chris@0: 0.0, 0.0, false); Chris@0: } Chris@0: Chris@0: BeatDetectionFunctionTransform::~BeatDetectionFunctionTransform() Chris@0: { Chris@0: // parent does it all Chris@0: } Chris@0: Chris@0: TransformName Chris@0: BeatDetectionFunctionTransform::getName() Chris@0: { Chris@0: return tr("Beat Detection Function"); Chris@0: } Chris@0: Chris@0: void Chris@0: BeatDetectionFunctionTransform::run() Chris@0: { Chris@0: SparseTimeValueModel *output = getOutput(); Chris@0: DenseTimeValueModel *input = getInput(); Chris@0: if (!input) { Chris@0: std::cerr << "BeatDetectionFunctionTransform::run: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; Chris@0: return; Chris@0: } Chris@0: Chris@0: DFConfig config; Chris@0: Chris@0: config.DFType = DF_COMPLEXSD; Chris@0: Chris@0: // Step resolution for the detection function in seconds Chris@0: config.stepSecs = 0.01161; Chris@0: Chris@0: // Step resolution for the detection function in samples Chris@0: config.stepSize = (unsigned int)floor((double)input->getSampleRate() * Chris@0: config.stepSecs ); Chris@0: Chris@0: config.frameLength = 2 * config.stepSize; Chris@0: Chris@0: unsigned int stepSize = config.stepSize; Chris@0: unsigned int frameLength = config.frameLength; Chris@0: Chris@0: output->setResolution(stepSize); Chris@0: Chris@0: //Tempo Tracking Configuration Parameters Chris@0: TTParams ttparams; Chris@0: Chris@0: // Low Pass filter coefficients for detection function smoothing Chris@0: double* aCoeffs = new double[3]; Chris@0: double* bCoeffs = new double[3]; Chris@0: Chris@0: aCoeffs[ 0 ] = 1; Chris@0: aCoeffs[ 1 ] = -0.5949; Chris@0: aCoeffs[ 2 ] = 0.2348; Chris@0: bCoeffs[ 0 ] = 0.1600; Chris@0: bCoeffs[ 1 ] = 0.3200; Chris@0: bCoeffs[ 2 ] = 0.1600; Chris@0: Chris@0: ttparams.winLength = 512; Chris@0: ttparams.lagLength = 128; Chris@0: ttparams.LPOrd = 2; Chris@0: ttparams.LPACoeffs = aCoeffs; Chris@0: ttparams.LPBCoeffs = bCoeffs; Chris@0: ttparams.alpha = 9; Chris@0: ttparams.WinT.post = 8; Chris@0: ttparams.WinT.pre = 7; Chris@0: Chris@0: //////////////////////////////////////////////////////////// Chris@0: // DetectionFunction Chris@0: //////////////////////////////////////////////////////////// Chris@0: // Instantiate and configure detection function object Chris@0: Chris@0: DetectionFunction df(config); Chris@0: Chris@0: size_t origin = input->getStartFrame(); Chris@0: size_t frameCount = input->getEndFrame() - origin; Chris@0: size_t blocks = (frameCount / stepSize); Chris@0: if (blocks * stepSize < frameCount) ++blocks; Chris@0: Chris@0: double *buffer = new double[frameLength]; Chris@0: Chris@0: // DF output with causal extension Chris@0: unsigned int clen = blocks + ttparams.winLength; Chris@0: double *dfOutput = new double[clen]; Chris@0: Chris@0: std::cerr << "Running beat detection function at step size " << stepSize << "..." << std::endl; Chris@0: Chris@0: for (size_t i = 0; i < clen; ++i) { Chris@0: Chris@0: // std::cerr << "block " << i << "/" << clen << std::endl; Chris@0: // std::cerr << "."; Chris@0: Chris@0: if (i < blocks) { Chris@0: size_t got = input->getValues(-1, //!!! needs to come from parent layer -- which is not supposed to be in scope at this point Chris@0: origin + i * stepSize, Chris@0: origin + i * stepSize + frameLength, Chris@0: buffer); Chris@0: while (got < frameLength) buffer[got++] = 0.0; Chris@0: dfOutput[i] = df.process(buffer); Chris@0: } else { Chris@0: dfOutput[i] = 0.0; Chris@0: } Chris@0: Chris@0: output->addPoint(SparseTimeValueModel::Point Chris@0: (i * stepSize, dfOutput[i], Chris@0: QString("%1").arg(dfOutput[i]))); Chris@0: // m_w->m_bdf->setCompletion(i * 99 / clen); Chris@0: output->setCompletion(i * 99 / clen); Chris@0: Chris@0: if (m_deleting) { Chris@0: delete [] buffer; Chris@0: delete [] dfOutput; Chris@0: delete [] aCoeffs; Chris@0: delete [] bCoeffs; Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: output->setCompletion(100); Chris@0: } Chris@0: Chris@0: DenseTimeValueModel * Chris@0: BeatDetectionFunctionTransform::getInput() Chris@0: { Chris@0: return dynamic_cast(getInputModel()); Chris@0: } Chris@0: Chris@0: SparseTimeValueModel * Chris@0: BeatDetectionFunctionTransform::getOutput() Chris@0: { Chris@0: return static_cast(getOutputModel()); Chris@0: } Chris@0: