summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-12-05 20:34:12 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2014-12-05 20:34:12 +0100
commit3b0d9e0c9c5e08b2e449aa266617fb1db86b5a22 (patch)
treef203a59c944714925d73ae2d33ad9c67d5b17070
parent29ec8552826f64bfa8cad01a433306886328c522 (diff)
parent2e7176bc558cb03d4e7c27769bab9cd45c703332 (diff)
Merge branch 'resample'
Add resample support.
-rw-r--r--.gitignore6
-rw-r--r--configure.ac83
-rw-r--r--drumgizmo/audiooutputenginedl.cc28
-rw-r--r--drumgizmo/audiooutputenginedl.h3
-rw-r--r--drumgizmo/drumgizmoc.cc4
-rw-r--r--drumgizmo/output/alsa/alsa.cc29
-rw-r--r--drumgizmo/output/dummy/dummy.cc30
-rw-r--r--drumgizmo/output/jackaudio/jackaudio.cc29
-rw-r--r--drumgizmo/output/wavfile/wavfile.cc38
m---------hugin0
-rw-r--r--lv2/Makefile.am12
-rw-r--r--lv2/output_lv2.cc17
-rw-r--r--src/Makefile.am.drumgizmo3
-rw-r--r--src/audiofile.cc36
-rw-r--r--src/chresampler.cc170
-rw-r--r--src/chresampler.h65
-rw-r--r--src/drumgizmo.cc63
-rw-r--r--src/drumgizmo.h8
-rw-r--r--src/drumkit.cc6
-rw-r--r--src/drumkit.h3
-rw-r--r--src/drumkitparser.cc8
-rw-r--r--test/Makefile.am14
-rw-r--r--test/resampler.cc112
-rw-r--r--vst/Makefile.mingw32.in8
24 files changed, 606 insertions, 169 deletions
diff --git a/.gitignore b/.gitignore
index 32c3162..4cfbcc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,4 +27,8 @@ Makefile.am.test
*.dll
plugingui/plugingui
plugingui/rcgen
-*.lo \ No newline at end of file
+*.lo
+test/result_*.xml
+test/resampler
+test/engine
+test/gui \ No newline at end of file
diff --git a/configure.ac b/configure.ac
index 8900d50..641f2f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -317,16 +317,83 @@ dnl Check for sndfile
dnl ======================
PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.20)
-AC_ARG_WITH(resample, [ --with-resample Build with resample support])
-if test x$with_resample == xyes; then
+
+AC_ARG_ENABLE([resampler],
+[ --enable-resampler[=lib] Enable resampler using either 'zita' or 'src' (libsamplerate). Use 'auto' for autodetect [default=auto]],,
+ [enable_resampler="auto"])
+if test "x$enable_resampler" = "xyes"; then
+ enable_resampler="auto"
+fi
+
+has_src=no
+has_zita=no
+if test x$enable_resampler != xno; then
AC_MSG_WARN([*** Building resample support!])
- AC_DEFINE(WITH_RESAMPLE, [], [Use resample])
+ AC_DEFINE(WITH_RESAMPLER, [], [Use resample])
- dnl ======================
- dnl Check for libsamplerate
- dnl ======================
- PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.7)
-fi
+ if test x$enable_resampler == xauto || test x$enable_resampler == xsrc; then
+ dnl ======================
+ dnl Check for libsamplerate
+ dnl ======================
+ PKG_CHECK_MODULES(SAMPLERATE, samplerate >= 0.1.7, has_src=yes, has_src=no)
+ fi
+
+ if test x$enable_resampler == xauto || test x$enable_resampler == xzita; then
+ dnl ======================
+ dnl Check for the zitaresampler library
+ dnl ======================
+ AC_LANG_PUSH([C++])
+ tmp_CXXFLAGS="$CXXFLAGS"
+ tmp_CPPFLAGS="$CPPFLAGS"
+ tmp_CFLAGS="$CFLAGS"
+ tmp_LDFLAGS="$LDFLAGS"
+ tmp_LIBS="$LIBS"
+ CXXFLAGS=""
+ CPPFLAGS="$ZITA_CPPFLAGS"
+ CFLAGS=""
+ LDFLAGS="$ZITA_LDFLAGS -lzita-resampler -lpthread"
+ LIBS=""
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([#include <zita-resampler/resampler.h>],
+ [Resampler r] ) ], has_zita=yes, has_zita=no)
+ ZITA_CPPFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS"
+ ZITA_LIBS="$LDFLAGS $LIBS"
+ CXXFLAGS="$tmp_CXXFLAGS"
+ CPPFLAGS="$tmp_CPPFLAGS"
+ CFLAGS="$tmp_CFLAGS"
+ LDFLAGS="$tmp_LDFLAGS"
+ LIBS="$tmp_LIBS"
+ AC_SUBST(ZITA_CPPFLAGS)
+ AC_SUBST(ZITA_LIBS)
+ AC_LANG_POP([C++])
+ fi
+fi
+
+if test x$enable_resampler == xauto; then
+ if test x$has_zita == xyes; then
+ enable_resampler=zita
+ elif test x$has_src == xyes; then
+ enable_resampler=src
+ else
+ AC_MSG_ERROR([*** No resampler library present. Either libsamplerate or zita-resampler must be installed.])
+ fi
+fi
+
+if test x$enable_resampler == xzita; then
+ if test x$has_zita == xyes; then
+ AC_DEFINE(USE_ZITA, [], [zita-resampler is present])
+ else
+ AC_MSG_ERROR([*** zita-resampler library or headers not found. Set ZITA_LDFLAGS or ZITA_CPPFLAGS to add searchpath.])
+ fi
+fi
+
+if test x$enable_resampler == xsrc; then
+ if test x$has_src == xyes; then
+ AC_DEFINE(USE_SRC, [], [libsamplerate is present])
+ else
+ AC_MSG_ERROR([*** Missing libsamplerate.])
+ fi
+fi
#dnl ======================
#dnl Check for zlib
diff --git a/drumgizmo/audiooutputenginedl.cc b/drumgizmo/audiooutputenginedl.cc
index 513d21b..2648e8f 100644
--- a/drumgizmo/audiooutputenginedl.cc
+++ b/drumgizmo/audiooutputenginedl.cc
@@ -111,6 +111,13 @@ AudioOutputEngineDL::AudioOutputEngineDL(std::string name)
o_bufsize = NULL;
}
+ o_samplerate = (output_samplerate_func_t) dlsym(lib, "samplerate");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol samplerate: %s\n", dlsym_error);
+ return;
+ }
+
ptr = o_create();
if(is_jack_plugin) {
@@ -181,19 +188,8 @@ size_t AudioOutputEngineDL::getBufferSize()
return 1024;
}
-#ifdef TEST_AUDIOOUTPUTENGINEDL
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_AUDIOOUTPUTENGINEDL*/
+size_t AudioOutputEngineDL::samplerate()
+{
+ if(o_samplerate) return o_samplerate(ptr);
+ return 44100;
+}
diff --git a/drumgizmo/audiooutputenginedl.h b/drumgizmo/audiooutputenginedl.h
index 471247e..75460f3 100644
--- a/drumgizmo/audiooutputenginedl.h
+++ b/drumgizmo/audiooutputenginedl.h
@@ -46,6 +46,7 @@ typedef void (*output_pre_func_t)(void*, size_t);
typedef void (*output_run_func_t)(void*,int,sample_t*,size_t);
typedef void (*output_post_func_t)(void*, size_t);
typedef size_t (*output_bufsize_func_t)(void*);
+typedef size_t (*output_samplerate_func_t)(void*);
class AudioOutputEngineDL : public AudioOutputEngine {
public:
@@ -64,6 +65,7 @@ public:
void post(size_t nsamples);
size_t getBufferSize();
+ size_t samplerate();
private:
void *ptr;
@@ -77,6 +79,7 @@ private:
output_run_func_t o_run;
output_post_func_t o_post;
output_bufsize_func_t o_bufsize;
+ output_samplerate_func_t o_samplerate;
bool is_jack_plugin;
JackClient *jackclient;
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index c96736f..61f8eaa 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -187,7 +187,7 @@ int main(int argc, char *argv[])
return 1;
}
- AudioOutputEngine *oe = new AudioOutputEngineDL(outputengine);
+ AudioOutputEngineDL *oe = new AudioOutputEngineDL(outputengine);
if(oe == NULL) {
printf("Invalid output engine: %s\n", outputengine.c_str());
@@ -248,6 +248,8 @@ int main(int argc, char *argv[])
return 1;
}
+ gizmo.setSamplerate(oe->samplerate());
+
if(!gizmo.init(preload)) {
printf("Failed init engine.\n");
return 1;
diff --git a/drumgizmo/output/alsa/alsa.cc b/drumgizmo/output/alsa/alsa.cc
index 7b3a395..dc2ac73 100644
--- a/drumgizmo/output/alsa/alsa.cc
+++ b/drumgizmo/output/alsa/alsa.cc
@@ -49,6 +49,7 @@ public:
void pre(size_t size);
void run(int channel, sample_t* data, size_t size);
void post(size_t size);
+ size_t samplerate();
private:
snd_pcm_t *handle;
@@ -157,6 +158,11 @@ void Alsa::post(size_t size)
snd_pcm_writei(handle, data, size);
}
+size_t Alsa::samplerate()
+{
+ return srate;
+}
+
extern "C" {
void *create()
{
@@ -210,21 +216,10 @@ extern "C" {
Alsa *alsa = (Alsa*)h;
alsa->post(s);
}
-}
-
-#ifdef TEST_AUDIOOUTPUTENGINEALSA
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_AUDIOOUTPUTENGINEALSA*/
+ size_t samplerate(void *h)
+ {
+ Alsa *alsa = (Alsa*)h;
+ return alsa->samplerate();
+ }
+}
diff --git a/drumgizmo/output/dummy/dummy.cc b/drumgizmo/output/dummy/dummy.cc
index cd210dc..e60f2b7 100644
--- a/drumgizmo/output/dummy/dummy.cc
+++ b/drumgizmo/output/dummy/dummy.cc
@@ -43,6 +43,8 @@ public:
void pre(size_t size);
void run(int channel, sample_t* data, size_t size);
void post(size_t size);
+
+ size_t samplerate();
};
Dummy::Dummy()
@@ -83,6 +85,11 @@ void Dummy::post(size_t size)
{
}
+size_t Dummy::samplerate()
+{
+ return 44100;
+}
+
extern "C" {
void *create()
{
@@ -136,21 +143,10 @@ extern "C" {
Dummy *dummy = (Dummy*)h;
dummy->post(size);
}
-}
-
-#ifdef TEST_AUDIOOUTPUTENGINEDUMMY
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_AUDIOOUTPUTENGINEDUMMY*/
+ size_t samplerate(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->samplerate();
+ }
+}
diff --git a/drumgizmo/output/jackaudio/jackaudio.cc b/drumgizmo/output/jackaudio/jackaudio.cc
index 2afe1ea..5c04146 100644
--- a/drumgizmo/output/jackaudio/jackaudio.cc
+++ b/drumgizmo/output/jackaudio/jackaudio.cc
@@ -54,6 +54,7 @@ public:
void jack_process(jack_nframes_t nframes);
size_t bufsize();
+ size_t samplerate();
private:
JackClient *jackclient;
@@ -146,6 +147,11 @@ size_t JackAudio::bufsize()
return jack_get_buffer_size(jackclient->jack_client);
}
+size_t JackAudio::samplerate()
+{
+ return jack_get_sample_rate(jackclient->jack_client);
+}
+
extern "C" {
void *create()
{
@@ -205,21 +211,10 @@ extern "C" {
JackAudio *jack = (JackAudio*)h;
return jack->bufsize();
}
-}
-
-#ifdef TEST_AUDIOINPUTENGINEJACKAUDIO
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_AUDIOINPUTENGINEJACKAUDIO*/
+ size_t samplerate(void *h)
+ {
+ JackAudio *jack = (JackAudio*)h;
+ return jack->samplerate();
+ }
+}
diff --git a/drumgizmo/output/wavfile/wavfile.cc b/drumgizmo/output/wavfile/wavfile.cc
index cb95715..fa4128e 100644
--- a/drumgizmo/output/wavfile/wavfile.cc
+++ b/drumgizmo/output/wavfile/wavfile.cc
@@ -44,6 +44,7 @@ public:
void pre(size_t size);
void run(int channel, sample_t* data, size_t size);
void post(size_t size);
+ size_t samplerate();
private:
SF_INFO sf_info;
@@ -58,6 +59,10 @@ WavFile::WavFile()
{
fh = NULL;
filename = "output";
+
+ sf_info.channels = 1;//channels;
+ sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
+ sf_info.samplerate = 44100;
}
WavFile::~WavFile()
@@ -74,10 +79,6 @@ WavFile::~WavFile()
bool WavFile::init(int channels, char *cnames[])
{
this->channels = channels;
-
- sf_info.channels = 1;//channels;
- sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
- sf_info.samplerate = 44100;
fh = (SNDFILE **)malloc(sizeof(SNDFILE *)*channels);
@@ -102,6 +103,7 @@ bool WavFile::init(int channels, char *cnames[])
void WavFile::setParm(std::string parm, std::string value)
{
if(parm == "file") filename = value;
+ if(parm == "srate") sf_info.samplerate = atoi(value.c_str());
}
bool WavFile::start()
@@ -126,6 +128,11 @@ void WavFile::post(size_t size)
{
}
+size_t WavFile::samplerate()
+{
+ return sf_info.samplerate;
+}
+
extern "C" {
void *create()
{
@@ -179,21 +186,10 @@ extern "C" {
WavFile *sndfile = (WavFile*)h;
sndfile->post(s);
}
-}
-
-#ifdef TEST_AUDIOOUTPUTENGINESNDFILE
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-TEST_END;
-
-#endif/*TEST_AUDIOOUTPUTENGINESNDFILE*/
+ size_t samplerate(void *h)
+ {
+ WavFile *wavfile = (WavFile*)h;
+ return wavfile->samplerate();
+ }
+}
diff --git a/hugin b/hugin
-Subproject 7e734710be0098ea77ca2d3f54fb626b65bbf47
+Subproject bb7388b685ed043b4a3030da86f7f1e49141477
diff --git a/lv2/Makefile.am b/lv2/Makefile.am
index a714dce..9939131 100644
--- a/lv2/Makefile.am
+++ b/lv2/Makefile.am
@@ -3,12 +3,6 @@ if ENABLE_LV2
include $(top_srcdir)/plugingui/Makefile.am.plugingui
include $(top_srcdir)/src/Makefile.am.drumgizmo
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/plugingui \
- -I$(top_srcdir)/include $(SNDFILE_CXXFLAGS) \
- $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) $(LV2_CFLAGS) \
- $(PLUGIN_GUI_CFLAGS) $(SSEFLAGS)\
- -DUSE_THREAD $(SAMPLERATE_CFLAGS)
-
plugindir = $(prefix)/lib/lv2/drumgizmo.lv2
plugin_LTLIBRARIES = drumgizmo.la
plugin_DATA = manifest.ttl drumgizmo.ttl
@@ -21,6 +15,12 @@ EXTRA_DIST = \
lv2_gui.h \
lv2_instance.h
+drumgizmo_la_CXXFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/plugingui \
+ -I$(top_srcdir)/include $(SNDFILE_CXXFLAGS) \
+ $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) $(LV2_CFLAGS) \
+ $(PLUGIN_GUI_CFLAGS) $(SSEFLAGS) $(ZITA_CPPFLAGS) \
+ -DUSE_THREAD $(SAMPLERATE_CFLAGS)
+
drumgizmo_la_SOURCES = \
$(DRUMGIZMO_SOURCES) \
$(PLUGIN_GUI_SOURCES) \
diff --git a/lv2/output_lv2.cc b/lv2/output_lv2.cc
index 8187a5a..ef2500b 100644
--- a/lv2/output_lv2.cc
+++ b/lv2/output_lv2.cc
@@ -82,20 +82,3 @@ sample_t *OutputLV2::getBuffer(int ch)
if(ch < NUM_OUTPUTS) return outputPorts[ch].samples;
return NULL;
}
-
-#ifdef TEST_OUTPUT_LV2
-//Additional dependency files
-//deps:
-//Required cflags (autoconf vars may be used)
-//cflags:
-//Required link options (autoconf vars may be used)
-//libs:
-#include "test.h"
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-
-TEST_END;
-
-#endif/*TEST_OUTPUT_LV2*/
diff --git a/src/Makefile.am.drumgizmo b/src/Makefile.am.drumgizmo
index c48c478..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 \
@@ -26,4 +27,4 @@ DRUMGIZMO_SOURCES = \
$(top_srcdir)/src/velocity.cc \
$(top_srcdir)/src/versionstr.cc
-DRUMGIZMO_LIBS = $(SNDFILE_LIBS) $(EXPAT_LIBS) $(SAMPLERATE_LIBS) \ No newline at end of file
+DRUMGIZMO_LIBS = $(ZITA_LIBS) $(SNDFILE_LIBS) $(EXPAT_LIBS) $(SAMPLERATE_LIBS) \ No newline at end of file
diff --git a/src/audiofile.cc b/src/audiofile.cc
index 874b9c5..59e0c14 100644
--- a/src/audiofile.cc
+++ b/src/audiofile.cc
@@ -34,9 +34,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <sndfile.h>
-#ifdef WITH_RESAMPLE
-#include <samplerate.h>
-#endif/*WITH_RESAMPLE*/
#include <hugin.hpp>
#include "configuration.h"
@@ -154,39 +151,6 @@ void AudioFile::load(int num_samples)
sf_close(fh);
-#ifdef WITH_RESAMPLE
-
- // Check environment to see if resample should be disabled.
- // Defaults to "1" which is 'enable'. All other values are 'disabled'.
- const char *env_res = getenv("DRUMGIZMO_RESAMPLE");
- if(env_res == NULL) env_res = "1";
-
- if( (strcmp(env_res, "1") == 0) &&
- Conf::samplerate != sf_info.samplerate) {
- // Resample data...
- size_t osize = size * ratio;
- sample_t *odata = new sample_t[osize];
-
- SRC_DATA src;
- src.data_in = data;
- src.input_frames = size;
-
- src.data_out = odata;
- src.output_frames = osize;
-
- src.src_ratio = ratio;
-
- // Do the conversion
- src_simple(&src, SRC_SINC_BEST_QUALITY, 1);
-
- delete[] data;
- data = odata;
- size = src.output_frames;
-
- DEBUG(audiofile,"Converted into %d samples %p\n", (int)size, this);
- }
-#endif/*WITH_RESAMPLE*/
-
this->data = data;
is_loaded = true;
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 0337fae..6b48cda 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -36,6 +36,8 @@
#include <hugin.hpp>
+#include <config.h>
+
#include "drumkitparser.h"
#include "audioinputenginemidi.h"
#include "configuration.h"
@@ -71,6 +73,12 @@ bool DrumGizmo::loadkit(std::string file)
loader.loadKit(&kit);
+#ifdef WITH_RESAMPLER
+ for(int i = 0; i < MAX_NUM_CHANNELS; i++) {
+ resampler[i].setup(kit.samplerate(), Conf::samplerate);
+ }
+#endif/*WITH_RESAMPLER*/
+
DEBUG(loadkit, "loadkit: Success\n");
return true;
@@ -239,7 +247,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;
+ evt->offset = (evs[e].offset + pos) * resampler[0].ratio();
activeevents[ch.num].push_back(evt);
}
j++;
@@ -253,11 +261,12 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
}
free(evs);
-
-
+
//
// Write audio
//
+#ifndef WITH_RESAMPLER
+ // No resampling needed
for(size_t c = 0; c < kit.channels.size(); c++) {
sample_t *buf = samples;
bool internal = false;
@@ -269,9 +278,49 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
memset(buf, 0, nsamples * sizeof(sample_t));
getSamples(c, pos, buf, nsamples);
+
if(!internal) oe->run(c, samples, nsamples);
}
}
+#else/*WITH_RESAMPLER*/
+ // Resampling needed
+
+ //
+ // 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)
+ //
+
+ // 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);
@@ -332,7 +381,7 @@ 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) {
@@ -391,6 +440,12 @@ int DrumGizmo::samplerate()
void DrumGizmo::setSamplerate(int samplerate)
{
Conf::samplerate = samplerate;
+#ifdef WITH_RESAMPLER
+ for(int i = 0; i < MAX_NUM_CHANNELS; i++) {
+ resampler[i].setup(kit.samplerate(), Conf::samplerate);
+ }
+#endif/*WITH_RESAMPLER*/
+
}
std::string float2str(float a)
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
diff --git a/src/drumkit.cc b/src/drumkit.cc
index c2aa221..4d75f3b 100644
--- a/src/drumkit.cc
+++ b/src/drumkit.cc
@@ -50,6 +50,7 @@ void DrumKit::clear()
_name = "";
_description = "";
+ _samplerate = 44100;
}
bool DrumKit::isValid()
@@ -72,6 +73,11 @@ std::string DrumKit::description()
return _description;
}
+size_t DrumKit::samplerate()
+{
+ return _samplerate;
+}
+
#ifdef TEST_DRUMKIT
//Additional dependency files
//deps:
diff --git a/src/drumkit.h b/src/drumkit.h
index 82fe69b..04b2c56 100644
--- a/src/drumkit.h
+++ b/src/drumkit.h
@@ -53,6 +53,8 @@ public:
bool isValid();
+ size_t samplerate();
+
private:
void *magic;
@@ -60,6 +62,7 @@ private:
std::string _name;
std::string _description;
+ size_t _samplerate;
VersionStr _version;
};
diff --git a/src/drumkitparser.cc b/src/drumkitparser.cc
index 1b7ecaf..2c21c52 100644
--- a/src/drumkitparser.cc
+++ b/src/drumkitparser.cc
@@ -60,6 +60,14 @@ void DrumKitParser::startTag(std::string name,
if(attr.find("name") != attr.end())
kit._name = attr["name"];
+ if(attr.find("samplerate") != attr.end()) {
+ kit._samplerate = atoi(attr["samplerate"].c_str());
+ } else {
+ // If 'samplerate' attribute is missing, assume 44k1Hz
+ // TODO: Ask instrument what samplerate is in the audiofiles...
+ kit._samplerate = 44100;
+ }
+
if(attr.find("description") != attr.end())
kit._description = attr["description"];
diff --git a/test/Makefile.am b/test/Makefile.am
index 77a0f96..e43a6ba 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,18 +1,15 @@
# Rules for the test code (use `make check` to execute)
include $(top_srcdir)/src/Makefile.am.drumgizmo
-TESTS = engine gui
+TESTS = engine gui resampler
check_PROGRAMS = $(TESTS)
engine_CXXFLAGS = -DOUTPUT=\"engine\" $(CPPUNIT_CFLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/include \
-I$(top_srcdir)/hugin -DDISABLE_HUGIN
-
engine_CFLAGS = -DDISABLE_HUGIN
-
engine_LDFLAGS = $(CPPUNIT_LIBS) $(DRUMGIZMO_LIBS) $(PTHREAD_LIBS)
-
engine_SOURCES = \
$(DRUMGIZMO_SOURCES) \
$(top_srcdir)/hugin/hugin.c \
@@ -24,3 +21,12 @@ gui_LDFLAGS = $(CPPUNIT_LIBS)
gui_SOURCES = \
test.cc \
gui.cc
+
+resampler_CXXFLAGS = -DOUTPUT=\"resampler\" $(CPPUNIT_CFLAGS) \
+ $(ZITA_CXXFLAGS) $(SAMPLERATE_CFLAGS) \
+ -I$(top_srcdir)/hugin -DDISABLE_HUGIN
+resampler_LDFLAGS = $(ZITA_LIBS) $(SAMPLERATE_LIBS) $(CPPUNIT_LIBS)
+resampler_SOURCES = \
+ $(top_srcdir)/src/chresampler.cc \
+ test.cc \
+ resampler.cc \ No newline at end of file
diff --git a/test/resampler.cc b/test/resampler.cc
new file mode 100644
index 0000000..445a5b3
--- /dev/null
+++ b/test/resampler.cc
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * resampler.cc
+ *
+ * Sun Oct 5 20:16:22 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 <cppunit/extensions/HelperMacros.h>
+
+#include "../src/chresampler.h"
+#include <unistd.h>
+
+#define BUFSZ 500
+
+static float round(float a) { return a<0.5?0:1; }
+
+class test_resampler : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(test_resampler);
+ CPPUNIT_TEST(resampling);
+ CPPUNIT_TEST(resampling_buffer_sizes);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() {}
+ void tearDown() {}
+
+ void resampling()
+ {
+ CHResampler r;
+ CPPUNIT_ASSERT_EQUAL(1.0, r.ratio());
+
+ r.setup(44100, 48000);
+ CPPUNIT_ASSERT_EQUAL(44100.0/48000.0, r.ratio());
+
+ float in[BUFSZ];
+ for(int i = 0; i < BUFSZ; i++) in[i] = 0;//(float)i/(float)BUFSZ;
+ in[100] = 1.0;
+
+ float out[BUFSZ];
+ r.setInputSamples(in, sizeof(in) / sizeof(float));
+ r.setOutputSamples(out, sizeof(out) / sizeof(float));
+ r.process();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, r.getInputSampleCount());
+
+ // CPPUNIT_ASSERT_EQUAL(, r.getOutputSampleCount());
+
+ int outidx = -1;
+ int inidx = -1;
+ for(int i = 0; i < BUFSZ - (int)r.getOutputSampleCount(); i++) {
+ if(in[i] == 1.0) inidx = i;
+ if(round(out[i]) == 1.0) outidx = i;
+ //printf("in[% 4d]\t= %f\t", i, in[i]);
+ //printf("out[% 4d]\t= %f\n", i, out[i]);
+ }
+
+ CPPUNIT_ASSERT(inidx != -1);
+ CPPUNIT_ASSERT(outidx != -1);
+
+ //printf("inidx: %d - outidx: %d\n", inidx, outidx);
+ //CPPUNIT_ASSERT_EQUAL(71, inidx - outidx); // This does not make sense...
+ }
+
+ void resampling_buffer_sizes()
+ {
+ CHResampler r;
+ CPPUNIT_ASSERT_EQUAL(1.0, r.ratio());
+
+ double infs = 24000;
+ double outfs = 48000;
+ r.setup(infs, outfs);
+ CPPUNIT_ASSERT_EQUAL(infs / outfs, r.ratio());
+
+ float in[BUFSZ];
+ float out[(int)(BUFSZ / r.ratio())];
+
+ // Preload resampler
+ r.setOutputSamples(out, 1);
+ while(r.getOutputSampleCount()) {
+ r.setInputSamples(in, 1);
+ r.process();
+ }
+
+ r.setInputSamples(in, sizeof(in) / sizeof(float));
+ r.setOutputSamples(out, sizeof(out) / sizeof(float));
+ r.process();
+ CPPUNIT_ASSERT_EQUAL((size_t)0, r.getInputSampleCount());
+ CPPUNIT_ASSERT_EQUAL((size_t)0, r.getOutputSampleCount());
+ }
+};
+
+// Registers the fixture into the 'registry'
+CPPUNIT_TEST_SUITE_REGISTRATION(test_resampler);
diff --git a/vst/Makefile.mingw32.in b/vst/Makefile.mingw32.in
index f8aab4d..66e02ed 100644
--- a/vst/Makefile.mingw32.in
+++ b/vst/Makefile.mingw32.in
@@ -11,6 +11,7 @@ DG_SRC = \
@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 \
@@ -92,7 +93,10 @@ ZLIB_CFLAGS=@ZLIB_CFLAGS@
ZLIB_LIBS=@ZLIB_LIBS@
SRC_CFLAGS=@SAMPLERATE_CFLAGS@
-SRC_LIBS=@SAMPLERATE_CFLAGS@
+SRC_LIBS=@SAMPLERATE_LIBS@
+
+ZITA_CXXFLAGS=@ZITA_CPPFLAGS@
+ZITA_LIBS=@ZITA_LIBS@
SRC = \
drumgizmo_vst.cc \
@@ -133,7 +137,7 @@ SRC = \
all:
gcc $(DBG_CFLAGS) @top_srcdir@/hugin/hugin.c -c
gcc $(DBG_CFLAGS) @top_srcdir@/hugin/hugin_syslog.c -c
- g++ -static -static-libgcc -O2 -g -Wall $(DBG_CFLAGS) $(DG_CFLAGS) $(DG_LIBS) $(VST_CFLAGS) hugin.o hugin_syslog.o $(DG_SRC) $(VST_SRC) ${SRC} ${GUI_SRC} ${GUI_CFLAGS} $(GUI_LIBS) $(EXPAT_CFLAGS) $(ZLIB_CFLAGS) $(SRC_CFLAGS) $(EXPAT_LIBS) $(ZLIB_LIBS) $(SNDFILE_CFLAGS) $(SNDFILE_LIBS) $(SRC_LIBS) -shared -o drumgizmo_vst.dll -Wl,--out-implib,libdrumgizmo_vst.a
+ g++ -static -static-libgcc -O2 -g -Wall $(DBG_CFLAGS) $(DG_CFLAGS) $(DG_LIBS) $(VST_CFLAGS) hugin.o hugin_syslog.o $(DG_SRC) $(VST_SRC) ${SRC} ${GUI_SRC} ${GUI_CFLAGS} $(GUI_LIBS) $(EXPAT_CFLAGS) $(ZLIB_CFLAGS) $(SRC_CFLAGS) $(ZITA_CXXFLAGS) $(EXPAT_LIBS) $(ZLIB_LIBS) $(SNDFILE_CFLAGS) $(SNDFILE_LIBS) $(SRC_LIBS) $(ZITA_LIBS) -shared -o drumgizmo_vst.dll -Wl,--out-implib,libdrumgizmo_vst.a
clean:
del -f drumgizmo_vst.dll libdrumgizmo_vst.a