diff options
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | configure.ac | 83 | ||||
| -rw-r--r-- | drumgizmo/audiooutputenginedl.cc | 28 | ||||
| -rw-r--r-- | drumgizmo/audiooutputenginedl.h | 3 | ||||
| -rw-r--r-- | drumgizmo/drumgizmoc.cc | 4 | ||||
| -rw-r--r-- | drumgizmo/output/alsa/alsa.cc | 29 | ||||
| -rw-r--r-- | drumgizmo/output/dummy/dummy.cc | 30 | ||||
| -rw-r--r-- | drumgizmo/output/jackaudio/jackaudio.cc | 29 | ||||
| -rw-r--r-- | drumgizmo/output/wavfile/wavfile.cc | 38 | ||||
| m--------- | hugin | 0 | ||||
| -rw-r--r-- | lv2/Makefile.am | 12 | ||||
| -rw-r--r-- | lv2/output_lv2.cc | 17 | ||||
| -rw-r--r-- | src/Makefile.am.drumgizmo | 3 | ||||
| -rw-r--r-- | src/audiofile.cc | 36 | ||||
| -rw-r--r-- | src/chresampler.cc | 170 | ||||
| -rw-r--r-- | src/chresampler.h | 65 | ||||
| -rw-r--r-- | src/drumgizmo.cc | 63 | ||||
| -rw-r--r-- | src/drumgizmo.h | 8 | ||||
| -rw-r--r-- | src/drumkit.cc | 6 | ||||
| -rw-r--r-- | src/drumkit.h | 3 | ||||
| -rw-r--r-- | src/drumkitparser.cc | 8 | ||||
| -rw-r--r-- | test/Makefile.am | 14 | ||||
| -rw-r--r-- | test/resampler.cc | 112 | ||||
| -rw-r--r-- | vst/Makefile.mingw32.in | 8 | 
24 files changed, 606 insertions, 169 deletions
| @@ -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 | 
