ProtoTracer  1.0
Real-time 3D rendering and animation engine
Loading...
Searching...
No Matches
FFTVoiceDetection.tpp
Go to the documentation of this file.
1#pragma once
2
3template <size_t peakCount>
4void FFTVoiceDetection<peakCount>::SetThreshold(float threshold) {
5 this->threshold = threshold;
6}
7
8template <size_t peakCount>
9float FFTVoiceDetection<peakCount>::GetViseme(MouthShape viseme) {
10 return *visRatios[viseme];
11}
12
13template <size_t peakCount>
14void FFTVoiceDetection<peakCount>::PrintVisemes() {
15 float max = 0.0f;
16 uint8_t ind = 10;
17
18 for (uint8_t i = 0; i < visemeCount; i++) {
19 if (max < *visRatios[i]) {
20 max = *visRatios[i];
21 ind = i;
22 }
23 }
24
25 if (ind < 7) {
26 Serial.print(f1);
27 Serial.print(',');
28 Serial.print(f2);
29 Serial.print(',');
30 }
31
32 switch (ind) {
33 case EE:
34 Serial.println("EE");
35 break;
36 case AE:
37 Serial.println("AE");
38 break;
39 case UH:
40 Serial.println("UH");
41 break;
42 case AR:
43 Serial.println("AR");
44 break;
45 case ER:
46 Serial.println("ER");
47 break;
48 case AH:
49 Serial.println("AH");
50 break;
51 case OO:
52 Serial.println("OO");
53 break;
54 default:
55 // Serial.println("?");
56 break;
57 }
58}
59
60template <size_t peakCount>
61void FFTVoiceDetection<peakCount>::ResetVisemes() {
62 for (uint8_t i = 0; i < visemeCount; i++) *visRatios[i] = 0.0f;
63}
64
65template <size_t peakCount>
66void FFTVoiceDetection<peakCount>::Update(float* peaks, float maxFrequency) {
67 CalculateFormants(peaks, 5);
68
69 f1 = f1 / float(peakCount) * (maxFrequency / 2.0f);
70 f2 = f2 / float(peakCount) * (maxFrequency / 2.0f);
71
72 CalculateVisemeGroup();
73}
74
75template <size_t peakCount>
76void FFTVoiceDetection<peakCount>::CalculateFormants(float* peaks, uint8_t bandwidth) {
77 // calculate forward and backward of bandwidth of sum for each peak for kernel density estimation
78 for (int16_t i = 0; i < int16_t(peakCount); i++) {
79 peakDensity[i] = 0;
80 float density = 0.0f;
81
82 for (int16_t j = 0; j < int16_t(bandwidth); j++) {
83 if (i < int16_t(bandwidth)) {
84 density += peaks[i + j];
85
86 if (i - j > 0) density += peaks[i - j];
87 } else if (i > int16_t(peakCount - bandwidth)) {
88 density += peaks[i - j];
89
90 if (i + j < int16_t(peakCount)) density += peaks[i + j];
91 } else {
92 density += peaks[i + j];
93 density += peaks[i - j];
94 }
95 }
96
97 peakDensity[i] = peakSmoothing.Filter(density);
98 }
99
100 peakDetection.Calculate(peakDensity, peaksBinary);
101
102 // check two largest consecutive peak blocks, find center
103
104 uint8_t tempCount = 0;
105 uint8_t firstStart = 0;
106 uint8_t firstCount = 0;
107 uint8_t secondStart = 0;
108 uint8_t secondCount = 0;
109
110 for (uint8_t i = 0; i < peakCount; i++) {
111 if (peaksBinary[i]) {
112 tempCount++;
113 } else {
114 if (firstCount < tempCount) {
115 secondCount = firstCount;
116 secondStart = firstStart;
117 firstCount = tempCount;
118 firstStart = i - tempCount;
119 } else if (secondCount < tempCount) {
120 secondCount = tempCount;
121 secondStart = i - tempCount;
122 }
123
124 tempCount = 0;
125 }
126 }
127
128 if (firstCount < 8) {
129 secondStart = firstStart;
130 secondCount = firstCount;
131 }
132
133 if (secondCount < 8) {
134 secondStart = firstStart;
135 secondCount = firstCount;
136 }
137
138 if (firstStart < secondStart) {
139 f1 = float(firstStart + firstCount / 2);
140 f2 = float(secondStart + secondCount / 2);
141 } else {
142 f1 = float(secondStart + secondCount / 2);
143 f2 = float(firstStart + firstCount / 2);
144 }
145}
146
147template <size_t peakCount>
148void FFTVoiceDetection<peakCount>::CalculateVisemeGroup(){
149 //update all viseme values
150 for(uint8_t i = 0; i < visemeCount; i++) *visRatios[i] = 0.0f;
151
152 if(f1 > threshold || f2 > threshold){
153 Vector2D formant = Vector2D(f1, f2);
154 uint8_t firstClosest = 0;
155 float firstDistance = 1000000.0f;//arbitrary large value
156
157 for(uint8_t i = 0; i < visemeCount; i++){//find two smallest values
158 float distance = formant.CalculateEuclideanDistance(*coordinates[i]);
159
160 if(distance < firstDistance){
161 firstClosest = i;
162 firstDistance = distance;
163 }
164 }
165
166 *visRatios[firstClosest] = 1.0f;
167 }
168}