Ignore:
Timestamp:
Oct 8, 2016, 7:59:41 PM (8 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
sampler
Children:
fefbbd8
Parents:
1b86a8b
Message:

src/synth/sampler.c: huge change adding a ringbuffer mode and preparing for the next steps

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/synth/sampler.c

    r1b86a8b r88a774c  
    1919*/
    2020
     21#include <assert.h>
    2122
    2223#include "config.h"
     
    2526#include "fmat.h"
    2627#include "io/source.h"
     28#include "utils/ringbuffer.h"
    2729#include "synth/sampler.h"
    2830
    2931#define HAVE_THREADS 1
    30 #define READER_THREAD_ON 0
     32#define READER_THREAD_ON 1
    3133#if 0
    3234#undef HAVE_THREADS
     
    3638#include <pthread.h>
    3739#endif
     40
     41typedef enum {
     42  aubio_sampler_reading_from_source,
     43  aubio_sampler_reading_from_table,
     44  aubio_sampler_n_reading_methods
     45} aubio_sampler_reading_method;
     46
     47
     48int check_wrote = 0;
     49
     50typedef enum {
     51  aubio_sampler_interp_pitchtime,
     52  aubio_sampler_interp_quad,
     53  aubio_sampler_interp_lin,
     54  aubio_sampler_n_interp_methods
     55} aubio_sampler_interp_method;
    3856
    3957struct _aubio_sampler_t {
    4058  uint_t samplerate;
    4159  uint_t blocksize;
     60  // current reading mode (can be a file or an array)
     61  uint_t reading_from;
     62  // current interpolation mode (can be quadratic, timestretch, ...)
     63  uint_t interp;
     64  // reading from a table
     65  aubio_ringbuffer_t *ring;
     66  uint_t perfectloop;
     67  fvec_t *samples;
     68  fmat_t *msamples;
     69  // reading from a source
    4270  aubio_source_t *source;
    4371  const char_t *uri;
     
    5482  pthread_cond_t read_avail;
    5583  pthread_cond_t read_request;
    56   pthread_t open_thread;        // file opening thread
     84  uint_t source_blocksize;
     85  fvec_t *source_output;
     86  fmat_t *source_moutput;
     87  uint_t channels;
     88  // file opening thread
     89  pthread_t open_thread;
    5790  pthread_mutex_t open_mutex;
    5891  uint_t waited;                // number of frames skipped while opening
     
    6497#endif
    6598};
     99
     100static sint_t aubio_sampler_pull_from_source(aubio_sampler_t *s);
     101
     102static void aubio_sampler_do_eof(aubio_sampler_t *s);
     103
     104static void aubio_sampler_read(aubio_sampler_t *s, fvec_t *output, uint_t *read);
     105static void aubio_sampler_read_from_source(aubio_sampler_t *s, fvec_t *output, uint_t *read);
     106static void aubio_sampler_read_from_table(aubio_sampler_t *s, fvec_t *output, uint_t *read);
    66107
    67108#ifdef HAVE_THREADS
     
    92133  s->available = 0;
    93134
    94 #ifdef HAVE_THREADS
    95   s->threaded_read = READER_THREAD_ON;
     135#if 0 // naive mode
     136  s->source_blocksize = s->blocksize;
     137  s->perfectloop = 0;
     138#elif 0 // threaded mode
     139  s->source_blocksize = s->blocksize;
     140  // FIXME: perfectloop fails if source_blocksize > 2048 ?!
     141  //s->source_blocksize = 4096; //32 * s->blocksize;
     142  s->perfectloop = 0;
     143  s->threaded_read = 0;
     144#elif 1 // unthreaded ringbuffer mode
     145  s->source_blocksize = 2048; //32 * s->blocksize;
     146  // FIXME: perfectloop fails if source_blocksize > 2048 ?!
     147  //s->source_blocksize = 4096; //32 * s->blocksize;
     148  s->perfectloop = 1;
     149#endif
     150
     151  if (s->perfectloop || s->source_blocksize != s->blocksize) {
     152    s->source_output = new_fvec(s->source_blocksize);
     153    s->ring = new_aubio_ringbuffer(s->source_blocksize, s->blocksize);
     154  }
     155
     156#ifdef HAVE_THREADS
    96157  aubio_sampler_open_opening_thread(s);
     158
    97159  if (s->threaded_read) {
     160    s->source_blocksize = s->blocksize;
     161    //s->source_output = new_fvec(s->source_blocksize);
     162    s->channels = 1;
     163    s->source_moutput = new_fmat(s->source_blocksize, s->channels);
    98164    aubio_sampler_open_reading_thread(s);
     165  } else if (0) {
     166    s->source_blocksize = s->blocksize;
     167  } else {
     168    //s->source_blocksize = 16*s->blocksize;
     169    //s->source_blocksize = 8192; //s->blocksize;
     170    //s->ring = new_aubio_ringbuffer(s->source_blocksize, s->source_blocksize);
    99171  }
    100172#endif
     
    159231  uint_t ret = AUBIO_FAIL;
    160232  aubio_source_t *oldsource = o->source, *newsource = NULL;
    161   newsource = new_aubio_source(uri, o->samplerate, o->blocksize);
     233  newsource = new_aubio_source(uri, o->samplerate, o->source_blocksize);
    162234  if (newsource) {
    163235    o->source = newsource;
     
    171243    o->opened = 1;
    172244    ret = AUBIO_OK;
    173     //AUBIO_WRN("sampler: loaded %s\n", o->uri);
     245    AUBIO_MSG("sampler: loaded %s\n", uri);
     246    if (o->waited) {
     247      AUBIO_WRN("sampler: loading took %.2fms (%d samples)\n", 1000. *
     248          o->waited / (smpl_t)o->samplerate, o->waited);
     249    }
    174250  } else {
    175251    o->source = NULL;
     
    181257    o->opened = 0;
    182258    AUBIO_WRN("sampler: failed loading %s\n", uri);
     259  }
     260  if (o->ring) {
     261    AUBIO_WRN("sampler: resetting ringbuffer\n");
     262    aubio_ringbuffer_reset(o->ring);
    183263  }
    184264  return ret;
     
    211291    // cancel previous open_thread
    212292    if (pthread_cancel(o->open_thread)) {
    213       AUBIO_WRN("sampler: cancelling open thread failed\n");
     293      AUBIO_WRN("sampler: failed queuing %s (cancelling existing open thread failed)\n", uri);
    214294      return AUBIO_FAIL;
    215295    } else {
    216       AUBIO_WRN("sampler: previous open of %s cancelled while opening %s\n",
     296      AUBIO_WRN("sampler: cancelled queuing %s (queuing %s now)\n",
    217297          o->next_uri, uri);
    218298    }
     
    224304  }
    225305  if (pthread_mutex_trylock(&o->open_mutex)) {
    226     AUBIO_WRN("sampler: failed locking in queue\n");
     306    AUBIO_WRN("sampler: failed queuing %s (locking failed)\n", uri);
    227307    ret = AUBIO_FAIL;
    228308    goto lock_failed;
     
    255335
    256336#ifdef HAVE_THREADS
     337
     338uint_t aubio_sampler_reading_from_source_ring_fetch(aubio_sampler_t*s);
    257339void *aubio_sampler_readfn(void *z) {
    258340  aubio_sampler_t *p = z;
    259341  while(1) {
    260342    pthread_mutex_lock(&p->read_mutex);
    261     if (1) {
    262       // idle
     343    if (p->open_thread_running) {
     344      //AUBIO_WRN("sampler: readfn(): file is being opened\n");
     345      pthread_cond_signal(&p->read_avail);
     346      //pthread_cond_wait(&p->read_request, &p->read_mutex);
     347    } else if (p->opened && !p->started && !p->finished) {
     348      //AUBIO_WRN("sampler: readfn(): file started\n");
     349      if (p->ring) {
     350        aubio_sampler_reading_from_source_ring_fetch(p);
     351      } else {
     352        p->available = aubio_sampler_pull_from_source(p);
     353        if (p->available < (sint_t)p->source_blocksize)
     354          aubio_sampler_do_eof(p);
     355      }
     356      pthread_cond_signal(&p->read_avail);
     357      if (!p->finished) {
     358        pthread_cond_wait(&p->read_request, &p->read_mutex);
     359      }
     360    } else {
     361      //AUBIO_WRN("sampler: readfn(): idle?\n");
     362      //pthread_cond_signal(&p->read_avail);
    263363      pthread_cond_wait(&p->read_request, &p->read_mutex);
    264364      if (p->read_thread_finish) {
     
    273373  pthread_exit(NULL);
    274374}
     375
     376void *aubio_sampler_readfn_ring(void *z) {
     377  aubio_sampler_t *p = z;
     378  while(1) {
     379    pthread_mutex_lock(&p->read_mutex);
     380    if (p->open_thread_running) {
     381      //AUBIO_WRN("sampler: readfn(): file is being opened\n");
     382      pthread_cond_signal(&p->read_avail);
     383      //pthread_cond_wait(&p->read_request, &p->read_mutex);
     384    } else if (p->opened && !p->started && !p->finished) {
     385      //AUBIO_WRN("sampler: readfn(): file started\n");
     386      p->available = aubio_sampler_pull_from_source(p);
     387      if (p->available < (sint_t)p->source_blocksize)
     388        aubio_sampler_do_eof(p);
     389      pthread_cond_signal(&p->read_avail);
     390      if (!p->finished) {
     391        pthread_cond_wait(&p->read_request, &p->read_mutex);
     392      }
     393    } else {
     394      //AUBIO_WRN("sampler: readfn(): idle?\n");
     395      //pthread_cond_signal(&p->read_avail);
     396      pthread_cond_wait(&p->read_request, &p->read_mutex);
     397      if (p->read_thread_finish) {
     398        goto done;
     399      }
     400    }
     401    pthread_mutex_unlock(&p->read_mutex);
     402  }
     403done:
     404  //AUBIO_WRN("sampler: exiting reading thread\n");
     405  pthread_mutex_unlock(&p->read_mutex);
     406  pthread_exit(NULL);
     407}
    275408#endif
    276409
    277410void
    278 aubio_sampler_fetch_from_source(aubio_sampler_t *o, fvec_t *output, uint_t *read) {
    279   if (o->opened == 1 && o->source && !o->finished)
    280     aubio_source_do(o->source, output, read);
    281 }
     411aubio_sampler_read(aubio_sampler_t *s, fvec_t *output, uint_t *read) {
     412  if (s->reading_from == aubio_sampler_reading_from_source) {
     413    aubio_sampler_read_from_source(s, output, read);
     414  } else if (s->reading_from == aubio_sampler_reading_from_table) {
     415    aubio_sampler_read_from_table(s, output, read);
     416  }
     417}
     418
     419static void aubio_sampler_do_perfectloop(aubio_sampler_t *s);
     420
     421static void
     422aubio_sampler_reading_from_source_naive(aubio_sampler_t *s, fvec_t * output,
     423    uint_t *read)
     424{
     425  // directly read from disk
     426  //aubio_source_do(s->source, output, read);
     427  s->source_output = output;
     428  *read = aubio_sampler_pull_from_source(s);
     429  check_wrote += s->source_blocksize;
     430  if (*read < s->source_blocksize) {
     431    //AUBIO_WRN("sampler: calling go_eof in _read_from_source()\n");
     432    aubio_sampler_do_eof(s);
     433  }
     434}
     435
     436uint_t
     437aubio_sampler_reading_from_source_ring_fetch(aubio_sampler_t*s) {
     438  // read source_blocksize (> blocksize) at once
     439  int ring_avail = aubio_ringbuffer_get_available(s->ring);
     440  //if (ring_avail < s->blocksize) {
     441  uint_t available = 0;
     442  if (ring_avail < (sint_t)s->blocksize) {
     443    available = aubio_sampler_pull_from_source(s);
     444#if 0
     445    //AUBIO_MSG("sampler: got %d / %d fetching from source\n", s->available,
     446    //    s->source_blocksize);
     447    if (s->available == 0) {
     448      //aubio_sampler_do_eof(s);
     449      //aubio_sampler_do_perfectloop(s, output);
     450    }
     451    if (s->available < s->source_blocksize) {
     452      AUBIO_ERR("sampler: short read from source"
     453          " s->available %d, ring_avail %d \n", s->available, ring_avail);
     454      //s->eof = 0;
     455      //abort();
     456    }
     457#endif
     458    if (available > 0) {
     459      aubio_ringbuffer_push(s->ring, s->source_output, available);
     460    } else {
     461      //if (s->playing && !s->finished)
     462      //AUBIO_WRN("sampler: not reading anymore should do eof now %d\n", check_wrote);
     463      // TODO: move eof fetch now
     464    }
     465  }
     466  return available;
     467}
     468
     469uint_t
     470aubio_sampler_write_remaining_ring(aubio_sampler_t *s, fvec_t *output, uint_t wrote);
     471
     472static void
     473aubio_sampler_reading_from_source_ring_pull(aubio_sampler_t *s, fvec_t *output,
     474    uint_t *read)
     475{
     476  // write into output
     477  int ring_avail = aubio_ringbuffer_get_available(s->ring);
     478  if (ring_avail >= (sint_t)s->blocksize) {
     479    //AUBIO_MSG("sampler: pulling %d / %d from ringbuffer\n", s->blocksize, ring_avail);
     480    aubio_ringbuffer_pull(s->ring, output, s->blocksize);
     481    check_wrote += s->blocksize;
     482    *read = s->blocksize;
     483  } else {
     484    //AUBIO_MSG("sampler: last frame, pulling remaining %d left\n", ring_avail);
     485    *read = 0;
     486    if (ring_avail > 0) {
     487      aubio_ringbuffer_pull(s->ring, output, ring_avail);
     488      check_wrote += ring_avail;
     489      *read += ring_avail;
     490    }
     491    aubio_sampler_do_eof(s);
     492    aubio_sampler_do_perfectloop(s);
     493    *read += aubio_sampler_write_remaining_ring(s, output, ring_avail);
     494  }
     495}
     496
     497static void
     498aubio_sampler_reading_from_source_ring(aubio_sampler_t *s, fvec_t *output,
     499    uint_t *read)
     500{
     501  aubio_sampler_reading_from_source_ring_fetch(s);
     502  aubio_sampler_reading_from_source_ring_pull(s, output, read);
     503}
     504
     505#ifdef HAVE_THREADS
     506static void
     507aubio_sampler_read_from_source_threaded(aubio_sampler_t *s, fvec_t *output,
     508    uint_t *read) {
     509  // request at least output->length
     510  // make sure we have enough samples read from source
     511  int available;
     512  pthread_mutex_lock(&s->read_mutex);
     513  if (!s->opened || s->open_thread_running) {
     514    //AUBIO_ERR("sampler: _read_from_source: not opened, signaling read_request\n");
     515    pthread_cond_signal(&s->read_request);
     516    available = 0;
     517  } else if (!s->finished) {
     518    //AUBIO_ERR("sampler: _read_from_source: waiting for read avail %d\n", s->started);
     519    pthread_cond_signal(&s->read_request);
     520    pthread_cond_wait(&s->read_avail, &s->read_mutex);
     521    //AUBIO_ERR("sampler: _read_from_source: %d\n", s->available);
     522    available = s->available;
     523  } else {
     524    //AUBIO_WRN("sampler: _read_from_source: eof\n");
     525    pthread_cond_signal(&s->read_request);
     526    available = 0;
     527  }
     528  pthread_mutex_unlock(&s->read_mutex);
     529  //AUBIO_WRN("sampler: got %d available in _read_from_source\n", available);
     530  // read -> number of samples read
     531  if (available >= (sint_t)s->blocksize) {
     532    fvec_copy(s->source_output, output);
     533    *read = s->blocksize;
     534  } else if (available > 0) {
     535    fvec_copy(s->source_output, output);
     536    *read = available;
     537  } else {
     538    fvec_zeros(output);
     539    *read = 0;
     540  }
     541  //*read = s->available;
     542}
     543#endif
    282544
    283545void
    284 aubio_sampler_fetch_from_source_multi(aubio_sampler_t *o, fmat_t *output, uint_t *read) {
    285   aubio_source_do_multi(o->source, output, read);
    286 }
    287 
     546aubio_sampler_read_from_source(aubio_sampler_t *s, fvec_t *output, uint_t *read) {
     547#ifdef HAVE_THREADS
     548  if (s->threaded_read) { // if threaded
     549    if (s->source_blocksize == s->blocksize) {
     550      aubio_sampler_read_from_source_threaded(s, output, read);
     551    } else {
     552      //abort();
     553    }
     554  } else
     555#endif
     556  {
     557    if (s->finished) {
     558      *read = 0;
     559    }
     560    else if (s->source_blocksize == s->blocksize && !s->perfectloop) {
     561      aubio_sampler_reading_from_source_naive(s, output, read);
     562    } else {
     563      aubio_sampler_reading_from_source_ring(s, output, read);
     564    }
     565#if 1
     566    if (s->loop && s->perfectloop && *read != s->blocksize) { // && s->started && !s->finished) {
     567      AUBIO_ERR("sampler: perfectloop but read only %d\n", *read);
     568    }
     569#endif
     570  }
     571}
     572
     573uint_t
     574aubio_sampler_write_remaining_ring(aubio_sampler_t *s, fvec_t *output, uint_t wrote){
     575  if (s->perfectloop && s->loop) {
     576    fvec_t tmpout;
     577    tmpout.data = output->data + wrote;
     578    tmpout.length = s->blocksize - wrote;
     579    aubio_ringbuffer_pull(s->ring, &tmpout, tmpout.length);
     580    //*read += tmpout.length;
    288581#if 0
     582    int ring_avail = aubio_ringbuffer_get_available(s->ring);
     583    AUBIO_WRN("sampler: perfectloop, "
     584        "%d left in ring, looping pulled %d more, wrote %d + %d\n",
     585        ring_avail, s->available, wrote, tmpout.length);
     586#endif
     587    check_wrote += tmpout.length;
     588    return tmpout.length;
     589  }
     590  return 0;
     591}
     592
    289593void
    290 aubio_sampler_fetch_from_array(aubio_sampler_t *o, fvec_t *output, uint_t *read) {
    291   // TODO
    292 }
    293 #endif
     594aubio_sampler_do_perfectloop(aubio_sampler_t *s) {
     595  // perfectloop fetched new samples from start of source to ringbuffer
     596  if (s->perfectloop && s->loop) {
     597    s->available = aubio_sampler_pull_from_source(s);
     598    if (s->available <= 0) {
     599      AUBIO_ERR("sampler: looping but s->available = 0 !\n");
     600    } else {
     601      //AUBIO_ERR("sampler: perfectloop fetch and push more\n");
     602      aubio_ringbuffer_push(s->ring, s->source_output, s->available);
     603    }
     604  }
     605}
     606
     607void
     608aubio_sampler_read_from_table(aubio_sampler_t *o, fvec_t *output, uint_t *read) {
     609  *read = 0;
     610  AUBIO_WRN("sampler: _pull_from_table not implemented for %d, %d, %d",
     611      o, output->length, *read);
     612}
     613
     614sint_t
     615aubio_sampler_pull_from_source(aubio_sampler_t *s)
     616{
     617  // pull source_blocksize samples from source, return available frames
     618  uint_t source_read = s->source_blocksize;
     619  if (s->source == NULL) {
     620    AUBIO_ERR("sampler: trying to fetch on NULL source\n");
     621    return -1;
     622  }
     623  // do actual reading
     624  aubio_source_do(s->source, s->source_output, &source_read);
     625#if 0
     626  if (source_read < s->source_blocksize) {
     627    //AUBIO_ERR("sampler: _pull_from_source: short read %d < %d\n", source_read,
     628    //    s->source_blocksize);
     629    //aubio_sampler_do_eof(s);
     630    if (s->loop) {
     631      AUBIO_ERR("sampler: _pull_from_source: loop, should seeking to 0? %d / %d\n",
     632          source_read, s->source_blocksize);
     633      //aubio_sampler_seek(s, 0);
     634    }
     635  }
     636  //AUBIO_ERR("sampler: _pull_from_source: read %d / %d\n", source_read, length);
     637#endif
     638  return source_read;
     639}
     640
    294641
    295642uint_t
     
    338685aubio_sampler_seek(aubio_sampler_t * o, uint_t pos)
    339686{
     687  //AUBIO_WRN("sampler: seeking to 0\n");
    340688  uint_t ret = AUBIO_FAIL;
    341689  o->finished = 0;
     
    350698aubio_sampler_do_eof (aubio_sampler_t * o)
    351699{
     700  //AUBIO_MSG("sampler: calling  _do_eof()\n");
    352701  o->finished = 1;
    353702  o->eof = 1;
     
    356705  } else {
    357706    aubio_sampler_seek(o, 0);
     707    //o->finished = 0;
    358708  }
    359709}
     
    363713  o->eof = 0;
    364714  if (o->opened == 1 && o->playing) {
    365     aubio_sampler_fetch_from_source(o, output, read);
     715    aubio_sampler_read(o, output, read);
     716    //AUBIO_WRN("sampler: _read got %d\n", *read);
    366717    if (*read < o->blocksize) {
    367       aubio_sampler_do_eof (o);
     718      if (*read > 0 && o->loop) {
     719        // TODO pull (hopsize - read) frames
     720      }
     721    }
     722  } else {
     723    fvec_zeros(output);
     724    *read = 0;
     725  }
     726}
     727
     728void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * output, uint_t *read)
     729{
     730  o->eof = 0;
     731  if (o->opened == 1 && o->playing) {
     732    //aubio_sampler_read_multi(o, output, read);
     733    if (*read < o->blocksize) {
    368734      if (*read > 0) {
    369735        // TODO pull (hopsize - read) frames
     
    372738    }
    373739  } else {
    374     fvec_zeros(output);
    375     *read = 0; //output->length;
    376   }
    377 }
    378 
    379 void aubio_sampler_do_multi ( aubio_sampler_t * o, fmat_t * output, uint_t *read)
    380 {
    381   o->eof = 0;
    382   if (o->playing) {
    383     aubio_sampler_fetch_from_source_multi(o, output, read);
    384     if (*read < o->blocksize) {
    385       aubio_sampler_do_eof (o);
    386       if (*read > 0) {
    387         // TODO pull (hopsize - read) frames
    388         //memset(...  tail , 0)
    389       }
    390     }
    391   } else {
    392740    fmat_zeros(output);
    393741    *read = 0;
     
    444792void del_aubio_sampler( aubio_sampler_t * o )
    445793{
     794  AUBIO_MSG("sampler: check_wrote: %d\n", check_wrote);
    446795#ifdef HAVE_THREADS
    447796  // close opening thread
     
    450799  aubio_sampler_close_reading_thread(o);
    451800#endif
     801  //if (o->source_output) {
     802  if (o->perfectloop || o->ring) {
     803    del_fvec(o->source_output);
     804  }
     805  if (o->source_moutput) {
     806    del_fmat(o->source_moutput);
     807  }
     808  if (o->ring) {
     809    del_aubio_ringbuffer(o->ring);
     810  }
    452811  if (o->source) {
    453812    del_aubio_source(o->source);
Note: See TracChangeset for help on using the changeset viewer.