ref: dd15573ec1e6e8e00e81f661d427058bea629a6c
parent: ac67de78638ac96266ad7c5bffc44f1ef4fa1c46
author: Paul Brossier <piem@piem.org>
date: Mon Sep 30 14:06:38 EDT 2013
added first version of wavetable
--- a/src/aubio.h
+++ b/src/aubio.h
@@ -185,6 +185,7 @@
#include "io/source.h"
#include "io/sink.h"
#include "synth/sampler.h"
+#include "synth/wavetable.h"
#if AUBIO_UNSTABLE
#include "mathutils.h"
--- /dev/null
+++ b/src/synth/wavetable.c
@@ -1,0 +1,213 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "config.h"
+#include "aubio_priv.h"
+#include "fvec.h"
+#include "fmat.h"
+#include "io/source.h"
+#include "synth/wavetable.h"
+
+#define WAVETABLE_LEN 4096
+
+struct _aubio_wavetable_t {
+ uint_t samplerate;
+ uint_t blocksize;
+ uint_t wavetable_length;
+ fvec_t *wavetable;
+ uint_t playing;
+ smpl_t last_pos;
+
+ smpl_t target_freq;
+ smpl_t freq;
+ smpl_t inc_freq;
+
+ smpl_t target_amp;
+ smpl_t amp;
+ smpl_t inc_amp;
+};
+
+aubio_wavetable_t *new_aubio_wavetable(uint_t samplerate, uint_t blocksize)
+{
+ aubio_wavetable_t *s = AUBIO_NEW(aubio_wavetable_t);
+ uint_t i = 0;
+ s->samplerate = samplerate;
+ s->blocksize = blocksize;
+ s->wavetable_length = WAVETABLE_LEN;
+ s->wavetable = new_fvec(s->wavetable_length + 3);
+ for (i = 0; i < s->wavetable_length; i++) {
+ s->wavetable->data[i] = SIN(TWO_PI * i / (smpl_t) s->wavetable_length );
+ }
+ s->wavetable->data[s->wavetable_length] = s->wavetable->data[0];
+ s->wavetable->data[s->wavetable_length + 1] = s->wavetable->data[1];
+ s->wavetable->data[s->wavetable_length + 2] = s->wavetable->data[2];
+ s->playing = 0;
+ s->last_pos = 0.;
+ s->freq = 0.;
+ s->target_freq = 0.;
+ s->inc_freq = 0.;
+
+ s->amp = 0.;
+ s->target_amp = 0.;
+ s->inc_amp = 0.;
+ return s;
+}
+
+static smpl_t interp_2(fvec_t *input, smpl_t pos) {
+ uint_t idx = (uint_t)FLOOR(pos);
+ smpl_t frac = pos - (smpl_t)idx;
+ smpl_t a = input->data[idx];
+ smpl_t b = input->data[idx + 1];
+ return a + frac * ( b - a );
+}
+
+void aubio_wavetable_do ( aubio_wavetable_t * s, fvec_t * input, fvec_t * output)
+{
+ uint_t i;
+ if (s->playing) {
+ smpl_t pos = s->last_pos;
+ for (i = 0; i < output->length; i++) {
+ if (s->freq != s->target_freq)
+ s->freq += s->inc_freq;
+ smpl_t inc = s->freq * (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
+ pos += inc;
+ while (pos > s->wavetable_length) {
+ pos -= s->wavetable_length;
+ }
+ if ( ABS(s->amp - s->target_amp) > ABS(s->inc_amp) )
+ s->amp += s->inc_amp;
+ else
+ s->amp = s->target_amp;
+ output->data[i] = s->amp * interp_2(s->wavetable, pos);
+ }
+ s->last_pos = pos;
+ } else {
+ fvec_set(output, 0.);
+ }
+ // add input to output if needed
+ if (input && input != output) {
+ for (i = 0; i < output->length; i++) {
+ output->data[i] += input->data[i];
+ }
+ }
+}
+
+void aubio_wavetable_do_multi ( aubio_wavetable_t * s, fmat_t * input, fmat_t * output)
+{
+ uint_t i, j;
+ if (s->playing) {
+ smpl_t pos = s->last_pos;
+ for (j = 0; j < output->length; j++) {
+ if (s->freq != s->target_freq)
+ s->freq += s->inc_freq;
+ smpl_t inc = s->freq * (smpl_t)(s->wavetable_length) / (smpl_t) (s->samplerate);
+ pos += inc;
+ while (pos > s->wavetable_length) {
+ pos -= s->wavetable_length;
+ }
+ for (i = 0; i < output->height; i++) {
+ output->data[i][j] = interp_2(s->wavetable, pos);
+ }
+ }
+ s->last_pos = pos;
+ } else {
+ for (j = 0; j < output->length; j++) {
+ if (s->freq != s->target_freq)
+ s->freq += s->inc_freq;
+ }
+ fmat_set(output, 0.);
+ }
+ // add output to input if needed
+ if (input && input != output) {
+ for (i = 0; i < output->height; i++) {
+ for (j = 0; j < output->length; j++) {
+ output->data[i][j] += input->data[i][j];
+ }
+ }
+ }
+}
+
+uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * s )
+{
+ return s->playing;
+}
+
+uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * s, uint_t playing )
+{
+ s->playing = (playing == 1) ? 1 : 0;
+ return 0;
+}
+
+uint_t aubio_wavetable_play ( aubio_wavetable_t * s )
+{
+ aubio_wavetable_set_amp (s, 0.7);
+ return aubio_wavetable_set_playing (s, 1);
+}
+
+uint_t aubio_wavetable_stop ( aubio_wavetable_t * s )
+{
+ //aubio_wavetable_set_freq (s, 0.);
+ aubio_wavetable_set_amp (s, 0.);
+ //s->last_pos = 0;
+ return aubio_wavetable_set_playing (s, 1);
+}
+
+uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * s, smpl_t freq )
+{
+ if (freq >= 0 && freq < s->samplerate / 2.) {
+ uint_t steps = 10;
+ s->inc_freq = (freq - s->freq) / steps;
+ s->target_freq = freq;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * s) {
+ return s->freq;
+}
+
+uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * s, smpl_t amp )
+{
+ AUBIO_MSG("amp: %f, s->amp: %f, target_amp: %f, inc_amp: %f\n",
+ amp, s->amp, s->target_amp, s->inc_amp);
+ if (amp >= 0. && amp < 1.) {
+ uint_t steps = 100;
+ s->inc_amp = (amp - s->amp) / steps;
+ s->target_amp = amp;
+ AUBIO_ERR("amp: %f, s->amp: %f, target_amp: %f, inc_amp: %f\n",
+ amp, s->amp, s->target_amp, s->inc_amp);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * s) {
+ return s->amp;
+}
+
+void del_aubio_wavetable( aubio_wavetable_t * s )
+{
+ del_fvec(s->wavetable);
+ AUBIO_FREE(s);
+}
--- /dev/null
+++ b/src/synth/wavetable.h
@@ -1,0 +1,179 @@
+/*
+ Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>
+
+ This file is part of aubio.
+
+ aubio is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ aubio is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with aubio. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _AUBIO_SYNTH_WAVETABLE_H
+#define _AUBIO_SYNTH_WAVETABLE_H
+
+/** \file
+
+ Load and play sound files.
+
+ This file loads a sample and gets ready to play it.
+
+ The `_do` function adds the new samples to the input, and write the result as
+ the output.
+
+ \example synth/test-wavetable.c
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** wavetable object */
+typedef struct _aubio_wavetable_t aubio_wavetable_t;
+
+/** create new wavetable object
+
+ \param samplerate the sampling rate of the new wavetable
+
+ \return the newly created ::aubio_wavetable_t
+
+*/
+aubio_wavetable_t * new_aubio_wavetable(uint_t samplerate, uint_t hop_size);
+
+/** load source in wavetable
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param uri the uri of the source to load
+
+ \return 0 if successful, non-zero otherwise
+
+*/
+uint_t aubio_wavetable_load( aubio_wavetable_t * o, char_t * uri );
+
+/** process wavetable function
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing sample to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do ( aubio_wavetable_t * o, fvec_t * input, fvec_t * output);
+
+/** process wavetable function, multiple channels
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param input input of the wavetable, to be added to the output
+ \param output output of the wavetable
+
+This function adds the new samples from the playing sample to the output.
+
+If `input` is not NULL and different from `output`, then the samples from `input`
+are added to the output.
+
+*/
+void aubio_wavetable_do_multi ( aubio_wavetable_t * o, fmat_t * input, fmat_t * output);
+
+/** get current playing state
+
+ \param o wavetable, created by ::new_aubio_wavetable
+
+ \return 0 if not playing, 1 if playing
+
+*/
+uint_t aubio_wavetable_get_playing ( aubio_wavetable_t * o );
+
+/** set current playing state
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_playing ( aubio_wavetable_t * o, uint_t playing );
+
+/** play sample from start
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_play ( aubio_wavetable_t * o );
+
+/** stop sample from start
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_stop ( aubio_wavetable_t * o );
+
+/** set wavetable frequency
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_freq ( aubio_wavetable_t * o, smpl_t freq );
+
+/** get wavetable frequency
+
+ \param o wavetable, created by ::new_aubio_wavetable
+
+ \return current frequency, in Hz
+
+*/
+smpl_t aubio_wavetable_get_freq ( aubio_wavetable_t * o);
+
+/** set wavetable amplitude
+
+ \param o wavetable, created by ::new_aubio_wavetable
+ \param playing 0 for not playing, 1 for playing
+
+ \return 0 if successful, 1 otherwise
+
+*/
+uint_t aubio_wavetable_set_amp ( aubio_wavetable_t * o, smpl_t amp );
+
+/** get wavetable amplitude
+
+ \param o wavetable, created by ::new_aubio_wavetable
+
+ \return current amplitude
+
+*/
+smpl_t aubio_wavetable_get_amp ( aubio_wavetable_t * o);
+
+/** destroy ::aubio_wavetable_t object
+
+ \param o wavetable, created by ::new_aubio_wavetable
+
+*/
+void del_aubio_wavetable( aubio_wavetable_t * o );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_SYNTH_WAVETABLE_H */
--- /dev/null
+++ b/tests/src/synth/test-wavetable.c
@@ -1,0 +1,68 @@
+#include <aubio.h>
+#include "utils_tests.h"
+
+int main (int argc, char **argv)
+{
+ sint_t err = 0;
+
+ if (argc < 2) {
+ err = 2;
+ PRINT_ERR("not enough arguments\n");
+ PRINT_MSG("usage: %s <output_path> [freq] [samplerate]\n", argv[0]);
+ return err;
+ }
+
+ uint_t samplerate = 44100; // default is the samplerate of input_path
+ uint_t hop_size = 256;
+ smpl_t freq = 440.;
+
+ char_t *sink_path = argv[1];
+ if ( argc == 4 ) samplerate = atoi(argv[3]);
+ if ( argc == 3 ) freq = atof(argv[2]);
+
+ fvec_t *vec = new_fvec(hop_size);
+ aubio_sink_t *sink = new_aubio_sink(sink_path, samplerate);
+
+ aubio_wavetable_t * wavetable = new_aubio_wavetable (samplerate, hop_size);
+
+ // 2 seconds duration, in samples
+ uint_t duration = 2 * samplerate;
+
+ uint_t n_frames = 0;
+ uint_t write = 0;
+
+ aubio_wavetable_play (wavetable);
+ aubio_wavetable_set_freq ( wavetable, freq );
+
+ uint_t region = 0;
+
+ do {
+ if ( n_frames > duration / 3 && region < 1) {
+ aubio_wavetable_stop (wavetable);
+ region++;
+ }
+ if ( n_frames > 2 * duration / 3 && region < 2) {
+ aubio_wavetable_play (wavetable);
+ aubio_wavetable_set_freq ( wavetable, freq / 2.);
+ region++;
+ }
+ if (duration - n_frames < hop_size * 2 ) {
+ aubio_wavetable_stop( wavetable );
+ }
+ if (duration - n_frames < hop_size ) {
+ write = duration - n_frames;
+ } else {
+ write = hop_size;
+ }
+ aubio_wavetable_do (wavetable, vec, vec);
+ aubio_sink_do(sink, vec, write);
+ n_frames += hop_size;
+ } while ( n_frames <= duration );
+
+ del_aubio_wavetable (wavetable);
+ del_aubio_sink(sink);
+ del_fvec(vec);
+ aubio_cleanup();
+
+ return 0;
+}