summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/src/nodes_audio_analysis.cpp4
-rw-r--r--rotord/src/nodes_audio_analysis.h95
-rw-r--r--rotord/src/rendercontext.cpp2
-rw-r--r--rotord/src/rotor.cpp90
-rw-r--r--rotord/src/rotor.h15
-rw-r--r--rotord/src/vampHost.cpp35
-rw-r--r--rotord/src/vampHost.h2
7 files changed, 162 insertions, 81 deletions
diff --git a/rotord/src/nodes_audio_analysis.cpp b/rotord/src/nodes_audio_analysis.cpp
index 220f14b..1e65668 100644
--- a/rotord/src/nodes_audio_analysis.cpp
+++ b/rotord/src/nodes_audio_analysis.cpp
@@ -83,11 +83,11 @@ namespace Rotor{
}
void Vamp_node::cleanup() {
analyser.cleanup();
- //print_features();
+ features=analyser.features;
}
string Vamp_node::get_features(){
string data;
- for (auto i: analyser.features) {
+ for (auto i: features) {
data=data+" ["+toString(i.second.number)+":"+toString(i.first);
if (i.second.values.size()) {
data+=" (";
diff --git a/rotord/src/nodes_audio_analysis.h b/rotord/src/nodes_audio_analysis.h
index 44ea3eb..620f277 100644
--- a/rotord/src/nodes_audio_analysis.h
+++ b/rotord/src/nodes_audio_analysis.h
@@ -9,6 +9,18 @@ namespace Rotor {
#define VAMPHOST_Timesteps 2
#define VAMPHOST_Valueline 3
#define VAMPHOST_Values 4
+ class Audio_processor: public Signal_node {
+ public:
+ virtual Audio_processor(){};
+ virtual ~Audio_processor(){};
+ virtual int process_frame(uint8_t *data,int samples)=0;
+ virtual bool init(int _channels,int _bits,int _samples,int _rate)=0;
+ virtual void cleanup()=0;
+ virtual void print_summary(){};
+ virtual string get_features(){};
+ int channels,bits,samples,rate;
+ };
+ //actual nodes-------------------------------------------------
class Audio_thumbnailer: public Audio_processor {
public:
Audio_thumbnailer(){
@@ -43,9 +55,9 @@ namespace Rotor {
void cleanup();
int process_frame(uint8_t *data,int samples_in_frame);
const float output(const Time_spec &time) {
- if (analyser.features.size()) {
- auto i=analyser.features.upper_bound(time.time); //the first element in the container whose key is considered to go after k
- if (i!=analyser.features.end()){
+ if (features.size()) {
+ auto i=features.upper_bound(time.time); //the first element in the container whose key is considered to go after k
+ if (i!=features.end()){
float uk=i->first;
float v1,v2;
v1=v2=0.0f;
@@ -72,15 +84,15 @@ namespace Rotor {
}
string get_features();
void print_summary(){
- cerr<<"vamp plugin "<<id<<" of library "<<soname<<" found "<<analyser.features.size()<<" features "<<endl;
+ cerr<<"vamp plugin "<<id<<" of library "<<soname<<" found "<<features.size()<<" features "<<endl;
};
protected:
string soname,id;
- int outputNo;
- vampHost::Analyser analyser;
- private:
- //??
+ int outputNo;
map <string,float> params;
+ map<float,vampHost::feature> features;
+ private:
+ vampHost::Analyser analyser;
};
class Audio_analysis: public Vamp_node {
//vamp node that allows the user to choose a plugin
@@ -170,20 +182,20 @@ namespace Rotor {
vector<int> act_count;
for (int i=0;i<(int)parameters["acts"]->value;i++) act_count.push_back(0);
- if (analyser.features.size()<=(int)parameters["acts"]->value+1){
+ if (features.size()<=(int)parameters["acts"]->value+1){
//iteratively split segments and refresh durations
//this could work well on the original data
//pick the longest and split it in two
//refresh durations - this can be a function
//keep going
//finally copy out
- while (analyser.features.size()<(int)parameters["acts"]->value+1){
+ while (features.size()<(int)parameters["acts"]->value+1){
map<int,float> durations;
map<int,float> times;
int i=0;
- for (map<float,vampHost::feature>::iterator f=analyser.features.begin();f!=analyser.features.end();++f){
+ for (map<float,vampHost::feature>::iterator f=features.begin();f!=features.end();++f){
auto g=f;
- if (++g!=analyser.features.end()){
+ if (++g!=features.end()){
durations[i]=g->first-f->first;
times[i]=f->first;
}
@@ -197,10 +209,10 @@ namespace Rotor {
n=d.first;
}
}
- analyser.features[times[n]+(durations[n]/2)]=analyser.features[times[n]];
+ features[times[n]+(durations[n]/2)]=features[times[n]];
}
int j=0;
- for (auto f: analyser.features){
+ for (auto f: features){
f.second.number=j;
acts[f.first]=f.second;
j++;
@@ -216,7 +228,7 @@ namespace Rotor {
//start with a set of the segments numbers
//(the aim: to access the segment numbers by the time that they start)
- map<float,vampHost::feature> segments=analyser.features;
+ map<float,vampHost::feature> segments=features;
segments.erase(--segments.end());
//assign the acts from the beginning and end in towards the middle
@@ -260,12 +272,61 @@ namespace Rotor {
}
}
//add last item back on
- acts[(*--analyser.features.end()).first]=analyser.features[(*--analyser.features.end()).first];
- analyser.features=acts;
+ acts[(*--features.end()).first]=features[(*--features.end()).first];
+ features=acts;
}
private:
};
+ class Intensity_segmenter: public Vamp_node {
+ //vamp node that applies a ruleset to manage a set of acts via a cycler
+ public:
+ Intensity_segmenter(){
+ title="Intensity segmenter";
+ description="Combines the output of segmentation, tempo, and intensity analysis plugins";
+ UID="6ce236b6-4080-11e3-90b7-74d02b29f6a6";
+ analysers["segmenter"]=vampHost::Analyser();
+ analysers["tempo"]=vampHost::Analyser();
+ analysers["intensity"]=vampHost::Analyser();
+ };
+ Intensity_segmenter(map<string,string> &settings):Intensity_segmenter() {
+ base_settings(settings);
+ };
+ ~Intensity_segmenter(){};
+ Intensity_segmenter* clone(map<string,string> &_settings) { return new Intensity_segmenter(_settings);};
+ bool init(int _channels,int _bits,int _samples,int _rate) {
+ return analysers["segmenter"].init("qm-vamp-plugins","qm-segmenter",_channels,_bits,_samples,_rate,0,params)\
+ &&analysers["tempo"].init("qm-vamp-plugins","qm-tempotracker",_channels,_bits,_samples,_rate,2,params)\
+ &&analysers["intensity"].init("bbc-vamp-plugins","bbc-intensity",_channels,_bits,_samples,_rate,0,params);
+ }
+ int process_frame(uint8_t *data,int samples_in_frame) {
+ //for (auto a:analysers) a.second.process_frame(data,samples_in_frame); //WHY NOT WORK
+ analysers["segmenter"].process_frame(data,samples_in_frame);
+ analysers["tempo"].process_frame(data,samples_in_frame);
+ analysers["intensity"].process_frame(data,samples_in_frame);
+ return 1;
+ }
+ void cleanup(){
+ //for (auto a:analysers) a.second.cleanup(); //WHY NOT WORK - its as if the call is const
+ analysers["segmenter"].cleanup();
+ analysers["tempo"].cleanup();
+ analysers["intensity"].cleanup();
+ cerr<<analysers["segmenter"].features.size()<<" segments"<<endl;
+ cerr<<analysers["tempo"].features.size()<<" tempo features"<<endl;
+ cerr<<analysers["intensity"].features.size()<<" intensity features"<<endl;
+ //auto f=analysers["segmenter"].features.begin();
+ //for (auto g=++analysers["segmenter"].features.begin();g!=analysers["segmenter"].features.end();f++,g++){
+ // cerr<<"calculating segment from "<<f.first<<" to "<<g.first<<endl;
+ // features[f.first]=f.second;
+ //}
+ return true;
+ }
+ void print_summary(){
+ cerr<<"Intensity segmenter found "<<features.size()<<" features "<<endl;
+ };
+ private:
+ map<string,vampHost::Analyser> analysers;
+ };
}
#endif
diff --git a/rotord/src/rendercontext.cpp b/rotord/src/rendercontext.cpp
index bba8d31..359116f 100644
--- a/rotord/src/rendercontext.cpp
+++ b/rotord/src/rendercontext.cpp
@@ -428,7 +428,7 @@ void Render_context::session_command(const Session_command& command,xmlIO& XML,H
}
else {
status=HTTPResponse::HTTP_BAD_REQUEST;
- logger.error("ERROR: Could not print features for node "+features_node);
+ logger.error("ERROR: Could not print features for node /"+features_node+"/");
}
}
else {
diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp
index d3a5486..a4ef055 100644
--- a/rotord/src/rotor.cpp
+++ b/rotord/src/rotor.cpp
@@ -19,60 +19,61 @@ Node_factory::Node_factory(){
//this can be hard coded also
//
- category["signals"]=vector<Node*>();
- add_type("time",new Time(),category["signals"]);
- add_type("track_time",new Track_time(),category["signals"]);
- add_type("at_track_time",new At_track_time(),category["signals"]);
+ category["Signals"]=vector<Node*>();
+ add_type("time",new Time(),category["Signals"]);
+ add_type("track_time",new Track_time(),category["Signals"]);
+ add_type("at_track_time",new At_track_time(),category["Signals"]);
//
add_type("signal_output",new Signal_output());
add_type("testcard",new Testcard());
//
- category["channels"]=vector<Node*>();
- add_type("invert",new Invert(),category["channels"]);
- add_type("monochrome",new Monochrome(),category["channels"]);
- add_type("blend",new Blend(),category["channels"]);
- add_type("image_arithmetic",new Image_arithmetic(),category["channels"]);
- add_type("alpha_merge",new Alpha_merge(),category["channels"]);
- add_type("difference_matte",new Difference_matte(),category["channels"]);
- add_type("rgb_levels",new RGB_levels(),category["channels"]);
- add_type("luma_levels",new Luma_levels(),category["channels"]);
+ category["Channels"]=vector<Node*>();
+ add_type("invert",new Invert(),category["Channels"]);
+ add_type("monochrome",new Monochrome(),category["Channels"]);
+ add_type("blend",new Blend(),category["Channels"]);
+ add_type("image_arithmetic",new Image_arithmetic(),category["Channels"]);
+ add_type("alpha_merge",new Alpha_merge(),category["Channels"]);
+ add_type("difference_matte",new Difference_matte(),category["Channels"]);
+ add_type("rgb_levels",new RGB_levels(),category["Channels"]);
+ add_type("luma_levels",new Luma_levels(),category["Channels"]);
- category["source"]=vector<Node*>();
- add_type("signal_colour",new Signal_colour(),category["source"]);
- add_type("signal_greyscale",new Signal_greyscale(),category["source"]);
- add_type("shape",new Shape(),category["source"]);
- add_type("text",new Text(),category["source"]);
- add_type("waves",new Waves(),category["source"]);
- add_type("still_image",new Still_image(),category["source"]);
- add_type("video_loader",new Video_loader(),category["source"]);
- add_type("svg",new Svg(),category["source"]);
+ category["Source"]=vector<Node*>();
+ add_type("signal_colour",new Signal_colour(),category["Source"]);
+ add_type("signal_greyscale",new Signal_greyscale(),category["Source"]);
+ add_type("shape",new Shape(),category["Source"]);
+ add_type("text",new Text(),category["Source"]);
+ add_type("waves",new Waves(),category["Source"]);
+ add_type("still_image",new Still_image(),category["Source"]);
+ add_type("video_loader",new Video_loader(),category["Source"]);
+ add_type("svg",new Svg(),category["Source"]);
- category["distort"]=vector<Node*>();
- add_type("mirror",new Mirror(),category["distort"]);
- add_type("transform",new Transform(),category["distort"]);
+ category["Distort"]=vector<Node*>();
+ add_type("mirror",new Mirror(),category["Distort"]);
+ add_type("transform",new Transform(),category["Distort"]);
- category["editing"]=vector<Node*>();
- add_type("video_cycler",new Video_cycler(),category["editing"]);
- add_type("video_output",new Video_output(),category["editing"]);
- add_type("act_segmenter",new Act_segmenter(),category["editing"]);
+ category["Editing"]=vector<Node*>();
+ add_type("video_cycler",new Video_cycler(),category["Editing"]);
+ add_type("video_output",new Video_output(),category["Editing"]);
+ add_type("act_segmenter",new Act_segmenter(),category["Editing"]);
- category["audio"]=vector<Node*>();
- add_type("audio_analysis",new Audio_analysis(),category["audio"]);
- add_type("audio_analysis2",new Audio_analysis2(),category["audio"]);
+ category["Audio"]=vector<Node*>();
+ add_type("audio_analysis",new Audio_analysis(),category["Audio"]);
+ add_type("audio_analysis2",new Audio_analysis2(),category["Audio"]);
+ add_type("intensity_segmenter",new Intensity_segmenter(),category["Audio"]);
- category["maths"]=vector<Node*>();
- add_type("comparison",new Comparison(),category["maths"]); //TODO: alias to symbols
- add_type("arithmetic",new Arithmetic(),category["maths"]); //TODO: alias to symbols
- add_type("bang",new Is_new_integer(),category["maths"]);
- add_type("on_off",new On_off(),category["maths"]);
- add_type("random",new Random(),category["maths"]);
- add_type("noise",new Noise(),category["maths"]);
+ category["Maths"]=vector<Node*>();
+ add_type("comparison",new Comparison(),category["Maths"]); //TODO: alias to symbols
+ add_type("arithmetic",new Arithmetic(),category["Maths"]); //TODO: alias to symbols
+ add_type("bang",new Is_new_integer(),category["Maths"]);
+ add_type("on_off",new On_off(),category["Maths"]);
+ add_type("random",new Random(),category["Maths"]);
+ add_type("noise",new Noise(),category["Maths"]);
- category["fx"]=vector<Node*>();
- add_type("blur",new Blur(),category["fx"]);
- add_type("vhs",new VHS(),category["fx"]);
- add_type("echo_trails",new Echo_trails(),category["fx"]);
- add_type("video_feedback",new Video_feedback(),category["fx"]);
+ category["FX"]=vector<Node*>();
+ add_type("blur",new Blur(),category["FX"]);
+ add_type("vhs",new VHS(),category["FX"]);
+ add_type("echo_trails",new Echo_trails(),category["FX"]);
+ add_type("video_feedback",new Video_feedback(),category["FX"]);
}
bool Signal_input::connect(Node* source) {
@@ -209,6 +210,7 @@ void Node_factory::list_categories(Json::Value &JSON){
category["name"]=_category.first;
category["nodes"]=Json::arrayValue;
for (auto& _node: _category.second){
+ cerr<<"Adding "<<_category.first<<":"<<_node->type<<endl;
Json::Value node;
node["type"]=_node->type;
node["title"]=_node->title;
diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h
index d9ba66d..f179efd 100644
--- a/rotord/src/rotor.h
+++ b/rotord/src/rotor.h
@@ -342,17 +342,6 @@ namespace Rotor {
protected:
unsigned char *lut;
};
- class Audio_processor: public Signal_node {
- public:
- virtual Audio_processor(){};
- virtual ~Audio_processor(){};
- virtual int process_frame(uint8_t *data,int samples)=0;
- virtual bool init(int _channels,int _bits,int _samples,int _rate)=0;
- virtual void cleanup()=0;
- virtual void print_summary(){};
- virtual string get_features(){};
- int channels,bits,samples,rate;
- };
//actual nodes-------------------------------------------------
#define CYCLER_cut 1
#define CYCLER_mix 2
@@ -712,8 +701,8 @@ namespace Rotor {
void list_categories(xmlIO XML);
void list_categories(Json::Value &JSON);
private:
- unordered_map<string,Node*> type_map;
- unordered_map<string,vector<Rotor::Node*> > category;
+ map<string,Node*> type_map;
+ map<string,vector<Rotor::Node*> > category;
};
}
diff --git a/rotord/src/vampHost.cpp b/rotord/src/vampHost.cpp
index 7bdbb0d..2ddc62f 100644
--- a/rotord/src/vampHost.cpp
+++ b/rotord/src/vampHost.cpp
@@ -275,6 +275,10 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
return false;
}
+ cerr << "Vamphost Plugin initialised: (channels = " << channels
+ << ", stepSize = " << stepSize << ", blockSize = "
+ << blockSize << ")" << endl;
+
wrapper = dynamic_cast<PluginWrapper *>(plugin);
if (wrapper) {
// See documentation for
@@ -294,6 +298,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
return true;
}
void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
+
int sample=0;
uint16_t *_data=(uint16_t*)data;
@@ -317,20 +322,25 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
//I /think/ that the vamp plugin keeps processing through the plugbuf until it encounters 0s
rt = RealTime::frame2RealTime(currentStep * stepSize, rate); //48000); //setting different rate doesn't affect it
+
Plugin::FeatureSet feat=plugin->process(plugbuf, rt);
+ float t;
+
for (unsigned int i = 0; i < feat[outputNo].size(); ++i) {
feature f;
f.number=featureNo;
f.values=feat[outputNo][i].values;
//fix for plugins that don't set timestamp properly
- float t=((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001);
+ t=((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001);
if (t<.01) t=((rt.sec)+(rt.nsec)*.000000001);
features[t]=f;
featureNo++;
}
+ //if (feat[outputNo].size()>0) cerr<<"vamphost: "<<t<<":"<<features.size()<<" features"<<endl;
+
//shunt it down
for (int i=0;i<blockSize-stepSize;i++){
for (int j=0;j<channels;j++){
@@ -338,13 +348,14 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
}
}
+ //if (feat[outputNo].size()>0) cerr<<plugin->getIdentifier()<<" step:"<<currentStep<<" sample:"<<currentStep * stepSize<<" features:"<<features.size()<<endl;
+
in_block-=stepSize;
- currentStep++;
+ currentStep++; //WTF this number does not increase when called the 2nd way
}
}
}
void vampHost::Analyser::cleanup(){
-
//process final block
while(in_block<blockSize) {
for (int i=0;i<channels;i++) {
@@ -389,3 +400,21 @@ void vampHost::Analyser::cleanup(){
delete[] plugbuf;
delete plugin;
}
+float vampHost::Analyser::get_value(const float &time) {
+ if (features.size()) {
+ auto i=features.upper_bound(time); //the first element in the container whose key is considered to go after k
+ if (i!=features.end()){
+ float uk=i->first;
+ float v1,v2;
+ v1=v2=0.0f;
+ if (i->second.values.size()) v2=i->second.values[0];
+ i--;
+ float lk=i->first;
+ int ln=i->second.number;
+ if (i->second.values.size()) v1=i->second.values[0];
+
+ return ((((time-lk)/(uk-lk))*(v2-v1))+v1);
+ }
+ }
+ return 0.0f;
+}
diff --git a/rotord/src/vampHost.h b/rotord/src/vampHost.h
index 56de901..856a2cc 100644
--- a/rotord/src/vampHost.h
+++ b/rotord/src/vampHost.h
@@ -64,7 +64,7 @@ namespace vampHost {
bool init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,int outputNo,const map<string,float> &params);
void process_frame(uint8_t *data,int samples_in_frame);
void cleanup();
-
+ float get_value(const float &time);
//map<double,int> features;
map<float,feature> features;
//map<time,featureNo>