1 // Copyright (c) Charles J. Cliffe
2 // SPDX-License-Identifier: GPL-2.0+
3
4 #include "SpectrumVisualProcessor.h"
5 #include "CubicSDR.h"
6
7 //50 ms
8 #define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000)
9
SpectrumVisualProcessor()10 SpectrumVisualProcessor::SpectrumVisualProcessor() : outputBuffers("SpectrumVisualProcessorBuffers") {
11 lastInputBandwidth = 0;
12 lastBandwidth = 0;
13 lastDataSize = 0;
14 resampler = nullptr;
15 resamplerRatio = 0;
16
17 fftInput = nullptr;
18 fftOutput = nullptr;
19 fftInData = nullptr;
20 fftLastData = nullptr;
21 fftPlan = nullptr;
22
23 is_view = false;
24 fftSize = 0;
25 centerFreq = 0;
26 bandwidth = 0;
27 hideDC = false;
28
29 freqShifter = nco_crcf_create(LIQUID_NCO);
30 shiftFrequency = 0;
31
32 fft_ceil_ma = fft_ceil_maa = 100.0;
33 fft_floor_ma = fft_floor_maa = 0.0;
34 fft_floor_peak = 0.0;
35 desiredInputSize = 0;
36 fft_average_rate = 0.65f;
37 scaleFactor = 1.0;
38 fftSizeChanged = false;
39 newFFTSize = 0;
40 lastView = false;
41 peakHold = false;
42 peakReset = false;
43
44 }
45
~SpectrumVisualProcessor()46 SpectrumVisualProcessor::~SpectrumVisualProcessor() {
47 nco_crcf_destroy(freqShifter);
48 }
49
isView()50 bool SpectrumVisualProcessor::isView() {
51
52 std::lock_guard < std::mutex > busy_lock(busy_run);
53
54 return is_view;
55 }
56
setView(bool bView)57 void SpectrumVisualProcessor::setView(bool bView) {
58
59 std::lock_guard < std::mutex > busy_lock(busy_run);
60
61 is_view = bView;
62 }
63
setView(bool bView,long long centerFreq_in,long bandwidth_in)64 void SpectrumVisualProcessor::setView(bool bView, long long centerFreq_in, long bandwidth_in) {
65
66 std::lock_guard < std::mutex > busy_lock(busy_run);
67 is_view = bView;
68 bandwidth = bandwidth_in;
69 centerFreq = centerFreq_in;
70 }
71
72
setFFTAverageRate(float fftAverageRate)73 void SpectrumVisualProcessor::setFFTAverageRate(float fftAverageRate) {
74
75 std::lock_guard < std::mutex > busy_lock(busy_run);
76
77 this->fft_average_rate = fftAverageRate;
78 }
79
getFFTAverageRate()80 float SpectrumVisualProcessor::getFFTAverageRate() {
81
82 std::lock_guard < std::mutex > busy_lock(busy_run);
83
84 return this->fft_average_rate;
85 }
86
setCenterFrequency(long long centerFreq_in)87 void SpectrumVisualProcessor::setCenterFrequency(long long centerFreq_in) {
88
89 std::lock_guard < std::mutex > busy_lock(busy_run);
90
91 centerFreq = centerFreq_in;
92 }
93
getCenterFrequency()94 long long SpectrumVisualProcessor::getCenterFrequency() {
95
96 std::lock_guard < std::mutex > busy_lock(busy_run);
97
98 return centerFreq;
99 }
100
setBandwidth(long bandwidth_in)101 void SpectrumVisualProcessor::setBandwidth(long bandwidth_in) {
102
103 std::lock_guard < std::mutex > busy_lock(busy_run);
104
105 bandwidth = bandwidth_in;
106 }
107
getBandwidth()108 long SpectrumVisualProcessor::getBandwidth() {
109
110 std::lock_guard < std::mutex > busy_lock(busy_run);
111
112 return bandwidth;
113 }
114
setPeakHold(bool peakHold_in)115 void SpectrumVisualProcessor::setPeakHold(bool peakHold_in) {
116
117 std::lock_guard < std::mutex > busy_lock(busy_run);
118
119 if (peakHold && peakHold_in) {
120 peakReset = PEAK_RESET_COUNT;
121 } else {
122 peakHold = peakHold_in;
123 peakReset = 1;
124 }
125 }
126
getPeakHold()127 bool SpectrumVisualProcessor::getPeakHold() {
128
129 std::lock_guard < std::mutex > busy_lock(busy_run);
130
131 return peakHold;
132 }
133
getDesiredInputSize()134 int SpectrumVisualProcessor::getDesiredInputSize() {
135 std::lock_guard < std::mutex > busy_lock(busy_run);
136
137 return desiredInputSize;
138 }
139
setup(unsigned int fftSize_in)140 void SpectrumVisualProcessor::setup(unsigned int fftSize_in) {
141
142 std::lock_guard < std::mutex > busy_lock(busy_run);
143
144 fftSize = fftSize_in;
145 fftSizeInternal = fftSize_in * SPECTRUM_VZM;
146 lastDataSize = 0;
147
148 int memSize = sizeof(liquid_float_complex) * fftSizeInternal;
149
150 if (fftInput) {
151 free(fftInput);
152 }
153 fftInput = (liquid_float_complex*)malloc(memSize);
154 memset(fftInput,0,memSize);
155
156 if (fftInData) {
157 free(fftInData);
158 }
159 fftInData = (liquid_float_complex*)malloc(memSize);
160 memset(fftInput,0,memSize);
161
162 if (fftLastData) {
163 free(fftLastData);
164 }
165 fftLastData = (liquid_float_complex*)malloc(memSize);
166 memset(fftInput,0,memSize);
167
168 if (fftOutput) {
169 free(fftOutput);
170 }
171 fftOutput = (liquid_float_complex*)malloc(memSize);
172 memset(fftInput,0,memSize);
173
174 if (fftPlan) {
175 fft_destroy_plan(fftPlan);
176 }
177 fftPlan = fft_create_plan(fftSizeInternal, fftInput, fftOutput, LIQUID_FFT_FORWARD, 0);
178 }
179
setFFTSize(unsigned int fftSize_in)180 void SpectrumVisualProcessor::setFFTSize(unsigned int fftSize_in) {
181
182 //then get the busy_lock
183 std::lock_guard < std::mutex > busy_lock(busy_run);
184
185 if (fftSize_in == fftSize) {
186 return;
187 }
188 newFFTSize = fftSize_in;
189 fftSizeChanged = true;
190 }
191
getFFTSize()192 unsigned int SpectrumVisualProcessor::getFFTSize() {
193
194 //then get the busy_lock
195 std::lock_guard < std::mutex > busy_lock(busy_run);
196
197 if (fftSizeChanged) {
198 return newFFTSize;
199 }
200 return fftSize;
201 }
202
203
setHideDC(bool hideDC_in)204 void SpectrumVisualProcessor::setHideDC(bool hideDC_in) {
205
206 std::lock_guard < std::mutex > busy_lock(busy_run);
207
208 hideDC = hideDC_in;
209 }
210
211
process()212 void SpectrumVisualProcessor::process() {
213 if (!isOutputEmpty()) {
214 return;
215 }
216 if (!input || input->empty()) {
217 return;
218 }
219
220 bool executeSetup = false;
221
222 { // scoped lock here
223 std::lock_guard < std::mutex > busy_lock(busy_run);
224 if (fftSizeChanged) {
225 executeSetup = true;
226 fftSizeChanged = false;
227 }
228 }
229
230 if (executeSetup) {
231 setup(newFFTSize);
232 }
233
234 DemodulatorThreadIQDataPtr iqData;
235
236 if (!input->pop(iqData, HEARTBEAT_CHECK_PERIOD_MICROS)) {
237 return;
238 }
239
240 if (!iqData) {
241 return;
242 }
243
244 //then get the busy_lock for the rest of the processing.
245 std::lock_guard < std::mutex > busy_lock(busy_run);
246
247 bool doPeak = peakHold && (peakReset == 0);
248
249 if (fft_result.size() != fftSizeInternal) {
250
251 if (fft_result.capacity() < fftSizeInternal) {
252 fft_result.reserve(fftSizeInternal);
253 fft_result_ma.reserve(fftSizeInternal);
254 fft_result_maa.reserve(fftSizeInternal);
255 fft_result_peak.reserve(fftSizeInternal);
256 }
257 fft_result.resize(fftSizeInternal);
258 fft_result_ma.resize(fftSizeInternal);
259 fft_result_maa.resize(fftSizeInternal);
260 fft_result_temp.resize(fftSizeInternal);
261 fft_result_peak.resize(fftSizeInternal);
262 }
263
264 if (peakReset != 0) {
265 peakReset--;
266 if (peakReset == 0) {
267 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
268 fft_result_peak[i] = fft_floor_maa;
269 }
270 fft_ceil_peak = fft_floor_maa;
271 fft_floor_peak = fft_ceil_maa;
272 }
273 }
274
275 std::vector<liquid_float_complex> *data = &iqData->data;
276
277 if (data && !data->empty()) {
278 unsigned int num_written;
279 long resampleBw = iqData->sampleRate;
280 bool newResampler = false;
281 int bwDiff = 0;
282
283 if (is_view) {
284 if (!iqData->sampleRate) {
285
286 return;
287 }
288
289 while (resampleBw / SPECTRUM_VZM >= (long) bandwidth) {
290 resampleBw /= SPECTRUM_VZM;
291 }
292
293 resamplerRatio = (double) (resampleBw) / (double) iqData->sampleRate;
294
295 size_t desired_input_size = fftSizeInternal / resamplerRatio;
296
297 this->desiredInputSize = desired_input_size;
298
299 if (iqData->data.size() < desired_input_size) {
300 // std::cout << "fft underflow, desired: " << desired_input_size << " actual:" << input->data.size() << std::endl;
301 desired_input_size = iqData->data.size();
302 }
303
304 if (centerFreq != iqData->frequency) {
305 if ((centerFreq - iqData->frequency) != shiftFrequency || lastInputBandwidth != iqData->sampleRate) {
306 if (abs(iqData->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
307 long lastShiftFrequency = shiftFrequency;
308 shiftFrequency = centerFreq - iqData->frequency;
309 nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) iqData->sampleRate)));
310
311 if (is_view) {
312 long freqDiff = shiftFrequency - lastShiftFrequency;
313
314 if (lastBandwidth!=0) {
315 double binPerHz = double(lastBandwidth) / double(fftSizeInternal);
316
317 unsigned int numShift = floor(double(abs(freqDiff)) / binPerHz);
318
319 if (numShift < fftSizeInternal/2 && numShift) {
320 if (freqDiff > 0) {
321 memmove(&fft_result_ma[0], &fft_result_ma[numShift], (fftSizeInternal-numShift) * sizeof(double));
322 memmove(&fft_result_maa[0], &fft_result_maa[numShift], (fftSizeInternal-numShift) * sizeof(double));
323 // memmove(&fft_result_peak[0], &fft_result_peak[numShift], (fftSizeInternal-numShift) * sizeof(double));
324 // memset(&fft_result_peak[fftSizeInternal-numShift], 0, numShift * sizeof(double));
325 } else {
326 memmove(&fft_result_ma[numShift], &fft_result_ma[0], (fftSizeInternal-numShift) * sizeof(double));
327 memmove(&fft_result_maa[numShift], &fft_result_maa[0], (fftSizeInternal-numShift) * sizeof(double));
328 // memmove(&fft_result_peak[numShift], &fft_result_peak[0], (fftSizeInternal-numShift) * sizeof(double));
329 // memset(&fft_result_peak[0], 0, numShift * sizeof(double));
330 }
331 }
332 }
333 }
334 }
335 peakReset = PEAK_RESET_COUNT;
336 }
337
338 if (shiftBuffer.size() != desired_input_size) {
339 if (shiftBuffer.capacity() < desired_input_size) {
340 shiftBuffer.reserve(desired_input_size);
341 }
342 shiftBuffer.resize(desired_input_size);
343 }
344
345 if (shiftFrequency < 0) {
346 nco_crcf_mix_block_up(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
347 } else {
348 nco_crcf_mix_block_down(freqShifter, &iqData->data[0], &shiftBuffer[0], desired_input_size);
349 }
350 } else {
351 shiftBuffer.assign(iqData->data.begin(), iqData->data.begin()+desired_input_size);
352 }
353
354 if (!resampler || resampleBw != lastBandwidth || lastInputBandwidth != iqData->sampleRate) {
355 float As = 480.0;
356
357 if (resampler) {
358 msresamp_crcf_destroy(resampler);
359 }
360
361 resampler = msresamp_crcf_create(resamplerRatio, As);
362
363 bwDiff = resampleBw-lastBandwidth;
364 lastBandwidth = resampleBw;
365 lastInputBandwidth = iqData->sampleRate;
366 newResampler = true;
367 peakReset = PEAK_RESET_COUNT;
368 }
369
370 unsigned int out_size = ceil((double) (desired_input_size) * resamplerRatio) + 512;
371
372 if (resampleBuffer.size() != out_size) {
373 if (resampleBuffer.capacity() < out_size) {
374 resampleBuffer.reserve(out_size);
375 }
376 resampleBuffer.resize(out_size);
377 }
378
379 msresamp_crcf_execute(resampler, &shiftBuffer[0], desired_input_size, &resampleBuffer[0], &num_written);
380
381 if (num_written < fftSizeInternal) {
382 memcpy(fftInData, resampleBuffer.data(), num_written * sizeof(liquid_float_complex));
383 memset(&(fftInData[num_written]), 0, (fftSizeInternal-num_written) * sizeof(liquid_float_complex));
384 } else {
385 memcpy(fftInData, resampleBuffer.data(), fftSizeInternal * sizeof(liquid_float_complex));
386 }
387 } else {
388 this->desiredInputSize = fftSizeInternal;
389
390 num_written = data->size();
391 if (data->size() < fftSizeInternal) {
392 memcpy(fftInData, data->data(), data->size() * sizeof(liquid_float_complex));
393 memset(&fftInData[data->size()], 0, (fftSizeInternal - data->size()) * sizeof(liquid_float_complex));
394 } else {
395 memcpy(fftInData, data->data(), fftSizeInternal * sizeof(liquid_float_complex));
396 }
397 }
398
399 bool execute = false;
400
401 if (num_written >= fftSizeInternal) {
402 execute = true;
403 memcpy(fftInput, fftInData, fftSizeInternal * sizeof(liquid_float_complex));
404 memcpy(fftLastData, fftInput, fftSizeInternal * sizeof(liquid_float_complex));
405
406 } else {
407 if (lastDataSize + num_written < fftSizeInternal) { // priming
408 unsigned int num_copy = fftSizeInternal - lastDataSize;
409 if (num_written > num_copy) {
410 num_copy = num_written;
411 }
412 memcpy(fftLastData, fftInData, num_copy * sizeof(liquid_float_complex));
413 lastDataSize += num_copy;
414 } else {
415 unsigned int num_last = (fftSizeInternal - num_written);
416 memcpy(fftInput, fftLastData + (lastDataSize - num_last), num_last * sizeof(liquid_float_complex));
417 memcpy(fftInput + num_last, fftInData, num_written * sizeof(liquid_float_complex));
418 memcpy(fftLastData, fftInput, fftSizeInternal * sizeof(liquid_float_complex));
419 execute = true;
420 }
421 }
422
423 if (execute) {
424 SpectrumVisualDataPtr output = outputBuffers.getBuffer();
425
426 if (output->spectrum_points.size() != fftSize * 2) {
427 output->spectrum_points.resize(fftSize * 2);
428 }
429 if (doPeak) {
430 if (output->spectrum_hold_points.size() != fftSize * 2) {
431 output->spectrum_hold_points.resize(fftSize * 2);
432 }
433 } else {
434 output->spectrum_hold_points.resize(0);
435 }
436
437 float fft_ceil = 0, fft_floor = 1;
438
439 fft_execute(fftPlan);
440
441 for (int i = 0, iMax = fftSizeInternal / 2; i < iMax; i++) {
442 float a = fftOutput[i].real;
443 float b = fftOutput[i].imag;
444 float c = sqrt(a * a + b * b);
445
446 float x = fftOutput[fftSizeInternal / 2 + i].real;
447 float y = fftOutput[fftSizeInternal / 2 + i].imag;
448 float z = sqrt(x * x + y * y);
449
450 fft_result[i] = (z);
451 fft_result[fftSizeInternal / 2 + i] = (c);
452 }
453
454 if (newResampler && lastView) {
455 if (bwDiff < 0) {
456 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
457 fft_result_temp[i] = fft_result_ma[(fftSizeInternal/4) + (i/2)];
458 }
459 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
460 fft_result_ma[i] = fft_result_temp[i];
461
462 fft_result_temp[i] = fft_result_maa[(fftSizeInternal/4) + (i/2)];
463 }
464 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
465 fft_result_maa[i] = fft_result_temp[i];
466 }
467 } else {
468 for (size_t i = 0, iMax = fftSizeInternal; i < iMax; i++) {
469 if (i < fftSizeInternal/4) {
470 fft_result_temp[i] = 0; // fft_result_ma[fftSizeInternal/4];
471 } else if (i >= fftSizeInternal - fftSizeInternal/4) {
472 fft_result_temp[i] = 0; // fft_result_ma[fftSizeInternal - fftSizeInternal/4-1];
473 } else {
474 fft_result_temp[i] = fft_result_ma[(i-fftSizeInternal/4)*2];
475 }
476 }
477 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
478 fft_result_ma[i] = fft_result_temp[i];
479
480 if (i < fftSizeInternal/4) {
481 fft_result_temp[i] = 0; //fft_result_maa[fftSizeInternal/4];
482 } else if (i >= fftSizeInternal - fftSizeInternal/4) {
483 fft_result_temp[i] = 0; // fft_result_maa[fftSizeInternal - fftSizeInternal/4-1];
484 } else {
485 fft_result_temp[i] = fft_result_maa[(i-fftSizeInternal/4)*2];
486 }
487 }
488 for (unsigned int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
489 fft_result_maa[i] = fft_result_temp[i];
490 }
491 }
492 }
493
494 for (int i = 0, iMax = fftSizeInternal; i < iMax; i++) {
495 if (fft_result_maa[i] != fft_result_maa[i]) fft_result_maa[i] = fft_result[i];
496 fft_result_maa[i] += (fft_result_ma[i] - fft_result_maa[i]) * fft_average_rate;
497 if (fft_result_ma[i] != fft_result_ma[i]) fft_result_ma[i] = fft_result[i];
498 fft_result_ma[i] += (fft_result[i] - fft_result_ma[i]) * fft_average_rate;
499
500 if (fft_result_maa[i] > fft_ceil || fft_ceil != fft_ceil) {
501 fft_ceil = fft_result_maa[i];
502 }
503 if (fft_result_maa[i] < fft_floor || fft_floor != fft_floor) {
504 fft_floor = fft_result_maa[i];
505 }
506 if (doPeak) {
507 if (fft_result_maa[i] > fft_result_peak[i]) {
508 fft_result_peak[i] = fft_result_maa[i];
509 }
510 }
511 }
512
513 if (fft_ceil_ma != fft_ceil_ma) fft_ceil_ma = fft_ceil;
514 fft_ceil_ma = fft_ceil_ma + (fft_ceil - fft_ceil_ma) * 0.05;
515 if (fft_ceil_maa != fft_ceil_maa) fft_ceil_maa = fft_ceil;
516 fft_ceil_maa = fft_ceil_maa + (fft_ceil_ma - fft_ceil_maa) * 0.05;
517
518 if (fft_floor_ma != fft_floor_ma) fft_floor_ma = fft_floor;
519 fft_floor_ma = fft_floor_ma + (fft_floor - fft_floor_ma) * 0.05;
520 if (fft_floor_maa != fft_floor_maa) fft_floor_maa = fft_floor;
521 fft_floor_maa = fft_floor_maa + (fft_floor_ma - fft_floor_maa) * 0.05;
522
523 if (doPeak) {
524 if (fft_ceil_maa > fft_ceil_peak) {
525 fft_ceil_peak = fft_ceil_maa;
526 }
527 if (fft_floor_maa < fft_floor_peak) {
528 fft_floor_peak = fft_floor_maa;
529 }
530 }
531
532 float sf = scaleFactor;
533
534 double visualRatio = (double(bandwidth) / double(resampleBw));
535 double visualStart = (double(fftSizeInternal) / 2.0) - (double(fftSizeInternal) * (visualRatio / 2.0));
536 double visualAccum = 0;
537 double peak_acc = 0, acc = 0, accCount = 0, i = 0;
538
539 double point_ceil = doPeak?fft_ceil_peak:fft_ceil_maa;
540 double point_floor = doPeak?fft_floor_peak:fft_floor_maa;
541
542 for (int x = 0, xMax = output->spectrum_points.size() / 2; x < xMax; x++) {
543 visualAccum += visualRatio * double(SPECTRUM_VZM);
544
545 while (visualAccum >= 1.0) {
546 unsigned int idx = round(visualStart+i);
547 if (idx > 0 && idx < fftSizeInternal) {
548 acc += fft_result_maa[idx];
549 if (doPeak) {
550 peak_acc += fft_result_peak[idx];
551 }
552 } else {
553 acc += fft_floor_maa;
554 if (doPeak) {
555 peak_acc += fft_floor_maa;
556 }
557 }
558 accCount += 1.0;
559 visualAccum -= 1.0;
560 i++;
561 }
562
563 output->spectrum_points[x * 2] = ((float) x / (float) xMax);
564 if (doPeak) {
565 output->spectrum_hold_points[x * 2] = ((float) x / (float) xMax);
566 }
567 if (accCount) {
568 output->spectrum_points[x * 2 + 1] = ((log10((acc/accCount)+0.25 - (point_floor-0.75)) / log10((point_ceil+0.25) - (point_floor-0.75))))*sf;
569 acc = 0.0;
570 if (doPeak) {
571 output->spectrum_hold_points[x * 2 + 1] = ((log10((peak_acc/accCount)+0.25 - (point_floor-0.75)) / log10((point_ceil+0.25) - (point_floor-0.75))))*sf;
572 peak_acc = 0.0;
573 }
574 accCount = 0.0;
575 }
576 }
577
578 if (hideDC) { // DC-spike removal
579 long long freqMin = centerFreq-(bandwidth/2);
580 long long freqMax = centerFreq+(bandwidth/2);
581 long long zeroPt = (iqData->frequency-freqMin);
582
583 if (freqMin < iqData->frequency && freqMax > iqData->frequency) {
584 int freqRange = int(freqMax-freqMin);
585 int freqStep = freqRange/fftSize;
586 int fftStart = (zeroPt/freqStep)-(2000/freqStep);
587 int fftEnd = (zeroPt/freqStep)+(2000/freqStep);
588
589 // std::cout << "range:" << freqRange << ", step: " << freqStep << ", start: " << fftStart << ", end: " << fftEnd << std::endl;
590
591 if (fftEnd-fftStart < 2) {
592 fftEnd++;
593 fftStart--;
594 }
595
596 int numSteps = (fftEnd-fftStart);
597 int halfWay = fftStart+(numSteps/2);
598
599 if ((fftEnd+numSteps/2+1 < (long long) fftSize) && (fftStart-numSteps/2-1 >= 0) && (fftEnd > fftStart)) {
600 int n = 1;
601 for (int i = fftStart; i < halfWay; i++) {
602 output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftStart - n) * 2 + 1];
603 n++;
604 }
605 n = 1;
606 for (int i = halfWay; i < fftEnd; i++) {
607 output->spectrum_points[i * 2 + 1] = output->spectrum_points[(fftEnd + n) * 2 + 1];
608 n++;
609 }
610 if (doPeak) {
611 int n = 1;
612 for (int i = fftStart; i < halfWay; i++) {
613 output->spectrum_hold_points[i * 2 + 1] = output->spectrum_hold_points[(fftStart - n) * 2 + 1];
614 n++;
615 }
616 n = 1;
617 for (int i = halfWay; i < fftEnd; i++) {
618 output->spectrum_hold_points[i * 2 + 1] = output->spectrum_hold_points[(fftEnd + n) * 2 + 1];
619 n++;
620 }
621 }
622 }
623 }
624 }
625
626 output->fft_ceiling = point_ceil/sf;
627 output->fft_floor = point_floor;
628
629 output->centerFreq = centerFreq;
630 output->bandwidth = bandwidth;
631
632 distribute(output);
633 }
634 }
635
636 lastView = is_view;
637 }
638
639
setScaleFactor(float sf)640 void SpectrumVisualProcessor::setScaleFactor(float sf) {
641 std::lock_guard < std::mutex > busy_lock(busy_run);
642
643 scaleFactor = sf;
644 }
645
646
getScaleFactor()647 float SpectrumVisualProcessor::getScaleFactor() {
648 std::lock_guard < std::mutex > busy_lock(busy_run);
649 return scaleFactor;
650 }
651
652