summaryrefslogtreecommitdiff
path: root/rotord/src/nodes_audio_analysis.cpp
blob: 74b0574515498f50ed10e2c5dfd152f0a33c0a84 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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+=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;
	}
}