#ifndef ROTOR_NODES_AUDIO_ANALYSIS #define ROTOR_NODES_AUDIO_ANALYSIS #include "rotor.h" #include "vampHost.h" namespace Rotor { #define VAMPHOST_Timeline 1 #define VAMPHOST_Timesteps 2 #define VAMPHOST_Valueline 3 #define VAMPHOST_Values 4 class Vamp_node: public Audio_processor { //base class for vamp plugin hosts public: bool init(int _channels,int _bits,int _samples,int _rate); 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()){ 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-1; //vamp numbers the first segment 0 if (i->second.values.size()) v1=i->second.values[0]; int m=attributes["mode"]->intVal; // switch (attributes["mode"]->intVal){ case VAMPHOST_Timeline: return (((time.time-lk)/(uk-lk))+ln); case VAMPHOST_Timesteps: return (float)ln; case VAMPHOST_Valueline: return ((((time.time-lk)/(uk-lk))*(v2-v1))+v1); case VAMPHOST_Values: return v1; } } } return 0.0f; } string get_features(); void print_summary(){ cerr<<"vamp plugin "< params; }; class Audio_analysis: public Vamp_node { //vamp node that allows the user to choose a plugin public: Audio_analysis(){ //create_attribute("soname","Plugin library to use","Plugin library","vamp-example-plugins",{"horiz","vert","horizR","vertR"}); //create_attribute("id","ID of Plugin to use","Plugin ID","percussiononsets",{"horiz","vert","horizR","vertR"}); create_attribute("analyser","Analyser Plugin to use","Analyser plugin","barbeattracker",{"barbeattracker","segmenter"}); create_attribute("mode","Data output mode","Mode","timeline",{"timeline","timesteps","valueline","values"}); create_parameter("outputNo","number","Plugin output to use","Output number",0.0f); title="Audio analysis"; description="Analyse audio and output"; }; Audio_analysis(map &settings):Audio_analysis() { base_settings(settings); soname=find_setting(settings,"soname"); id=find_setting(settings,"id"); outputNo=find_setting(settings,"outputNo",0); }; ~Audio_analysis(){}; Audio_analysis* clone(map &_settings) { return new Audio_analysis(_settings);}; private: }; class Act_segmenter: public Vamp_node { //vamp node that applies a ruleset to manage a set of acts via a cycler public: Act_segmenter(){ create_parameter("outputNo","number","Plugin output to use","Output number",0.0f); create_parameter("acts","number","Number of acts defined","Acts",0.0f); title="Act manager"; description="Applies a ruleset to manage acts based on segments"; }; Act_segmenter(map &settings):Act_segmenter() { base_settings(settings); soname="qm-vamp-plugins"; id="qm-segmenter"; outputNo=find_setting(settings,"outputNo",0); }; ~Act_segmenter(){}; Act_segmenter* clone(map &_settings) { return new Act_segmenter(_settings);}; void cleanup(){ Vamp_node::cleanup(); //cerr<<"act segmenter custom cleanup"< durations; for (map::iterator f=analyser.features.begin();f!=analyser.features.end();++f){ auto g=f; if (++g!=analyser.features.end()){ durations.push_back(g->first-f->first); } } //distribute acts amongst segments; if (analyser.features.size()==(int)parameters["acts"]->value+1){ for (auto f: analyser.features){ acts[f.first]=f.second.number; } } else if (analyser.features.size()<(int)parameters["acts"]->value+1){ //find longest segment } else { //extra segments to distribute } } private: map acts; }; } #endif