Minor tidy-ups to MTDM code; add test.
[ardour.git] / libs / ardour / mtdm.cc
1 /*
2     Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <math.h>
20
21 #include "ardour/mtdm.h"
22
23 MTDM::MTDM ()
24         : _cnt (0)
25         , _inv (0)
26 {
27         int   i;
28         Freq  *F;
29
30         _freq [0].f = 4096;
31         _freq [1].f =  512;
32         _freq [2].f = 1088;
33         _freq [3].f = 1544;
34         _freq [4].f = 2049;
35
36         _freq [0].a = 0.2f;
37         _freq [1].a = 0.1f;
38         _freq [2].a = 0.1f;
39         _freq [3].a = 0.1f;
40         _freq [4].a = 0.1f;
41
42         for (i = 0, F = _freq; i < 5; i++, F++) {
43                 F->p = 128;
44                 F->xa = F->ya = 0.0f;
45                 F->xf = F->yf = 0.0f;
46         }
47 }
48
49 int
50 MTDM::process (size_t len, float *ip, float *op)
51 {
52         int    i;
53         float  vip, vop, a, c, s;
54         Freq   *F;
55
56         while (len--)
57         {
58                 vop = 0.0f;
59                 vip = *ip++;
60                 for (i = 0, F = _freq; i < 5; i++, F++)
61                 {
62                         a = 2 * (float) M_PI * (F->p & 65535) / 65536.0;
63                         F->p += F->f;
64                         c =  cosf (a);
65                         s = -sinf (a);
66                         vop += F->a * s;
67                         F->xa += s * vip;
68                         F->ya += c * vip;
69                 }
70                 *op++ = vop;
71                 if (++_cnt == 16)
72                 {
73                         for (i = 0, F = _freq; i < 5; i++, F++)
74                         {
75                                 F->xf += 1e-3f * (F->xa - F->xf + 1e-20);
76                                 F->yf += 1e-3f * (F->ya - F->yf + 1e-20);
77                                 F->xa = F->ya = 0.0f;
78                         }
79                         _cnt = 0;
80                 }
81         }
82
83         return 0;
84 }
85
86 int
87 MTDM::resolve ()
88 {
89         int     i, k, m;
90         double  d, e, f0, p;
91         Freq    *F = _freq;
92
93         if (hypot (F->xf, F->yf) < 0.01) {
94                 return -1;
95         }
96
97         d = atan2 (F->yf, F->xf) / (2 * M_PI);
98
99         if (_inv) {
100                 d += 0.5f;
101         }
102
103         if (d > 0.5f) {
104                 d -= 1.0f;
105         }
106
107         f0 = _freq [0].f;
108         m = 1;
109         _err = 0.0;
110
111         for (i = 0; i < 4; i++) {
112                 F++;
113                 p = atan2 (F->yf, F->xf) / (2 * M_PI) - d * F->f / f0;
114                 if (_inv) {
115                         p += 0.5f;
116                 }
117                 p -= floor (p);
118                 p *= 8;
119                 k = (int)(floor (p + 0.5));
120                 e = fabs (p - k);
121                 if (e > _err) {
122                         _err = e;
123                 }
124                 if (e > 0.4) {
125                         return 1;
126                 }
127                 d += m * (k & 7);
128                 m *= 8;
129         }
130
131         _del = 16 * d;
132
133         return 0;
134 }