From 332c7c24301700ca0a4ceb104051bcd3a3b3bc4b Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Thu, 4 Apr 2013 18:03:14 +0100 Subject: analyser loader --- rotord/01.xml | 2 +- rotord/rotor.cpp | 101 ++++++++++++++++++++++++++++------------------------ rotord/rotor.h | 74 +++++++++++++++++++++++--------------- rotord/vampHost.cpp | 20 ++++++++++- rotord/vampHost.h | 9 +++++ 5 files changed, 129 insertions(+), 77 deletions(-) diff --git a/rotord/01.xml b/rotord/01.xml index 830c3a3..e351184 100644 --- a/rotord/01.xml +++ b/rotord/01.xml @@ -1,6 +1,6 @@ Off and on template ©Rotor 2013 - beats + beats segmenter diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index f7c017d..cd288e3 100644 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -21,9 +21,13 @@ void Render_context::runTask() { mutex.unlock(); if (cmd==ANALYSE_AUDIO) { state=ANALYSING_AUDIO; - vector proc; - proc.push_back(audio_thumb); - if (load_audio(audio_filename,proc)) { + vector processors; + processors.push_back(audio_thumb); + vector analysers=graph.find_nodes("audio_analysis"); + for (auto a: analysers) { + processors.push_back(a); + } + if (load_audio(audio_filename,processors)) { state=AUDIO_READY; } else state=IDLE; @@ -118,9 +122,9 @@ Command_response Render_context::session_command(const std::vector& } if (command[2]=="graph") { if (command[0]=="GET") { - if (xml.bDocLoaded) { + if (graph.loaded) { response.status=HTTPResponse::HTTP_OK; - xml.copyXmlToString(response.description); + response.description=graph.toString(); } else { response.description="Rotor: graph not loaded\n"; @@ -134,14 +138,14 @@ Command_response Render_context::session_command(const std::vector& Poco::File f=Poco::File(command[3]); if (f.exists()) { string graph_filename=command[3]; - if (load_graph(graph_filename)) { + if (graph.load(graph_filename)) { response.status=HTTPResponse::HTTP_OK; //response.description="Rotor: loaded graph "+command[3]+"\n"; - string xmlstring; - xml.copyXmlToString(xmlstring); - response.description=xmlstring; + response.description=graph.toString(); //the graph could actually contain an xml object and we could just print it here? //or could our nodes even be subclassed from xml nodes? + //the graph or the audio could load first- have to analyse the audio with vamp after the graph is loaded + //for now the graph must load 1st } else { response.status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; //~/sources/poco-1.4.6-all/Net/include/Poco/Net/HTTPResponse.h @@ -248,13 +252,10 @@ Command_response Render_context::session_command(const std::vector& return response; } - - - //http://blog.tomaka17.com/2012/03/libavcodeclibavformat-tutorial/ //great to use c++11 features -bool Render_context::load_audio(const string &filename,vector processors){ +bool Render_context::load_audio(const string &filename,vector processors){ av_register_all(); @@ -325,14 +326,12 @@ bool Render_context::load_audio(const string &filename,vectorsample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<init(codecContext->channels,16,samples); + p->init(codecContext->channels,16,samples,codecContext->sample_rate); } AVPacket packet; av_init_packet(&packet); int sample_processed=0; - - bool diag=true; while (true) { @@ -361,11 +360,7 @@ bool Render_context::load_audio(const string &filename,vectornb_samples<<" samples in "<format)<<" format with channel layout "<channel_layout<< std::endl; - diag=false; - } - + //now we can pass the data to the processor(s) for (auto p: processors) { sample_processed=p->process_frame(frame->data[0],frame->nb_samples); @@ -408,11 +403,19 @@ bool Render_context::load_audio(const string &filename,vectorcreate_signal_input(xml.getValue("signal_input","",i2)); + nodes[nodeID]->create_signal_input(xml.getValue("signal_input","",i2)); string fromID=xml.getAttribute("signal_input","from","",i2); - if (graph.nodes.find(fromID)!=graph.nodes.end()) { - if (!graph.nodes[nodeID]->inputs[i2]->connect((Signal_node*)graph.nodes[fromID])){ + if (nodes.find(fromID)!=nodes.end()) { + if (!nodes[nodeID]->inputs[i2]->connect((Signal_node*)nodes[fromID])){ cerr << "Rotor: graph loader cannot connect input " << i2 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl; return false; } @@ -453,6 +456,7 @@ bool Render_context::load_graph(string &filename){ } xml.popTag(); } + loaded=true; return true; } else return false; @@ -465,15 +469,11 @@ 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) { +void Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) { //base_audio_processor::init(_channels,_bits,_samples); channels=_channels; bits=_bits; samples=_samples; - - cerr << "init audio thumbnailer with "<offset) this_val=-(this_val-(offset*2)); - - //this_val -=offset; + //presume 16 bits for now... double val=((double)((int16_t)this_val))*scale; accum+=val*val; samples++; @@ -539,7 +529,7 @@ int audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ } return out_sample; } -string audio_thumbnailer::print(){ +string Audio_thumbnailer::print(){ string output; for (int j=0;j &settings) { base_settings(settings); + soname=check(settings,"soname"); + id=check(settings,"id"); }; Audio_analysis* clone(map &_settings) { return new Audio_analysis(_settings);}; + void init(int _channels,int _bits,int _samples,int _rate); + int process_frame(uint8_t *data,int samples_in_frame); float get_output(const float &time) { float t=time; return t; } + private: + string soname,id; + vampHost::Analyser analyser; }; class Signal_divide: public Signal_node { //divides incoming signal by a fixed amount @@ -308,52 +321,61 @@ namespace Rotor { }; class Graph{ public: - Graph(){framerate=25.0f;duration=10.0f;}; - Graph(const string& _uid,const string& _desc){ uid=_uid;description=_desc;framerate=25.0f;duration=10.0f;}; + Graph(){framerate=25.0f;duration=10.0f;loaded = false;}; + Graph(const string& _uid,const string& _desc){init(_uid,_desc);}; + void init(const string& _uid,const string& _desc){ uid=_uid;description=_desc;framerate=25.0f;duration=10.0f;}; string uid; //every version of a graph has a UUID, no particular need to actually read its data(?) //?? is it faster than using strings?? string description; std::unordered_map nodes; - Node* find(const string &type){ + vector find_nodes(const string &type){ + vector found; + for (std::unordered_map::iterator it=nodes.begin();it!=nodes.end();++it) { + if (it->second->type==type) found.push_back(it->second); + } + return found; + }; + Node* find_node(const string &type){ for (std::unordered_map::iterator it=nodes.begin();it!=nodes.end();++it) { if (it->second->type==type) return it->second; } - return NULL; + return nullptr; //can be tested against }; bool signal_render(const float _fr,string &signal_xml) { if (_fr>.001) framerate=_fr; - if (find("signal_output")) { - Signal_output *signal_output=dynamic_cast(find("signal_output")); + if (find_node("signal_output")) { + Signal_output *signal_output=dynamic_cast(find_node("signal_output")); return signal_output->render(duration,framerate,signal_xml); } else return false; } + int load(Poco::UUID uid); + bool load(string &graph_filename); + UUID save(); //save to DB, returns UUID of saved graph + bool loaded; + const string toString(); private: Node_factory factory; float framerate; float duration; + xmlIO xml; }; - class base_audio_processor { - public: - virtual int process_frame(uint8_t *data,int samples)=0; - virtual void init(int _channels,int _bits,int _samples)=0; - int channels,bits,samples; - }; - class audio_thumbnailer: public base_audio_processor { + class Audio_thumbnailer: public Base_audio_processor { //how to deal with the fact that frames don't correspond with pixels? //buffer the data somehow //draw pixels based on rms value public: - audio_thumbnailer(){ - height=48; - width=128; //fit + Audio_thumbnailer(){ + height=32; + width=64; //fit data=new uint8_t[height*width]; memset(data,0,height*width); - } - ~audio_thumbnailer(){ + }; + ~Audio_thumbnailer(){ delete[] data; - } - void init(int _channels,int _bits,int _samples); + }; + Audio_thumbnailer* clone(map &_settings) { return new Audio_thumbnailer();}; + void init(int _channels,int _bits,int _samples,int _rate); int process_frame(uint8_t *data,int samples_in_frame); string print(); uint8_t *data; @@ -369,7 +391,7 @@ namespace Rotor { //and low level interface onto the graph public: Render_context(const std::string& name): Task(name) { - audio_thumb=new audio_thumbnailer(); + audio_thumb=new Audio_thumbnailer(); state=IDLE; }; void runTask(); @@ -378,10 +400,7 @@ namespace Rotor { Render_status get_status(); void cancel(); //interrupt locking process int make_preview(int nodeID, float time); //starts a frame preview - returns status code - how to retrieve? - int load_graph(Poco::UUID uid); - bool load_graph(string &graph_filename); //should eventually be as above - UUID save_graph(); //returns UUID of saved graph - bool load_audio(const string &filename,vector processors); + bool load_audio(const string &filename,vector processors); Render_requirements get_requirements(); int load_video(int num,string &filename); //can be performance or clip @@ -392,9 +411,8 @@ namespace Rotor { std::deque work_queue; Poco::Mutex mutex; //lock for access from parent thread std::string audio_filename; - audio_thumbnailer *audio_thumb; + Audio_thumbnailer *audio_thumb; vampHost::QMAnalyser audio_analyser; - xmlIO xml; Graph graph; Node_factory factory; }; diff --git a/rotord/vampHost.cpp b/rotord/vampHost.cpp index 947e49a..b9b0781 100644 --- a/rotord/vampHost.cpp +++ b/rotord/vampHost.cpp @@ -587,4 +587,22 @@ float vampHost::QMAnalyser::get_progress(){ p=progress; mutex.unlock(); return p; -} \ No newline at end of file +} +void vampHost::Analyser::init(const string &soname,const string &id,const int &rate){ + + loader = PluginLoader::getInstance(); + key = loader->composePluginKey(soname, id); + Plugin *plugin = loader->loadPlugin(key, rate, PluginLoader::ADAPT_ALL_SAFE); + if (!plugin) { + cerr << ": ERROR: Failed to load plugin \"" << id + << "\" from library \"" << soname << "\"" << endl; + return; + } + + cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; + + delete plugin; + + return; +} + diff --git a/rotord/vampHost.h b/rotord/vampHost.h index dfff408..de6ae02 100644 --- a/rotord/vampHost.h +++ b/rotord/vampHost.h @@ -53,6 +53,15 @@ namespace vampHost { float progress; Poco::Mutex mutex; //lock for progress data }; + class Analyser{ + public: + void init(const string &soname,const string &id,const int &rate); + vector beats; + private: + PluginLoader *loader; + PluginLoader::PluginKey key; + Plugin *plugin; + }; string getQMBeats(const string soundfile); void printFeatures(int, int, int, Plugin::FeatureSet, ostream &, bool frames); -- cgit v1.2.3