summaryrefslogtreecommitdiff
path: root/NT/src/graph.cpp
blob: 5b0a15a45e50f463dc514be9140d11845bd7277c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#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<Audio_processor*> processors;
	//processors.push_back(audio_thumb);
	for (auto a: nodes) {
		if (dynamic_cast<Audio_processor*>(a.second)){
			processors.push_back(dynamic_cast<Audio_processor*>(a.second));
		}
	}
	for (auto p: processors) {
		if(!p->init_vamp(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<string,Node*>::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"];
	//std::cerr<<"json parser found "<<jnodes.size()<<" nodes"<<std::endl;
	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