summaryrefslogtreecommitdiff
path: root/rotord/rotor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'rotord/rotor.cpp')
-rw-r--r--rotord/rotor.cpp101
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;
+}