| Chris@0 | 1 /* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@0 | 2 | 
| Chris@0 | 3 /* | 
| Chris@0 | 4     A waveform viewer and audio annotation editor. | 
| Chris@2 | 5     Chris Cannam, Queen Mary University of London, 2005-2006 | 
| Chris@0 | 6 | 
| Chris@0 | 7     This is experimental software.  Not for distribution. | 
| Chris@0 | 8 */ | 
| Chris@0 | 9 | 
| Chris@0 | 10 #include "BeatDetectionFunctionTransform.h" | 
| Chris@0 | 11 | 
| Chris@0 | 12 #include "model/DenseTimeValueModel.h" | 
| Chris@0 | 13 #include "model/SparseTimeValueModel.h" | 
| Chris@0 | 14 | 
| Chris@0 | 15 #include <iostream> | 
| Chris@0 | 16 #include "dsp/onsets/DetectionFunction.h" | 
| Chris@0 | 17 #include "dsp/tempotracking/TempoTrack.h" | 
| Chris@0 | 18 | 
| Chris@0 | 19 | 
| Chris@0 | 20 BeatDetectionFunctionTransform::BeatDetectionFunctionTransform(Model *inputModel) : | 
| Chris@0 | 21     Transform(inputModel) | 
| Chris@0 | 22 { | 
| Chris@0 | 23     m_output = new SparseTimeValueModel(inputModel->getSampleRate(), 1, | 
| Chris@0 | 24 					0.0, 0.0, false); | 
| Chris@0 | 25 } | 
| Chris@0 | 26 | 
| Chris@0 | 27 BeatDetectionFunctionTransform::~BeatDetectionFunctionTransform() | 
| Chris@0 | 28 { | 
| Chris@0 | 29     // parent does it all | 
| Chris@0 | 30 } | 
| Chris@0 | 31 | 
| Chris@0 | 32 TransformName | 
| Chris@0 | 33 BeatDetectionFunctionTransform::getName() | 
| Chris@0 | 34 { | 
| Chris@0 | 35     return tr("Beat Detection Function"); | 
| Chris@0 | 36 } | 
| Chris@0 | 37 | 
| Chris@0 | 38 void | 
| Chris@0 | 39 BeatDetectionFunctionTransform::run() | 
| Chris@0 | 40 { | 
| Chris@0 | 41     SparseTimeValueModel *output = getOutput(); | 
| Chris@0 | 42     DenseTimeValueModel *input = getInput(); | 
| Chris@0 | 43     if (!input) { | 
| Chris@0 | 44 	std::cerr << "BeatDetectionFunctionTransform::run: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; | 
| Chris@0 | 45 	return; | 
| Chris@0 | 46     } | 
| Chris@0 | 47 | 
| Chris@0 | 48     DFConfig config; | 
| Chris@0 | 49 | 
| Chris@0 | 50     config.DFType = DF_COMPLEXSD; | 
| Chris@0 | 51 | 
| Chris@0 | 52     // Step resolution for the detection function in seconds | 
| Chris@0 | 53     config.stepSecs = 0.01161; | 
| Chris@0 | 54 | 
| Chris@0 | 55     // Step resolution for the detection function in samples | 
| Chris@0 | 56     config.stepSize = (unsigned int)floor((double)input->getSampleRate() * | 
| Chris@0 | 57 					  config.stepSecs ); | 
| Chris@0 | 58 | 
| Chris@0 | 59     config.frameLength = 2 * config.stepSize; | 
| Chris@0 | 60 | 
| Chris@0 | 61     unsigned int stepSize = config.stepSize; | 
| Chris@0 | 62     unsigned int frameLength = config.frameLength; | 
| Chris@0 | 63 | 
| Chris@0 | 64     output->setResolution(stepSize); | 
| Chris@0 | 65 | 
| Chris@0 | 66     //Tempo Tracking Configuration Parameters | 
| Chris@0 | 67     TTParams ttparams; | 
| Chris@0 | 68 | 
| Chris@0 | 69     // Low Pass filter coefficients for detection function smoothing | 
| Chris@0 | 70     double* aCoeffs = new double[3]; | 
| Chris@0 | 71     double* bCoeffs = new double[3]; | 
| Chris@0 | 72 | 
| Chris@0 | 73     aCoeffs[ 0 ] = 1; | 
| Chris@0 | 74     aCoeffs[ 1 ] = -0.5949; | 
| Chris@0 | 75     aCoeffs[ 2 ] = 0.2348; | 
| Chris@0 | 76     bCoeffs[ 0 ] = 0.1600; | 
| Chris@0 | 77     bCoeffs[ 1 ] = 0.3200; | 
| Chris@0 | 78     bCoeffs[ 2 ] = 0.1600; | 
| Chris@0 | 79 | 
| Chris@0 | 80     ttparams.winLength = 512; | 
| Chris@0 | 81     ttparams.lagLength = 128; | 
| Chris@0 | 82     ttparams.LPOrd = 2; | 
| Chris@0 | 83     ttparams.LPACoeffs = aCoeffs; | 
| Chris@0 | 84     ttparams.LPBCoeffs = bCoeffs; | 
| Chris@0 | 85     ttparams.alpha = 9; | 
| Chris@0 | 86     ttparams.WinT.post = 8; | 
| Chris@0 | 87     ttparams.WinT.pre = 7; | 
| Chris@0 | 88 | 
| Chris@0 | 89     //////////////////////////////////////////////////////////// | 
| Chris@0 | 90     // DetectionFunction | 
| Chris@0 | 91     //////////////////////////////////////////////////////////// | 
| Chris@0 | 92     // Instantiate and configure detection function object | 
| Chris@0 | 93 | 
| Chris@0 | 94     DetectionFunction df(config); | 
| Chris@0 | 95 | 
| Chris@0 | 96     size_t origin = input->getStartFrame(); | 
| Chris@0 | 97     size_t frameCount = input->getEndFrame() - origin; | 
| Chris@0 | 98     size_t blocks = (frameCount / stepSize); | 
| Chris@0 | 99     if (blocks * stepSize < frameCount) ++blocks; | 
| Chris@0 | 100 | 
| Chris@0 | 101     double *buffer = new double[frameLength]; | 
| Chris@0 | 102 | 
| Chris@0 | 103     // DF output with causal extension | 
| Chris@0 | 104     unsigned int clen = blocks + ttparams.winLength; | 
| Chris@0 | 105     double *dfOutput = new double[clen]; | 
| Chris@0 | 106 | 
| Chris@0 | 107     std::cerr << "Running beat detection function at step size " << stepSize << "..." << std::endl; | 
| Chris@0 | 108 | 
| Chris@0 | 109     for (size_t i = 0; i < clen; ++i) { | 
| Chris@0 | 110 | 
| Chris@0 | 111 //	std::cerr << "block " << i << "/" << clen << std::endl; | 
| Chris@0 | 112 //	std::cerr << "."; | 
| Chris@0 | 113 | 
| Chris@0 | 114 	if (i < blocks) { | 
| Chris@0 | 115 	    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 | 116 					  origin + i * stepSize, | 
| Chris@0 | 117 					  origin + i * stepSize + frameLength, | 
| Chris@0 | 118 					  buffer); | 
| Chris@0 | 119 	    while (got < frameLength) buffer[got++] = 0.0; | 
| Chris@0 | 120 	    dfOutput[i] = df.process(buffer); | 
| Chris@0 | 121 	} else { | 
| Chris@0 | 122 	    dfOutput[i] = 0.0; | 
| Chris@0 | 123 	} | 
| Chris@0 | 124 | 
| Chris@0 | 125 	output->addPoint(SparseTimeValueModel::Point | 
| Chris@0 | 126 			 (i * stepSize, dfOutput[i], | 
| Chris@0 | 127 			  QString("%1").arg(dfOutput[i]))); | 
| Chris@0 | 128 //	m_w->m_bdf->setCompletion(i * 99 / clen); | 
| Chris@0 | 129 	output->setCompletion(i * 99 / clen); | 
| Chris@0 | 130 | 
| Chris@0 | 131 	if (m_deleting) { | 
| Chris@0 | 132 	    delete [] buffer; | 
| Chris@0 | 133 	    delete [] dfOutput; | 
| Chris@0 | 134 	    delete [] aCoeffs; | 
| Chris@0 | 135 	    delete [] bCoeffs; | 
| Chris@0 | 136 	    return; | 
| Chris@0 | 137 	} | 
| Chris@0 | 138     } | 
| Chris@0 | 139 | 
| Chris@0 | 140     output->setCompletion(100); | 
| Chris@0 | 141 } | 
| Chris@0 | 142 | 
| Chris@0 | 143 DenseTimeValueModel * | 
| Chris@0 | 144 BeatDetectionFunctionTransform::getInput() | 
| Chris@0 | 145 { | 
| Chris@0 | 146     return dynamic_cast<DenseTimeValueModel *>(getInputModel()); | 
| Chris@0 | 147 } | 
| Chris@0 | 148 | 
| Chris@0 | 149 SparseTimeValueModel * | 
| Chris@0 | 150 BeatDetectionFunctionTransform::getOutput() | 
| Chris@0 | 151 { | 
| Chris@0 | 152     return static_cast<SparseTimeValueModel *>(getOutputModel()); | 
| Chris@0 | 153 } | 
| Chris@0 | 154 |