summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/rotor.cpp28
-rwxr-xr-xrotord/rotor.h13
-rw-r--r--rotord/vampHost.cpp155
-rw-r--r--rotord/vampHost.h12
4 files changed, 190 insertions, 18 deletions
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
index cd288e3..73577f4 100644
--- a/rotord/rotor.cpp
+++ b/rotord/rotor.cpp
@@ -30,7 +30,10 @@ void Render_context::runTask() {
if (load_audio(audio_filename,processors)) {
state=AUDIO_READY;
}
- else state=IDLE;
+ else {
+ //an error occurred: TODO have to clean up allocated data. autoptr?
+ state=IDLE;
+ }
}
sleep(100);
}
@@ -326,7 +329,10 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process
std::cout << "The data is in format " <<codecContext->sample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<<std::endl;
for (auto p: processors) {
- p->init(codecContext->channels,16,samples,codecContext->sample_rate);
+ if(!p->init(codecContext->channels,16,samples,codecContext->sample_rate) ){
+ cerr<<"Plugin failed to initialse"<<endl;
+ return false;
+ }
}
AVPacket packet;
@@ -397,6 +403,10 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process
cerr << "finished processing: "<<sample_processed << " samples of "<<samples<<", "<<((double)sample_processed*100)/samples<<"%"<< std::endl;
// Clean up!
+ for (auto p: processors) {
+ p->cleanup();
+ }
+
av_free(frame);
avcodec_close(codecContext);
av_close_input_file(formatContext);
@@ -469,7 +479,7 @@ Node_factory::Node_factory(){
add_type("==",new Is_new_integer());
add_type("signal_output",new Signal_output());
}
-void Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) {
+bool Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) {
//base_audio_processor::init(_channels,_bits,_samples);
channels=_channels;
bits=_bits;
@@ -482,6 +492,7 @@ void Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) {
sample=0;
samples=0;
accum=0.0;
+ return true;
}
int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){
//begin by processing remaining samples
@@ -539,13 +550,13 @@ string Audio_thumbnailer::print(){
}
return output;
}
-void Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) {
+bool Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) {
//need these to make sense of data
channels=_channels;
bits=_bits;
samples=_samples;
-
- analyser.init(soname,id,_rate);
+
+ return analyser.init(soname,id,_channels,_bits,_samples,_rate);
//attempt to load vamp plugin and prepare to receive frames of data
//should the audio analysis contain a vamphost or should it inherit?
@@ -553,6 +564,9 @@ void Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) {
}
int Audio_analysis::process_frame(uint8_t *data,int samples_in_frame) {
- //the standard vamp process takes a file
+ analyser.process_frame(data,samples_in_frame);
return 1;
}
+void Audio_analysis::cleanup() {
+ analyser.cleanup();
+}
diff --git a/rotord/rotor.h b/rotord/rotor.h
index 11e1170..105ed98 100755
--- a/rotord/rotor.h
+++ b/rotord/rotor.h
@@ -183,7 +183,7 @@ namespace Rotor {
string type;
string output_type;
string ID;
- string check(map<string,string> &settings,string key){ if (settings.find(key)!=settings.end()) return settings[key]; else return "";};
+ string check(map<string,string> &settings,string key,string def=""){ if (settings.find(key)!=settings.end()) return settings[key]; else return def;};
void base_settings(map<string,string> &settings) {
description=check(settings,"description");
type=check(settings,"type");
@@ -225,7 +225,8 @@ namespace Rotor {
class Base_audio_processor: public Signal_node {
public:
virtual int process_frame(uint8_t *data,int samples)=0;
- virtual void init(int _channels,int _bits,int _samples,int _rate)=0;
+ virtual bool init(int _channels,int _bits,int _samples,int _rate)=0;
+ virtual void cleanup()=0;
int channels,bits,samples,rate;
};
//actual nodes-------------------------------------------------
@@ -236,9 +237,11 @@ namespace Rotor {
base_settings(settings);
soname=check(settings,"soname");
id=check(settings,"id");
+ outputNo=ofToInt(check(settings,"output","0"));
};
Audio_analysis* clone(map<string,string> &_settings) { return new Audio_analysis(_settings);};
- void init(int _channels,int _bits,int _samples,int _rate);
+ bool init(int _channels,int _bits,int _samples,int _rate);
+ void cleanup();
int process_frame(uint8_t *data,int samples_in_frame);
float get_output(const float &time) {
float t=time;
@@ -246,6 +249,7 @@ namespace Rotor {
}
private:
string soname,id;
+ int outputNo;
vampHost::Analyser analyser;
};
class Signal_divide: public Signal_node {
@@ -375,7 +379,8 @@ namespace Rotor {
delete[] data;
};
Audio_thumbnailer* clone(map<string,string> &_settings) { return new Audio_thumbnailer();};
- void init(int _channels,int _bits,int _samples,int _rate);
+ bool init(int _channels,int _bits,int _samples,int _rate);
+ void cleanup(){};
int process_frame(uint8_t *data,int samples_in_frame);
string print();
uint8_t *data;
diff --git a/rotord/vampHost.cpp b/rotord/vampHost.cpp
index b9b0781..e28419c 100644
--- a/rotord/vampHost.cpp
+++ b/rotord/vampHost.cpp
@@ -588,21 +588,164 @@ float vampHost::QMAnalyser::get_progress(){
mutex.unlock();
return p;
}
-void vampHost::Analyser::init(const string &soname,const string &id,const int &rate){
+bool vampHost::Analyser::init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,const int &_outputNo,const string &_output){
+
+ //stuff that only happens once
+ channels =_channels;
+ samples=_samples;
+ rate=_rate;
+ bits=_bits;
+ outputNo=_outputNo;
+ output=_output;
+
+ //http://www.mega-nerd.com/libsndfile/api.html#note1
+ //libsndfile returns -1..1 for fp data
+ bytes=(bits>>3);
+ stride=channels*bytes;
+ scale=(1.0f/pow(2.0f,bits));
+
+
loader = PluginLoader::getInstance();
key = loader->composePluginKey(soname, id);
- Plugin *plugin = loader->loadPlugin(key, rate, PluginLoader::ADAPT_ALL_SAFE);
+ Plugin *plugin = loader->loadPlugin(key, _rate, PluginLoader::ADAPT_ALL_SAFE);
if (!plugin) {
cerr << ": ERROR: Failed to load plugin \"" << id
<< "\" from library \"" << soname << "\"" << endl;
- return;
+ return false;
}
cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
- delete plugin;
+ blockSize = plugin->getPreferredBlockSize();
+ stepSize = plugin->getPreferredStepSize();
- return;
-}
+ if (blockSize == 0) {
+ blockSize = 1024;
+ }
+ if (stepSize == 0) {
+ if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
+ stepSize = blockSize/2;
+ } else {
+ stepSize = blockSize;
+ }
+ }
+ else if (stepSize > blockSize) {
+ cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
+ if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
+ blockSize = stepSize * 2;
+ } else {
+ blockSize = stepSize;
+ }
+ cerr << blockSize << endl;
+ }
+ overlapSize = blockSize - stepSize;
+ 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];
+
+ cerr << "Using block size = " << blockSize << ", step size = "
+ << stepSize << endl;
+
+ // The channel queries here are for informational purposes only --
+ // a PluginChannelAdapter is being used automatically behind the
+ // scenes, and it will take case of any channel mismatch
+
+ int minch = plugin->getMinChannelCount();
+ int maxch = plugin->getMaxChannelCount();
+ cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
+ cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
+
+ Plugin::OutputList outputs = plugin->getOutputDescriptors();
+ Plugin::OutputDescriptor od;
+
+ int returnValue = 1;
+ int prog = 0;
+
+ RealTime rt;
+ PluginWrapper *wrapper = 0;
+ RealTime adjustment = RealTime::zeroTime;
+
+ if (outputs.empty()) {
+ cerr << "ERROR: Plugin has no outputs!" << endl;
+ return false;
+ }
+ if (outputNo < 0) {
+ for (size_t oi = 0; oi < outputs.size(); ++oi) {
+ if (outputs[oi].identifier == output) {
+ outputNo = oi;
+ break;
+ }
+ }
+ if (outputNo < 0) {
+ cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
+ return false;
+ }
+ }
+ else {
+ if (int(outputs.size()) <= outputNo) {
+ cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
+ return false;
+ }
+ }
+ od = outputs[outputNo];
+ cerr << "Output is: \"" << od.identifier << "\"" << endl;
+
+ if (!plugin->initialise(channels, stepSize, blockSize)) {
+ cerr << "ERROR: Plugin initialise (channels = " << channels
+ << ", stepSize = " << stepSize << ", blockSize = "
+ << blockSize << ") failed." << endl;
+ return false;
+ }
+
+ wrapper = dynamic_cast<PluginWrapper *>(plugin);
+ if (wrapper) {
+ // See documentation for
+ // PluginInputDomainAdapter::getTimestampAdjustment
+ PluginInputDomainAdapter *ida =wrapper->getWrapper<PluginInputDomainAdapter>();
+ if (ida) adjustment = ida->getTimestampAdjustment();
+ }
+
+ //everything is prepared to start consuming data in blocks
+
+ in_block=0;
+ blocks_processed=0;
+
+ return true;
+}
+void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
+ int sample=0;
+ //process the whole frame which may be f>1<f blocks
+ //when the frame is finished leave the partial block for the next frame
+ while(sample<samples_in_frame) {
+ while(sample<samples_in_frame&&in_block<blockSize) {
+ for (int i=0;i<channels;i++) {
+ unsigned int this_val=0;
+ for (int j=0;j<bytes;j++) {
+ this_val+=data[(sample*stride)+(i*bytes)+j]<<(j*8);
+ }
+ plugbuf[i][in_block]=((float)((int16_t)this_val))*scale;
+ }
+ in_block++;
+ sample++;
+ }
+ if (in_block==blockSize) {
+ //block is ready to be processed
+ cerr<<"processing block "<<blocks_processed<<endl;
+ in_block=0;
+ blocks_processed++;
+ }
+ }
+}
+void vampHost::Analyser::cleanup(){
+ delete[] filebuf;
+ for (int c = 0; c < channels; ++c) {
+ delete[] plugbuf[c];
+ }
+ delete[] plugbuf;
+ delete plugin;
+}
diff --git a/rotord/vampHost.h b/rotord/vampHost.h
index de6ae02..942c98b 100644
--- a/rotord/vampHost.h
+++ b/rotord/vampHost.h
@@ -55,12 +55,22 @@ namespace vampHost {
};
class Analyser{
public:
- void init(const string &soname,const string &id,const int &rate);
+ 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();
vector<float> beats;
private:
PluginLoader *loader;
PluginLoader::PluginKey key;
Plugin *plugin;
+ 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;
};
string getQMBeats(const string soundfile);