diff options
Diffstat (limited to 'rotord/src/nodes_audio_analysis.cpp')
| -rw-r--r-- | rotord/src/nodes_audio_analysis.cpp | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/rotord/src/nodes_audio_analysis.cpp b/rotord/src/nodes_audio_analysis.cpp new file mode 100644 index 0000000..925858f --- /dev/null +++ b/rotord/src/nodes_audio_analysis.cpp @@ -0,0 +1,135 @@ +#include "nodes_audio_analysis.h" + +namespace Rotor{ + bool Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) { + //base_audio_processor::init(_channels,_bits,_samples); + channels=_channels; + bits=_bits; + samples=_samples; + samples_per_column=samples/width; + column=0; //point thumbnail bitmap + out_sample=0; //sample in whole track + offset=0x1<<(bits-1); //signed audio + scale=1.0f/offset; + sample=0; + samples=0; + accum=0.0; + return true; + } + 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 + int bytes=(bits>>3); + int stride=channels*bytes; + int in_sample=0; + while (in_sample<samples_in_frame&&column<width) { + //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[(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... + double val=((double)((int16_t)this_val))*scale; + accum+=val*val; + samples++; + } + in_sample++; + sample++; + out_sample++; + } + if (sample==samples_per_column) { //finished a column + //get root-mean + double mean=pow(accum/samples,0.5); + //if (column==0) { + // cerr << "first column total: "<< accum << " in " << samples << " samples, average " << (accum/samples)<<endl; + //} + int colheight=height*mean*0.5; + int hh=height>>1; + for (int i=0;i<height;i++) { + data[i*width+column]=abs(i-hh)<colheight?0xff:0x00; + } + vectordata[column]=mean; + column++; + sample=0; + samples=0; + accum=0.0; + } + } + return out_sample; + } + string Audio_thumbnailer::print(){ + //base64 encode the image data output it + + stringstream output; + Poco::Base64Encoder *enc=new Poco::Base64Encoder(output); + + enc->write((char*)data,width*height); + //tring output; + /* + for (int j=0;j<height;j++) { + for (int i=0;i<width;i++) { + output+=data[j*width+i]<0x7f?"0":"1"; + } + output +="\n"; + } + */ + enc->close(); + delete enc; + return output.str(); + } + void Audio_thumbnailer::print_vector(xmlIO XML){ + string vdata; + for (int i=0;i<width;i++){ + if (i>0) vdata+=","; + vdata+=ofToString(vectordata[i]); + } + XML.addValue("data",vdata); + } + bool Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) { + //need these to make sense of data + channels=_channels; + bits=_bits; + samples=_samples; + + return analyser.init(soname,id,_channels,_bits,_samples,_rate,outputNo,params); + + + //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) { + analyser.process_frame(data,samples_in_frame); + return 1; + } + void Audio_analysis::cleanup() { + analyser.cleanup(); + //print_features(); + } + string Audio_analysis::get_features(){ + string data; + for (auto i: analyser.features) { + data=data+" ["+ofToString(i.second.number)+":"+ofToString(i.first); + if (i.second.values.size()) { + data+=" ("; + bool first=true; + for (auto j: i.second.values) { + if (first){ + first=false; + } + else data+=","; + data=data+ofToString(j); + } + data+=") "; + } + data+="]"; + } + return data; + } +}
\ No newline at end of file |
