ref: 284fe8a875a1bfa847b1141d3e2fafa119216102
parent: 45598638afa30afad96ad3b4a0a8399a775e06e1
author: Paul Brossier <piem@piem.org>
date: Mon Nov 28 09:30:40 EST 2016
src/effects/timestretch*: move out threaded file reading stuff, add _push and _available
--- a/src/effects/timestretch.h
+++ b/src/effects/timestretch.h
@@ -63,7 +63,6 @@
/** creation of the time stretching object
- \param uri path to create the source from
\param method time stretching algorithm ("default")
\param stretch initial time stretching factor
\param hop_size block size at which the frames should be produced
@@ -72,9 +71,29 @@
\return newly created ::aubio_timestretch_t
*/
-aubio_timestretch_t *new_aubio_timestretch (const char_t * uri,
- const char_t * method, smpl_t stretch, uint_t hop_size, uint_t samplerate);
+aubio_timestretch_t *new_aubio_timestretch (const char_t * method,
+ smpl_t stretch, uint_t hop_size, uint_t samplerate);
+/** push length samples from in to time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+ \param in input vector of new samples to push to time stretching object
+ \param length number of new samples to push from input vector
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_push(aubio_timestretch_t * o, fvec_t *in, uint_t length);
+
+/** get number of currently available samples from time stretching object
+
+ \param o time stretching object as returned by ::new_aubio_timestretch()
+
+ \return number of currently available samples
+
+ */
+sint_t aubio_timestretch_get_available(aubio_timestretch_t * o);
+
/** get the latency of the time stretching object, in samples
\param o time stretching object as returned by ::new_aubio_timestretch()
@@ -156,19 +175,14 @@
*/
smpl_t aubio_timestretch_get_transpose (aubio_timestretch_t * o);
-/** seek to a posisition the transposition of the time stretching object, in semitones
+/** reset the time stretching object
\param o time stretching object as returned by ::new_aubio_timestretch()
- \param pos position to seek to, in frames
- \return transposition of the time stretching object, in semitones
+ \return 0 on success, non-zero otherwise
*/
-uint_t aubio_timestretch_seek(aubio_timestretch_t * o, uint_t pos);
-
-uint_t aubio_timestretch_queue (aubio_timestretch_t *p, const char_t *uri, uint_t samplerate);
-
-uint_t aubio_timestretch_get_opened (aubio_timestretch_t *p);
+uint_t aubio_timestretch_reset(aubio_timestretch_t * o);
#ifdef __cplusplus
}
--- a/src/effects/timestretch_dummy.c
+++ b/src/effects/timestretch_dummy.c
@@ -43,7 +43,7 @@
}
aubio_timestretch_t *
-new_aubio_timestretch (const char_t * uri UNUSED, const char_t * method UNUSED,
+new_aubio_timestretch (const char_t * method UNUSED,
smpl_t pitchscale UNUSED, uint_t hop_size UNUSED, uint_t samplerate UNUSED)
{
AUBIO_ERR ("timestretch: aubio was not compiled with rubberband\n");
@@ -86,7 +86,16 @@
return 0.;
}
-uint_t aubio_timestretch_seek(aubio_timestretch_t *o UNUSED, uint_t pos UNUSED) {
+uint_t aubio_timestretch_reset(aubio_timestretch_t *o UNUSED) {
+ return AUBIO_FAIL;
+}
+
+sint_t aubio_timestretch_push(aubio_timestretch_t * o UNUSED, fvec_t * in
+ UNUSED, uint_t length UNUSED) {
+ return AUBIO_FAIL;
+}
+
+sint_t aubio_timestretch_get_available(aubio_timestretch_t * o UNUSED) {
return AUBIO_FAIL;
}
// end of dummy implementation
--- a/src/effects/timestretch_rubberband.c
+++ b/src/effects/timestretch_rubberband.c
@@ -50,47 +50,20 @@
smpl_t stretchratio; /**< time ratio */
smpl_t pitchscale; /**< pitch scale */
- aubio_source_t *source;
- uint_t source_hopsize; /**< hop size at which the source is read */
- fvec_t *in;
- uint_t eof;
-
RubberBandState rb;
RubberBandOptions rboptions;
-
- uint_t opened;
- const char_t *uri;
-#ifdef HAVE_THREADS
- pthread_t read_thread;
- pthread_mutex_t read_mutex;
- pthread_cond_t read_avail;
- pthread_cond_t read_request;
- pthread_t open_thread;
- pthread_mutex_t open_mutex;
- uint_t open_thread_running;
- sint_t available;
- uint_t started;
- uint_t finish;
-#endif
};
extern RubberBandOptions aubio_get_rubberband_opts(const char_t *mode);
static void aubio_timestretch_warmup (aubio_timestretch_t * p);
-static sint_t aubio_timestretch_fetch(aubio_timestretch_t *p, uint_t fetch);
-#ifdef HAVE_THREADS
-static void *aubio_timestretch_readfn(void *p);
-static void *aubio_timestretch_openfn(void *z);
-#endif
aubio_timestretch_t *
-new_aubio_timestretch (const char_t * uri, const char_t * mode,
- smpl_t stretchratio, uint_t hopsize, uint_t samplerate)
+new_aubio_timestretch (const char_t * mode, smpl_t stretchratio, uint_t hopsize,
+ uint_t samplerate)
{
aubio_timestretch_t *p = AUBIO_NEW (aubio_timestretch_t);
p->hopsize = hopsize;
- //p->source_hopsize = 2048;
- p->source_hopsize = hopsize;
p->pitchscale = 1.;
if (stretchratio <= MAX_STRETCH_RATIO && stretchratio >= MIN_STRETCH_RATIO) {
@@ -107,38 +80,13 @@
goto beach;
}
- p->in = new_fvec(p->source_hopsize);
+ p->rb = rubberband_new(samplerate, 1, p->rboptions, p->stretchratio, p->pitchscale);
+ if (!p->rb) goto beach;
-#ifndef HAVE_THREADS
- if (aubio_timestretch_queue(p, uri, samplerate)) goto beach;
- aubio_timestretch_warmup(p);
-#else
- p->started = 0;
- p->finish = 0;
- p->open_thread_running = 0;
- //p->uri = uri;
- p->eof = 0;
- //p->samplerate = samplerate;
- //if (aubio_timestretch_open(p, uri, samplerate)) goto beach;
- pthread_mutex_init(&p->open_mutex, 0);
- pthread_mutex_init(&p->read_mutex, 0);
- pthread_cond_init (&p->read_avail, 0);
- pthread_cond_init (&p->read_request, 0);
- //AUBIO_WRN("timestretch: creating thread\n");
- pthread_create(&p->read_thread, 0, aubio_timestretch_readfn, p);
- //AUBIO_DBG("timestretch: new_ waiting for warmup, got %d available\n", p->available);
- pthread_mutex_lock(&p->read_mutex);
- aubio_timestretch_queue(p, uri, samplerate);
-#if 0
- pthread_cond_wait(&p->read_avail, &p->read_mutex);
- if (!p->opened) {
- goto beach;
- }
-#endif
- pthread_mutex_unlock(&p->read_mutex);
- //AUBIO_DBG("timestretch: new_ warm up success, got %d available\n", p->available);
-#endif
+ p->samplerate = samplerate;
+ //aubio_timestretch_warmup(p);
+
return p;
beach:
@@ -146,182 +94,6 @@
return NULL;
}
-#define HAVE_OPENTHREAD 1
-//#undef HAVE_OPENTHREAD
-
-uint_t
-aubio_timestretch_queue(aubio_timestretch_t *p, const char_t* uri, uint_t samplerate)
-{
-#ifdef HAVE_THREADS
-#ifdef HAVE_OPENTHREAD
- if (p->open_thread_running) {
-#if 1
- if (pthread_cancel(p->open_thread)) {
- AUBIO_WRN("timestretch: cancelling open thread failed\n");
- return AUBIO_FAIL;
- } else {
- AUBIO_WRN("timestretch: previous open of '%s' cancelled\n", p->uri);
- }
- p->open_thread_running = 0;
-#else
- void *threadfn;
- if (pthread_join(p->open_thread, &threadfn)) {
- AUBIO_WRN("timestretch: failed joining existing open thread\n");
- return AUBIO_FAIL;
- }
-#endif
- }
- //AUBIO_WRN("timestretch: queueing %s\n", uri);
- //pthread_mutex_lock(&p->read_mutex);
- p->opened = 0;
- p->started = 0;
- p->available = 0;
- p->uri = uri;
- p->samplerate = samplerate;
- //AUBIO_WRN("timestretch: creating thread\n");
- pthread_create(&p->open_thread, 0, aubio_timestretch_openfn, p);
-#endif
- //pthread_mutex_unlock(&p->read_mutex);
- return AUBIO_OK;
-}
-
-uint_t
-aubio_timestretch_open(aubio_timestretch_t *p, const char_t* uri, uint_t samplerate)
-{
- uint_t err = AUBIO_FAIL;
- p->available = 0;
- pthread_mutex_lock(&p->open_mutex);
- p->open_thread_running = 1;
-#else
- uint_t err = AUBIO_FAIL;
-#endif
- p->opened = 0;
- if (p->source) del_aubio_source(p->source);
- p->source = new_aubio_source(uri, samplerate, p->source_hopsize);
- if (!p->source) goto fail;
- p->uri = uri;
- p->samplerate = aubio_source_get_samplerate(p->source);
- p->eof = 0;
-
- if (p->rb == NULL) {
- AUBIO_WRN("timestretch: creating with stretch: %.2f pitchscale: %.2f\n",
- p->stretchratio, p->pitchscale);
- p->rb = rubberband_new(p->samplerate, 1, p->rboptions, p->stretchratio, p->pitchscale);
- //rubberband_set_debug_level(p->rb, 10);
- rubberband_set_max_process_size(p->rb, p->source_hopsize);
- } else {
- if (samplerate != p->samplerate) {
- AUBIO_WRN("timestretch: samplerate change requested, but not implemented\n");
- }
- rubberband_reset(p->rb);
- }
- p->opened = 1;
- err = AUBIO_OK;
- goto unlock;
-fail:
- p->opened = 2;
- AUBIO_ERR("timestretch: opening %s failed\n", uri);
-unlock:
-#ifdef HAVE_THREADS
- p->open_thread_running = 0;
- pthread_mutex_unlock(&p->open_mutex);
- //AUBIO_WRN("timestretch: failed opening %s at %dHz\n", uri, samplerate);
-#endif
- return err;
-}
-
-#ifdef HAVE_THREADS
-void *
-aubio_timestretch_openfn(void *z) {
- aubio_timestretch_t *p = z;
- int oldtype;
- pthread_setcancelstate(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
- //AUBIO_WRN("timestretch: creating thread\n");
- void *ret;
- uint_t err = aubio_timestretch_open(p, p->uri, p->samplerate);
- ret = &err;
- pthread_exit(ret);
-}
-#endif
-
-uint_t
-aubio_timestretch_get_opened(aubio_timestretch_t *p)
-{
- if (p == NULL) return 0;
- else return p->opened;
-}
-
-#ifdef HAVE_THREADS
-void *
-aubio_timestretch_readfn(void *z)
-{
- aubio_timestretch_t *p = z;
- //AUBIO_WRN("timestretch: entering thread with %s at %dHz\n", p->uri, p->samplerate);
- while(1) { //p->available < (int)p->hopsize && p->eof != 1) {
- //AUBIO_WRN("timestretch: locking in readfn\n");
- pthread_mutex_lock(&p->read_mutex);
-#if 1
- if (p->opened == 2) {
- pthread_cond_signal(&p->read_avail);
- } else
- if (p->opened == 0) {
-#ifdef HAVE_OPENTHREAD
- //(!aubio_timestretch_open(p, p->uri, p->samplerate)) {
- void * threadfn;
- if (p->open_thread_running && pthread_join(p->open_thread, &threadfn)) {
- AUBIO_WRN("timestretch: failed to join opening thread %s at %dHz in thread "
- "(opened: %d, playing: %d, eof: %d)\n",
- p->uri, p->samplerate, p->opened, p->started, p->eof);
- }
-#else
- //AUBIO_WRN("timestretch: opening source %s\n", p->uri);
- if (!aubio_timestretch_open(p, p->uri, p->samplerate)) {
- AUBIO_WRN("timestretch: opened %s at %dHz in thread "
- "(opened: %d, playing: %d, eof: %d)\n",
- p->uri, p->samplerate, p->opened, p->started, p->eof);
- //pthread_cond_signal(&p->read_avail);
- } else {
- AUBIO_WRN("timestretch: failed opening %s, exiting thread\n", p->uri);
- //pthread_cond_signal(&p->read_avail);
- //pthread_mutex_unlock(&p->read_mutex);
- //goto end;
- }
-#endif
- } else
- if (!p->started && !p->eof) {
-#endif
- // fetch the first few samples and mark as started
- aubio_timestretch_warmup(p);
- pthread_cond_signal(&p->read_avail);
- //pthread_cond_wait(&p->read_request, &p->read_mutex);
- p->started = 1;
- } else if (!p->eof) {
- // fetch at least p->hopsize stretched samples
- p->available = aubio_timestretch_fetch(p, p->hopsize);
- // signal available frames
- pthread_cond_signal(&p->read_avail);
- if (p->eof != 1) {
- // the end of file was not reached yet, wait for the next read_request
- pthread_cond_wait(&p->read_request, &p->read_mutex);
- } else {
- // eof was reached, do not wait for a read request and mark as stopped
- p->started = 0;
- }
- } else {
- //pthread_cond_signal(&p->read_avail);
- pthread_cond_wait(&p->read_request, &p->read_mutex);
- //AUBIO_WRN("timestretch: finished idle in readfn\n");
- if (p->finish) pthread_exit(NULL);
- }
- //AUBIO_WRN("timestretch: unlocking in readfn\n");
- pthread_mutex_unlock(&p->read_mutex);
- }
-end:
- //AUBIO_WRN("timestretch: exiting readfn\n");
- pthread_exit(NULL);
-}
-#endif
-
static void
aubio_timestretch_warmup (aubio_timestretch_t * p)
{
@@ -328,47 +100,17 @@
// warm up rubber band
//AUBIO_WRN("timestretch: warming-up\n");
unsigned int latency = MAX(p->hopsize, rubberband_get_latency(p->rb));
-#ifdef HAVE_THREADS
- p->available = aubio_timestretch_fetch(p, latency);
-#else
- aubio_timestretch_fetch(p, latency);
-#endif
- //AUBIO_WRN("timestretch: warmup got %d\n", latency);
+ fvec_t *input = new_fvec(p->hopsize);
+ while (aubio_timestretch_push(p, input, input->length) < (int)latency) {
+ //sint_t available = aubio_timestretch_get_available(p);
+ //AUBIO_WRN("timestretch: warmup got %d, latency: %d\n", available, latency);
+ }
+ del_fvec(input);
}
void
del_aubio_timestretch (aubio_timestretch_t * p)
{
-#ifdef HAVE_THREADS
- void *threadfn;
- //AUBIO_WRN("timestretch: entering delete\n");
- if (p->open_thread_running) {
- if (pthread_cancel(p->open_thread)) {
- AUBIO_WRN("timestretch: cancelling open thread failed\n");
- }
- if (pthread_join(p->open_thread, &threadfn)) {
- AUBIO_WRN("timestretch: joining open thread failed\n");
- }
- }
- if (!p->opened) goto cleanup;
- pthread_mutex_lock(&p->read_mutex);
- p->finish = 1;
- pthread_cond_signal(&p->read_request);
- //pthread_cond_wait(&p->read_avail, &p->read_mutex);
- pthread_mutex_unlock(&p->read_mutex);
- if ((p->eof == 0) && (pthread_cancel(p->read_thread))) {
- AUBIO_WRN("timestretch: cancelling thread failed\n");
- }
- if (pthread_join(p->read_thread, &threadfn)) {
- AUBIO_WRN("timestretch: joining thread failed\n");
- }
- pthread_mutex_destroy(&p->read_mutex);
- pthread_cond_destroy(&p->read_avail);
- pthread_cond_destroy(&p->read_request);
-cleanup:
-#endif
- if (p->in) del_fvec(p->in);
- if (p->source) del_aubio_source(p->source);
if (p->rb) {
rubberband_delete(p->rb);
}
@@ -450,65 +192,37 @@
}
sint_t
-aubio_timestretch_fetch(aubio_timestretch_t *p, uint_t length)
+aubio_timestretch_push(aubio_timestretch_t *p, fvec_t *input, uint_t length)
{
- uint_t source_read = p->source_hopsize;
- if (p->source == NULL) {
- AUBIO_ERR("timestretch: trying to fetch on NULL source\n");
- return 0;
- }
- // read more samples from source until we have enough available or eof is reached
- int available = rubberband_available(p->rb);
- while ((available < (int)length) && (p->eof == 0)) {
- aubio_source_do(p->source, p->in, &source_read);
- if (source_read < p->source_hopsize) {
- p->eof = 1;
- }
- rubberband_process(p->rb, (const float* const*)&(p->in->data), source_read, p->eof);
- available = rubberband_available(p->rb);
- }
+ // push new samples to rubberband, return available
+ int available;
+ int eof = (input->length != length) ? 1 : 0;
+ rubberband_process(p->rb, (const float* const*)&(input->data), length, eof);
+ available = rubberband_available(p->rb);
+ //AUBIO_WRN("timestretch: processed %d, %d available, eof: %d\n",
+ // length, available, eof);
return available;
}
+sint_t
+aubio_timestretch_get_available(aubio_timestretch_t *p) {
+ return rubberband_available(p->rb);
+}
+
void
-aubio_timestretch_do (aubio_timestretch_t * p, fvec_t * out, uint_t * read)
+aubio_timestretch_do(aubio_timestretch_t * p, fvec_t * out, uint_t * read)
{
-#ifndef HAVE_THREADS
- int available = aubio_timestretch_fetch(p, p->hopsize);
-#else /* HAVE_THREADS */
- int available;
- pthread_mutex_lock(&p->read_mutex);
-#if 1
- if (!p->opened) {
- // this may occur if _do was was called while being opened
- //AUBIO_WRN("timestretch: calling _do before opening a file\n");
- pthread_cond_signal(&p->read_request);
- //available = 0;
- //pthread_cond_wait(&p->read_avail, &p->read_mutex);
- available = 0; //p->available;
- } else
-#endif
- if (p->eof != 1) {
- //AUBIO_WRN("timestretch: calling _do after opening a file\n");
- // signal a read request
- pthread_cond_signal(&p->read_request);
- // wait for an available signal
- pthread_cond_wait(&p->read_avail, &p->read_mutex);
- available = p->available;
- } else {
- available = rubberband_available(p->rb);
- //AUBIO_WRN("timestretch: reached eof (%d/%d)\n", p->hopsize, available);
- }
- pthread_mutex_unlock(&p->read_mutex);
-#endif /* HAVE_THREADS */
// now retrieve the samples and write them into out->data
- if (available >= (int)p->hopsize) {
- rubberband_retrieve(p->rb, (float* const*)&(out->data), p->hopsize);
- *read = p->hopsize;
+ int available = rubberband_available(p->rb);
+ if (available >= (int)out->length) {
+ rubberband_retrieve(p->rb, (float* const*)&(out->data), out->length);
+ *read = out->length;
} else if (available > 0) {
// this occurs each time the end of file is reached
//AUBIO_WRN("timestretch: short read\n");
rubberband_retrieve(p->rb, (float* const*)&(out->data), available);
+ fvec_t zeros; zeros.length = out->length - available; zeros.data = out->data + available;
+ fvec_zeros(&zeros);
*read = available;
} else {
// this may occur if the previous was a short read available == hopsize
@@ -515,57 +229,15 @@
fvec_zeros(out);
*read = 0;
}
-#ifdef HAVE_THREADS
- //pthread_mutex_unlock(&p->read_mutex);
-#endif
}
uint_t
-aubio_timestretch_seek (aubio_timestretch_t *p, uint_t pos)
+aubio_timestretch_reset(aubio_timestretch_t *p)
{
uint_t err = AUBIO_OK;
-#if HAVE_THREADS
- if (p == NULL) {
- AUBIO_WRN("seeking but object not set yet (ignoring)\n");
- return AUBIO_FAIL;
- }
- pthread_mutex_lock(&p->read_mutex);
- if (p->open_thread_running) {
- //AUBIO_WRN("seeking but opening thread not completed yet (ignoring)\n");
- err = AUBIO_OK;
- goto beach;
- }
- if (!p->opened || !p->source) {
- //AUBIO_WRN("timestretch: seeking but source not opened yet (ignoring)\n");
- err = AUBIO_OK;
- goto beach;
- }
-#endif
- p->eof = 0;
if (p->rb) {
rubberband_reset(p->rb);
}
-#ifdef HAVE_THREADS
-#ifdef HAVE_OPENTHREAD
- pthread_mutex_lock(&p->open_mutex);
-#endif
-#endif
- if (p->source) {
- err = aubio_source_seek(p->source, pos);
- } else {
- AUBIO_WRN("timestretch: seeking but p->source not created?!\n");
- err = AUBIO_FAIL;
- goto beach;
- }
-#if HAVE_THREADS
- pthread_mutex_unlock(&p->open_mutex);
- p->available = 0;
- p->started = 1;
-beach:
- pthread_mutex_unlock(&p->read_mutex);
-#else
-beach:
-#endif
return err;
}