Changeset 88042ef for src/synth


Ignore:
Timestamp:
Oct 4, 2016, 11:16:14 PM (8 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
sampler
Children:
0a756ea
Parents:
923670d
Message:

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

Location:
src/synth
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/synth/sampler.c

    r923670d r88042ef  
    2727#include "synth/sampler.h"
    2828
     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
    2938struct _aubio_sampler_t {
    3039  uint_t samplerate;
    3140  uint_t blocksize;
    3241  aubio_source_t *source;
    33   fvec_t *source_output;
    34   fmat_t *source_output_multi;
    35   char_t *uri;
     42  const char_t *uri;
    3643  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
    3758};
    3859
    39 aubio_sampler_t *new_aubio_sampler(uint_t samplerate, uint_t blocksize)
     60aubio_sampler_t *new_aubio_sampler(uint_t blocksize, uint_t samplerate)
    4061{
    4162  aubio_sampler_t *s = AUBIO_NEW(aubio_sampler_t);
     
    4667  s->samplerate = samplerate;
    4768  s->blocksize = blocksize;
    48   s->source_output = new_fvec(blocksize);
    49   s->source_output_multi = new_fmat(4, blocksize);
    5069  s->source = NULL;
    5170  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
    5283  return s;
    5384beach:
     
    5889uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri )
    5990{
    60   if (o->source) del_aubio_source(o->source);
    61 
    62   if (o->uri) AUBIO_FREE(o->uri);
    63   o->uri = AUBIO_ARRAY(char_t, strnlen(uri, PATH_MAX));
    64   strncpy(o->uri, uri, strnlen(uri, PATH_MAX));
    65 
    66   o->source = new_aubio_source(uri, o->samplerate, o->blocksize);
    67   if (o->source) return 0;
    68   AUBIO_ERR("sampler: failed loading %s", uri);
    69   return 1;
    70 }
    71 
    72 void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output)
    73 {
    74   uint_t read = 0, i;
     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
    75232  if (o->playing) {
    76     aubio_source_do (o->source, o->source_output, &read);
    77     for (i = 0; i < output->length; i++) {
    78       output->data[i] += o->source_output->data[i];
    79     }
    80     if (read < o->blocksize) o->playing = 0;
    81   }
    82   if (input && input != output) {
    83     for (i = 0; i < output->length; i++) {
    84       output->data[i] += input->data[i];
    85     }
    86   }
    87 }
    88 
    89 void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output)
    90 {
    91   uint_t read = 0, i, j;
     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;
    92301  if (o->playing) {
    93     aubio_source_do_multi (o->source, o->source_output_multi, &read);
    94     for (i = 0; i < output->height; i++) {
    95       for (j = 0; j < output->length; j++) {
    96         output->data[i][j] += o->source_output_multi->data[i][j];
     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)
    97308      }
    98309    }
    99     if ( read < o->blocksize ) o->playing = 0;
    100   }
    101   if (input && input != output) {
    102     for (i = 0; i < output->height; i++) {
    103       for (j = 0; j < output->length; j++) {
    104         output->data[i][j] += input->data[i][j];
    105       }
    106     }
     310  } else {
     311    fmat_zeros(output);
     312    *read = 0;
    107313  }
    108314}
     
    119325}
    120326
     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
    121338uint_t aubio_sampler_play ( aubio_sampler_t * o )
    122339{
    123   aubio_source_seek (o->source, 0);
     340  //aubio_source_seek (o->source, 0);
    124341  return aubio_sampler_set_playing (o, 1);
    125342}
     
    130347}
    131348
     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
    132363void del_aubio_sampler( aubio_sampler_t * o )
    133364{
     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
    134379  if (o->source) {
    135380    del_aubio_source(o->source);
    136381  }
    137   if (o->uri) AUBIO_FREE(o->uri);
    138   del_fvec(o->source_output);
    139   del_fmat(o->source_output_multi);
    140382  AUBIO_FREE(o);
    141383}
  • src/synth/sampler.h

    r923670d r88042ef  
    2424/** \file
    2525
    26   Load and play sound files.
     26  Load and play a sound file.
    2727
    2828  This file loads a sample and gets ready to play it.
     
    3030  The `_do` function adds the new samples to the input, and write the result as
    3131  the output.
     32
     33TODO:
     34  - add _preset_threaded(level)
     35  - add _set_stretch
     36  - add _set_pitch
    3237
    3338  \example synth/test-sampler.c
     
    5055
    5156*/
    52 aubio_sampler_t * new_aubio_sampler(uint_t samplerate, uint_t hop_size);
     57aubio_sampler_t * new_aubio_sampler(uint_t hop_size, uint_t samplerate);
    5358
    5459/** load source in sampler
     
    6267uint_t aubio_sampler_load( aubio_sampler_t * o, const char_t * uri );
    6368
     69/** queue source in sampler
     70
     71  \param o sampler, created by new_aubio_sampler()
     72  \param uri the uri of the source to load
     73
     74  \return 0 if successfully queued, non-zero otherwise
     75
     76*/
     77uint_t aubio_sampler_queue(aubio_sampler_t * o, const char_t * uri );
     78
    6479/** process sampler function
    6580
    6681  \param o sampler, created by new_aubio_sampler()
    67   \param input input of the sampler, to be added to the output
    6882  \param output output of the sampler
    6983
    70 This function adds the new samples from the playing source to the output.
    71 
    72 If `input` is not NULL and different from `output`, then the samples from `input`
    73 are added to the output.
    74 
    75 */
    76 void aubio_sampler_do ( aubio_sampler_t * o, const fvec_t * input, fvec_t * output);
     84This function get new samples from the playing source into output.
     85
     86*/
     87void aubio_sampler_do ( aubio_sampler_t * o, fvec_t * output, uint_t *read);
    7788
    7889/** process sampler function, multiple channels
    7990
    8091  \param o sampler, created by new_aubio_sampler()
    81   \param input input of the sampler, to be added to the output
    8292  \param output output of the sampler
    8393
    84 This function adds the new samples from the playing source to the output.
    85 
    86 If `input` is not NULL and different from `output`, then the samples from `input`
    87 are added to the output.
    88 
    89 */
    90 void aubio_sampler_do_multi ( aubio_sampler_t * o, const fmat_t * input, fmat_t * output);
     94This function gets new samples from the playing source into output.
     95
     96*/
     97void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * output, uint_t *read);
    9198
    9299/** get current playing state
     
    109116uint_t aubio_sampler_set_playing ( aubio_sampler_t * o, uint_t playing );
    110117
     118uint_t aubio_sampler_get_loop(aubio_sampler_t * o);
     119
     120/** set current looping state
     121
     122  \param o sampler, created by new_aubio_sampler()
     123  \param looping 0 for not looping, 1 for looping
     124
     125  \return 0 if successful, 1 otherwise
     126
     127*/
     128uint_t aubio_sampler_set_loop(aubio_sampler_t * o, uint_t loop);
     129
    111130/** play sample from start
    112131
     
    118137uint_t aubio_sampler_play ( aubio_sampler_t * o );
    119138
     139/** play sample from start, looping it
     140
     141  \param o sampler, created by new_aubio_sampler()
     142
     143  \return 0 if successful, 1 otherwise
     144
     145*/
     146uint_t aubio_sampler_loop ( aubio_sampler_t * o );
     147
     148/** play sample from start, once
     149
     150  \param o sampler, created by new_aubio_sampler()
     151
     152  \return 0 if successful, 1 otherwise
     153
     154*/
     155uint_t aubio_sampler_trigger ( aubio_sampler_t * o );
     156
    120157/** stop sample
    121158
     
    126163*/
    127164uint_t aubio_sampler_stop ( aubio_sampler_t * o );
     165
     166/** get end-of-file status
     167
     168  \param o sampler, created by new_aubio_sampler()
     169
     170  \return 1 when the eof is being reached, 0 otherwise
     171
     172*/
     173uint_t aubio_sampler_get_eof(aubio_sampler_t * o);
     174
     175/** get end-of-file status
     176
     177  \param o sampler, created by new_aubio_sampler()
     178
     179  \return 1 when the eof is being reached, 0 otherwise
     180
     181*/
     182uint_t aubio_sampler_get_finished (aubio_sampler_t * o);
     183
     184/** get samplerate
     185
     186  \param o sampler, created by new_aubio_sampler()
     187
     188  \return samplerate of the sampler
     189
     190*/
     191uint_t aubio_sampler_get_samplerate(aubio_sampler_t * o);
     192
     193/** get the number of samples that were set to zero while opening a file
     194
     195  \param o sampler, created by new_aubio_sampler()
     196
     197  \return samplerate of the sampler
     198
     199*/
     200uint_t aubio_sampler_get_waited_opening(aubio_sampler_t * o, uint_t waited);
     201
     202/** seek to position
     203
     204  \param o sampler, created by new_aubio_sampler()
     205  \param pos position to seek to, in samples
     206
     207  \return 0 if successful, 1 otherwise
     208
     209*/
     210uint_t aubio_sampler_seek(aubio_sampler_t * o, uint_t pos);
    128211
    129212/** destroy ::aubio_sampler_t object
Note: See TracChangeset for help on using the changeset viewer.