source: src/synth/sampler.c @ 88042ef

sampler
Last change on this file since 88042ef was 88042ef, checked in by Paul Brossier <piem@piem.org>, 8 years ago

src/synth/sampler.c: refactor interface, add file opening thread and utility functions

  • Property mode set to 100644
File size: 8.9 KB
Line 
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/sampler.h"
28
29#define HAVE_THREADS 1
30#if 0
31#undef HAVE_THREADS
32#endif
33
34#ifdef HAVE_THREADS
35#include <pthread.h>
36#endif
37
38struct _aubio_sampler_t {
39  uint_t samplerate;
40  uint_t blocksize;
41  aubio_source_t *source;
42  const char_t *uri;
43  uint_t playing;
44  uint_t opened;
45  uint_t loop;
46  uint_t finished;
47  uint_t eof;
48#ifdef HAVE_THREADS
49  pthread_t open_thread;        // file opening thread
50  pthread_mutex_t open_mutex;
51  uint_t waited;                // number of frames skipped while opening
52  const char_t *next_uri;
53  uint_t open_thread_running;
54  sint_t available;             // number of samples currently available
55  uint_t started;               // source warmed up
56  uint_t finish;                // flag to tell reading thread to exit
57#endif
58};
59
60aubio_sampler_t *new_aubio_sampler(uint_t blocksize, uint_t samplerate)
61{
62  aubio_sampler_t *s = AUBIO_NEW(aubio_sampler_t);
63  if ((sint_t)blocksize < 1) {
64    AUBIO_ERR("sampler: got blocksize %d, but can not be < 1\n", blocksize);
65    goto beach;
66  }
67  s->samplerate = samplerate;
68  s->blocksize = blocksize;
69  s->source = NULL;
70  s->playing = 0;
71  s->loop = 0;
72  s->uri = NULL;
73  s->finished = 1;
74  s->eof = 0;
75  s->opened = 0;
76
77#ifdef HAVE_THREADS
78  pthread_mutex_init(&s->open_mutex, 0);
79  s->waited = 0;
80  s->open_thread = 0;
81  s->open_thread_running = 0;
82#endif
83  return s;
84beach:
85  AUBIO_FREE(s);
86  return NULL;
87}
88
89uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri )
90{
91  uint_t ret = AUBIO_FAIL;
92  aubio_source_t *oldsource = o->source, *newsource = NULL;
93  newsource = new_aubio_source(uri, o->samplerate, o->blocksize);
94  if (newsource) {
95    o->source = newsource;
96    if (oldsource) del_aubio_source(oldsource);
97    if (o->samplerate == 0) {
98      o->samplerate = aubio_source_get_samplerate(o->source);
99    }
100    o->uri = uri;
101    o->finished = 0;
102    o->eof = 0;
103    o->opened = 1;
104    ret = AUBIO_OK;
105    //AUBIO_WRN("sampler: loaded %s\n", o->uri);
106  } else {
107    o->source = NULL;
108    if (oldsource) del_aubio_source(oldsource);
109    o->playing = 0;
110    o->uri = NULL;
111    o->finished = 1;
112    o->eof = 0;
113    o->opened = 0;
114    AUBIO_WRN("sampler: failed loading %s\n", uri);
115  }
116  return ret;
117}
118
119#ifdef HAVE_THREADS
120static void *aubio_sampler_openfn(void *z) {
121  aubio_sampler_t *p = z;
122  uint_t err;
123  int oldtype;
124  void *ret;
125  pthread_setcancelstate(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
126  pthread_mutex_lock(&p->open_mutex);
127  p->open_thread_running = 1;
128  err = aubio_sampler_load(p, p->next_uri);
129  p->open_thread_running = 0;
130  pthread_mutex_unlock(&p->open_mutex);
131  ret = &err;
132  pthread_exit(ret);
133}
134#endif
135
136uint_t
137aubio_sampler_queue(aubio_sampler_t *o, const char_t *uri)
138{
139#ifdef HAVE_THREADS
140  uint_t ret = AUBIO_OK;
141  /* open uri in open_thread */
142  if (o->open_thread_running) {
143    // cancel previous open_thread
144    if (pthread_cancel(o->open_thread)) {
145      AUBIO_WRN("sampler: cancelling open thread failed\n");
146      return AUBIO_FAIL;
147    } else {
148      AUBIO_WRN("sampler: previous open of %s cancelled while opening %s\n",
149          o->next_uri, uri);
150    }
151    o->open_thread_running = 0;
152  }
153  void *threadret;
154  if (o->open_thread && pthread_join(o->open_thread, &threadret)) {
155    AUBIO_WRN("sampler: joining thread failed\n");
156  }
157  if (pthread_mutex_trylock(&o->open_mutex)) {
158    AUBIO_WRN("sampler: failed locking in queue\n");
159    ret = AUBIO_FAIL;
160    goto lock_failed;
161  }
162  o->opened = 0; // while opening
163  o->started = 0;
164  o->available = 0;
165  o->next_uri = uri;
166  if (pthread_create(&o->open_thread, 0, aubio_sampler_openfn, o) != 0) {
167    AUBIO_ERR("sampler: failed creating opening thread\n");
168    ret = AUBIO_FAIL;
169    goto thread_create_failed;
170  }
171
172thread_create_failed:
173  pthread_mutex_unlock(&o->open_mutex);
174lock_failed:
175  if (ret == AUBIO_OK) {
176    //AUBIO_WRN("sampler: queued %s\n", uri);
177  } else {
178    AUBIO_ERR("sampler: queueing %s failed\n", uri);
179  }
180  return ret;
181#else
182  AUBIO_WRN("sampler: opening %s, not queueing (not compiled with threading)\n", uri);
183  return aubio_sampler_load(o, uri);
184#endif
185}
186
187void
188aubio_sampler_fetch_from_source(aubio_sampler_t *o, fvec_t *output, uint_t *read) {
189  if (o->opened == 1 && o->source && !o->finished)
190    aubio_source_do(o->source, output, read);
191}
192
193void
194aubio_sampler_fetch_from_source_multi(aubio_sampler_t *o, fmat_t *output, uint_t *read) {
195  aubio_source_do_multi(o->source, output, read);
196}
197
198#if 0
199void
200aubio_sampler_fetch_from_array(aubio_sampler_t *o, fvec_t *output, uint_t *read) {
201  // TODO
202}
203#endif
204
205uint_t
206aubio_sampler_get_samplerate (aubio_sampler_t *o)
207{
208  return o->samplerate;
209}
210
211uint_t
212aubio_sampler_get_opened (aubio_sampler_t *o)
213{
214  return o->opened; //== 1 ? AUBIO_OK : AUBIO_FAIL;
215}
216
217uint_t
218aubio_sampler_get_finished(aubio_sampler_t *o)
219{
220  return o->finished;
221}
222
223uint_t
224aubio_sampler_get_eof (aubio_sampler_t *o)
225{
226  return o->eof;
227}
228
229uint_t
230aubio_sampler_get_waited_opening (aubio_sampler_t *o, uint_t waited) {
231#ifdef HAVE_THREADS
232  if (o->playing) {
233    if (!o->opened) {
234      o->waited += waited;
235    } else if (o->waited) {
236      //AUBIO_WRN("sampler: waited %d frames (%.2fms) while opening %s\n",
237      //    o->waited, 1000.*o->waited/(smpl_t)o->samplerate, o->uri);
238      uint_t waited = o->waited;
239      o->waited = 0;
240      return waited;
241    }
242  }
243#endif
244  return 0;
245}
246
247uint_t
248aubio_sampler_seek(aubio_sampler_t * o, uint_t pos)
249{
250  uint_t ret = AUBIO_FAIL;
251  o->finished = 0;
252  if (!o->opened) return AUBIO_OK;
253#ifdef HAVE_THREADS
254  if (pthread_mutex_trylock(&o->open_mutex)) {
255    AUBIO_WRN("sampler: failed locking in seek\n");
256    return ret;
257  }
258#endif
259  if (o->source) {
260    ret = aubio_source_seek(o->source, pos);
261  }
262#ifdef HAVE_THREADS
263  pthread_mutex_unlock(&o->open_mutex);
264#endif
265  return ret;
266}
267
268void
269aubio_sampler_do_eof (aubio_sampler_t * o)
270{
271  o->finished = 1;
272  o->eof = 1;
273  if (!o->loop) {
274    o->playing = 0;
275  } else {
276    aubio_sampler_seek(o, 0);
277  }
278}
279
280void aubio_sampler_do ( aubio_sampler_t * o, fvec_t * output, uint_t *read)
281{
282  o->eof = 0;
283  if (o->opened == 1 && o->playing) {
284    aubio_sampler_fetch_from_source(o, output, read);
285    if (*read < o->blocksize) {
286      aubio_sampler_do_eof (o);
287      if (*read > 0) {
288        // TODO pull (hopsize - read) frames
289        //memset(...  tail , 0)
290      }
291    }
292  } else {
293    fvec_zeros(output);
294    *read = 0; //output->length;
295  }
296}
297
298void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * output, uint_t *read)
299{
300  o->eof = 0;
301  if (o->playing) {
302    aubio_sampler_fetch_from_source_multi(o, output, read);
303    if (*read < o->blocksize) {
304      aubio_sampler_do_eof (o);
305      if (*read > 0) {
306        // TODO pull (hopsize - read) frames
307        //memset(...  tail , 0)
308      }
309    }
310  } else {
311    fmat_zeros(output);
312    *read = 0;
313  }
314}
315
316uint_t aubio_sampler_get_playing ( const aubio_sampler_t * o )
317{
318  return o->playing;
319}
320
321uint_t aubio_sampler_set_playing ( aubio_sampler_t * o, uint_t playing )
322{
323  o->playing = (playing == 1) ? 1 : 0;
324  return 0;
325}
326
327uint_t aubio_sampler_get_loop ( aubio_sampler_t * o )
328{
329  return o->loop;
330}
331
332uint_t aubio_sampler_set_loop ( aubio_sampler_t * o, uint_t loop )
333{
334  o->loop = (loop == 1) ? 1 : 0;
335  return 0;
336}
337
338uint_t aubio_sampler_play ( aubio_sampler_t * o )
339{
340  //aubio_source_seek (o->source, 0);
341  return aubio_sampler_set_playing (o, 1);
342}
343
344uint_t aubio_sampler_stop ( aubio_sampler_t * o )
345{
346  return aubio_sampler_set_playing (o, 0);
347}
348
349uint_t aubio_sampler_loop ( aubio_sampler_t * o )
350{
351  aubio_sampler_set_loop(o, 1);
352  aubio_sampler_seek(o, 0);
353  return aubio_sampler_set_playing (o, 1);
354}
355
356uint_t aubio_sampler_trigger ( aubio_sampler_t * o )
357{
358  aubio_sampler_set_loop(o, 0);
359  aubio_sampler_seek(o, 0);
360  return aubio_sampler_set_playing (o, 1);
361}
362
363void del_aubio_sampler( aubio_sampler_t * o )
364{
365#ifdef HAVE_THREADS
366  AUBIO_WRN("sampler: cleaning up\n");
367  pthread_mutex_destroy(&o->open_mutex);
368  if (o->open_thread_running) {
369    if (pthread_cancel(o->open_thread)) {
370      AUBIO_WRN("sampler: cancelling open thread failed\n");
371    }
372  }
373  void *threadret;
374  if (pthread_join(o->open_thread, &threadret)) {
375    AUBIO_WRN("sampler: joining open thread failed\n");
376  }
377  pthread_mutex_destroy(&o->open_mutex);
378#endif
379  if (o->source) {
380    del_aubio_source(o->source);
381  }
382  AUBIO_FREE(o);
383}
Note: See TracBrowser for help on using the repository browser.