diff options
-rw-r--r-- | INSTALL | 8 | ||||
-rw-r--r-- | configure.ac | 83 | ||||
-rw-r--r-- | drumgizmo/audiooutputenginedl.cc | 12 | ||||
-rw-r--r-- | drumgizmo/audiooutputenginedl.h | 3 | ||||
-rw-r--r-- | drumgizmo/output/jackaudio/jackaudio.cc | 12 | ||||
m--------- | hugin | 0 | ||||
-rw-r--r-- | lv2/Makefile.am | 12 | ||||
-rw-r--r-- | lv2/lv2.cc | 2 | ||||
-rw-r--r-- | lv2/output_lv2.cc | 22 | ||||
-rw-r--r-- | lv2/output_lv2.h | 6 | ||||
-rw-r--r-- | plugingui/Makefile.am | 1 | ||||
-rw-r--r-- | plugingui/Makefile.am.plugingui | 7 | ||||
-rw-r--r-- | plugingui/Makefile.mingw32 | 1 | ||||
-rw-r--r-- | plugingui/directory.cc | 40 | ||||
-rw-r--r-- | plugingui/pluginconfig.cc | 165 | ||||
-rw-r--r-- | plugingui/pluginconfig.h | 48 | ||||
-rw-r--r-- | plugingui/plugingui.cc | 28 | ||||
-rw-r--r-- | plugingui/plugingui.h | 3 | ||||
-rw-r--r-- | src/Makefile.am.drumgizmo | 3 | ||||
-rw-r--r-- | src/audiofile.cc | 36 | ||||
-rw-r--r-- | src/audiooutputengine.h | 7 | ||||
-rw-r--r-- | src/chresampler.cc | 170 | ||||
-rw-r--r-- | src/chresampler.h | 65 | ||||
-rw-r--r-- | src/drumgizmo.cc | 67 | ||||
-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 | 13 |
29 files changed, 740 insertions, 99 deletions
@@ -1,7 +1,7 @@ Installation Instructions ************************* -Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, @@ -309,10 +309,9 @@ causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf limitation. Until the limitation is lifted, you can use -this workaround: +an Autoconf bug. Until the bug is fixed you can use this workaround: - CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== @@ -368,3 +367,4 @@ operates. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. + diff --git a/configure.ac b/configure.ac index 8900d50..37e3013 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" + LIBS="" + AC_CHECK_HEADER(zita-resampler/resampler.h, + AC_CHECK_LIB(zita-resampler, _Z28zita_resampler_major_versionv, has_zita=yes, has_zita=no), + has_zita=no) + ZITA_CPPFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS" + ZITA_LIBS="$LDFLAGS $LIBS -lzita-resampler" + 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..fcedd9d 100644 --- a/drumgizmo/audiooutputenginedl.cc +++ b/drumgizmo/audiooutputenginedl.cc @@ -111,6 +111,12 @@ AudioOutputEngineDL::AudioOutputEngineDL(std::string name) o_bufsize = NULL; } + o_samplerate = (output_samplerate_func_t) dlsym(lib, "samplerate"); + dlsym_error = dlerror(); + if(dlsym_error) { + o_samplerate = NULL; + } + ptr = o_create(); if(is_jack_plugin) { @@ -181,6 +187,12 @@ size_t AudioOutputEngineDL::getBufferSize() return 1024; } +size_t AudioOutputEngineDL::samplerate() +{ + if(o_samplerate) return o_samplerate(ptr); + return UNKNOWN_SAMPLERATE; +} + #ifdef TEST_AUDIOOUTPUTENGINEDL //Additional dependency files //deps: 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/output/jackaudio/jackaudio.cc b/drumgizmo/output/jackaudio/jackaudio.cc index 2afe1ea..b7fa4f9 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,6 +211,12 @@ extern "C" { JackAudio *jack = (JackAudio*)h; return jack->bufsize(); } + + size_t samplerate(void *h) + { + JackAudio *jack = (JackAudio*)h; + return jack->samplerate(); + } } #ifdef TEST_AUDIOINPUTENGINEJACKAUDIO 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) \ @@ -248,7 +248,7 @@ LV2_Handle instantiate(const struct _LV2_Descriptor *descriptor, dg_descriptor.get_pci = dg_get_pci; dglv2->in = new InputLV2(); - dglv2->out = new OutputLV2(); + dglv2->out = new OutputLV2(sample_rate); dglv2->buffer = NULL; dglv2->buffer_size = 0; diff --git a/lv2/output_lv2.cc b/lv2/output_lv2.cc index 8187a5a..b4a6877 100644 --- a/lv2/output_lv2.cc +++ b/lv2/output_lv2.cc @@ -28,8 +28,9 @@ #include <string.h> -OutputLV2::OutputLV2() +OutputLV2::OutputLV2(double sample_rate) { + this->sample_rate = sample_rate; for(size_t i = 0; i < NUM_OUTPUTS; i++) { outputPorts[i].size = 0; outputPorts[i].samples = NULL; @@ -83,19 +84,8 @@ sample_t *OutputLV2::getBuffer(int ch) 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; +size_t OutputLV2::samplerate() +{ + return sample_rate; +} -#endif/*TEST_OUTPUT_LV2*/ diff --git a/lv2/output_lv2.h b/lv2/output_lv2.h index 1b4e8c9..272a78c 100644 --- a/lv2/output_lv2.h +++ b/lv2/output_lv2.h @@ -39,7 +39,7 @@ public: class OutputLV2 : public AudioOutputEngine { public: - OutputLV2(); + OutputLV2(double sample_rate); ~OutputLV2(); bool init(Channels channels); @@ -54,9 +54,13 @@ public: void post(size_t nsamples); sample_t *getBuffer(int c); + + size_t samplerate(); // sample_t *outputPort[NUM_OUTPUTS]; OutputPort outputPorts[NUM_OUTPUTS]; + + double sample_rate; }; #endif/*__DRUMGIZMO_OUTPUT_LV2_H__*/ diff --git a/plugingui/Makefile.am b/plugingui/Makefile.am index 3cf60a5..32228f4 100644 --- a/plugingui/Makefile.am +++ b/plugingui/Makefile.am @@ -26,6 +26,7 @@ EXTRA_DIST = \ button.h \ checkbox.h \ colour.h \ + pluginconfig.h \ combobox.h \ directory.h \ eventhandler.h \ diff --git a/plugingui/Makefile.am.plugingui b/plugingui/Makefile.am.plugingui index 0b4f2d2..bd703b2 100644 --- a/plugingui/Makefile.am.plugingui +++ b/plugingui/Makefile.am.plugingui @@ -1,10 +1,4 @@ -if ENABLE_PUGL -puglsources = $(top_srcdir)/pugl/pugl/pugl_x11.c $(top_srcdir)/plugingui/nativewindow_pugl.cc -else -puglsources = -endif - PLUGIN_GUI_SOURCES = \ $(top_srcdir)/hugin/hugin.c \ $(top_srcdir)/hugin/hugin_syslog.c \ @@ -36,6 +30,7 @@ PLUGIN_GUI_SOURCES = \ $(top_srcdir)/plugingui/combobox.cc \ $(top_srcdir)/plugingui/progressbar.cc \ $(top_srcdir)/plugingui/verticalline.cc \ + $(top_srcdir)/plugingui/pluginconfig.cc \ $(top_srcdir)/plugingui/resource.cc \ $(top_srcdir)/plugingui/resource_data.cc \ $(top_srcdir)/plugingui/lodepng/lodepng.cpp diff --git a/plugingui/Makefile.mingw32 b/plugingui/Makefile.mingw32 index 3a9542a..7863463 100644 --- a/plugingui/Makefile.mingw32 +++ b/plugingui/Makefile.mingw32 @@ -40,6 +40,7 @@ CXX_SOURCES = \ $(top_srcdir)/plugingui/resource.cc \ $(top_srcdir)/plugingui/resource_data.cc \ $(top_srcdir)/plugingui/lodepng/lodepng.cpp \ + $(top_srcdir)/plugingui/pluginconfig.cc \ $(top_srcdir)/src/thread.cc \ $(top_srcdir)/src/semaphore.cc \ $(top_srcdir)/src/mutex.cc \ diff --git a/plugingui/directory.cc b/plugingui/directory.cc index 9ebfe70..1465c86 100644 --- a/plugingui/directory.cc +++ b/plugingui/directory.cc @@ -34,9 +34,7 @@ #include <string.h> #ifdef WIN32 -#ifdef __MINGW32__ #include <direct.h> -#endif #include <windows.h> #endif @@ -153,7 +151,7 @@ Directory::EntryList Directory::listFiles(std::string path, unsigned char filter if(Directory::isRoot(path) && name == "..") continue; unsigned char entryinfo = 0; - if(isHidden(name)) { + if(isHidden(path + SEP + name)) { entryinfo |= DIRECTORY_HIDDEN; } @@ -183,8 +181,8 @@ Directory::EntryList Directory::listFiles(std::string path, unsigned char filter #ifdef WIN32 - DEBUG(directory, "root is %s\n", Directory::root(path).c_str()); - DEBUG(directory, "current path %s is root? %d", path.c_str(), Directory::isRoot(path)); + DEBUG(directory, "Root is %s\n", Directory::root(path).c_str()); + DEBUG(directory, "Current path %s is root? %d", path.c_str(), Directory::isRoot(path)); if(Directory::isRoot(path)) entries.push_back(".."); #endif @@ -291,15 +289,15 @@ bool Directory::isDir() bool Directory::isDir(std::string path) { - DEBUG(directory, "Is '%s' dir?\n", path.c_str()); + DEBUG(directory, "Is '%s' a directory?\n", path.c_str()); struct stat st; if(stat(path.c_str(), &st) == 0) { if((st.st_mode & S_IFDIR) != 0) { - DEBUG(directory, "Yes\n"); + DEBUG(directory, "\t...yes!\n"); return true; } } - DEBUG(directory, "No\n"); + DEBUG(directory, "\t...no!\n"); return false; } @@ -320,19 +318,39 @@ bool Directory::exists(std::string path) bool Directory::isHidden(std::string path) { - // TODO: Handle hidden and system files in windows + DEBUG(directory, "Is '%s' hidden?\n", path.c_str()); #ifdef WIN32 - return false; -#else + // We dont want to filter out '..' pointing to root of a partition unsigned pos = path.find_last_of("/\\"); std::string entry = path.substr(pos+1); + if(entry == "..") { + return false; + } + DWORD fattribs = GetFileAttributes(path.c_str()); + if(fattribs & FILE_ATTRIBUTE_HIDDEN) { + DEBUG(directory, "\t...yes!\n"); + return true; + } + else if(fattribs & FILE_ATTRIBUTE_SYSTEM) { + DEBUG(directory, "\t...yes!\n"); + return true; + } + else { + DEBUG(directory, "\t...no!\n"); + return false; + } +#else + unsigned pos = path.find_last_of("/\\"); + std::string entry = path.substr(pos+1); if(entry.size() > 1 && entry.at(0) == '.' && entry.at(1) != '.') { + DEBUG(directory, "\t...yes!\n"); return true; } else { + DEBUG(directory, "\t...no!\n"); return false; } #endif diff --git a/plugingui/pluginconfig.cc b/plugingui/pluginconfig.cc new file mode 100644 index 0000000..d57d9df --- /dev/null +++ b/plugingui/pluginconfig.cc @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * config.cc + * + * Tue Jun 3 13:54:05 CEST 2014 + * Copyright 2014 Jonas Suhr Christensen + * jsc@umbraculum.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 "pluginconfig.h" + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "directory.h" + +#ifdef WIN32 +#include <direct.h> +#include <windows.h> +#include <Shlobj.h> +#include <Shlwapi.h> +#else +#endif + +#include <hugin.hpp> + +#define CONFIGFILENAME "plugingui.conf" + +#ifdef WIN32 + #define SEP "\\" + #define CONFIGDIRNAME ".drumgizmo" +#else + #define SEP "/" + #define CONFIGDIRNAME ".drumgizmo" +#endif + +Config::Config() +{ + +} + +Config::~Config() +{ + +} + +static std::string configPath() { + #ifdef WIN32 + std::string configpath; + TCHAR szPath[256]; + if(SUCCEEDED(SHGetFolderPath(NULL, + CSIDL_APPDATA | CSIDL_FLAG_CREATE, + NULL, + 0, + szPath))); { + configpath = szPath; + } +#else + std::string configpath = strdup(getenv("HOME")); +#endif + configpath += SEP; + configpath += CONFIGDIRNAME; + + return configpath; +} + +static bool createConfigPath() { + std::string configpath = configPath(); + + if(!Directory::exists(configpath)) { + DEBUG(pluginconfig, "No configuration exists, creating directory '%s'\n", configpath.c_str()); +#ifdef WIN32 + if( (mkdir(configpath.c_str())) < 0) { +#else + if( (mkdir(configpath.c_str(), 0755)) < 0) { +#endif + DEBUG(pluginconfig, "Could not create config directory\n"); + } + return false; + } + + return true; +} + +static FILE* openConfigFile(std::string mode) { + + std::string configpath = configPath(); + + FILE *fp; + std::string configfile = configpath; + configfile += SEP; + configfile += CONFIGFILENAME; + + DEBUG(pluginconfig, "Opening config file '%s'\n", configfile.c_str()); + if(! (fp = fopen(configfile.c_str(), mode.c_str())) ) { + return NULL; + } + + return fp; +} + +void Config::load() +{ + DEBUG(pluginconfig, "Loading config file...\n"); + FILE *fp = openConfigFile("r"); + if(!fp) return; + + lastkit.clear(); + lastmidimap.clear(); + + char buf[4096]; + while( fgets(buf, 4096, fp) ) { + if(!strncmp(buf, "lastkit:", 8)) { + DEBUG(pluginconfig, "Loading last kit path\n"); + // Dont copy newline + if(strlen(buf) > 8 + 1) { + lastkit.append(buf+8, strlen(buf+8) - 1); + DEBUG(pluginconfig, "\t path is %s\n", lastkit.c_str()); + } + } + if(!strncmp(buf, "lastmidimap:", 12)) { + DEBUG(pluginconfig, "Loading lastmidimap path\n"); + // Dont copy newline + if(strlen(buf) > 12+1) lastmidimap.append(buf+12, strlen(buf+12) - 1); + DEBUG(pluginconfig, "\t path is %s\n", lastmidimap.c_str()); + } + } +} + +void Config::save() +{ + DEBUG(pluginconfig, "Saving configuration...\n"); + + createConfigPath(); + + FILE *fp = openConfigFile("w"); + if(!fp) return; + + std::string buf; + buf.append("lastkit:" + lastkit + '\n'); + buf.append("lastmidimap:" + lastmidimap + '\n'); + + fputs(buf.c_str(), fp); + + fclose(fp); +} diff --git a/plugingui/pluginconfig.h b/plugingui/pluginconfig.h new file mode 100644 index 0000000..d0e9bcd --- /dev/null +++ b/plugingui/pluginconfig.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * config.h + * + * Tue Jun 3 13:51:29 CEST 2014 + * Copyright 2014 Jonas Suhr Christensen + * jsc@umbraculum.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_CONFIG_H__ +#define __DRUMGIZMO_CONFIG_H__ + +#include <string> +#include <list> + +#define DIRECTORY_HIDDEN 1 + +class Config { + + public: + Config(); + ~Config(); + + void load(); + void save(); + + std::string lastkit; + std::string lastmidimap; +}; + +#endif/*__DRUMGIZMO_CONFIG_H__*/ diff --git a/plugingui/plugingui.cc b/plugingui/plugingui.cc index 6601be7..b235af3 100644 --- a/plugingui/plugingui.cc +++ b/plugingui/plugingui.cc @@ -33,6 +33,7 @@ #include "verticalline.h" #include "../version.h" +#include "pluginconfig.h" #include "messagehandler.h" static void checkClick(void *ptr) @@ -81,6 +82,12 @@ static void knobChange2(void *ptr) #endif } +//static void quit(void *ptr) { +// PluginGUI *gui = (PluginGUI*)ptr; +// +// gui->stopThread(); +//} + GUI::FileBrowser *fb; static void selectKitFile(void *ptr, std::string filename) { @@ -91,6 +98,8 @@ static void selectKitFile(void *ptr, std::string filename) std::string drumkit = gui->lineedit->text(); + gui->config->lastkit = drumkit; + gui->progress->setProgress(0); gui->progress->setState(GUI::ProgressBar::blue); @@ -105,6 +114,7 @@ static void kitBrowseClick(void *ptr) PluginGUI *gui = (PluginGUI*)ptr; std::string path = gui->lineedit->text(); + if(path == "") path = gui->config->lastkit; if(path == "") path = gui->lineedit2->text(); fb->setPath(path); @@ -121,6 +131,8 @@ static void selectMapFile(void *ptr, std::string filename) std::string midimap = gui->lineedit2->text(); + gui->config->lastmidimap = midimap; + LoadMidimapMessage *msg = new LoadMidimapMessage(); msg->midimapfile = midimap; msghandler.sendMessage(MSGRCV_ENGINE, msg); @@ -137,6 +149,7 @@ static void midimapBrowseClick(void *ptr) PluginGUI *gui = (PluginGUI*)ptr; std::string path = gui->lineedit2->text(); + if(path == "") path = gui->config->lastmidimap; if(path == "") path = gui->lineedit->text(); fb->setPath(path); @@ -268,6 +281,10 @@ void PluginGUI::thread_main() void PluginGUI::deinit() { + if(config) { + config->save(); + delete config; + } if(window) delete window; } @@ -280,6 +297,10 @@ void closeEventHandler(void *ptr) void PluginGUI::init() { DEBUG(gui, "init"); + + config = new Config(); + config->load(); + window = new GUI::Window(); window->eventHandler()->registerCloseHandler(closeEventHandler, (void*)&closing); @@ -428,6 +449,13 @@ void PluginGUI::init() filebrowser->hide(); fb = filebrowser; + // Enable quit button +// GUI::Button *btn_quit = new GUI::Button(window); +// btn_quit->setText("Quit"); +// btn_quit->move(50,280); +// btn_quit->resize(80,80); +// btn_quit->registerClickHandler(quit, this); + window->show(); sem.post(); diff --git a/plugingui/plugingui.h b/plugingui/plugingui.h index 7ec5e77..f94a062 100644 --- a/plugingui/plugingui.h +++ b/plugingui/plugingui.h @@ -36,6 +36,7 @@ #include "button.h" #include "knob.h" #include "progressbar.h" +#include "pluginconfig.h" #include "filebrowser.h" @@ -80,6 +81,8 @@ public: GUI::LineEdit *lineedit2; GUI::ProgressBar *progress2; + Config *config; + void (*windowClosedHandler)(void *); void *windowClosedPtr; 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/audiooutputengine.h b/src/audiooutputengine.h index 7f15e49..25b6ea0 100644 --- a/src/audiooutputengine.h +++ b/src/audiooutputengine.h @@ -33,6 +33,8 @@ #include "channel.h" +#define UNKNOWN_SAMPLERATE 0 + class AudioOutputEngine { public: virtual ~AudioOutputEngine() {} @@ -55,6 +57,11 @@ public: * Overload this method to force engine to use different buffer size. */ virtual size_t getBufferSize() { return 1024; } + + /** + * Overload this method to report output engine samplerate. + */ + virtual size_t samplerate() { return UNKNOWN_SAMPLERATE; } }; #endif/*__DRUMGIZMO_AUDIOOUTPUTENGINE_H__*/ 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 1abbb10..2370d43 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" @@ -55,6 +57,8 @@ bool DrumGizmo::loadkit(std::string file) { 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. @@ -66,12 +70,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; } @@ -157,6 +172,7 @@ void DrumGizmo::handleMessage(Message *msg) bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) { + // printf("."); fflush(stdout); // Handle engine messages, at most one in each iteration: handleMessages(1); @@ -239,7 +255,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++; @@ -254,10 +270,11 @@ 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 +286,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); @@ -300,6 +357,7 @@ void DrumGizmo::run(int endpos) free(samples); } +#undef SSE #ifdef SSE #define N 8 @@ -332,7 +390,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 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..136ba28 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,11 @@ gui_LDFLAGS = $(CPPUNIT_LIBS) gui_SOURCES = \ test.cc \ gui.cc + +resampler_CXXFLAGS = -DOUTPUT=\"resampler\" $(CPPUNIT_CFLAGS) \ + $(ZITA_CXXFLAGS) $(SAMPLERATE_CFLAGS) +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 |