summaryrefslogtreecommitdiff
path: root/rotord/src/nodes_audio_analysis.cpp
blob: 1e65668a4fee335b70754d0be7500ff9becc5d88 (plain)
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
108
#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;
		offset=0x1<<(bits-1); //signed audio
		scale=1.0f/offset;

		out_sample=0; //sample in whole track
		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) {
			//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
				//why does valgrind complain here about uninitialised vars
				double mean=pow(accum/samples,0.5f);
				audiodata.push_back(mean);
				sample=0;
				samples=0;
				accum=0.0;
			}
		}
		return out_sample;
	}
	void Audio_thumbnailer::print_vector(xmlIO XML){
		string vdata;
		int i=0;
		for (auto sample: audiodata){
			if (i>0) vdata+=",";
			vdata+=toString(sample);
		}
		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();
		features=analyser.features;
	}
	string Vamp_node::get_features(){
		string data;
		for (auto i: 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;
	}
}