1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
#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);
vectordata[column]=mean;
column++;
sample=0;
samples=0;
accum=0.0;
}
}
return out_sample;
}
void Audio_thumbnailer::print_vector(xmlIO XML){
string vdata;
for (int i=0;i<width;i++){
if (i>0) vdata+=",";
vdata+=toString(vectordata[i]);
}
XML.addValue("data",vdata);
}
bool Vamp_node::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 Vamp_node::process_frame(uint8_t *data,int samples_in_frame) {
analyser.process_frame(data,samples_in_frame);
return 1;
}
void Vamp_node::cleanup() {
analyser.cleanup();
//print_features();
}
string Vamp_node::get_features(){
string data;
for (auto i: analyser.features) {
data=data+" ["+toString(i.second.number)+":"+toString(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+toString(j);
}
data+=") ";
}
data+="]";
}
return data;
}
}
|