src/synth/wavetable.c: make sure samplerate is valid
[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 "utils/parameter.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   aubio_parameter_t *freq;
40   aubio_parameter_t *amp;
41 };
42
43 aubio_wavetable_t *new_aubio_wavetable(uint_t samplerate, uint_t blocksize)
44 {
45   aubio_wavetable_t *s = AUBIO_NEW(aubio_wavetable_t);
46   if ((sint_t)samplerate <= 0) {
47     AUBIO_ERR("Can not create wavetable with samplerate %d\n", samplerate);
48     goto beach;
49   }
50   uint_t i = 0;
51   s->samplerate = samplerate;
52   s->blocksize = blocksize;
53   s->wavetable_length = WAVETABLE_LEN;
54   s->wavetable = new_fvec(s->wavetable_length + 3);
55   for (i = 0; i < s->wavetable_length; i++) {
56     s->wavetable->data[i] = SIN(TWO_PI * i / (smpl_t) s->wavetable_length );
57   }
58   s->wavetable->data[s->wavetable_length] = s->wavetable->data[0];
59   s->wavetable->data[s->wavetable_length + 1] = s->wavetable->data[1];
60   s->wavetable->data[s->wavetable_length + 2] = s->wavetable->data[2];
61   s->playing = 0;
62   s->last_pos = 0.;
63   s->freq = new_aubio_parameter( 0., s->samplerate / 2., 10 );
64   s->amp = new_aubio_parameter( 0., 1., 100 );
65   return s;
66 beach:
67   AUBIO_FREE(s);
68   return NULL;
69 }
70
71 static smpl_t interp_2(fvec_t *input, smpl_t pos) {
72   uint_t idx = (uint_t)FLOOR(pos);
73   smpl_t frac = pos - (smpl_t)idx;
74   smpl_t a = input->data[idx];
75   smpl_t b = input->data[idx + 1];
76   return a + frac * ( b - a );
77 }
78
79 void aubio_wavetable_do ( aubio_wavetable_t * s, fvec_t * input, fvec_t * output)
80 {
81   uint_t i;
82   if (s->playing) {
83     smpl_t pos = s->last_pos;
84     for (i = 0; i < output->length; i++) {
85       smpl_t inc = aubio_parameter_get_next_value( s->freq );
86       inc *= (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
87       pos += inc;
88       while (pos > s->wavetable_length) {
89         pos -= s->wavetable_length;
90       }
91       output->data[i] = aubio_parameter_get_next_value ( s->amp );
92       output->data[i] *= interp_2(s->wavetable, pos);
93     }
94     s->last_pos = pos;
95   } else {
96     for (i = 0; i < output->length; i++) {
97       aubio_parameter_get_next_value ( s->freq );
98       aubio_parameter_get_next_value ( s->amp );
99     }
100     fvec_set(output, 0.);
101   }
102   // add input to output if needed
103   if (input && input != output) {
104     for (i = 0; i < output->length; i++) {
105       output->data[i] += input->data[i];
106     }
107   }
108 }
109
110 void aubio_wavetable_do_multi ( aubio_wavetable_t * s, fmat_t * input, fmat_t * output)
111 {
112   uint_t i, j;
113   if (s->playing) {
114     smpl_t pos = s->last_pos;
115     for (j = 0; j < output->length; j++) {
116       smpl_t inc = aubio_parameter_get_next_value( s->freq );
117       inc *= (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
118       pos += inc;
119       while (pos > s->wavetable_length) {
120         pos -= s->wavetable_length;
121       }
122       smpl_t amp = aubio_parameter_get_next_value ( s->amp );
123       for (i = 0; i < output->height; i++) {
124         output->data[i][j] = amp * interp_2(s->wavetable, pos);
125       }
126     }
127     s->last_pos = pos;
128   } else {
129     for (j = 0; j < output->length; j++) {
130       aubio_parameter_get_next_value ( s->freq );
131       aubio_parameter_get_next_value ( s->amp );
132     }
133     fmat_set(output, 0.);
134   }
135   // add output to input if needed
136   if (input && input != output) {
137     for (i = 0; i < output->height; i++) {
138       for (j = 0; j < output->length; j++) {
139         output->data[i][j] += input->data[i][j];
140       }
141     }
142   }
143 }
144
145 uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * s )
146 {
147   return s->playing;
148 }
149
150 uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * s, uint_t playing )
151 {
152   s->playing = (playing == 1) ? 1 : 0;
153   return 0;
154 }
155
156 uint_t aubio_wavetable_play ( aubio_wavetable_t * s )
157 {
158   aubio_wavetable_set_amp (s, 0.7);
159   return aubio_wavetable_set_playing (s, 1);
160 }
161
162 uint_t aubio_wavetable_stop ( aubio_wavetable_t * s )
163 {
164   //aubio_wavetable_set_freq (s, 0.);
165   aubio_wavetable_set_amp (s, 0.);
166   //s->last_pos = 0;
167   return aubio_wavetable_set_playing (s, 1);
168 }
169
170 uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
171 {
172   return aubio_parameter_set_target_value ( s->freq, freq );
173 }
174
175 smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * s) {
176   return aubio_parameter_get_current_value ( s->freq);
177 }
178
179 uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * s, smpl_t amp )
180 {
181   return aubio_parameter_set_target_value ( s->amp, amp );
182 }
183
184 smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * s) {
185   return aubio_parameter_get_current_value ( s->amp );
186 }
187
188 void del_aubio_wavetable( aubio_wavetable_t * s )
189 {
190   del_aubio_parameter(s->freq);
191   del_aubio_parameter(s->amp);
192   del_fvec(s->wavetable);
193   AUBIO_FREE(s);
194 }