summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-10-12 21:15:56 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2014-10-12 21:15:56 +0200
commitfafc815d3b2f525e703ab9482a008201097ab90d (patch)
treef16a60541eefd32ac3a22138765a47425e156034
parent484eb4f976568ba058c91a36f6482a404e35d486 (diff)
Add new resampler class and use it in engine.
-rw-r--r--src/Makefile.am.drumgizmo1
-rw-r--r--src/chresampler.cc170
-rw-r--r--src/chresampler.h65
-rw-r--r--src/drumgizmo.cc138
-rw-r--r--src/drumgizmo.h8
5 files changed, 313 insertions, 69 deletions
diff --git a/src/Makefile.am.drumgizmo b/src/Makefile.am.drumgizmo
index da5d839..26e2a30 100644
--- a/src/Makefile.am.drumgizmo
+++ b/src/Makefile.am.drumgizmo
@@ -3,6 +3,7 @@ DRUMGIZMO_SOURCES = \
$(top_srcdir)/src/audiofile.cc \
$(top_srcdir)/src/channel.cc \
$(top_srcdir)/src/channelmixer.cc \
+ $(top_srcdir)/src/chresampler.cc \
$(top_srcdir)/src/configuration.cc \
$(top_srcdir)/src/configparser.cc \
$(top_srcdir)/src/drumgizmo.cc \
diff --git a/src/chresampler.cc b/src/chresampler.cc
new file mode 100644
index 0000000..301e650
--- /dev/null
+++ b/src/chresampler.cc
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * chresampler.cc
+ *
+ * Tue Sep 23 20:42:14 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo 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 DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "chresampler.h"
+
+#include <config.h>
+#include <hugin.hpp>
+#include <stdio.h>
+
+#ifdef WITH_RESAMPLER
+
+#if defined(USE_ZITA)
+ #include <zita-resampler/resampler.h>
+#elif defined(USE_SRC)
+ #include <samplerate.h>
+#else
+ #error "No resampler selected"
+#endif
+
+class CHResampler::Prv {
+public:
+#if defined(USE_ZITA)
+ Resampler zita;
+#elif defined(USE_SRC)
+ SRC_STATE *state;
+ SRC_DATA data;
+#endif
+};
+
+CHResampler::CHResampler()
+{
+ input_fs = 44100;
+ output_fs = 44100;
+
+ prv = new Prv();
+#if defined(SRC)
+ prv->state = NULL;
+#endif
+}
+
+void CHResampler::setup(double input_fs, double output_fs)
+{
+ int nchan = 1; // always mono
+
+ this->input_fs = input_fs;
+ this->output_fs = output_fs;
+
+#if defined(USE_ZITA)
+ DEBUG(resampler, "Using zita-resampler (%d -> %d)", (int)input_fs, (int)output_fs);
+
+ int hlen = 72; // 16 ≤ hlen ≤ 96
+ // delay is 2 * hlen, 72 corresponds to delay introduced by SRC.
+ prv->zita.setup(input_fs, output_fs, nchan, hlen);
+#elif defined(USE_SRC)
+ DEBUG(resampler, "Using libsamplerate (%d -> %d)", (int)input_fs, (int)output_fs);
+
+ int err;
+ prv->state = src_new(SRC_SINC_BEST_QUALITY, nchan, &err);
+ (void)err;
+ // printf("err: %d\n", err);
+ src_set_ratio(prv->state, output_fs / input_fs);
+ prv->data.src_ratio = output_fs / input_fs;
+ prv->data.end_of_input = 0;
+#endif
+}
+
+CHResampler::~CHResampler()
+{
+#if defined(USE_ZITA)
+#elif defined(USE_SRC)
+ if(prv->state) src_delete(prv->state);
+#endif
+ delete prv;
+}
+
+void CHResampler::setInputSamples(float *samples, size_t count)
+{
+#if defined(USE_ZITA)
+ prv->zita.inp_data = samples;
+ prv->zita.inp_count = count;
+#elif defined(USE_SRC)
+ prv->data.data_in = samples;
+ prv->data.input_frames = count;
+#endif
+}
+
+void CHResampler::setOutputSamples(float *samples, size_t count)
+{
+#if defined(USE_ZITA)
+ prv->zita.out_data = samples;
+ prv->zita.out_count = count;
+#elif defined(USE_SRC)
+ prv->data.data_out = samples;
+ prv->data.output_frames = count;
+#endif
+}
+
+void CHResampler::process()
+{
+#if defined(USE_ZITA)
+ prv->zita.process();
+#elif defined(USE_SRC)
+ src_process(prv->state, &prv->data);
+ prv->data.output_frames -= prv->data.output_frames_gen;
+ prv->data.data_out += prv->data.output_frames_gen;
+ prv->data.input_frames -= prv->data.input_frames_used;
+ prv->data.data_in += prv->data.input_frames_used;
+#endif
+}
+
+size_t CHResampler::getInputSampleCount()
+{
+#if defined(USE_ZITA)
+ return prv->zita.inp_count;
+#elif defined(USE_SRC)
+ return prv->data.input_frames;
+#endif
+}
+
+size_t CHResampler::getOutputSampleCount()
+{
+#if defined(USE_ZITA)
+ return prv->zita.out_count;
+#elif defined(USE_SRC)
+ return prv->data.output_frames;
+#endif
+}
+
+double CHResampler::ratio()
+{
+ return input_fs / output_fs;
+}
+
+#else
+
+// Dummy implementation
+CHResampler::CHResampler() {}
+CHResampler::~CHResampler() {}
+void CHResampler::setup(double, double) {}
+void CHResampler::setInputSamples(float *, size_t) {}
+void CHResampler::setOutputSamples(float *, size_t) {}
+void CHResampler::process() {}
+size_t CHResampler::getInputSampleCount() { return 0; }
+size_t CHResampler::getOutputSampleCount() { return 0; }
+double CHResampler::ratio() { return 1; }
+
+#endif/*WITH_RESAMPLER*/
diff --git a/src/chresampler.h b/src/chresampler.h
new file mode 100644
index 0000000..5943627
--- /dev/null
+++ b/src/chresampler.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * chresampler.h
+ *
+ * Tue Sep 23 20:42:14 CEST 2014
+ * Copyright 2014 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of DrumGizmo.
+ *
+ * DrumGizmo 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DrumGizmo 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 DrumGizmo; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __DRUMGIZMO_CHRESAMPLER_H__
+#define __DRUMGIZMO_CHRESAMPLER_H__
+
+#include <stdlib.h>
+
+/**
+ * Channel resampler class using either zita-resampler or secret rabbit code
+ * (really!!) depending on the value of the WITH_RESAMPLER macro.
+ * If WITH_RESAMPLER is unset the resampler is disabled entirely.
+ * If WITH_RESAMPLER=="zita" zita-resampler will be used.
+ * If WITH_RESAMPLER=="src" Secret Rabbit Code will be used.
+ */
+class CHResampler {
+public:
+ CHResampler();
+ ~CHResampler();
+
+ void setup(double input_fs, double output_fs);
+
+ void setInputSamples(float *samples, size_t count);
+ void setOutputSamples(float *samples, size_t count);
+
+ void process();
+
+ size_t getInputSampleCount();
+ size_t getOutputSampleCount();
+
+ double ratio();
+
+private:
+ class Prv;
+ Prv *prv;
+
+ double input_fs;
+ double output_fs;
+};
+
+
+#endif/*__DRUMGIZMO_CHRESAMPLER_H__*/
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 8fb449a..5f27ae1 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -38,17 +38,6 @@
#include <config.h>
-//
-// Warning: Zita currently not working...
-//
-#ifdef WITH_RESAMPLE
-#ifdef ZITA
-#include <zita-resampler/resampler.h>
-#else
-#include <samplerate.h>
-#endif/*ZITA*/
-#endif/*WITH_RESAMPLE*/
-
#include "drumkitparser.h"
#include "audioinputenginemidi.h"
#include "configuration.h"
@@ -66,9 +55,12 @@ DrumGizmo::~DrumGizmo()
bool DrumGizmo::loadkit(std::string file)
{
+ printf("loadkit(%s)\n", file.c_str());
if(file == kit.file()) return 1;
if(file == "") return 1;
+ printf("loadkit() go\n");
+
DEBUG(drumgizmo, "loadkit(%s)\n", file.c_str());
// Remove all queue AudioFiles from loader before we actually delete them.
@@ -80,12 +72,23 @@ bool DrumGizmo::loadkit(std::string file)
DrumKitParser parser(file, kit);
if(parser.parse()) {
ERR(drumgizmo, "Drumkit parser failed: %s\n", file.c_str());
- return false;
+ printf("loadkit() parser failed\n");
+ return false;
}
loader.loadKit(&kit);
+#ifdef WITH_RESAMPLER
+ unsigned int output_fs = kit.samplerate();
+ if(oe->samplerate() != UNKNOWN_SAMPLERATE) output_fs = oe->samplerate();
+ for(int i = 0; i < MAX_NUM_CHANNELS; i++) {
+ resampler[i].setup(kit.samplerate(), output_fs);
+ }
+#endif/*WITH_RESAMPLER*/
+
+
DEBUG(loadkit, "loadkit: Success\n");
+ printf("loadkit() done\n");
return true;
}
@@ -171,13 +174,7 @@ void DrumGizmo::handleMessage(Message *msg)
bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
{
- double samplerate_scale = 1.0;
-#ifdef WITH_RESAMPLE
- if(oe->samplerate() != UNKNOWN_SAMPLERATE) {
- samplerate_scale = (double)kit.samplerate() / (double)oe->samplerate();
- }
-#endif/*WITH_RESAMPLE*/
-
+ // printf("."); fflush(stdout);
// Handle engine messages, at most one in each iteration:
handleMessages(1);
@@ -260,7 +257,7 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
} else {
//DEBUG(drumgizmo, "Adding event %d.\n", evs[e].offset);
Event *evt = new EventSample(ch.num, 1.0, af, i->group(), i);
- evt->offset = (evs[e].offset + pos) * samplerate_scale;
+ evt->offset = (evs[e].offset + pos) * resampler[0].ratio();
activeevents[ch.num].push_back(evt);
}
j++;
@@ -278,59 +275,62 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
//
// Write audio
//
+#ifndef WITH_RESAMPLER
+ // No resampling needed
for(size_t c = 0; c < kit.channels.size(); c++) {
- if(samplerate_scale == 1.0) {
- // No resampling needed
- sample_t *buf = samples;
- bool internal = false;
- if(oe->getBuffer(c)) {
- buf = oe->getBuffer(c);
- internal = true;
- }
- if(buf) {
- memset(buf, 0, nsamples * sizeof(sample_t));
+ sample_t *buf = samples;
+ bool internal = false;
+ if(oe->getBuffer(c)) {
+ buf = oe->getBuffer(c);
+ internal = true;
+ }
+ if(buf) {
+ memset(buf, 0, nsamples * sizeof(sample_t));
- getSamples(c, pos, buf, nsamples);
-
- if(!internal) oe->run(c, samples, nsamples);
- }
- } else {
-#ifdef WITH_RESAMPLE
- // Resampling needed
- size_t nkitsamples = nsamples * samplerate_scale;
- sample_t kitsamples[nkitsamples];
-
- memset(kitsamples, 0, nkitsamples * sizeof(sample_t));
- getSamples(c, pos * samplerate_scale, kitsamples, nkitsamples);
-
-#ifdef ZITA
- Resampler resampler;
- resampler.setup(kit.samplerate(), oe->samplerate(), 1, 96);
-
- resampler.inp_data = kitsamples;
- resampler.inp_count = nkitsamples;
-
- resampler.out_data = samples;
- resampler.out_count = nsamples;
-
- resampler.process();
-#else
- SRC_DATA src;
- src.data_in = kitsamples;
- src.input_frames = nkitsamples;
-
- src.data_out = samples;
- src.output_frames = nsamples;
-
- src.src_ratio = 1.0 / samplerate_scale;
+ getSamples(c, pos, buf, nsamples);
+
+ if(!internal) oe->run(c, samples, nsamples);
+ }
+ }
+#else/*WITH_RESAMPLER*/
+ // Resampling needed
- src_simple(&src, SRC_SINC_BEST_QUALITY, 1);
-#endif/*ZITA*/
+ //
+ // NOTE: Channels must be processed one buffer at a time on all channels in
+ // parallel - NOT all buffers on one channel and then all buffer on the next
+ // one since this would mess up the event queue (it would jump back and forth
+ // in time)
+ //
- oe->run(c, samples, nsamples);
-#endif/*WITH_RESAMPLE*/
+ // Prepare output buffer
+ for(size_t c = 0; c < kit.channels.size(); c++) {
+ resampler[c].setOutputSamples(resampler_output_buffer[c], nsamples);
+ }
+
+ // Process channel data
+ size_t kitpos = pos * resampler[0].ratio();
+ //printf("ratio: %f\n", resampler[c].ratio());
+ while(resampler[0].getOutputSampleCount() > 0) {
+ for(size_t c = 0; c < kit.channels.size(); c++) {
+ if(resampler[c].getInputSampleCount() == 0) {
+ sample_t *sin = resampler_input_buffer[c];
+ size_t insize = sizeof(resampler_input_buffer[c]) / sizeof(sample_t);
+ memset(resampler_input_buffer[c], 0,
+ sizeof(resampler_input_buffer[c]));
+ getSamples(c, kitpos, sin, insize);
+ kitpos += insize;
+
+ resampler[c].setInputSamples(sin, insize);
+ }
+ resampler[c].process();
}
}
+
+ // Write output data to output engine.
+ for(size_t c = 0; c < kit.channels.size(); c++) {
+ oe->run(c, resampler_output_buffer[c], nsamples);
+ }
+#endif/*WITH_RESAMPLER*/
ie->post();
oe->post(nsamples);
@@ -359,6 +359,7 @@ void DrumGizmo::run(int endpos)
free(samples);
}
+#undef SSE
#ifdef SSE
#define N 8
@@ -391,7 +392,8 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz)
size_t n = 0;
if(evt->offset > (size_t)pos) n = evt->offset - pos;
size_t end = sz;
- if(evt->t + end - n > af->size) end = af->size - evt->t + n;
+ if((evt->t + end - n) > af->size) end = af->size - evt->t + n;
+ if(end > sz) end = sz;
if(evt->rampdown == NO_RAMPDOWN) {
#ifdef SSE
diff --git a/src/drumgizmo.h b/src/drumgizmo.h
index 37b26e5..138e61c 100644
--- a/src/drumgizmo.h
+++ b/src/drumgizmo.h
@@ -45,7 +45,9 @@
#include "messagereceiver.h"
-#define MAX_NUM_CHANNELS 512
+#include "chresampler.h"
+
+#define MAX_NUM_CHANNELS 64
class DrumGizmo : public MessageReceiver {
public:
@@ -87,6 +89,10 @@ private:
std::list< Event* > activeevents[MAX_NUM_CHANNELS];
+ CHResampler resampler[MAX_NUM_CHANNELS];
+ sample_t resampler_output_buffer[MAX_NUM_CHANNELS][4096];
+ sample_t resampler_input_buffer[MAX_NUM_CHANNELS][64];
+
std::map<std::string, AudioFile *> audiofiles;
#ifdef TEST_DRUMGIZMO