diff options
| -rw-r--r-- | rotord/rotor.cpp | 6 | ||||
| -rwxr-xr-x | rotord/rotor.h | 16 | ||||
| -rw-r--r-- | rotord/vampHost.cpp | 132 | ||||
| -rw-r--r-- | rotord/vampHost.h | 14 |
4 files changed, 65 insertions, 103 deletions
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index 2cd894f..af0bd7e 100644 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -567,4 +567,10 @@ int Audio_analysis::process_frame(uint8_t *data,int samples_in_frame) { } void Audio_analysis::cleanup() { analyser.cleanup(); + //print_features(); } +void Audio_analysis::print_features(){ + for (auto i: analyser.features) { + cerr<<i.second<<" "<<i.first<<endl; + } +}
\ No newline at end of file diff --git a/rotord/rotor.h b/rotord/rotor.h index 105ed98..7dbb18d 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -244,9 +244,21 @@ namespace Rotor { void cleanup(); int process_frame(uint8_t *data,int samples_in_frame); float get_output(const float &time) { - float t=time; - return t; + if (analyser.features.size()) { + auto i=analyser.features.lower_bound(time); + if (i!=analyser.features.end()){ + float lk=i->first; + int ln=i->second; + if (i++!=analyser.features.end()){ + float uk=i->first; + return (((time-lk)/(uk-lk))+ln); + } + else return (float)ln; + } + } + return 0.0f; } + void print_features(); private: string soname,id; int outputNo; diff --git a/rotord/vampHost.cpp b/rotord/vampHost.cpp index 21f5db5..2713e38 100644 --- a/rotord/vampHost.cpp +++ b/rotord/vampHost.cpp @@ -604,7 +604,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_ stride=channels*bytes; scale=(1.0f/pow(2.0f,bits)); - + features[0.0f]=0; loader = PluginLoader::getInstance(); key = loader->composePluginKey(soname, id); @@ -643,7 +643,6 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_ currentStep = 0; finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF - filebuf = new float[blockSize * channels]; plugbuf = new float*[channels]; for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; @@ -716,7 +715,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_ blocks_processed=0; currentStep=0; - featureNo=0; + featureNo=1; return true; } @@ -725,63 +724,6 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){ //process the whole frame which may be f>1<f blocks //when the frame is finished leave the partial block for the next frame - - //seems that the vamp plugin needs to be given a block context bigger than the step that it processes - /* - each frame that comes in contains samples_in_frame samples (samples*bytes*channels data) - we may have part of a block remaining from the previous frames/s - - filebuf is filled from incoming frames - - when filebuf is full, fill plugbuf from filebuf (necessary?) - - the point is, each step is smaller than a block, but we manage the steps and blocks- seems a bit stupid - - after each processing step, 'shunt down' the data and prepare the pointer to fill the next - - - /// - int count; - - if ((blockSize==stepSize) || (currentStep==0)) { - // read a full fresh block - if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { - cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; - break; - } - if (count != blockSize) --finalStepsRemaining; - } else { - // otherwise shunt the existing data down and read the remainder. - memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float)); - if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) { - cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; - break; - } - if (count != stepSize) --finalStepsRemaining; - count += overlapSize; - } - - for (int c = 0; c < channels; ++c) { - int j = 0; - while (j < count) { - plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; - ++j; - } - while (j < blockSize) { - plugbuf[c][j] = 0.0f; - ++j; - } - } - - rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); - - /// - - - */ - - - while(sample<samples_in_frame) { while(sample<samples_in_frame&&in_block<blockSize) { for (int i=0;i<channels;i++) { @@ -795,6 +737,10 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){ sample++; } if (in_block==blockSize) { + //block is ready to be processed + //cerr<<plugin->getIdentifier()<<" processed block "<<blocks_processed<<endl; + + //I /think/ that the vamp plugin keeps processing through the plugbuf until it encounters 0s rt = RealTime::frame2RealTime(currentStep * stepSize, rate); Plugin::FeatureSet feat=plugin->process(plugbuf, rt); @@ -804,45 +750,45 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){ featureNo++; } + //shunt it down + for (int i=0;i<blockSize-stepSize;i++){ + for (int j=0;j<channels;j++){ + plugbuf[j][i]=plugbuf[j][i+stepSize]; + } + } + in_block-=stepSize; currentStep++; - - //shunt down the data - - for (int i=0;i<in_block;i++){ - for (int j=0;j<channels;j++){ - plugbuf[j][i]=plugbuf[j][i+stepSize]; - } - } } } } void vampHost::Analyser::cleanup(){ - - //fill remainder of final block with zeroes - for (int i=in_block;i<blockSize;i++){ - for (int j=0;j<channels;j++){ - plugbuf[j][i]=0.0f; - } - } - - rt = RealTime::frame2RealTime(currentStep * stepSize, rate); - - Plugin::FeatureSet feat=plugin->process(plugbuf, rt); - - for (unsigned int i = 0; i < feat[outputNo].size(); ++i) { - features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo; - featureNo++; - } - - feat = plugin->getRemainingFeatures(); - - for (unsigned int i = 0; i < feat[outputNo].size(); ++i) { - features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo; - featureNo++; - } - - cerr<<plugin->getIdentifier()<<" found "<<features.size()<<" features"<<endl; + + //process final block + while(in_block<blockSize) { + for (int i=0;i<channels;i++) { + plugbuf[i][in_block]=0.0f; + } + in_block++; + } + + rt = RealTime::frame2RealTime(currentStep * stepSize, rate); + + Plugin::FeatureSet feat=plugin->process(plugbuf, rt); + + for (unsigned int i = 0; i < feat[outputNo].size(); ++i) { + features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo; + featureNo++; + } + + feat=plugin->getRemainingFeatures(); + + for (unsigned int i = 0; i < feat[outputNo].size(); ++i) { + features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo; + featureNo++; + } + + cerr<<plugin->getIdentifier()<<" found "<<(features.size()-1)<<" features"<<endl; //deal with left over data? for (int c = 0; c < channels; ++c) { delete[] plugbuf[c]; diff --git a/rotord/vampHost.h b/rotord/vampHost.h index c632e44..3758055 100644 --- a/rotord/vampHost.h +++ b/rotord/vampHost.h @@ -59,28 +59,26 @@ namespace vampHost { bool init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,const int &_outputNo=0,const string &_output=""); void process_frame(uint8_t *data,int samples_in_frame); void cleanup(); + + map<float,int> features; + //map<time,featureNo> + //this is the best way to store features: because map allows to search for the key below and above the present time + private: PluginLoader *loader; PluginLoader::PluginKey key; Plugin *plugin; + RealTime rt; int channels,bits,samples,rate; int bytes,stride; float scale; int blockSize,stepSize,overlapSize,finalStepsRemaining,currentStep,outputNo; int in_block,blocks_processed; string output; - float *filebuf; float **plugbuf; - RealTime rt; int featureNo; - map<float,int> features; - //what's the best way to store features? - //how will it be used? - //we ask for a signal at a time, return interpolated value representing feature number + fraction - //is there a quick way to search the keys and return the last one below a given value - }; string getQMBeats(const string soundfile); |
