#include "graph.h" using namespace Rotor; using namespace std; bool Graph::check_audio(string audio,string path){ Logger& logger = Logger::get(id); if (audio!="") { audio_filename=path+audio; Poco::File f=Poco::File(audio_filename); if (f.exists()) { //here we should check the audio is actually valid audio_loaded=true; logger.information("Loading "+audio_filename+" from graph"); return true; } logger.error("Audio file "+audio_filename+" not found"); } return false; } bool Graph::load_audio(const std::string &filename) { Logger& logger = Logger::get(id); if (filename.size()==0) { logger.information("ERROR: empty filename for audio analysis"); return false; } libav::audio_decoder loader; if (!loader.open(filename)) { logger.error("ERROR: Could not open audio: "+filename); return false; } logger.information("Analysing "+filename); duration=loader.get_duration(); int rate = loader.get_sample_rate(); int samples = loader.get_number_samples(); int channels= loader.get_number_channels(); int bits = loader.get_bit_depth(); vector processors; //processors.push_back(audio_thumb); for (auto a: nodes) { if (dynamic_cast(a.second)){ processors.push_back(dynamic_cast(a.second)); } } for (auto p: processors) { if(!p->init(channels,bits,samples,rate) ){ logger.error("ERROR: Audio plugin failed to initialse"); return false; } } bool finished=false; uint16_t *audio=new uint16_t[1024*loader.get_number_channels()]; uint64_t sample=0; while (!finished&&!cancelled) { if (loader.get_samples(audio,sample,1024)) { //now we can pass the data to the processor(s) for (auto p: processors) { p->process_frame((uint8_t*)audio,1024); } sample+=1024; //mutex.lock(); progress=((double)sample)/samples; //atomic on 64 bit? //mutex.unlock(); } else finished=true; } loader.cleanup(); for (auto p: processors) { p->cleanup(); p->print_summary(); } logger.information("Finished audio analysis"); //audio_loaded=true; return true; } bool Graph::load_file(std::string filename,std::string media_path){ Logger& logger = Logger::get(id); Poco::File f=Poco::File(filename); if (f.exists()) { Poco::FileInputStream fis(filename); Poco::CountingInputStream countingIstr(fis); std::string str; Poco::StreamCopier::copyToString(countingIstr, str); return parse_json(str,media_path); } logger.error("Graph "+filename+" not found"); return false; } Node* Graph::find_node(const string &type){ for (std::unordered_map::iterator it=nodes.begin();it!=nodes.end();++it) { if (it->second->get_type()==type) return it->second; } return nullptr; }; Node* Graph::get_node(const std::string &id){ if (nodes.find(id)!=nodes.end()) return nodes[id]; return nullptr; } bool Graph::parse_json(string &data,string &media_path){ Logger& logger = Logger::get(id); Json::Value root; // will contain the root value after parsing. Json::Reader reader; bool parsing_successful = reader.parse( data, root ); if ( !parsing_successful ) { logger.error("Failed to parse configuration: "+reader.getFormattedErrorMessages()); return false; } //The json validates, now we should attempt to retain nodes which haven't changed //for now just clear the existing graph clear(); Node_factory factory(id); check_audio(root["audio"].asString(),media_path); init(root["id"].asString()); Json::Value jnodes = root["nodes"]; for ( uint32_t i = 0; i < jnodes.size(); ++i ) { string node_id=jnodes[i]["id"].asString(); Node* node=factory.create(jnodes[i]); if (node) { if (nodes.find(node_id)==nodes.end()){ logger.information("Creating node '"+node_id+"'': '"+jnodes[i]["type"].asString()+"'"); node->create_connections(nodes); nodes[node_id]=node; } else logger.error("ERROR: duplicate node '"+node_id+"' "); } else { logger.error("ERROR: graph loader cannot find node '"+jnodes[i]["type"].asString()+"'"); return false; } } return true; } //should nodes be identified by uuid rather than name? //array inlets can be identified by number as this is all they usually are