diff options
Diffstat (limited to 'rotord/rotor.cpp')
| -rw-r--r-- | rotord/rotor.cpp | 101 |
1 files changed, 54 insertions, 47 deletions
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<base_audio_processor*> proc; - proc.push_back(audio_thumb); - if (load_audio(audio_filename,proc)) { + vector<Base_audio_processor*> processors; + processors.push_back(audio_thumb); + vector<Node*> 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<std::string>& } 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="<status>Rotor: graph not loaded</status>\n"; @@ -134,14 +138,14 @@ Command_response Render_context::session_command(const std::vector<std::string>& 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="<status context='"+command[1]+"'>Rotor: loaded graph "+command[3]+"</status>\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<std::string>& 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<base_audio_processor*> processors){ +bool Render_context::load_audio(const string &filename,vector<Base_audio_processor*> processors){ av_register_all(); @@ -325,14 +326,12 @@ 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); + 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,vector<base_audio_process //av_get_channel_layout_string (char *buf, int buf_size, int nb_channels, uint64_t channel_layout) - if (diag) { - cerr << "first frame: "<<bytes << ", "<<frame->nb_samples<<" samples in "<<av_get_sample_fmt_name(frame->format)<<" format with channel layout "<<frame->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,vector<base_audio_process return true; } - -bool Render_context::load_graph(string &filename){ - printf("loading %s\n",filename.c_str()); +const string Graph::toString(){ + string xmlgraph; + if (loaded) { + xml.copyXmlToString(xmlgraph); + return xmlgraph; + } + else return ""; +} +bool Graph::load(string &filename){ + loaded=false; + printf("loading graph: %s\n",filename.c_str()); if(xml.loadFile(filename) ){ - graph=Graph(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0)); + init(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0)); if(xml.pushTag("patchbay")) { int n1=xml.getNumTags("node"); for (int i1=0;i1<n1;i1++){ @@ -428,14 +431,14 @@ bool Render_context::load_graph(string &filename){ if (node) { cerr << "Rotor: created '" << xml.getAttribute("node","type","",i1) << "'" << endl; string nodeID=xml.getAttribute("node","ID","",i1); - graph.nodes[nodeID]=node; + nodes[nodeID]=node; if(xml.pushTag("node",i1)) { int n2=xml.getNumTags("signal_input"); for (int i2=0;i2<n2;i2++){ - graph.nodes[nodeID]->create_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 "<<channels<<" channels, "<<samples<<" samples of "<< bits<<" bits."<<endl; - - samples_per_column=samples/width; column=0; //point thumbnail bitmap out_sample=0; //sample in whole track @@ -483,7 +483,7 @@ void audio_thumbnailer::init(int _channels,int _bits,int _samples) { samples=0; accum=0.0; } -int audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ +int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ //begin by processing remaining samples //samples per column could be larger than a frame! (probably is) //but all we are doing is averaging @@ -501,17 +501,7 @@ int audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ this_val+=_data[(sample*stride)+(i*bytes)+j]<<(j*8); } //convert from integer data format - i.e s16p - to audio signal in -1..1 range - //don't know how many bytes we are dealing with necessarily? - //double val=((double)(this_val-offset))*scale; - - // - //cerr << this_val << " "; - // - - - //if (this_val>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<height;j++) { for (int i=0;i<width;i++) { @@ -549,3 +539,20 @@ string audio_thumbnailer::print(){ } return output; } +void 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); + + //attempt to load vamp plugin and prepare to receive frames of data + //should the audio analysis contain a vamphost or should it inherit? + //maybe neater to contain it in terms of headers etc + +} +int Audio_analysis::process_frame(uint8_t *data,int samples_in_frame) { + //the standard vamp process takes a file + return 1; +} |
