wavspa 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,918 @@
1
+ /*
2
+ * Ooura FFT library interface
3
+ *
4
+ * Copyright (C) 2016 Hiroshi Kuwagata <kgt9221@gmail.com>
5
+ */
6
+
7
+ /*
8
+ * $Id$
9
+ */
10
+
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <stdint.h>
14
+ #include <string.h>
15
+ #include <math.h>
16
+
17
+ #include "fft.h"
18
+
19
+ #define N(x) (sizeof(x)/sizeof(*x))
20
+ #define IS_POW2(n) (!((n) & ((n) - 1)))
21
+ #define ALLOC(t) ((t*)malloc(sizeof(t)))
22
+ #define NALLOC(t,n) ((t*)malloc(sizeof(t) * (n)))
23
+ #define MAX(m,n) (((m) > (n))? (m): (n))
24
+
25
+ #define ERR __LINE__
26
+
27
+ #define FMT_U8 0x0001
28
+ #define FMT_U16LE 0x0002
29
+ #define FMT_U16BE 0x0012
30
+ #define FMT_S16LE 0x0102
31
+ #define FMT_S16BE 0x0112
32
+ #define FMT_S24LE 0x0203
33
+ #define FMT_S24BE 0x0213
34
+
35
+ typedef struct {
36
+ int pos;
37
+ int n;
38
+ } lc_t;
39
+
40
+ extern void rdft(int, int, double *, int *, double *);
41
+
42
+ int
43
+ fft_new(char* _fmt, int capa, fft_t** _obj)
44
+ {
45
+ int ret;
46
+ fft_t* obj;
47
+
48
+ int fmt;
49
+
50
+ double* data;
51
+ double* wtbl;
52
+ lc_t* line;
53
+
54
+ double* a;
55
+ int* ip;
56
+ double* w;
57
+
58
+ /*
59
+ * initialize
60
+ */
61
+ ret = 0;
62
+
63
+ obj = NULL;
64
+ data = NULL;
65
+ wtbl = NULL;
66
+ a = NULL;
67
+ ip = NULL;
68
+ w = NULL;
69
+
70
+ /*
71
+ * argument check
72
+ */
73
+ if (_fmt == NULL) ret = ERR;
74
+ if (!capa || !IS_POW2(capa)) ret = ERR;
75
+ if (_obj == NULL) ret = ERR;
76
+
77
+ if (strcasecmp("u8", _fmt) == 0) {
78
+ fmt = FMT_U8;
79
+
80
+ } else if (strcasecmp("u16be", _fmt) == 0) {
81
+ fmt = FMT_U16BE;
82
+
83
+ } else if (strcasecmp("u16le", _fmt) == 0) {
84
+ fmt = FMT_U16LE;
85
+
86
+ } else if (strcasecmp("s16be", _fmt) == 0) {
87
+ fmt = FMT_S16BE;
88
+
89
+ } else if (strcasecmp("s16le", _fmt) == 0) {
90
+ fmt = FMT_S16LE;
91
+
92
+ } else if (strcasecmp("s24be", _fmt) == 0) {
93
+ fmt = FMT_S24BE;
94
+
95
+ } else if (strcasecmp("s24le", _fmt) == 0) {
96
+ fmt = FMT_S24LE;
97
+
98
+ } else {
99
+ ret = ERR;
100
+ }
101
+
102
+ /*
103
+ * memory allocation
104
+ */
105
+ if (!ret) {
106
+ obj = ALLOC(fft_t);
107
+ if (obj == NULL) ret = ERR;
108
+ }
109
+
110
+ if (!ret) {
111
+ data = NALLOC(double, capa);
112
+ if (data == NULL) ret = ERR;
113
+ }
114
+
115
+ if (!ret) {
116
+ wtbl = NALLOC(double, capa);
117
+ if (wtbl == NULL) ret = ERR;
118
+ }
119
+
120
+ if (!ret) {
121
+ line = NALLOC(lc_t, capa / 2);
122
+ if (line == NULL) ret = ERR;
123
+ }
124
+
125
+ if (!ret) {
126
+ a = NALLOC(double, capa);
127
+ if (a == NULL) ret = ERR;
128
+ }
129
+
130
+ if (!ret) {
131
+ ip = NALLOC(int, 2 + (int)sqrt(capa / 2));
132
+ if (ip == NULL) ret = ERR;
133
+ }
134
+
135
+ if (!ret) {
136
+ w = NALLOC(double, capa / 2);
137
+ if (w == NULL) ret = ERR;
138
+ }
139
+
140
+ /*
141
+ * set return parameter
142
+ */
143
+ if (!ret) {
144
+ ip[0] = 0;
145
+ rdft(capa, 1, a, ip, w);
146
+
147
+ memset(data, 0, sizeof(double) * capa);
148
+
149
+ obj->data = data;
150
+ obj->wtbl = wtbl;
151
+
152
+ obj->line = line;
153
+ obj->width = capa / 2;
154
+
155
+ obj->fmt = fmt;
156
+
157
+ obj->capa = capa;
158
+ obj->used = 0;
159
+
160
+ obj->magnify = 1;
161
+
162
+ obj->mode = FFT_LOGSCALE_MODE;
163
+ obj->fq_s = 44100;
164
+ obj->fq_h = 16000;
165
+ obj->fq_l = 100;
166
+
167
+ obj->a = a;
168
+ obj->ip = ip;
169
+ obj->w = w;
170
+
171
+ fft_set_window(obj, FFT_WINDOW_BLACKMAN);
172
+ fft_set_width(obj, 480);
173
+
174
+ *_obj = obj;
175
+ }
176
+
177
+ /*
178
+ * post process
179
+ */
180
+ if (ret) {
181
+ if (obj != NULL) free(obj);
182
+ if (data != NULL) free(data);
183
+ if (wtbl != NULL) free(wtbl);
184
+ if (line != NULL) free(line);
185
+ if (a != NULL) free(a);
186
+ if (ip != NULL) free(ip);
187
+ if (w != NULL) free(w);
188
+ }
189
+
190
+ return ret;
191
+ }
192
+
193
+ int
194
+ fft_destroy(fft_t* fft)
195
+ {
196
+ int ret;
197
+
198
+ /*
199
+ * initialize
200
+ */
201
+ ret = 0;
202
+
203
+ /*
204
+ * argument check
205
+ */
206
+ if (fft == NULL) ret = ERR;
207
+
208
+ /*
209
+ * release memory
210
+ */
211
+ if (!ret) {
212
+ free(fft->data);
213
+ free(fft->wtbl);
214
+ free(fft->line);
215
+ free(fft->a);
216
+ free(fft->ip);
217
+ free(fft->w);
218
+
219
+ free(fft);
220
+ }
221
+
222
+ return ret;
223
+ }
224
+
225
+ static void
226
+ import_u8(double* dst, uint8_t* src, int n)
227
+ {
228
+ int i;
229
+
230
+ for (i = 0; i < n; i++) {
231
+ dst[i] = ((double)src[i] - 128.0) / 128.0;
232
+ }
233
+ }
234
+
235
+ static void
236
+ import_u16le(double* dst, uint8_t* src, int n)
237
+ {
238
+ int i;
239
+ uint16_t smpl;
240
+
241
+ for (i = 0; i < n; i++, src += 2) {
242
+ smpl = ((((uint16_t)src[0] << 0) & 0x00ff)|
243
+ (((uint16_t)src[1] << 8) & 0xff00));
244
+
245
+ dst[i] = ((double)smpl - 32768.0) / 32768.0;
246
+ }
247
+ }
248
+
249
+ static void
250
+ import_u16be(double* dst, uint8_t* src, int n)
251
+ {
252
+ int i;
253
+ uint16_t smpl;
254
+
255
+ for (i = 0; i < n; i++, src += 2) {
256
+ smpl = ((((uint16_t)src[1] << 0) & 0x00ff)|
257
+ (((uint16_t)src[0] << 8) & 0xff00));
258
+
259
+ dst[i] = ((double)smpl - 32768.0) / 32768.0;
260
+ }
261
+ }
262
+
263
+ static void
264
+ import_s16le(double* dst, uint8_t* src, int n)
265
+ {
266
+ int i;
267
+ int16_t smpl;
268
+
269
+ for (i = 0; i < n; i++, src += 2) {
270
+ smpl = ((((int16_t)src[0] << 0) & 0x00ff)|
271
+ (((int16_t)src[1] << 8) & 0xff00));
272
+
273
+ dst[i] = (double)smpl / 32768.0;
274
+ }
275
+ }
276
+
277
+ static void
278
+ import_s16be(double* dst, uint8_t* src, int n)
279
+ {
280
+ int i;
281
+ int16_t smpl;
282
+
283
+ for (i = 0; i < n; i++, src += 2) {
284
+ smpl = ((((int16_t)src[1] << 0) & 0x00ff)|
285
+ (((int16_t)src[0] << 8) & 0xff00));
286
+
287
+ dst[i] = (double)smpl / 32768.0;
288
+ }
289
+ }
290
+
291
+ static void
292
+ import_s24le(double* dst, uint8_t* src, int n)
293
+ {
294
+ int i;
295
+ int32_t smpl;
296
+
297
+ for (i = 0; i < n; i++, src += 3) {
298
+ smpl = ((((int32_t)src[0] << 8) & 0x0000ff00)|
299
+ (((int32_t)src[1] << 16) & 0x00ff0000)|
300
+ (((int32_t)src[2] << 24) & 0xff000000));
301
+
302
+ dst[i] = (double)smpl / 2147483648.0;
303
+ }
304
+ }
305
+
306
+ static void
307
+ import_s24be(double* dst, uint8_t* src, int n)
308
+ {
309
+ int i;
310
+ int32_t smpl;
311
+
312
+ for (i = 0; i < n; i++, src += 3) {
313
+ smpl = ((((int32_t)src[2] << 8) & 0x0000ff00)|
314
+ (((int32_t)src[1] << 16) & 0x00ff0000)|
315
+ (((int32_t)src[0] << 24) & 0xff000000));
316
+
317
+ dst[i] = (double)smpl / 2147483648.0;
318
+ }
319
+ }
320
+
321
+ int
322
+ fft_shift_in(fft_t* fft, void* src, int n)
323
+ {
324
+ int ret;
325
+ double* dst;
326
+
327
+ /*
328
+ * initialize
329
+ */
330
+ ret = 0;
331
+
332
+ /*
333
+ * argument check
334
+ */
335
+ if (fft == NULL) ret = ERR;
336
+ if (src == NULL) ret = ERR;
337
+ if (n < 0) ret = ERR;
338
+
339
+ if (!ret) {
340
+ if (n > fft->capa) ret = ERR;
341
+ }
342
+
343
+ /*
344
+ * do import
345
+ */
346
+ if (!ret) {
347
+ memmove(fft->data, fft->data + n, sizeof(double) * (fft->capa - n));
348
+
349
+ dst = fft->data + (fft->capa - n);
350
+ switch (fft->fmt) {
351
+ case FMT_U8:
352
+ import_u8(dst, src, n);
353
+ break;
354
+
355
+ case FMT_U16BE:
356
+ import_u16be(dst, src, n);
357
+ break;
358
+
359
+ case FMT_U16LE:
360
+ import_u16le(dst, src, n);
361
+ break;
362
+
363
+ case FMT_S16BE:
364
+ import_s16be(dst, src, n);
365
+ break;
366
+
367
+ case FMT_S16LE:
368
+ import_s16le(dst, src, n);
369
+ break;
370
+
371
+ case FMT_S24BE:
372
+ import_s24be(dst, src, n);
373
+ break;
374
+
375
+ case FMT_S24LE:
376
+ import_s24le(dst, src, n);
377
+ break;
378
+ }
379
+
380
+ fft->used += n;
381
+
382
+ if (fft->used > fft->capa) {
383
+ fft->used = fft->capa;
384
+ }
385
+ }
386
+
387
+ return ret;
388
+ }
389
+
390
+ int
391
+ fft_reset(fft_t* fft)
392
+ {
393
+ int ret;
394
+
395
+ /*
396
+ * initialize
397
+ */
398
+ ret = 0;
399
+
400
+ /*
401
+ * argument check
402
+ */
403
+ if (fft == NULL) ret = ERR;
404
+
405
+ /*
406
+ * do reset buffer
407
+ */
408
+ if (!ret) {
409
+ memset(fft->data, 0, sizeof(double) * fft->capa);
410
+
411
+ fft->used = 0;
412
+ }
413
+
414
+ return ret;
415
+ }
416
+
417
+
418
+ static void
419
+ set_rectangular_window(double* dst, int n)
420
+ {
421
+ int i;
422
+
423
+ for (i = 0; i <= n; i++) {
424
+ dst[i] = 1.0;
425
+ }
426
+ }
427
+
428
+ static void
429
+ set_hamming_window(double* dst, int n)
430
+ {
431
+ int i;
432
+ double x;
433
+
434
+ n--;
435
+
436
+ for (i = 0; i <= n; i++) {
437
+ x = ((double)i / (double)n) * M_PI * 2.0;
438
+ dst[i] = 0.54 - (0.46 * cos(x));
439
+ }
440
+ }
441
+
442
+ static void
443
+ set_hann_window(double* dst, int n)
444
+ {
445
+ int i;
446
+ double x;
447
+
448
+ n--;
449
+
450
+ for (i = 0; i <= n; i++) {
451
+ x = ((double)i / (double)n) * M_PI * 2.0;
452
+ dst[i] = 0.50 - (0.50 * cos(x));
453
+ }
454
+ }
455
+
456
+ static void
457
+ set_blackman_window(double* dst, int n)
458
+ {
459
+ int i;
460
+ double x;
461
+
462
+ n--;
463
+
464
+ for (i = 0; i <= n; i++) {
465
+ x = ((double)i / (double)n) * M_PI;
466
+ dst[i] = 0.42 - (0.50 * cos(2.0 * x)) + (0.08 * cos(4.0 * x));
467
+ }
468
+ }
469
+
470
+ static void
471
+ set_blackman_nuttall_window(double* dst, int n)
472
+ {
473
+ int i;
474
+ double x;
475
+
476
+ n--;
477
+
478
+ for (i = 0; i <= n; i++) {
479
+ x = ((double)i / (double)n) * M_PI * 2.0;
480
+ dst[i] = 0.3635819 - (0.4891775 * cos(x)) +
481
+ (0.1365995 * cos(2.0 * x)) - (0.0106411 * cos(3.0 * x));
482
+ }
483
+ }
484
+
485
+ static void
486
+ set_flat_top_window(double* dst, int n)
487
+ {
488
+ int i;
489
+ double x;
490
+
491
+ n--;
492
+
493
+ for (i = 0; i <= n; i++) {
494
+ x = ((double)i / (double)n) * M_PI * 2.0;
495
+ dst[i] = 1.0 - (1.93 * cos(x)) + (1.29 * cos(2.0 * x)) -
496
+ (0.388 * cos(3.0 * x)) + (0.032 * cos(4.0 * x));
497
+ }
498
+ }
499
+
500
+ int
501
+ fft_set_window(fft_t* fft, int type)
502
+ {
503
+ int ret;
504
+
505
+ /*
506
+ * initialize
507
+ */
508
+ ret = 0;
509
+
510
+ /*
511
+ * argument chack
512
+ */
513
+ if (fft == NULL) ret = ERR;
514
+
515
+ /*
516
+ * set window function
517
+ */
518
+ switch (type) {
519
+ case FFT_WINDOW_RECTANGULAR:
520
+ set_rectangular_window(fft->wtbl, fft->capa);
521
+ break;
522
+
523
+ case FFT_WINDOW_HAMMING:
524
+ set_hamming_window(fft->wtbl, fft->capa);
525
+ break;
526
+
527
+ case FFT_WINDOW_HANN:
528
+ set_hann_window(fft->wtbl, fft->capa);
529
+ break;
530
+
531
+ case FFT_WINDOW_BLACKMAN:
532
+ set_blackman_window(fft->wtbl, fft->capa);
533
+ break;
534
+
535
+ case FFT_WINDOW_BLACKMAN_NUTTALL:
536
+ set_blackman_nuttall_window(fft->wtbl, fft->capa);
537
+ break;
538
+
539
+ case FFT_WINDOW_FLAT_TOP:
540
+ set_flat_top_window(fft->wtbl, fft->capa);
541
+ break;
542
+
543
+ default:
544
+ ret = ERR;
545
+ break;
546
+ }
547
+
548
+ return ret;
549
+ }
550
+
551
+ static void
552
+ set_linear_mapping(fft_t* fft)
553
+ {
554
+ double pos;
555
+ double step;
556
+ int head;
557
+ int tail;
558
+ lc_t* lc;
559
+ int i;
560
+
561
+ pos = fft->capa * (fft->fq_l / fft->fq_s);
562
+ step = (fft->capa * ((fft->fq_h - fft->fq_l) / fft->fq_s)) / fft->width;
563
+ head = (int)round(pos);
564
+ lc = (lc_t*)fft->line;
565
+
566
+ for (i = 0; i < fft->width; i++) {
567
+ pos += step;
568
+ tail = (int)round(pos);
569
+
570
+ lc->pos = head;
571
+ lc->n = (tail == head)? 1: (tail - head);
572
+
573
+ head = tail;
574
+ lc++;
575
+ }
576
+ }
577
+
578
+ static void
579
+ set_log_mapping(fft_t* fft)
580
+ {
581
+ double pos;
582
+ double step;
583
+ int i;
584
+ int head;
585
+ int tail;
586
+ lc_t* lc;
587
+
588
+ pos = fft->capa * (fft->fq_l / fft->fq_s);
589
+ step = pow((fft->fq_h / fft->fq_l), (1.0 / fft->width));
590
+ head = (int)round(pos);
591
+ lc = (lc_t*)fft->line;
592
+
593
+ for (i = 0; i < fft->width; i++) {
594
+ pos *= step;
595
+ tail = (int)round(pos);
596
+
597
+ lc->pos = head;
598
+ lc->n = (tail == head)? 1: (tail - head);
599
+
600
+ head = tail;
601
+ lc++;
602
+ }
603
+ }
604
+
605
+ static void
606
+ set_line_mapping(fft_t* fft)
607
+ {
608
+ /*
609
+ * calc step
610
+ */
611
+ switch (fft->mode) {
612
+ case FFT_LINEARSCALE_MODE:
613
+ set_linear_mapping(fft);
614
+ break;
615
+
616
+ case FFT_LOGSCALE_MODE:
617
+ set_log_mapping(fft);
618
+ break;
619
+ }
620
+ }
621
+
622
+ int
623
+ fft_set_width(fft_t* fft, int width)
624
+ {
625
+ int ret;
626
+ lc_t* line;
627
+
628
+ /*
629
+ * initialize
630
+ */
631
+ ret = 0;
632
+ line = NULL;
633
+
634
+ /*
635
+ * argument check
636
+ */
637
+ if (fft == NULL) ret = ERR;
638
+ if (!ret) {
639
+ if (width > (fft->capa / 2)) ret = ERR;
640
+ }
641
+
642
+ /*
643
+ * alloc spectrum line buffer
644
+ */
645
+ if (!ret) {
646
+ line = NALLOC(lc_t, width);
647
+ if (line == NULL) ret = ERR;
648
+ }
649
+
650
+ /*
651
+ * modify FFT context
652
+ */
653
+ if (!ret) {
654
+ if (fft->line) free(fft->line);
655
+ fft->line = line;
656
+ fft->width = width;
657
+
658
+ set_line_mapping(fft);
659
+ }
660
+
661
+ return ret;
662
+ }
663
+
664
+ int
665
+ fft_set_scale_mode(fft_t* fft, int mode)
666
+ {
667
+ int ret;
668
+
669
+ do {
670
+ /*
671
+ * argument check
672
+ */
673
+ if (fft == NULL) {
674
+ ret = ERR;
675
+ break;
676
+ }
677
+
678
+ if (mode != FFT_LOGSCALE_MODE &&
679
+ mode != FFT_LINEARSCALE_MODE) {
680
+ ret = ERR;
681
+ break;
682
+ }
683
+
684
+ /*
685
+ * modify FFT context
686
+ */
687
+ fft->mode = mode;
688
+ set_line_mapping(fft);
689
+
690
+ /*
691
+ * mark success
692
+ */
693
+ ret = 0;
694
+ } while(0);
695
+
696
+ return ret;
697
+ }
698
+
699
+ int
700
+ fft_set_frequency(fft_t* fft, double s, double l, double h)
701
+ {
702
+ int ret;
703
+
704
+ do {
705
+ /*
706
+ * argument check
707
+ */
708
+ if (fft == NULL) {
709
+ ret = ERR;
710
+ break;
711
+ }
712
+
713
+ if (h > (s / 2.0)) {
714
+ ret = ERR;
715
+ break;
716
+ }
717
+
718
+ if (l > h) {
719
+ ret = ERR;
720
+ break;
721
+ }
722
+
723
+ /*
724
+ * modify FFT context
725
+ */
726
+ fft->fq_s = s;
727
+ fft->fq_h = h;
728
+ fft->fq_l = l;
729
+
730
+ set_line_mapping(fft);
731
+
732
+ /*
733
+ * mark success
734
+ */
735
+ ret = 0;
736
+ } while(0);
737
+
738
+ return ret;
739
+ }
740
+
741
+ int
742
+ fft_transform(fft_t* fft)
743
+ {
744
+ int ret;
745
+ int i;
746
+
747
+ /*
748
+ * initialize
749
+ */
750
+ ret = 0;
751
+
752
+ /*
753
+ * argument chack
754
+ */
755
+ if (fft == NULL) ret = ERR;
756
+
757
+ /*
758
+ * do transform
759
+ */
760
+ if (!ret) {
761
+ for (i = 0; i < fft->capa; i++) {
762
+ fft->a[i] = fft->data[i] * fft->wtbl[i];
763
+ }
764
+
765
+ rdft(fft->capa, 1, fft->a, fft->ip, fft->w);
766
+ }
767
+
768
+ return ret;
769
+ }
770
+
771
+ int
772
+ fft_calc_spectrum(fft_t* fft, double* dst)
773
+ {
774
+ int ret;
775
+ int i;
776
+ int j;
777
+ double* a;
778
+ double v;
779
+ lc_t* lc;
780
+
781
+ do {
782
+ /*
783
+ * argument check
784
+ */
785
+ if (fft == NULL) {
786
+ ret = ERR;
787
+ break;
788
+ }
789
+
790
+ if (dst == NULL) {
791
+ ret = ERR;
792
+ break;
793
+ }
794
+
795
+ /*
796
+ * calc power spectrum
797
+ */
798
+ for (i = 0, lc = (lc_t*)fft->line; i < fft->width; i++, lc++) {
799
+ v = 0;
800
+
801
+ for(j = 0, a = fft->a + (lc->pos * 2); j < lc->n; j++, a += 2) {
802
+ v += (10 * log10((a[0] * a[0]) + (a[1] * a[1])));
803
+ }
804
+
805
+ dst[i] = v / j;
806
+ }
807
+
808
+ /*
809
+ * mark success
810
+ */
811
+ ret = 0;
812
+ } while(0);
813
+
814
+ return ret;
815
+ }
816
+
817
+ /*
818
+ * 注意
819
+ * この関数はfft_calcs_spectrum()と異なり、dB値への変換を
820
+ * 行った結果を返します。
821
+ */
822
+ int
823
+ fft_calc_amplitude(fft_t* fft, double* dst)
824
+ {
825
+ int ret;
826
+ int i;
827
+ int j;
828
+ double* a;
829
+ double v;
830
+ double base;
831
+ lc_t* lc;
832
+
833
+ do {
834
+ /*
835
+ * argument check
836
+ */
837
+ if (fft == NULL) {
838
+ ret = ERR;
839
+ break;
840
+ }
841
+
842
+ if (dst == NULL) {
843
+ ret = ERR;
844
+ break;
845
+ }
846
+
847
+ /*
848
+ * calc power spectrum
849
+ */
850
+ base = (double)fft->used;
851
+
852
+ for (i = 0, lc = (lc_t*)fft->line; i < fft->width; i++, lc++) {
853
+ v = 0;
854
+
855
+ for(j = 0, a = fft->a + (lc->pos * 2); j < lc->n; j++, a += 2) {
856
+ v += 20.0 * log10(sqrt((a[0] * a[0]) + (a[1] * a[1])) / base);
857
+ }
858
+
859
+ dst[i] = v / j;
860
+ }
861
+
862
+ /*
863
+ * mark success
864
+ */
865
+ ret = 0;
866
+ } while(0);
867
+
868
+ return ret;
869
+ }
870
+
871
+ int
872
+ fft_calc_absolute(fft_t* fft, double* dst)
873
+ {
874
+ int ret;
875
+ int i;
876
+ int j;
877
+ double* a;
878
+ double v;
879
+ double base;
880
+ lc_t* lc;
881
+
882
+ do {
883
+ /*
884
+ * argument check
885
+ */
886
+ if (fft == NULL) {
887
+ ret = ERR;
888
+ break;
889
+ }
890
+
891
+ if (dst == NULL) {
892
+ ret = ERR;
893
+ break;
894
+ }
895
+
896
+ /*
897
+ * calc power spectrum
898
+ */
899
+ base = (double)fft->used;
900
+
901
+ for (i = 0, lc = (lc_t*)fft->line; i < fft->width; i++, lc++) {
902
+ v = 0;
903
+
904
+ for(j = 0, a = fft->a + (lc->pos * 2); j < lc->n; j++, a += 2) {
905
+ v += (sqrt((a[0] * a[0]) + (a[1] * a[1])) / base);
906
+ }
907
+
908
+ dst[i] = v / j;
909
+ }
910
+
911
+ /*
912
+ * mark success
913
+ */
914
+ ret = 0;
915
+ } while(0);
916
+
917
+ return ret;
918
+ }