summaryrefslogtreecommitdiff
path: root/rotord
diff options
context:
space:
mode:
Diffstat (limited to 'rotord')
-rw-r--r--rotord/rotor.cpp26
-rw-r--r--rotord/vampHost.cpp85
-rw-r--r--rotord/vampHost.h10
3 files changed, 73 insertions, 48 deletions
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
index 73577f4..2cd894f 100644
--- a/rotord/rotor.cpp
+++ b/rotord/rotor.cpp
@@ -259,7 +259,7 @@ Command_response Render_context::session_command(const std::vector<std::string>&
//great to use c++11 features
bool Render_context::load_audio(const string &filename,vector<Base_audio_processor*> processors){
-
+
av_register_all();
AVFrame* frame = avcodec_alloc_frame();
@@ -363,22 +363,22 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process
// the audio data, so I won't add any junk here that might confuse you. Typically, if I want to find
// documentation on an FFmpeg structure or function, I just type "<name> doxygen" into google (like
// "AVFrame doxygen" for AVFrame's docs)
-
+
//av_get_channel_layout_string (char *buf, int buf_size, int nb_channels, uint64_t channel_layout)
-
-
+
+
//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);
}
-
+
mutex.lock();
progress=((double)sample_processed)/samples;
mutex.unlock();
}
}
// You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory
- av_free_packet(&packet);
+ av_free_packet(&packet);
}
// Some codecs will cause frames to be buffered up in the decoding process. If the CODEC_CAP_DELAY flag
@@ -399,14 +399,14 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process
mutex.unlock();
}
}
-
+
cerr << "finished processing: "<<sample_processed << " samples of "<<samples<<", "<<((double)sample_processed*100)/samples<<"%"<< std::endl;
-
+
// Clean up!
for (auto p: processors) {
p->cleanup();
}
-
+
av_free(frame);
avcodec_close(codecContext);
av_close_input_file(formatContext);
@@ -471,7 +471,6 @@ bool Graph::load(string &filename){
}
else return false;
}
-
Node_factory::Node_factory(){
//for now, statically load prototype map in constructor
add_type("audio_analysis",new Audio_analysis());
@@ -502,14 +501,13 @@ int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){
int stride=channels*bytes;
int in_sample=0;
while (in_sample<samples_in_frame&&column<width) {
- //start a new column
-
+ //continue the column
while (sample<samples_per_column&&in_sample<samples_in_frame) {
//accumulate samples for this column until we run out of samples
for (int i=0;i<channels;i++) {
unsigned int this_val=0;
for (int j=0;j<bytes;j++) {
- this_val+=_data[(sample*stride)+(i*bytes)+j]<<(j*8);
+ this_val+=_data[(in_sample*stride)+(i*bytes)+j]<<(j*8);
}
//convert from integer data format - i.e s16p - to audio signal in -1..1 range
//presume 16 bits for now...
@@ -557,7 +555,7 @@ bool Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) {
samples=_samples;
return analyser.init(soname,id,_channels,_bits,_samples,_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
diff --git a/rotord/vampHost.cpp b/rotord/vampHost.cpp
index 2521f46..805481c 100644
--- a/rotord/vampHost.cpp
+++ b/rotord/vampHost.cpp
@@ -477,7 +477,7 @@ void vampHost::rotorGetFeatures(int frame, int sr, int output,Plugin::FeatureSet
}
for (unsigned int i = 0; i < features[output].size(); ++i) {
-
+
int displayFrame = frame;
@@ -501,15 +501,15 @@ int vampHost::QMAnalyser::process(const string inputFile){
//
//int runPlugin(string myname, string soname, string id, string output,int outputNo, string inputFile, ostream& out, bool frames);
-
+
//we want to run a specific plugin, outputting progress to a mutex-protected passed variable
//and ultimately passing the data back as a string?
//or capture it as an array of floats?
//get the progress as a float
//how to handle errors?
-
+
//debugger fucking up! program stalls after 1 request in debug!?
-
+
string soname="qm-vamp-plugins";
string id="qm-tempotracker";
string myname="";
@@ -521,18 +521,18 @@ int vampHost::QMAnalyser::process(const string inputFile){
}
void vampHost::getTimestamps(int output,Plugin::FeatureSet features, vector<float>& out){
-
+
/*
- vamp-simple-host qm-vamp-plugins:qm-tempotracker 01.wav
+ vamp-simple-host qm-vamp-plugins:qm-tempotracker 01.wav
0.046439908: 156.61 bpm
0.429569160: 156.61 bpm
0.812698412: 161.50 bpm
1.184217686: 152.00 bpm
-
-
+
+
vamp-simple-host qm-vamp-plugins:qm-segmenter 01.wav
-
+
0.000000000: 4 4
23.800000000: 6 6
44.600000000: 5 5
@@ -544,33 +544,33 @@ void vampHost::getTimestamps(int output,Plugin::FeatureSet features, vector<floa
143.800000000: 5 5
153.400000000: 3 3
163.000000000: 8 8
-
+
seems to be FP seconds then another metric
for now we can just take the first part
-
+
features[output][i].timestamp is of type RealTime: represents time values to nanosecond precision
int sec;
int nsec;
1 sec = 10^9 nanosec
-
+
actually maybe this would be the way to go for rotor- avoiding rounding errors etc
for now - ideally will get a float representation
-
+
features[output][i].values is a vector of floats + a description
WE DON'T CARE ABOUT ANYTHING <.01 seconds
-
+
static long realTime2Frame(const RealTime &r, unsigned int sampleRate);
-
+
get a vector of floats out, using frames, presuming data has a timestamp
-
-
+
+
this is crashing with "Aborted (core dumped)"
if we check for timestamp
-
+
*/
-
+
cout << "." << features[output].size();
-
+
//if (!features[output][0].hasTimestamp) {
// cerr << output << " channel, getTimestamps: error, featureset doesn't support timestamp" << endl;
//}_
@@ -589,7 +589,7 @@ float vampHost::QMAnalyser::get_progress(){
return p;
}
bool vampHost::Analyser::init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,const int &_outputNo,const string &_output){
-
+
//stuff that only happens once
channels =_channels;
samples=_samples;
@@ -597,18 +597,18 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
bits=_bits;
outputNo=_outputNo;
output=_output;
-
+
//http://www.mega-nerd.com/libsndfile/api.html#note1
//libsndfile returns -1..1 for fp data
bytes=(bits>>3);
stride=channels*bytes;
scale=(1.0f/pow(2.0f,bits));
-
-
+
+
loader = PluginLoader::getInstance();
key = loader->composePluginKey(soname, id);
- Plugin *plugin = loader->loadPlugin(key, _rate, PluginLoader::ADAPT_ALL_SAFE);
+ plugin = loader->loadPlugin(key, _rate, PluginLoader::ADAPT_ALL_SAFE);
if (!plugin) {
cerr << ": ERROR: Failed to load plugin \"" << id
<< "\" from library \"" << soname << "\"" << endl;
@@ -616,7 +616,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
}
cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
-
+
blockSize = plugin->getPreferredBlockSize();
stepSize = plugin->getPreferredStepSize();
@@ -629,7 +629,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
} else {
stepSize = blockSize;
}
- }
+ }
else if (stepSize > blockSize) {
cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to ";
if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
@@ -642,7 +642,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
overlapSize = blockSize - stepSize;
currentStep = 0;
finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF
-
+
plugbuf = new float*[channels];
for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2];
@@ -684,7 +684,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
return false;
}
- }
+ }
else {
if (int(outputs.size()) <= outputNo) {
cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
@@ -700,7 +700,7 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
<< blockSize << ") failed." << endl;
return false;
}
-
+
wrapper = dynamic_cast<PluginWrapper *>(plugin);
if (wrapper) {
// See documentation for
@@ -708,16 +708,20 @@ bool vampHost::Analyser::init(const string &soname,const string &id,const int &_
PluginInputDomainAdapter *ida =wrapper->getWrapper<PluginInputDomainAdapter>();
if (ida) adjustment = ida->getTimestampAdjustment();
}
-
+
//everything is prepared to start consuming data in blocks
-
+
in_block=0;
blocks_processed=0;
+ currentStep=0;
+ featureNo=0;
+
return true;
}
void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
int sample=0;
+ RealTime rt;
//process the whole frame which may be f>1<f blocks
//when the frame is finished leave the partial block for the next frame
while(sample<samples_in_frame) {
@@ -734,13 +738,28 @@ void vampHost::Analyser::process_frame(uint8_t *data,int samples_in_frame){
}
if (in_block==blockSize) {
//block is ready to be processed
- cerr<<"processing block "<<blocks_processed<<endl;
+ //cerr<<plugin->getIdentifier()<<" processed block "<<blocks_processed<<endl;
+
+ //I /think/ that the vamp plugin keeps processing through the plugbuf until it encounters 0s
+ rt = RealTime::frame2RealTime(in_block * stepSize, rate);
+
+ Plugin::FeatureSet feat=plugin->process(plugbuf, rt);
+
+ for (unsigned int i = 0; i < feat[outputNo].size(); ++i) {
+ features[((float)feat[outputNo][i].timestamp.sec)+(((float)feat[outputNo][i].timestamp.nsec)*.000000001)]=featureNo;
+ featureNo++;
+ }
+
+ //all good but no features! what gives?
+
in_block=0;
blocks_processed++;
}
}
}
void vampHost::Analyser::cleanup(){
+ cerr<<plugin->getIdentifier()<<" found "<<features.size()<<" features"<<endl;
+ //deal with left over data?
for (int c = 0; c < channels; ++c) {
delete[] plugbuf[c];
}
diff --git a/rotord/vampHost.h b/rotord/vampHost.h
index 18fe297..f6693a9 100644
--- a/rotord/vampHost.h
+++ b/rotord/vampHost.h
@@ -59,7 +59,6 @@ namespace vampHost {
bool init(const string &soname,const string &id,const int &_channels,const int &_bits,const int &_samples,const int &_rate,const int &_outputNo=0,const string &_output="");
void process_frame(uint8_t *data,int samples_in_frame);
void cleanup();
- vector<float> beats;
private:
PluginLoader *loader;
PluginLoader::PluginKey key;
@@ -71,6 +70,15 @@ namespace vampHost {
int in_block,blocks_processed;
string output;
float **plugbuf;
+
+ int featureNo;
+ map<float,int> features;
+ //what's the best way to store features?
+ //how will it be used?
+ //we ask for a signal at a time, return interpolated value representing feature number + fraction
+ //is there a quick way to search the keys and return the last one below a given value
+
+
};
string getQMBeats(const string soundfile);