source: src/synth/sampler.c @ 0a756ea

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

src/synth/sampler.{c,h}: prepare reading thread, reset waited in _queue, only join open thread if still open, improve documentation

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