added first version of wavetable
[aubio.git] / src / synth / wavetable.c
1 /*
2   Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
3
4   This file is part of aubio.
5
6   aubio is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   aubio is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "config.h"
23 #include "aubio_priv.h"
24 #include "fvec.h"
25 #include "fmat.h"
26 #include "io/source.h"
27 #include "synth/wavetable.h"
28
29 #define WAVETABLE_LEN 4096
30
31 struct _aubio_wavetable_t {
32   uint_t samplerate;
33   uint_t blocksize;
34   uint_t wavetable_length;
35   fvec_t *wavetable;
36   uint_t playing;
37   smpl_t last_pos;
38
39   smpl_t target_freq;
40   smpl_t freq;
41   smpl_t inc_freq;
42
43   smpl_t target_amp;
44   smpl_t amp;
45   smpl_t inc_amp;
46 };
47
48 aubio_wavetable_t *new_aubio_wavetable(uint_t samplerate, uint_t blocksize)
49 {
50   aubio_wavetable_t *s = AUBIO_NEW(aubio_wavetable_t);
51   uint_t i = 0;
52   s->samplerate = samplerate;
53   s->blocksize = blocksize;
54   s->wavetable_length = WAVETABLE_LEN;
55   s->wavetable = new_fvec(s->wavetable_length + 3);
56   for (i = 0; i < s->wavetable_length; i++) {
57     s->wavetable->data[i] = SIN(TWO_PI * i / (smpl_t) s->wavetable_length );
58   }
59   s->wavetable->data[s->wavetable_length] = s->wavetable->data[0];
60   s->wavetable->data[s->wavetable_length + 1] = s->wavetable->data[1];
61   s->wavetable->data[s->wavetable_length + 2] = s->wavetable->data[2];
62   s->playing = 0;
63   s->last_pos = 0.;
64   s->freq = 0.;
65   s->target_freq = 0.;
66   s->inc_freq = 0.;
67
68   s->amp = 0.;
69   s->target_amp = 0.;
70   s->inc_amp = 0.;
71   return s;
72 }
73
74 static smpl_t interp_2(fvec_t *input, smpl_t pos) {
75   uint_t idx = (uint_t)FLOOR(pos);
76   smpl_t frac = pos - (smpl_t)idx;
77   smpl_t a = input->data[idx];
78   smpl_t b = input->data[idx + 1];
79   return a + frac * ( b - a );
80 }
81
82 void aubio_wavetable_do ( aubio_wavetable_t * s, fvec_t * input, fvec_t * output)
83 {
84   uint_t i;
85   if (s->playing) {
86     smpl_t pos = s->last_pos;
87     for (i = 0; i < output->length; i++) {
88       if (s->freq != s->target_freq)
89         s->freq += s->inc_freq;
90       smpl_t inc = s->freq * (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
91       pos += inc;
92       while (pos > s->wavetable_length) {
93         pos -= s->wavetable_length;
94       }
95       if ( ABS(s->amp - s->target_amp) > ABS(s->inc_amp) )
96         s->amp += s->inc_amp;
97       else
98         s->amp = s->target_amp;
99       output->data[i] = s->amp * interp_2(s->wavetable, pos);
100     }
101     s->last_pos = pos;
102   } else {
103     fvec_set(output, 0.);
104   }
105   // add input to output if needed
106   if (input && input != output) {
107     for (i = 0; i < output->length; i++) {
108       output->data[i] += input->data[i];
109     }
110   }
111 }
112
113 void aubio_wavetable_do_multi ( aubio_wavetable_t * s, fmat_t * input, fmat_t * output)
114 {
115   uint_t i, j;
116   if (s->playing) {
117     smpl_t pos = s->last_pos;
118     for (j = 0; j < output->length; j++) {
119       if (s->freq != s->target_freq)
120         s->freq += s->inc_freq;
121       smpl_t inc = s->freq * (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
122       pos += inc;
123       while (pos > s->wavetable_length) {
124         pos -= s->wavetable_length;
125       }
126       for (i = 0; i < output->height; i++) {
127         output->data[i][j] = interp_2(s->wavetable, pos);
128       }
129     }
130     s->last_pos = pos;
131   } else {
132     for (j = 0; j < output->length; j++) {
133       if (s->freq != s->target_freq)
134         s->freq += s->inc_freq;
135     }
136     fmat_set(output, 0.);
137   }
138   // add output to input if needed
139   if (input && input != output) {
140     for (i = 0; i < output->height; i++) {
141       for (j = 0; j < output->length; j++) {
142         output->data[i][j] += input->data[i][j];
143       }
144     }
145   }
146 }
147
148 uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * s )
149 {
150   return s->playing;
151 }
152
153 uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * s, uint_t playing )
154 {
155   s->playing = (playing == 1) ? 1 : 0;
156   return 0;
157 }
158
159 uint_t aubio_wavetable_play ( aubio_wavetable_t * s )
160 {
161   aubio_wavetable_set_amp (s, 0.7);
162   return aubio_wavetable_set_playing (s, 1);
163 }
164
165 uint_t aubio_wavetable_stop ( aubio_wavetable_t * s )
166 {
167   //aubio_wavetable_set_freq (s, 0.);
168   aubio_wavetable_set_amp (s, 0.);
169   //s->last_pos = 0;
170   return aubio_wavetable_set_playing (s, 1);
171 }
172
173 uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
174 {
175   if (freq >= 0 && freq < s->samplerate / 2.) {
176     uint_t steps = 10;
177     s->inc_freq = (freq - s->freq) / steps; 
178     s->target_freq = freq;
179     return 0;
180   } else {
181     return 1;
182   }
183 }
184
185 smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * s) {
186   return s->freq;
187 }
188
189 uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * s, smpl_t amp )
190 {
191   AUBIO_MSG("amp: %f, s->amp: %f, target_amp: %f, inc_amp: %f\n",
192       amp, s->amp, s->target_amp, s->inc_amp);
193   if (amp >= 0. && amp < 1.) {
194     uint_t steps = 100;
195     s->inc_amp = (amp - s->amp) / steps; 
196     s->target_amp = amp;
197     AUBIO_ERR("amp: %f, s->amp: %f, target_amp: %f, inc_amp: %f\n",
198         amp, s->amp, s->target_amp, s->inc_amp);
199     return 0;
200   } else {
201     return 1;
202   }
203 }
204
205 smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * s) {
206   return s->amp;
207 }
208
209 void del_aubio_wavetable( aubio_wavetable_t * s )
210 {
211   del_fvec(s->wavetable);
212   AUBIO_FREE(s);
213 }