summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am7
-rw-r--r--configure.in209
-rw-r--r--dgedit/.cvsignore3
-rw-r--r--dgedit/Makefile.am4
-rw-r--r--dgedit/audioextractor.cc65
-rw-r--r--dgedit/audioextractor.h3
-rw-r--r--dgedit/canvas.cc128
-rw-r--r--dgedit/canvas.h8
-rw-r--r--dgedit/mainwindow.cc11
-rw-r--r--dgedit/mipmap.cc99
-rw-r--r--dgedit/mipmap.h (renamed from src/audiooutputenginealsa.h)47
-rw-r--r--dgedit/samplesorter.cc139
-rw-r--r--dgedit/samplesorter.h21
-rw-r--r--dgedit/selection.h2
-rw-r--r--drumgizmo/Makefile.am43
-rw-r--r--drumgizmo/audioinputenginedl.cc236
-rw-r--r--drumgizmo/audioinputenginedl.h71
-rw-r--r--drumgizmo/audiooutputenginedl.cc176
-rw-r--r--drumgizmo/audiooutputenginedl.h77
-rw-r--r--drumgizmo/drumgizmoc.cc (renamed from src/cli.cc)124
-rw-r--r--drumgizmo/input/Makefile.am1
-rw-r--r--drumgizmo/input/dummy/Makefile.am26
-rw-r--r--drumgizmo/input/dummy/dummy.cc185
-rw-r--r--drumgizmo/input/jackmidi/Makefile.am28
-rw-r--r--drumgizmo/input/jackmidi/audioinputenginejackmidi.cc (renamed from src/audioinputenginejackmidi.cc)89
-rw-r--r--drumgizmo/input/jackmidi/audioinputenginejackmidi.h (renamed from src/audioinputenginejackmidi.h)14
-rw-r--r--drumgizmo/input/jackmidi/jackclient.cc96
-rw-r--r--drumgizmo/input/jackmidi/jackclient.h (renamed from src/jackclient.h)49
-rw-r--r--drumgizmo/input/jackmidi/jackmidi.cc232
-rw-r--r--drumgizmo/input/midifile/Makefile.am27
-rw-r--r--drumgizmo/input/midifile/audioinputenginemidifile.cc (renamed from src/audioinputenginemidifile.cc)0
-rw-r--r--drumgizmo/input/midifile/audioinputenginemidifile.h (renamed from src/audioinputenginemidifile.h)2
-rw-r--r--drumgizmo/input/midifile/midifile.cc235
-rw-r--r--drumgizmo/input/midifile/midimap.cc96
-rw-r--r--drumgizmo/input/midifile/midimap.h (renamed from src/audiooutputenginesndfile.h)32
-rw-r--r--drumgizmo/input/test/Makefile.am26
-rw-r--r--drumgizmo/input/test/test.cc170
-rw-r--r--drumgizmo/output/Makefile.am1
-rw-r--r--drumgizmo/output/alsa/Makefile.am26
-rw-r--r--drumgizmo/output/alsa/alsa.cc230
-rw-r--r--drumgizmo/output/dummy/Makefile.am26
-rw-r--r--drumgizmo/output/dummy/dummy.cc156
-rw-r--r--drumgizmo/output/wavfile/Makefile.am26
-rw-r--r--drumgizmo/output/wavfile/wavfile.cc199
-rw-r--r--lv2/Makefile.am44
-rw-r--r--lv2/drumgizmo.ttl130
-rw-r--r--lv2/input_lv2.cc121
-rw-r--r--lv2/input_lv2.h53
-rw-r--r--lv2/lv2.cc306
-rw-r--r--lv2/manifest.ttl7
-rw-r--r--lv2/output_lv2.cc (renamed from src/event.cc)75
-rw-r--r--lv2/output_lv2.h53
-rw-r--r--src/Makefile.am64
-rw-r--r--src/audio.h10
-rw-r--r--src/audiofile.cc2
-rw-r--r--src/audiofile.h1
-rw-r--r--src/audioinputengine.cc13
-rw-r--r--src/audioinputengine.h18
-rw-r--r--src/audiooutputengine.cc14
-rw-r--r--src/audiooutputengine.h19
-rw-r--r--src/audiooutputenginealsa.cc194
-rw-r--r--src/audiooutputenginejack.cc106
-rw-r--r--src/audiooutputenginesndfile.cc84
-rw-r--r--src/channel.h3
-rw-r--r--src/drumgizmo.cc221
-rw-r--r--src/drumgizmo.h36
-rw-r--r--src/drumkit.h17
-rw-r--r--src/drumkitparser.cc177
-rw-r--r--src/drumkitparser.h2
-rw-r--r--src/event.h123
-rw-r--r--src/instrument.cc17
-rw-r--r--src/instrument.h59
-rw-r--r--src/instrumentparser.cc219
-rw-r--r--src/instrumentparser.h (renamed from src/audiooutputenginejack.h)47
-rw-r--r--src/jackclient.cc260
-rw-r--r--src/path.cc61
-rw-r--r--src/path.h (renamed from src/cli.h)17
-rw-r--r--src/sample.cc11
-rw-r--r--src/sample.h7
-rw-r--r--tools/Makefile.am.test14
-rwxr-xr-xtools/add_file17
-rwxr-xr-xtools/test38
-rw-r--r--tools/test.h262
-rwxr-xr-xtools/testlist31
84 files changed, 5021 insertions, 1377 deletions
diff --git a/Makefile.am b/Makefile.am
index 58820cc..654bae0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,6 @@
AUTOMAKE_OPTIONS = gnu
-SUBDIRS = src dgedit
-DISTDIRS = src dgedit
+SUBDIRS = src lv2 drumgizmo dgedit
+DISTDIRS = src lv2 drumgizmo dgedit
+
+test:
+ $(MAKE) -C src test
diff --git a/configure.in b/configure.in
index 5823288..0e08d1c 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
# Filename: configure.in
AC_INIT(src/drumgizmo.cc)
-AM_INIT_AUTOMAKE( drumgizmo, 0.0.2 )
+AM_INIT_AUTOMAKE( drumgizmo, 0.1.0 )
AC_PROG_CXX
@@ -11,13 +11,152 @@ AM_PROG_LIBTOOL
AM_CONFIG_HEADER(config.h)
AC_STDC_HEADERS
-AC_ARG_WITH(debug, [ --with-debug build with debug support])
+dnl ======================
+dnl Init pkg-config
+dnl ======================
+PKG_PROG_PKG_CONFIG(0.23)
+
+AC_ARG_WITH(debug, [ --with-debug Build with debug support])
if test x$with_debug == xyes; then
AC_MSG_WARN([*** Building with debug support!])
CXXFLAGS="$CXXFLAGS -Wall -Werror -g"
fi
dnl ======================
+dnl Compile LV2 plugin
+dnl ======================
+AC_ARG_ENABLE([lv2],
+[ --with-lv2 Compile the LV2 plugin [default=yes]],,
+ [with_lv2="yes"])
+if test "x$with_lv2" = "xyes"; then
+ with_lv2=yes
+else
+ AC_MSG_RESULT([*** LV2 plugin will not be compiled ***])
+ with_lv2=no
+fi
+AM_CONDITIONAL([WITH_LV2], [test "x$with_lv2" = "xyes"])
+
+dnl ***
+dnl *** Input plugins
+dnl ***
+
+dnl *** Dummy
+AC_ARG_ENABLE([input_dummy],
+[ --disable-input-dummy Disable input dummy plugin [default=enabled]],,
+ [enable_input_dummy="yes"])
+if test "x$enable_input_dummy" = "xyes"; then
+ have_input_dummy=yes
+else
+ AC_MSG_RESULT([*** input dummy plugin disabled per user request ***])
+ have_input_dummy=no
+fi
+AM_CONDITIONAL([HAVE_INPUT_DUMMY], [test "x$have_input_dummy" = "xyes"])
+
+dnl *** Test
+AC_ARG_ENABLE([input_test],
+[ --disable-input-test Disable input test plugin [default=enabled]],,
+ [enable_input_test="yes"])
+if test "x$enable_input_test" = "xyes"; then
+ have_input_test=yes
+else
+ AC_MSG_RESULT([*** input test plugin disabled per user request ***])
+ have_input_test=no
+fi
+AM_CONDITIONAL([HAVE_INPUT_TEST], [test "x$have_input_test" = "xyes"])
+
+dnl *** Jackmidi
+AC_ARG_ENABLE([input_jackmidi],
+[ --disable-input-jackmidi Disable input jackmidi plugin [default=enabled]],,
+ [enable_input_jackmidi="yes"])
+if test "x$enable_input_jackmidi" = "xyes"; then
+ have_input_jackmidi=yes
+else
+ AC_MSG_RESULT([*** input jackmidi plugin disabled per user request ***])
+ have_input_jackmidi=no
+fi
+AM_CONDITIONAL([HAVE_INPUT_JACKMIDI], [test "x$have_input_jackmidi" = "xyes"])
+
+dnl *** Midifile
+AC_ARG_ENABLE([input_midifile],
+[ --disable-input-midifile Disable input midifile plugin [default=enabled]],,
+ [enable_input_midifile="yes"])
+if test "x$enable_input_midifile" = "xyes"; then
+ have_input_midifile=yes
+else
+ AC_MSG_RESULT([*** input midifile plugin disabled per user request ***])
+ have_input_midifile=no
+fi
+AM_CONDITIONAL([HAVE_INPUT_MIDIFILE], [test "x$have_input_midifile" = "xyes"])
+
+
+INPUT_PLUGINS="midifile jackmidi dummy test"
+AC_SUBST(INPUT_PLUGINS)
+
+
+dnl ***
+dnl *** Output plugins
+dnl ***
+
+dnl *** dummy
+AC_ARG_ENABLE([output_dummy],
+[ --disable-output-dummy Disable output dummy plugin [default=enabled]],,
+ [enable_output_dummy="yes"])
+if test "x$enable_output_dummy" = "xyes"; then
+ have_output_dummy=yes
+else
+ AC_MSG_RESULT([*** output dummy plugin disabled per user request ***])
+ have_output_dummy=no
+fi
+AM_CONDITIONAL([HAVE_OUTPUT_DUMMY], [test "x$have_output_dummy" = "xyes"])
+
+dnl *** alsa
+AC_ARG_ENABLE([output_alsa],
+[ --disable-output-alsa Disable output alsa plugin [default=enabled]],,
+ [enable_output_alsa="yes"])
+if test "x$enable_output_alsa" = "xyes"; then
+ have_output_alsa=yes
+else
+ AC_MSG_RESULT([*** output alsa plugin disabled per user request ***])
+ have_output_alsa=no
+fi
+AM_CONDITIONAL([HAVE_OUTPUT_ALSA], [test "x$have_output_alsa" = "xyes"])
+
+dnl *** wavfile
+AC_ARG_ENABLE([output_wavfile],
+[ --disable-output-wavfile Disable output wavfile plugin [default=enabled]],,
+ [enable_output_wavfile="yes"])
+if test "x$enable_output_wavfile" = "xyes"; then
+ have_output_wavfile=yes
+else
+ AC_MSG_RESULT([*** output wavfile plugin disabled per user request ***])
+ have_output_wavfile=no
+fi
+AM_CONDITIONAL([HAVE_OUTPUT_WAVFILE], [test "x$have_output_wavfile" = "xyes"])
+
+OUTPUT_PLUGINS="dummy alsa wavfile"
+AC_SUBST(OUTPUT_PLUGINS)
+
+dnl
+dnl Setup plugin paths
+dnl
+plugindir=${libdir}/drumgizmo
+AC_SUBST([plugindir])
+
+INPUT_PLUGIN_DIR=${plugindir}/input
+OUTPUT_PLUGIN_DIR=${plugindir}/output
+LV2_PLUGIN_DIR=${plugindir}/lv2
+AC_SUBST([INPUT_PLUGIN_DIR])
+AC_SUBST([OUTPUT_PLUGIN_DIR])
+AC_SUBST([LV2_PLUGIN_DIR])
+
+AC_DEFINE_UNQUOTED(INPUT_PLUGIN_DIR, "${prefix}/lib/drumgizmo/input",
+ [Input plugin dir])
+AC_DEFINE_UNQUOTED(OUTPUT_PLUGIN_DIR, "${prefix}/lib/drumgizmo/output",
+ [Output plugin dir])
+AC_DEFINE_UNQUOTED(LV2_PLUGIN_DIR, "${prefix}/lib/drumgizmo/lv2",
+ [LV2 plugin dir])
+
+dnl ======================
dnl Check for libsmf
dnl ======================
PKG_CHECK_MODULES(SMF, smf >= 1.2)
@@ -25,18 +164,67 @@ PKG_CHECK_MODULES(SMF, smf >= 1.2)
dnl ======================
dnl Check for jack
dnl ======================
-PKG_CHECK_MODULES(JACK, jack >= 0.109.2)
+PKG_CHECK_MODULES(JACK, jack >= 0.120.2)
+
+dnl ======================
+dnl Check for alsa library
+dnl ======================
+PKG_CHECK_MODULES(ALSA, alsa >= 1.0.18)
dnl ======================
dnl Check for sndfile
dnl ======================
-PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.17)
+PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.21)
+
+dnl ======================
+dnl Check for the pthread library
+dnl ======================
+tmp_CXXFLAGS="$CXXFLAGS"
+tmp_CPPFLAGS="$CPPFLAGS"
+tmp_CFLAGS="$CFLAGS"
+tmp_LDFLAGS="$LDFLAGS"
+tmp_LIBS="$LIBS"
+CXXFLAGS=""
+CPPFLAGS=""
+CFLAGS=""
+LDFLAGS=""
+LIBS=""
+AC_CHECK_HEADER(pthread.h, , AC_MSG_ERROR([*** pthread header file not found!]))
+AC_CHECK_LIB(pthread, pthread_mutex_init, , AC_MSG_ERROR([*** pthread library not found!]))
+PTHREAD_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS"
+PTHREAD_LIBS="$LDFLAGS $LIBS"
+CXXFLAGS="$tmp_CXXFLAGS"
+CPPFLAGS="$tmp_CPPFLAGS"
+CFLAGS="$tmp_CFLAGS"
+LDFLAGS="$tmp_LDFLAGS"
+LIBS="$tmp_LIBS"
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LIBS)
dnl ======================
dnl Check for eXpat library
dnl ======================
+tmp_CXXFLAGS="$CXXFLAGS"
+tmp_CPPFLAGS="$CPPFLAGS"
+tmp_CFLAGS="$CFLAGS"
+tmp_LDFLAGS="$LDFLAGS"
+tmp_LIBS="$LIBS"
+CXXFLAGS=""
+CPPFLAGS=""
+CFLAGS=""
+LDFLAGS=""
+LIBS=""
AC_CHECK_HEADER(expat.h, , AC_MSG_ERROR([*** eXpat header file not found!]))
-AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!]))
+AC_CHECK_LIB(expat, XML_ParserCreate, , AC_MSG_ERROR([*** eXpat library not found!]))
+EXPAT_CFLAGS="$CXXFLAGS $CPPFLAGS $CFLAGS"
+EXPAT_LIBS="$LDFLAGS $LIBS"
+CXXFLAGS="$tmp_CXXFLAGS"
+CPPFLAGS="$tmp_CPPFLAGS"
+CFLAGS="$tmp_CFLAGS"
+LDFLAGS="$tmp_LDFLAGS"
+LIBS="$tmp_LIBS"
+AC_SUBST(EXPAT_CFLAGS)
+AC_SUBST(EXPAT_LIBS)
dnl ======================
dnl Check for Qt
@@ -68,5 +256,16 @@ AC_SUBST(LDFLAGS)
AC_OUTPUT(
Makefile
src/Makefile
+ lv2/Makefile
+ drumgizmo/Makefile
+ drumgizmo/input/Makefile
+ drumgizmo/input/dummy/Makefile
+ drumgizmo/input/test/Makefile
+ drumgizmo/input/jackmidi/Makefile
+ drumgizmo/input/midifile/Makefile
+ drumgizmo/output/Makefile
+ drumgizmo/output/dummy/Makefile
+ drumgizmo/output/alsa/Makefile
+ drumgizmo/output/wavfile/Makefile
dgedit/Makefile)
diff --git a/dgedit/.cvsignore b/dgedit/.cvsignore
new file mode 100644
index 0000000..e995588
--- /dev/null
+++ b/dgedit/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/dgedit/Makefile.am b/dgedit/Makefile.am
index dad5437..1aa940a 100644
--- a/dgedit/Makefile.am
+++ b/dgedit/Makefile.am
@@ -3,7 +3,7 @@ bin_PROGRAMS = dgedit
dgedit_LDADD = $(SNDFILE_LIBS) $(QT_LIBS) $(shell ../tools/MocList o )
dgedit_CXXFLAGS = $(SNDFILE_CXXFLAGS) $(QT_CFLAGS)
-CXXFLAGS += $(QT_CFLAGS)
+AM_CXXFLAGS = $(QT_CFLAGS)
dgedit_SOURCES = $(shell ../tools/MocList cc ) \
dgedit.cc \
@@ -12,6 +12,7 @@ dgedit_SOURCES = $(shell ../tools/MocList cc ) \
filelist.cc \
itemeditor.cc \
mainwindow.cc \
+ mipmap.cc \
samplesorter.cc \
dgedit.qrc \
dgedit_qrc.cpp
@@ -22,6 +23,7 @@ EXTRA_DIST = \
filelist.h \
itemeditor.h \
mainwindow.h \
+ mipmap.h \
samplesorter.h
dgedit_MOC = $(shell ../tools/MocList cc )
diff --git a/dgedit/audioextractor.cc b/dgedit/audioextractor.cc
index 63273d1..015d323 100644
--- a/dgedit/audioextractor.cc
+++ b/dgedit/audioextractor.cc
@@ -28,6 +28,7 @@
#include <QDomDocument>
#include <QFile>
+#include <QDir>
#include <sndfile.h>
@@ -48,10 +49,10 @@ float *AudioExtractor::load(QString file, size_t *size)
return NULL;
}
- *size = sf_seek(fh, 0, SEEK_END);
+ *size = sf_info.frames;
+
data = new float[*size];
- sf_seek(fh, 0, SEEK_SET);
sf_read_float(fh, data, *size);
sf_close(fh);
@@ -67,7 +68,11 @@ void AudioExtractor::exportSelection(QString filename,
printf("Writing: %s (sz: %d, from %d to %d)\n",
filename.toStdString().c_str(), size, sel.from, sel.to);
- if(sel.from > (int)size || sel.to > (int)size || sel.to < 0 || sel.from < 0 || sel.to < sel.from) {
+ if(sel.from > (int)size ||
+ sel.to > (int)size ||
+ sel.to < 0 ||
+ sel.from < 0 ||
+ sel.to < sel.from) {
printf("Out of bounds\n");
return;
}
@@ -98,7 +103,8 @@ void AudioExtractor::exportSelection(QString filename,
sf_close(fh);
}
-void AudioExtractor::exportSelections(Selections selections, QVector<int> levels)
+void AudioExtractor::exportSelections(Selections selections,
+ Levels levels)
{
// Do the actual exporting one file at the time.
AudioFileList::iterator j = audiofiles.begin();
@@ -117,8 +123,12 @@ void AudioExtractor::exportSelections(Selections selections, QVector<int> levels
while(i != selections.end()) {
index++;
- QString file = exportpath + "/" + prefix + "/samples/" +
- prefix + "-" + name + "-" + QString::number(index) + ".wav";
+ QString path = exportpath + "/" + prefix + "/samples";
+ QString file = path + "/" + QString::number(index) +
+ "-" + prefix + "-" + name + ".wav";
+
+ QDir d;
+ d.mkpath(path);
exportSelection(file, index, data, size, i.value());
i++;
@@ -147,8 +157,10 @@ void AudioExtractor::exportSelections(Selections selections, QVector<int> levels
while(i != selections.end()) {
index++;
+ i->name = prefix + "-" + QString::number(index);
+
QDomElement sample = doc.createElement("sample");
- sample.setAttribute("name", prefix + "-" + QString::number(index));
+ sample.setAttribute("name", i->name);
samples.appendChild(sample);
AudioFileList::iterator j = audiofiles.begin();
@@ -158,8 +170,9 @@ void AudioExtractor::exportSelections(Selections selections, QVector<int> levels
QString name = j->second;
QDomElement audiofile = doc.createElement("audiofile");
- audiofile.setAttribute("file", "samples/" + prefix + "-" + name + "-"
- + QString::number(index) + ".wav");
+ audiofile.setAttribute("file", "samples/" +
+ QString::number(index) + "-" + prefix +
+ "-" + name + ".wav");
audiofile.setAttribute("channel", name);
sample.appendChild(audiofile);
@@ -172,17 +185,37 @@ void AudioExtractor::exportSelections(Selections selections, QVector<int> levels
QDomElement velocities = doc.createElement("velocities");
instrument.appendChild(velocities);
- QVector<int>::iterator k = levels.begin();
+ Levels::iterator k = levels.begin();
while(k != levels.end()) {
+
+ Levels::iterator nxt = k;
+ nxt++;
+ int next;
+ if(nxt == levels.end()) next = 127;
+ else next = nxt->velocity - 1;
+
+
QDomElement velocity = doc.createElement("velocity");
- velocity.setAttribute("lower", "0");
- velocity.setAttribute("upper", "127");
+ velocity.setAttribute("lower", k->velocity);
+ velocity.setAttribute("upper", next);
velocities.appendChild(velocity);
- QDomElement sampleref = doc.createElement("sampleref");
- sampleref.setAttribute("name", "bleh");
- sampleref.setAttribute("probability", "0.1");
- velocity.appendChild(sampleref);
+ QMap<float, Selection>::iterator i = k->selections.begin();
+ while(i != k->selections.end()) {
+
+ QMap<int, Selection>::iterator j = selections.begin();
+ while(j != selections.end()) {
+ if(i->from == j->from && i->to == j->to) {
+ QDomElement sampleref = doc.createElement("sampleref");
+ sampleref.setAttribute("name", j->name);
+ sampleref.setAttribute("probability",
+ 1.0 / (double)k->selections.size());
+ velocity.appendChild(sampleref);
+ }
+ j++;
+ }
+ i++;
+ }
k++;
}
diff --git a/dgedit/audioextractor.h b/dgedit/audioextractor.h
index 2f4ce98..33ccf71 100644
--- a/dgedit/audioextractor.h
+++ b/dgedit/audioextractor.h
@@ -34,6 +34,7 @@
#include <QVector>
#include "selection.h"
+#include "samplesorter.h"
typedef QLinkedList< QPair<QString, QString> > AudioFileList;
@@ -46,7 +47,7 @@ public slots:
void addFile(QString file, QString name);
void changeName(QString file, QString name);
void removeFile(QString file, QString name);
- void exportSelections(Selections selections, QVector<int> levels);
+ void exportSelections(Selections selections, Levels levels);
void setExportPath(const QString &path);
void setOutputPrefix(const QString &prefix);
diff --git a/dgedit/canvas.cc b/dgedit/canvas.cc
index 4c63e5e..5fc1f1f 100644
--- a/dgedit/canvas.cc
+++ b/dgedit/canvas.cc
@@ -35,7 +35,6 @@
#include <math.h>
#define DEFYSCALE 200
-#define MIPMAPS 65536
Canvas::Canvas(QWidget *parent)
: QWidget(parent)
@@ -43,8 +42,12 @@ Canvas::Canvas(QWidget *parent)
setAttribute(Qt::WA_StaticContents);
setMouseTracking(true);
setFocusPolicy(Qt::ClickFocus);
+
+ mipmap = NULL;
+
data = NULL;
size = 0;
+
xscale = 1.0;
yscale = 1.0;
xoffset = 0.0;
@@ -77,31 +80,7 @@ Canvas::Canvas(QWidget *parent)
Canvas::~Canvas()
{
if(data) delete[] data;
-}
-
-#define VALL(x) (x*4)
-#define VALU(x) (x*4+1)
-#define POWL(x) (x*4+2)
-#define POWU(x) (x*4+3)
-
-static void genmipmap(float *in, size_t insz, float *out, size_t outsz)
-{
- float *lookup = out;
-
- for(size_t i = 0; i < outsz; i++) {
- lookup[VALL(i)] = 0.0;
- lookup[VALU(i)] = 0.0;
- lookup[POWL(i)] = 0.0;
- lookup[POWU(i)] = 0.0;
-
- for(size_t j = i * (insz / outsz); j < (i+1)*(insz / outsz); j++) {
- if(in[VALU(j)] > lookup[VALU(i)]) lookup[VALU(i)] = in[VALU(j)];
- if(in[VALL(j)] < lookup[VALL(i)]) lookup[VALL(i)] = in[VALL(j)];
- if(in[POWU(j)] > 0) lookup[POWU(i)] += in[POWU(j)];
- if(in[POWL(j)] < 0) lookup[POWL(i)] += in[POWL(j)];
- }
-
- }
+ if(mipmap) delete mipmap;
}
void Canvas::load(QString file)
@@ -110,55 +89,30 @@ void Canvas::load(QString file)
delete[] data;
data = NULL;
size = 0;
+ }
- QMap<int, float*>::iterator i = mipmaps.begin();
- while(i != mipmaps.end()) {
- delete[] i.value();
- i++;
- }
-
+ if(mipmap) {
+ delete mipmap;
+ mipmap = NULL;
}
SF_INFO sf_info;
SNDFILE *fh = sf_open(file.toStdString().c_str(), SFM_READ, &sf_info);
if(!fh) {
printf("Load error...\n");
+ return;
}
- size = sf_seek(fh, 0, SEEK_END);
+ size = sf_info.frames;
+
+ printf("Size: %u\n", (unsigned int)sf_info.frames);
data = new float[size];
- sf_seek(fh, 0, SEEK_SET);
sf_read_float(fh, data, size);
sf_close(fh);
- size_t lastsz = 0;
- for(size_t dev = 2; dev <= MIPMAPS; dev*=2) {
- size_t mipmapsize = size/dev;
-
- float *lookup = new float[mipmapsize * 4];
-
- if(dev == 2) {
- for(size_t i = 0; i < mipmapsize; i++) {
- lookup[VALL(i)] = 0.0;
- lookup[VALU(i)] = 0.0;
- lookup[POWL(i)] = 0.0;
- lookup[POWU(i)] = 0.0;
- for(size_t j = i * dev; j < (i + 1) * dev; j++) {
- if(data[j] > lookup[VALU(i)]) lookup[VALU(i)] = data[j];
- if(data[j] < lookup[VALL(i)]) lookup[VALL(i)] = data[j];
- if(data[j] > 0) lookup[POWU(i)] += data[j];
- if(data[j] < 0) lookup[POWL(i)] += data[j];
- }
- }
- } else {
- genmipmap(mipmaps[dev/2], lastsz, lookup, mipmapsize);
- }
-
- lastsz = mipmapsize;
- mipmaps[dev] = lookup;
- }
+ mipmap = new MipMap(data, size);
updateWav();
update();
@@ -323,42 +277,17 @@ void Canvas::resizeEvent(QResizeEvent *)
update();
}
-void Canvas::getWavValues(int last, int lx, float *vu, float *vl, float *avgu, float *avgl)
+void Canvas::getWavValues(int last, int lx, float *vu, float *vl,
+ float *avgu, float *avgl)
{
- float *lookup = data;
- int dev = 1;
-
- int i = 2;
- while(i < (lx - last) && mipmaps.find(i) != mipmaps.end()) {
- lookup = mipmaps[i];
- dev = i;
- i *= 2;
- }
+ if(mipmap == NULL) return;
- *vu = *vl = *avgu = *avgl = 0;
- for(int i = last / dev; i < lx / dev; i++) {
- float lval;
- float uval;
- float lpow;
- float upow;
- if(dev > 1) {
- lval = -lookup[VALL(i)];
- uval = -lookup[VALU(i)];
- upow = -lookup[POWL(i)];
- lpow = -lookup[POWU(i)];
- } else {
- lpow = upow = lval = uval = -lookup[i];
- }
- if(lpow < 0.0) *avgl += lpow;
- if(upow > 0.0) *avgu += upow;
- if(lval > *vl) *vl = lval;
- if(uval < *vu) *vu = uval;
- }
-
- if((lx - last) != 0) {
- *avgu /= (float)(lx - last);
- *avgl /= (float)(lx - last);
- }
+ MipMapValue val = mipmap->lookup(last, lx);
+
+ *vu = val.max;
+ *vl = val.min;
+ *avgu = val.uavg;
+ *avgl = val.lavg;
}
void Canvas::updateWav()
@@ -514,10 +443,15 @@ void Canvas::autoCreateSelections()
}
}
+ int minsize = 100; // attack.
+ float minval = 0.0001; // noise floor
int to = i;
- float runavg = fabs(data[to]);
- while(runavg > 0.001 && to < (int)size) {
- runavg = runavg * 0.99999 + fabs(data[to]) * 0.00001;
+ float runavg = fabs(data[from]);
+ while((runavg > minval ||
+ to < from + minsize) &&
+ to < (int)size) {
+ double p = 0.9;
+ runavg = runavg * p + fabs(data[to]) * (1 - p);
to++;
}
_selections[from] = Selection(from, to, 2, (to - from) / 3);
diff --git a/dgedit/canvas.h b/dgedit/canvas.h
index 2a06d03..b881d01 100644
--- a/dgedit/canvas.h
+++ b/dgedit/canvas.h
@@ -32,6 +32,7 @@
#include <QImage>
#include "selection.h"
+#include "mipmap.h"
class Canvas : public QWidget {
Q_OBJECT
@@ -64,8 +65,11 @@ protected:
void keyReleaseEvent(QKeyEvent *event);
private:
+ MipMap *mipmap;
+
void updateWav();
- void getWavValues(int last, int lx, float *vu, float *vl, float *avgu, float *avgl);
+ void getWavValues(int last, int lx, float *vu, float *vl,
+ float *avgu, float *avgl);
float mapX(float x);
float unmapX(float x);
float mapY(float y);
@@ -77,8 +81,6 @@ public:
float *data;
size_t size;
private:
- QMap<int, float *> mipmaps;
-
float xscale;
float yscale;
float xoffset;
diff --git a/dgedit/mainwindow.cc b/dgedit/mainwindow.cc
index f9b0147..9454a97 100644
--- a/dgedit/mainwindow.cc
+++ b/dgedit/mainwindow.cc
@@ -78,8 +78,10 @@ MainWindow::MainWindow()
connect(xoffset, SIGNAL(valueChanged(int)), this, SLOT(setXOffset(int)));
sorter = new SampleSorter();
- connect(canvas, SIGNAL(selectionsChanged(Selections)), sorter, SLOT(setSelections(Selections)));
- connect(canvas, SIGNAL(activeSelectionChanged(Selection)), sorter, SLOT(setActiveSelection(Selection)));
+ connect(canvas, SIGNAL(selectionsChanged(Selections)),
+ sorter, SLOT(setSelections(Selections)));
+ connect(canvas, SIGNAL(activeSelectionChanged(Selection)),
+ sorter, SLOT(setActiveSelection(Selection)));
lh->addWidget(canvas);
lh->addWidget(yscale);
@@ -117,7 +119,7 @@ MainWindow::MainWindow()
QLineEdit *prefix = new QLineEdit();
connect(prefix, SIGNAL(textChanged(const QString &)),
extractor, SLOT(setOutputPrefix(const QString &)));
- prefix->setText("china");
+ prefix->setText("kick-r");
configs->addWidget(prefix);
configs->addWidget(new QLabel("Export path:"));
@@ -133,7 +135,8 @@ MainWindow::MainWindow()
configs->addWidget(new QLabel("Files: (double-click to set as master)"));
filelist = new FileList();
- connect(filelist, SIGNAL(masterFileChanged(QString)), this, SLOT(loadFile(QString)));
+ connect(filelist, SIGNAL(masterFileChanged(QString)),
+ this, SLOT(loadFile(QString)));
connect(loadbtn, SIGNAL(clicked()), filelist, SLOT(addFiles()));
connect(filelist, SIGNAL(fileAdded(QString, QString)),
extractor, SLOT(addFile(QString, QString)));
diff --git a/dgedit/mipmap.cc b/dgedit/mipmap.cc
new file mode 100644
index 0000000..09b15b6
--- /dev/null
+++ b/dgedit/mipmap.cc
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * mipmap.cc
+ *
+ * Fri Sep 3 16:39:46 CEST 2010
+ * Copyright 2010 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 "mipmap.h"
+
+MipMap::MipMap(float *data, size_t size)
+{
+ this->data = data;
+ this->size = size;
+ this->zoom = 1;
+}
+
+MipMapValue MipMap::data_lookup(size_t begin, size_t end)
+{
+ MipMapValue val;
+
+ size_t numlavg = 0;
+ size_t numuavg = 0;
+ for(size_t i = begin; i <= end; i++) {
+ if(i > size || i < 0) break;
+ if(data[i] > val.max) val.max = data[i];
+ if(data[i] < val.min) val.min = data[i];
+
+ if(data[i] > 0) { val.uavg += data[i]; numuavg++; }
+ if(data[i] < 0) { val.lavg += data[i]; numlavg++; }
+ }
+
+ if(numlavg) val.lavg /= (float) numlavg;
+ if(numuavg) val.uavg /= (float) numuavg;
+
+ return val;
+}
+
+MipMapValue MipMap::mipmap_lookup(size_t begin, size_t end)
+{
+ MipMapValue val;
+
+ size_t numlavg = 0;
+ size_t numuavg = 0;
+ for(size_t i = begin; i <= end; i++) {
+ if(i > size || i < 0) break;
+ if(data[i] > val.max) val.max = data[i];
+ if(data[i] < val.min) val.min = data[i];
+
+ if(data[i] > 0) { val.uavg += data[i]; numuavg++; }
+ if(data[i] < 0) { val.lavg += data[i]; numlavg++; }
+ }
+
+ if(numlavg) val.lavg /= (float) numlavg;
+ if(numuavg) val.uavg /= (float) numuavg;
+
+ return val;
+}
+
+#define ABS(x) (x>0?x:-x)
+
+MipMapValue MipMap::lookup(size_t begin, size_t end)
+{
+ return data_lookup(begin, end);
+ /*
+
+ size_t zoom_factor = ABS(end - begin);
+
+ if(zoom_factor < zoom / 2) {
+ if(zoom == 1) { // Lookup in original data.
+ return data_lookup(begin, end);
+ }
+
+ return mipmap_lookup(begin, end);
+ }
+
+ if(lowerlevel) return lowerlevel->lookup(begin,end);
+
+ return MipMapValue();
+ */
+}
diff --git a/src/audiooutputenginealsa.h b/dgedit/mipmap.h
index 8aef940..550d6ae 100644
--- a/src/audiooutputenginealsa.h
+++ b/dgedit/mipmap.h
@@ -1,8 +1,8 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * audiooutputenginealsa.h
+ * mipmap.h
*
- * Thu Sep 16 11:22:52 CEST 2010
+ * Fri Sep 3 16:39:45 CEST 2010
* Copyright 2010 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,28 +24,39 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __DRUMGIZMO_AUDIOOUTPUTENGINEALSA_H__
-#define __DRUMGIZMO_AUDIOOUTPUTENGINEALSA_H__
+#ifndef __DRUMGIZMO_MIPMAP_H__
+#define __DRUMGIZMO_MIPMAP_H__
-// Use the newer ALSA API
-#define ALSA_PCM_NEW_HW_PARAMS_API
+#include <QMap>
+#include <stddef.h>
-#include <asoundlib.h>
-
-#include "audiooutputengine.h"
+class MipMapValue {
+public:
+ MipMapValue() { max = min = uavg = lavg = 0.0; }
+ float max;
+ float min;
+ float uavg;
+ float lavg;
+};
-class AudioOutputEngineAlsa : public AudioOutputEngine {
+class MipMap {
public:
- AudioOutputEngineAlsa();
- ~AudioOutputEngineAlsa();
+ MipMap(float *data, size_t size);
- bool init(Channels *channels);
+ MipMapValue lookup(size_t begin, size_t end);
- void run(DrumGizmo *drumgizmo);
-
private:
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *params;
+ float *data;
+ size_t size;
+
+ MipMapValue *values;
+
+ size_t zoom;
+
+ MipMapValue data_lookup(size_t begin, size_t end);
+ MipMapValue mipmap_lookup(size_t begin, size_t end);
+
+ MipMap *lowerlevel;
};
-#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINEALSA_H__*/
+#endif/*__DRUMGIZMO_MIPMAP_H__*/
diff --git a/dgedit/samplesorter.cc b/dgedit/samplesorter.cc
index e93754c..545c7cd 100644
--- a/dgedit/samplesorter.cc
+++ b/dgedit/samplesorter.cc
@@ -29,18 +29,24 @@
#include <QPainter>
#include <QPaintEvent>
+#include <stdio.h>
+
#include <math.h>
#ifndef MAXFLOAT
#define MAXFLOAT (3.40282347e+38F)
#endif
-#define NUM_LEVELS 6
-
SampleSorter::SampleSorter()
{
+ setMouseTracking(true);
+
data = NULL;
size = 0;
attlen = 666; // Magical constants needs biblical proportions...
+
+ cur_thr = -1;
+ threshold.push_back(100);
+ threshold_is_moving = false;
}
void SampleSorter::setWavData(const float *data, size_t size)
@@ -81,20 +87,41 @@ Selections SampleSorter::selections()
return s;
}
-QVector<int> SampleSorter::levels()
+Levels SampleSorter::levels()
{
- QVector<int> lvls;
- int idx = 0;
- float next = min;
+ Levels lvls;
+
+ for(int i = 0; i < threshold.size(); i++) {
+ for(int j = 0; j < threshold.size(); j++) {
+ if(threshold[i] < threshold[j]) {
+ int tmp = threshold[i];
+ threshold[i] = threshold[j];
+ threshold[j] = tmp;
+ }
+ }
+ }
+
- QMap<float, Selection>::iterator i = sorted.begin();
- while(i != sorted.end()) {
- if(i.key() >= next) {
- lvls.push_back(idx);
- next += (max - min) / NUM_LEVELS;
+ for(int i = -1; i < threshold.size(); i++) {
+ Level lvl;
+
+ if(i == -1) lvl.velocity = 0;
+ else lvl.velocity = threshold[i];
+
+ int next;
+ if(i == threshold.size() - 1) next = 127;
+ else next = threshold[i+1];
+
+ QMap<float, Selection>::iterator i = sorted.begin();
+ while(i != sorted.end()) {
+ float val = (i.key()/max)*127.0;
+ if(val >= lvl.velocity && val <= next) {
+ lvl.selections[i.key()] = i.value();
+ }
+ i++;
}
- i++;
- idx++;
+
+ lvls.push_back(lvl);
}
return lvls;
@@ -114,7 +141,8 @@ void SampleSorter::resort()
Selection s = i.value();
for(size_t idx = s.from;
- (idx < (size_t)s.from + (size_t)attackLength()) && (idx < (size_t)s.to) && (idx < size);
+ (idx < (size_t)s.from + (size_t)attackLength()) &&
+ (idx < (size_t)s.to) && (idx < size);
idx++) {
energy += data[idx] * data[idx];
}
@@ -142,6 +170,12 @@ void SampleSorter::setActiveSelection(Selection s)
#define MAP(p) (height()-(int)(p*((float)height()/(float)width())))
+#define unmapX(x) ((double)x/(double)(width()-1)*127.0)
+#define unmapY(x) x
+#define mapX(x) (((double)x/127.0)*(width()-1))
+#define mapY(x) x
+
+
static void drawCircle(QPainter &p, int x, int y)
{
p.drawEllipse(x-2, y-2, 4, 4);
@@ -155,6 +189,7 @@ void SampleSorter::paintEvent(QPaintEvent *event)
QColor colFg = QColor(160, 180, 160);
QColor colPt = QColor(255, 100, 100);
QColor colPtSel = QColor(255, 255, 100);
+ QColor colVel = QColor(0, 0, 0);
painter.setPen(colBg);
painter.setBrush(colBg);
@@ -167,10 +202,84 @@ void SampleSorter::paintEvent(QPaintEvent *event)
QMap<float, Selection>::iterator i = sorted.begin();
while(i != sorted.end()) {
- if(sel.to == i.value().to && sel.from == i.value().from) painter.setPen(colPtSel);
+ if(sel.to == i.value().to && sel.from == i.value().from)
+ painter.setPen(colPtSel);
else painter.setPen(colPt);
float x = (i.key()/max)*(float)width();
drawCircle(painter, x, MAP(x));
i++;
}
+
+ for(int i = 0; i < threshold.size(); i++) {
+ if(cur_thr == i) painter.setPen(colPtSel);
+ else painter.setPen(colPt);
+ painter.drawLine(mapX(threshold[i]), 0, mapX(threshold[i]), height());
+ char valstr[32];
+ sprintf(valstr, "%d", (int)threshold[i]);
+ painter.setPen(colVel);
+ painter.drawText(mapX(threshold[i]), height(), valstr);
+ }
+}
+
+void SampleSorter::mouseMoveEvent(QMouseEvent *event)
+{
+ if(cur_thr != -1 && cur_thr < threshold.size()) {
+ float val = unmapX(event->x());
+ if(val < 0) val = 0;
+ if(val > 127) val = 127;
+ threshold[cur_thr] = fabs(val);
+ update();
+ return;
+ }
+
+ if(event->button() != Qt::LeftButton) {
+ setCursor(Qt::ArrowCursor);
+ for(size_t i = 0; i < (size_t)threshold.size(); i++) {
+ if(abs(event->x() - mapX(threshold[i])) < 2 ||
+ abs(event->x() - mapX(-threshold[i])) < 2 ) {
+ setCursor(Qt::SplitHCursor);
+ }
+ }
+ }
+}
+
+void SampleSorter::mousePressEvent(QMouseEvent *event)
+{
+ if(event->button() == Qt::LeftButton) {
+
+ // Check if threshold is being dragged.
+ for(size_t i = 0; i < (size_t)threshold.size(); i++) {
+ if(abs(event->x() - mapX(threshold[i])) < 2 ||
+ abs(event->x() - mapX(-threshold[i])) < 2 ) {
+ cur_thr = i;
+ threshold_is_moving = true;
+ update();
+ return;
+ }
+ }
+
+ // Make new selection
+ int from = unmapX(event->x());
+ threshold.push_back(from);
+ cur_thr = threshold.size() - 1;
+ threshold_is_moving = true;
+ update();
+ return;
+ }
+}
+
+void SampleSorter::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(event->button() == Qt::LeftButton) {
+ if(threshold_is_moving) {
+ if(threshold[cur_thr] == 0 || threshold[cur_thr] == 127) {
+ threshold.remove(cur_thr);
+ }
+ threshold_is_moving = false;
+ cur_thr = -1;
+ setCursor(Qt::ArrowCursor);
+ update();
+ return;
+ }
+ }
}
diff --git a/dgedit/samplesorter.h b/dgedit/samplesorter.h
index a7c356d..ff45f3e 100644
--- a/dgedit/samplesorter.h
+++ b/dgedit/samplesorter.h
@@ -28,15 +28,24 @@
#define __DRUMGIZMO_SAMPLESORTER_H__
#include <QWidget>
+#include <QVector>
#include "selection.h"
+class Level {
+public:
+ int velocity;
+ QMap<float, Selection> selections;
+};
+
+typedef QVector<Level> Levels;
+
class SampleSorter : public QWidget {
Q_OBJECT
public:
SampleSorter();
Selections selections();
- QVector<int> levels();
+ Levels levels();
public slots:
void setSelections(Selections selections);
@@ -48,6 +57,9 @@ public slots:
protected:
void paintEvent(QPaintEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
private:
Selections _selections;
@@ -61,6 +73,13 @@ private:
size_t size;
Selection sel;
+
+ QVector<int> threshold;
+ bool threshold_is_moving;
+ bool selection_is_moving_left;
+ bool selection_is_moving_right;
+ int cur_thr;
+
};
#endif/*__DRUMGIZMO_SAMPLESORTER_H__*/
diff --git a/dgedit/selection.h b/dgedit/selection.h
index 02d5163..283b642 100644
--- a/dgedit/selection.h
+++ b/dgedit/selection.h
@@ -41,6 +41,8 @@ public:
int to;
int fadein;
int fadeout;
+
+ QString name;
};
typedef QMap<int, Selection> Selections;
diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am
new file mode 100644
index 0000000..dbbd6e3
--- /dev/null
+++ b/drumgizmo/Makefile.am
@@ -0,0 +1,43 @@
+SUBDIRS = input output
+
+bin_PROGRAMS = drumgizmo
+
+drumgizmo_LDADD = $(SNDFILE_LIBS) $(PTHREAD_LIBS) $(EXPAT_LIBS) -ldl
+
+drumgizmo_CXXFLAGS = $(SNDFILE_CXXFLAGS) $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/src
+
+drumgizmo_SOURCES = \
+ audioinputenginedl.cc \
+ audiooutputenginedl.cc \
+ drumgizmoc.cc \
+ $(top_srcdir)/src/audiofile.cc \
+ $(top_srcdir)/src/channel.cc \
+ $(top_srcdir)/src/channelmixer.cc \
+ $(top_srcdir)/src/drumgizmo.cc \
+ $(top_srcdir)/src/drumkit.cc \
+ $(top_srcdir)/src/drumkitparser.cc \
+ $(top_srcdir)/src/events.cc \
+ $(top_srcdir)/src/instrument.cc \
+ $(top_srcdir)/src/instrumentparser.cc \
+ $(top_srcdir)/src/midimapper.cc \
+ $(top_srcdir)/src/mutex.cc \
+ $(top_srcdir)/src/path.cc \
+ $(top_srcdir)/src/sample.cc \
+ $(top_srcdir)/src/saxparser.cc \
+ $(top_srcdir)/src/thread.cc \
+ $(top_srcdir)/src/velocity.cc
+
+EXTRA_DIST = \
+ audioinputenginedl.h \
+ audiooutputenginedl.h
+
+################
+# Test Section #
+################
+
+TEST_SOURCE_DEPS = ${drumgizmo_SOURCES} ${EXTRA_DIST}
+TEST_SCRIPT_DIR = $(top_srcdir)/tools
+
+include ${TEST_SCRIPT_DIR}/Makefile.am.test
+
+include Makefile.am.test
diff --git a/drumgizmo/audioinputenginedl.cc b/drumgizmo/audioinputenginedl.cc
new file mode 100644
index 0000000..3b2a483
--- /dev/null
+++ b/drumgizmo/audioinputenginedl.cc
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audioinputenginedl.cc
+ *
+ * Wed Jul 13 14:39:54 CEST 2011
+ * Copyright 2011 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 "audioinputenginedl.h"
+
+#include <stdio.h>
+
+#include <dlfcn.h>
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+
+AudioInputEngineDL::AudioInputEngineDL(std::string name)
+{
+ std::string plugin = INPUT_PLUGIN_DIR"/lib" + name + ".so";
+ void *lib = dlopen(plugin.c_str(), RTLD_LAZY);
+ if(!lib) {
+ printf("Cannot load device: %s\n", dlerror());
+ return;
+ }
+
+ i_create = (input_create_func_t) dlsym(lib, "create");
+ const char* dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol create: %s\n", dlsym_error);
+ return;
+ }
+
+ i_destroy = (input_destroy_func_t) dlsym(lib, "destroy");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_init = (input_init_func_t) dlsym(lib, "init");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_setparm = (input_setparm_func_t) dlsym(lib, "setparm");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_start = (input_start_func_t) dlsym(lib, "start");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_stop = (input_stop_func_t) dlsym(lib, "stop");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_pre = (input_pre_func_t) dlsym(lib, "pre");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_run = (input_run_func_t) dlsym(lib, "run");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ i_post = (input_post_func_t) dlsym(lib, "post");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ ptr = i_create();
+}
+
+AudioInputEngineDL::~AudioInputEngineDL()
+{
+ i_destroy(ptr);
+}
+
+bool AudioInputEngineDL::init(Instruments &instruments)
+{
+ char **n = (char**)malloc(sizeof(char*)*instruments.size());
+ for(size_t i = 0; i < instruments.size(); i++) {
+ n[i] = strdup(instruments[i].name().c_str());
+ }
+
+ bool ret = i_init(ptr, instruments.size(), n);
+
+ for(size_t i = 0; i < instruments.size(); i++) {
+ free(n[i]);
+ }
+ free(n);
+
+ return ret;
+}
+
+void AudioInputEngineDL::setParm(std::string parm, std::string value)
+{
+ i_setparm(ptr, parm.c_str(), value.c_str());
+}
+
+bool AudioInputEngineDL::start()
+{
+ return i_start(ptr);
+}
+
+void AudioInputEngineDL::stop()
+{
+ return i_stop(ptr);
+}
+
+void AudioInputEngineDL::pre()
+{
+ return i_pre(ptr);
+}
+
+event_t *AudioInputEngineDL::run(size_t pos, size_t len, size_t *nevents)
+{
+ return i_run(ptr, pos, len, nevents);
+}
+
+void AudioInputEngineDL::post()
+{
+ return i_post(ptr);
+}
+
+//#include "audioinputenginedummy.h"
+//#include "audioinputenginejackmidi.h"
+//#include "audioinputenginemidifile.h"
+
+/*
+
+typedef Device* (*create_func_t)(void);
+typedef void (*destroy_func_t)(Device*);
+
+struct device_t {
+ Device* dev;
+ destroy_func_t destroyer;
+ void* lib;
+};
+
+int load_shared_device(device_t &dev, std::string devlib,
+ std::string devfile, ConfMap devconfmap) {
+ // load library
+ dev.lib = dlopen(devlib.c_str(), RTLD_LAZY);
+ if(!dev.lib ) {
+ printf("Cannot load device: %s\n", dlerror());
+ return -1;
+ }
+
+ create_func_t create_device = (create_func_t) dlsym(dev.lib, "create");
+ const char* dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol create: %s\n", dlsym_error);
+ return -1;
+ }
+
+ dev.destroyer = (destroy_func_t) dlsym(dev.lib, "destroy");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return -1;
+ }
+
+ dev.dev = create_device();
+
+ // initialize device
+ DevData devdata = dev.dev->init(devfile, devconfmap);
+ if(devdata.retval != DevData::VALUE_SUCCESS) {
+ printf("Error while initializing device: %s\n", devdata.msg.c_str());
+ return -1;
+ }
+
+ return 0;
+}
+
+void unload_shared_device(device_t &dev) {
+
+ dev.destroyer(dev.dev);
+ dlclose(dev.lib);
+}
+*/
+
+#ifdef TEST_AUDIOINPUTENGINEDL
+//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_AUDIOINPUTENGINEDL*/
diff --git a/drumgizmo/audioinputenginedl.h b/drumgizmo/audioinputenginedl.h
new file mode 100644
index 0000000..b8829e5
--- /dev/null
+++ b/drumgizmo/audioinputenginedl.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audioinputenginedl.h
+ *
+ * Wed Jul 13 14:39:54 CEST 2011
+ * Copyright 2011 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_AUDIOINPUTENGINEDL_H__
+#define __DRUMGIZMO_AUDIOINPUTENGINEDL_H__
+
+#include "audioinputengine.h"
+
+typedef void* (*input_create_func_t)(void);
+typedef void (*input_destroy_func_t)(void*);
+typedef bool (*input_init_func_t)(void*,int,char**);
+typedef void (*input_setparm_func_t)(void*,const char*,const char*);
+typedef bool (*input_start_func_t)(void*);
+typedef void (*input_stop_func_t)(void*);
+typedef void (*input_pre_func_t)(void*);
+typedef event_t* (*input_run_func_t)(void*,size_t,size_t,size_t*);
+typedef void (*input_post_func_t)(void*);
+
+class AudioInputEngineDL : public AudioInputEngine {
+public:
+ AudioInputEngineDL(std::string name);
+ ~AudioInputEngineDL();
+
+ bool init(Instruments &instruments);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+
+private:
+ void *ptr;
+ input_create_func_t i_create;
+ input_destroy_func_t i_destroy;
+ input_init_func_t i_init;
+ input_setparm_func_t i_setparm;
+ input_start_func_t i_start;
+ input_stop_func_t i_stop;
+ input_pre_func_t i_pre;
+ input_run_func_t i_run;
+ input_post_func_t i_post;
+};
+
+#endif/*__DRUMGIZMO_AUDIOINPUTENGINEDL_H__*/
diff --git a/drumgizmo/audiooutputenginedl.cc b/drumgizmo/audiooutputenginedl.cc
new file mode 100644
index 0000000..411c14b
--- /dev/null
+++ b/drumgizmo/audiooutputenginedl.cc
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputenginedl.cc
+ *
+ * Wed Jul 13 14:40:01 CEST 2011
+ * Copyright 2011 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 "audiooutputenginedl.h"
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <config.h>
+#include <string.h>
+
+AudioOutputEngineDL::AudioOutputEngineDL(std::string name)
+{
+ std::string plugin = OUTPUT_PLUGIN_DIR"/lib" + name + ".so";
+ void *lib = dlopen(plugin.c_str(), RTLD_LAZY);
+ if(!lib) {
+ printf("Cannot load device: %s\n", dlerror());
+ return;
+ }
+
+ o_create = (output_create_func_t) dlsym(lib, "create");
+ const char* dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol create: %s\n", dlsym_error);
+ return;
+ }
+
+ o_destroy = (output_destroy_func_t) dlsym(lib, "destroy");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_init = (output_init_func_t) dlsym(lib, "init");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_setparm = (output_setparm_func_t) dlsym(lib, "setparm");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_start = (output_start_func_t) dlsym(lib, "start");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_stop = (output_stop_func_t) dlsym(lib, "stop");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_pre = (output_pre_func_t) dlsym(lib, "pre");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_run = (output_run_func_t) dlsym(lib, "run");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ o_post = (output_post_func_t) dlsym(lib, "post");
+ dlsym_error = dlerror();
+ if(dlsym_error) {
+ printf("Cannot load symbol destroy: %s\n", dlsym_error);
+ return;
+ }
+
+ ptr = o_create();
+}
+
+AudioOutputEngineDL::~AudioOutputEngineDL()
+{
+ o_destroy(ptr);
+}
+
+bool AudioOutputEngineDL::init(Channels channels)
+{
+ char **n = (char**)malloc(sizeof(char*)*channels.size());
+ for(size_t i = 0; i < channels.size(); i++) {
+ n[i] = strdup(channels[i].name.c_str());
+ }
+
+ bool ret = o_init(ptr, channels.size(), n);
+
+ for(size_t i = 0; i < channels.size(); i++) {
+ free(n[i]);
+ }
+ free(n);
+
+ return ret;
+}
+
+void AudioOutputEngineDL::setParm(std::string parm, std::string value)
+{
+ o_setparm(ptr, parm.c_str(), value.c_str());
+}
+
+bool AudioOutputEngineDL::start()
+{
+ return o_start(ptr);
+}
+
+void AudioOutputEngineDL::stop()
+{
+ return o_stop(ptr);
+}
+
+void AudioOutputEngineDL::pre(size_t size)
+{
+ return o_pre(ptr, size);
+}
+
+void AudioOutputEngineDL::run(int ch, sample_t *samples, size_t nsamples)
+{
+ o_run(ptr, ch, samples, nsamples);
+}
+
+void AudioOutputEngineDL::post(size_t size)
+{
+ return o_post(ptr, size);
+}
+
+#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*/
diff --git a/drumgizmo/audiooutputenginedl.h b/drumgizmo/audiooutputenginedl.h
new file mode 100644
index 0000000..7faa78e
--- /dev/null
+++ b/drumgizmo/audiooutputenginedl.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputenginedl.h
+ *
+ * Wed Jul 13 14:40:01 CEST 2011
+ * Copyright 2011 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_AUDIOOUTPUTENGINEDL_H__
+#define __DRUMGIZMO_AUDIOOUTPUTENGINEDL_H__
+
+#include <string>
+#include <stdlib.h>
+#include <audiotypes.h>
+
+#include "channel.h"
+
+#include "audiooutputengine.h"
+
+typedef void* (*output_create_func_t)(void);
+typedef void (*output_destroy_func_t)(void*);
+typedef bool (*output_start_func_t)(void*);
+typedef void (*output_stop_func_t)(void*);
+typedef bool (*output_init_func_t)(void*,int,char**);
+typedef void (*output_setparm_func_t)(void*,const char*,const char*);
+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);
+
+class AudioOutputEngineDL : public AudioOutputEngine {
+public:
+ AudioOutputEngineDL(std::string name);
+ ~AudioOutputEngineDL();
+
+ bool init(Channels channels);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre(size_t nsamples);
+ void run(int ch, sample_t *samples, size_t nsamples);
+ void post(size_t nsamples);
+
+private:
+ void *ptr;
+ output_create_func_t o_create;
+ output_destroy_func_t o_destroy;
+ output_init_func_t o_init;
+ output_setparm_func_t o_setparm;
+ output_start_func_t o_start;
+ output_stop_func_t o_stop;
+ output_pre_func_t o_pre;
+ output_run_func_t o_run;
+ output_post_func_t o_post;
+};
+
+#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINEDL_H__*/
diff --git a/src/cli.cc b/drumgizmo/drumgizmoc.cc
index bb0eae2..de16dd9 100644
--- a/src/cli.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -33,8 +33,8 @@
#include "drumgizmo.h"
-#include "audiooutputengine.h"
-#include "audioinputengine.h"
+#include "audiooutputenginedl.h"
+#include "audioinputenginedl.h"
#include "event.h"
@@ -43,7 +43,7 @@ static const char version_str[] =
;
static const char copyright_str[] =
-"Copyright (C) 2008-2009 Bent Bisballe Nyeng - Aasimon.org.\n"
+"Copyright (C) 2008-2011 Bent Bisballe Nyeng - Aasimon.org.\n"
"This is free software. You may redistribute copies of it under the terms of\n"
"the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"
@@ -55,8 +55,10 @@ static const char usage_str[] =
"Usage: %s [options] drumkitfile\n"
"Options:\n"
" -p, --preload Load entire kit audio files into memory (uses ALOT of memory).\n"
-" -o, --outputengine alsa|jack|sndfile Use said audio engine.\n"
-" -i, --inputengine jackmidi|midifile Use said audio engine.\n"
+" -i, --inputengine dummy|test|jackmidi|midifile Use said event input engine.\n"
+" -I, --inputparms parmlist Set input engine parameters.\n"
+" -o, --outputengine dummy|alsa|jack|sndfile Use said audio output engine.\n"
+" -O, --outputparms parmlist Set output engine parameters.\n"
" -v, --version Print version information and exit.\n"
" -h, --help Print this message and exit.\n"
;
@@ -67,31 +69,51 @@ int main(int argc, char *argv[])
std::string outputengine;
std::string inputengine;
+ std::string iparms;
+ std::string oparms;
bool preload = false;
int option_index = 0;
while(1) {
static struct option long_options[] = {
{"preload", no_argument, 0, 'p'},
- {"outputengine", required_argument, 0, 'o'},
{"inputengine", required_argument, 0, 'i'},
+ {"inputparms", required_argument, 0, 'I'},
+ {"outputengine", required_argument, 0, 'o'},
+ {"outputparms", required_argument, 0, 'O'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
- c = getopt_long (argc, argv, "hvpo:i:", long_options, &option_index);
+ c = getopt_long (argc, argv, "hvpo:O:i:I:", long_options, &option_index);
if (c == -1)
break;
switch(c) {
+ case 'i':
+ inputengine = optarg;
+ if(inputengine == "help") {
+ printf("Available input engines: jackmidi, midifile.\n");
+ return 0;
+ }
+ break;
+
+ case 'I':
+ iparms = optarg;
+ break;
+
case 'o':
outputengine = optarg;
+ if(outputengine == "help") {
+ printf("Available output engines: alsa, jack, sndfile.\n");
+ return 0;
+ }
break;
- case 'i':
- inputengine = optarg;
+ case 'O':
+ oparms = optarg;
break;
case 'p':
@@ -114,31 +136,84 @@ int main(int argc, char *argv[])
}
}
- if(outputengine == "") {
- printf("Missing output engine\n");
+ if(inputengine == "") {
+ printf("Missing input engine\n");
return 1;
}
- AudioOutputEngine *oe = createAudioOutputEngine(outputengine);
+ AudioInputEngine *ie = new AudioInputEngineDL(inputengine);
- if(oe == NULL) {
- printf("Invalid output engine: %s\n", outputengine.c_str());
+ if(ie == NULL) {
+ printf("Invalid input engine: %s\n", inputengine.c_str());
return 1;
}
+ {
+ std::string parm;
+ std::string val;
+ bool inval = false;
+ for(size_t i = 0; i < iparms.size(); i++) {
+ if(iparms[i] == ',') {
+ ie->setParm(parm, val);
+ parm = "";
+ val = "";
+ inval = false;
+ continue;
+ }
- if(inputengine == "") {
- printf("Missing input engine\n");
+ if(iparms[i] == '=') {
+ inval = true;
+ continue;
+ }
+
+ if(inval) {
+ val += iparms[i];
+ } else {
+ parm += iparms[i];
+ }
+ }
+ if(parm != "") ie->setParm(parm, val);
+ }
+
+ if(outputengine == "") {
+ printf("Missing output engine\n");
return 1;
}
- AudioInputEngine *ie = createAudioInputEngine(inputengine);
+ AudioOutputEngine *oe = new AudioOutputEngineDL(outputengine);
- if(ie == NULL) {
- printf("Invalid input engine: %s\n", outputengine.c_str());
+ if(oe == NULL) {
+ printf("Invalid output engine: %s\n", outputengine.c_str());
return 1;
}
+ {
+ std::string parm;
+ std::string val;
+ bool inval = false;
+ for(size_t i = 0; i < oparms.size(); i++) {
+ if(oparms[i] == ',') {
+ oe->setParm(parm, val);
+ parm = "";
+ val = "";
+ inval = false;
+ continue;
+ }
+
+ if(oparms[i] == '=') {
+ inval = true;
+ continue;
+ }
+
+ if(inval) {
+ val += oparms[i];
+ } else {
+ parm += oparms[i];
+ }
+ }
+ if(parm != "") oe->setParm(parm, val);
+ }
+
std::string kitfile;
if(option_index < argc) {
@@ -160,15 +235,8 @@ int main(int argc, char *argv[])
printf("Using kitfile: %s\n", kitfile.c_str());
- Channels channels;
- Channel c1; c1.num = 0;
- Channel c2; c2.num = 1;
- channels.push_back(c1);
- channels.push_back(c2);
- ChannelMixer m(channels, &channels[0]);
-
- DrumGizmo gizmo(*oe, *ie, m);
- if(/*kitfile == "" ||*/ !gizmo.loadkit(kitfile)) {
+ DrumGizmo gizmo(oe, ie);
+ if(kitfile == "" || !gizmo.loadkit(kitfile)) {
printf("Failed to load \"%s\".\n", kitfile.c_str());
return 1;
}
diff --git a/drumgizmo/input/Makefile.am b/drumgizmo/input/Makefile.am
new file mode 100644
index 0000000..d4bdad8
--- /dev/null
+++ b/drumgizmo/input/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = @INPUT_PLUGINS@
diff --git a/drumgizmo/input/dummy/Makefile.am b/drumgizmo/input/dummy/Makefile.am
new file mode 100644
index 0000000..10bd70f
--- /dev/null
+++ b/drumgizmo/input/dummy/Makefile.am
@@ -0,0 +1,26 @@
+
+dummysources = \
+ dummy.cc
+
+if HAVE_INPUT_DUMMY
+
+dummyltlibs = libdummy.la
+dummybuildsources = $(dummysources)
+
+else
+
+dummyltlibs =
+dummybuildsources =
+
+endif
+
+EXTRA_DIST = $(dummysources)
+
+lib_LTLIBRARIES = $(dummyltlibs)
+
+libdir = $(INPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/include
+libdummy_la_LDFLAGS =
+libdummy_la_LIBADD =
+libdummy_la_SOURCES = $(dummybuildsources)
diff --git a/drumgizmo/input/dummy/dummy.cc b/drumgizmo/input/dummy/dummy.cc
new file mode 100644
index 0000000..4a570db
--- /dev/null
+++ b/drumgizmo/input/dummy/dummy.cc
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * dummy.cc
+ *
+ * Sat Apr 30 21:11:54 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <string>
+#include <event.h>
+
+class Dummy {
+public:
+ Dummy() {}
+ ~Dummy() {}
+
+ bool init(int instruments, char *inames[]);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+};
+
+bool Dummy::init(int instruments, char *inames[])
+{
+ return true;
+}
+
+void Dummy::setParm(std::string parm, std::string value)
+{
+}
+
+bool Dummy::start()
+{
+ return true;
+}
+
+void Dummy::stop()
+{
+}
+
+void Dummy::pre()
+{
+}
+
+event_t *Dummy::run(size_t pos, size_t len, size_t *nevents)
+{
+ *nevents = 0;
+ return NULL;
+ /*
+ if(rand() % 10 != 0) return;
+
+ Instrument *i = NULL;
+ int d = rand() % drumkit->instruments.size();
+ Instruments::iterator it = drumkit->instruments.begin();
+ while(d--) {
+ i = &(it->second);
+ it++;
+ }
+
+ if(i == NULL) return;
+
+ Sample *s = i->sample((double)rand()/(double)RAND_MAX);
+
+ if(s == NULL) {
+ printf("Missing Sample.\n");
+ // continue;
+ }
+
+ Channels::iterator j = drumkit->channels.begin();
+ while(j != drumkit->channels.end()) {
+ Channel &ch = *j;
+ AudioFile *af = s->getAudioFile(&ch);
+ if(af == NULL) {
+ printf("Missing AudioFile.\n");
+ } else {
+ printf("Adding event.\n");
+ Event *evt = new EventSample(ch.num, 1.0, af);
+ eventqueue->post(evt, pos);
+ }
+ j++;
+ }
+ */
+}
+
+void Dummy::post()
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new Dummy();
+ }
+
+ void destroy(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ delete dummy;
+ }
+
+ bool init(void *h, int i, char *inames[])
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->init(i, inames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->start();
+ }
+
+ void stop(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->stop();
+ }
+
+ void pre(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->pre();
+ }
+
+ event_t *run(void *h, size_t pos, size_t len, size_t *nev)
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->run(pos, len, nev);
+ }
+
+ void post(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->post();
+ }
+}
+
+#ifdef TEST_AUDIOINPUTENGINEDUMMY
+//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_AUDIOINPUTENGINEDUMMY*/
diff --git a/drumgizmo/input/jackmidi/Makefile.am b/drumgizmo/input/jackmidi/Makefile.am
new file mode 100644
index 0000000..f357b56
--- /dev/null
+++ b/drumgizmo/input/jackmidi/Makefile.am
@@ -0,0 +1,28 @@
+
+jackmidisources = \
+ jackmidi.cc \
+ jackclient.cc \
+ jackclient.h
+
+if HAVE_INPUT_JACKMIDI
+
+jackmidiltlibs = libjackmidi.la
+jackmidibuildsources = $(jackmidisources)
+
+else
+
+jackmidiltlibs =
+jackmidibuildsources =
+
+endif
+
+EXTRA_DIST = $(jackmidisources)
+
+lib_LTLIBRARIES = $(jackmidiltlibs)
+
+libdir = $(INPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/include $(JACK_CFLAGS)
+libjackmidi_la_LDFLAGS = $(JACK_LIBS)
+libjackmidi_la_LIBADD =
+libjackmidi_la_SOURCES = $(jackmidibuildsources)
diff --git a/src/audioinputenginejackmidi.cc b/drumgizmo/input/jackmidi/audioinputenginejackmidi.cc
index 49bfde4..5e1fb85 100644
--- a/src/audioinputenginejackmidi.cc
+++ b/drumgizmo/input/jackmidi/audioinputenginejackmidi.cc
@@ -28,73 +28,110 @@
#define NOTE_ON 0x90
-extern "C" {
- static int _wrap_jack_process(jack_nframes_t nframes, void *arg){
- return ((AudioInputEngineJackMidi*)arg)->process(nframes);}
-}
-
AudioInputEngineJackMidi::AudioInputEngineJackMidi()
{
+ jackclient = init_jack_client();
+
+ jackclient->addJackProcess(this);
+
pos = 0;
}
AudioInputEngineJackMidi::~AudioInputEngineJackMidi()
{
- // wait_stop();
- jack_client_close(jack_client);
+ jackclient->removeJackProcess(this);
+ close_jack_client();
}
-int AudioInputEngineJackMidi::process(jack_nframes_t nframes)
+void AudioInputEngineJackMidi::jack_process(jack_nframes_t nframes)
{
- // printf(" jk: %d\n", pos);
-
void *midibuffer = jack_port_get_buffer(midi_port, nframes);
jack_nframes_t midievents = jack_midi_get_event_count(midibuffer);
- // if(midievents) printf("#%d\n", midievents);
+
for(jack_nframes_t i = 0; i < midievents; i++) {
jack_midi_event_t event;
jack_midi_event_get(&event, midibuffer, i);
-
if(event.size != 3) continue;
if((event.buffer[0] & NOTE_ON) != NOTE_ON) continue;
int key = event.buffer[1];
int velocity = event.buffer[2];
- //if(velocity == 0) continue;
-
printf("Event key:%d vel:%d\n", key, velocity);
- Event *evt = new EventSine(0, key * 10, (float)velocity / 127.0, 1000);
- eventqueue->post(evt, pos + event.time);
+ /*
+ if(kit->midimap.find(key) == kit->midimap.end()) {
+ printf("Missing note %d in midimap.\n", key);
+ continue;
+ }
+
+ std::string instr = kit->midimap[key];
+
+ if(kit->instruments.find(instr) == kit->instruments.end()) {
+ printf("Missing instrument %s.\n", instr.c_str());
+ continue;
+ }
+ */
+
+ Instrument *i = NULL;
+ int d = key % kit->instruments.size();
+ Instruments::iterator it = kit->instruments.begin();
+ while(d--) {
+ i = &(it->second);
+ it++;
+ }
+
+ if(i == NULL) {
+ continue;
+ }
+
+ // Sample *s = i.sample((float)velocity/127.0);
+ Sample *s = i->sample(0.5);
+
+ if(s == NULL) {
+ printf("Missing Sample.\n");
+ continue;
+ }
+
+ Channels::iterator j = kit->channels.begin();
+ while(j != kit->channels.end()) {
+ Channel &ch = *j;
+ AudioFile *af = s->getAudioFile(&ch);
+ if(af == NULL) {
+ printf("Missing AudioFile.\n");
+ } else {
+ printf("Adding event.\n");
+ Event *evt = new EventSample(ch.num, 1.0, af);
+ eventqueue->post(evt, pos + event.time + nframes);
+ }
+ j++;
+ }
}
jack_midi_clear_buffer(midibuffer);
pos += nframes;
-
- return 0;
}
-bool AudioInputEngineJackMidi::init(EventQueue *e)
+bool AudioInputEngineJackMidi::init(EventQueue *e, DrumKit *dk)
{
eventqueue = e;
+ kit = dk;
- jack_status_t status;
-
- jack_client = jack_client_open("DrumGizmo", JackNullOption, &status);
-
- midi_port = jack_port_register(jack_client,
+ midi_port = jack_port_register(jackclient->jack_client,
"drumgizmo_midiin",
JACK_DEFAULT_MIDI_TYPE,
JackPortIsInput,// | JackPortIsTerminal,
0);
- jack_set_process_callback(jack_client, _wrap_jack_process, this);
+ return true;
+}
- jack_activate(jack_client);
+bool AudioInputEngineJackMidi::activate()
+{
+ jackclient->activate();
return true;
}
diff --git a/src/audioinputenginejackmidi.h b/drumgizmo/input/jackmidi/audioinputenginejackmidi.h
index 9807a40..e4c6e69 100644
--- a/src/audioinputenginejackmidi.h
+++ b/drumgizmo/input/jackmidi/audioinputenginejackmidi.h
@@ -33,23 +33,29 @@
#include "audioinputengine.h"
#include "event.h"
-class AudioInputEngineJackMidi : public AudioInputEngine {
+#include "jackclient.h"
+
+class AudioInputEngineJackMidi : public AudioInputEngine, public JackProcess {
public:
AudioInputEngineJackMidi();
~AudioInputEngineJackMidi();
- bool init(EventQueue *e);
+ bool init(EventQueue *e, DrumKit *drumkit);
+ bool activate();
void run(size_t pos, size_t len) {}
void thread_main();
- int process(jack_nframes_t nframes);
+ void jack_process(jack_nframes_t nframes);
private:
+ DrumKit *kit;
size_t pos;
EventQueue *eventqueue;
- jack_client_t *jack_client;
+
+ JackClient *jackclient;
jack_port_t *midi_port;
};
#endif/*__DRUMGIZMO_AUDIOINPUTENGINEJACKMIDI_H__*/
+
diff --git a/drumgizmo/input/jackmidi/jackclient.cc b/drumgizmo/input/jackmidi/jackclient.cc
new file mode 100644
index 0000000..4fbafb5
--- /dev/null
+++ b/drumgizmo/input/jackmidi/jackclient.cc
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * jackclient.cc
+ *
+ * Sun Jul 20 21:48:44 CEST 2008
+ * Copyright 2008 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 "jackclient.h"
+
+extern "C"
+{
+ int _wrap_jack_process(jack_nframes_t nframes, void *arg){
+ return ((JackClient*)arg)->process(nframes);}
+} // extern "C"
+
+JackClient::JackClient()
+ : refcnt(0)
+{
+ jack_status_t status;
+
+ jack_client = jack_client_open("DrumGizmo", JackNullOption, &status);
+
+ jack_set_process_callback(jack_client, _wrap_jack_process, this);
+}
+
+JackClient::~JackClient()
+{
+ jack_client_close(jack_client);
+}
+
+void JackClient::addJackProcess(JackProcess *process)
+{
+ jack_processes.insert(process);
+}
+
+void JackClient::removeJackProcess(JackProcess *process)
+{
+ jack_processes.erase(process);
+}
+
+void JackClient::activate()
+{
+ if(!active) jack_activate(jack_client);
+ active = true;
+}
+
+int JackClient::process(jack_nframes_t nframes)
+{
+ std::set<JackProcess *>::iterator i = jack_processes.begin();
+ while(i != jack_processes.end()) {
+ JackProcess *jp = *i;
+ jp->jack_process(nframes);
+ i++;
+ }
+
+ return 0;
+}
+
+JackClient *jackclient = NULL;
+
+JackClient *init_jack_client()
+{
+ if(jackclient == NULL) jackclient = new JackClient();
+ jackclient->refcnt++;
+ return jackclient;
+
+}
+void close_jack_client()
+{
+ if(jackclient) {
+ jackclient->refcnt--;
+ if(jackclient->refcnt == 0) {
+ delete jackclient;
+ jackclient = NULL;
+ }
+ }
+}
diff --git a/src/jackclient.h b/drumgizmo/input/jackmidi/jackclient.h
index 21e1615..88e4bbf 100644
--- a/src/jackclient.h
+++ b/drumgizmo/input/jackmidi/jackclient.h
@@ -27,49 +27,38 @@
#ifndef __DRUMGIZMO_JACKCLIENT_H__
#define __DRUMGIZMO_JACKCLIENT_H__
-#include <vector>
-
#include <jack/jack.h>
-#include <jack/midiport.h>
-
-#include "drumkit.h"
-#include "event.h"
-#include "sample.h"
-#include "midimapper.h"
-#include "beatmapper.h"
+#include <set>
-typedef std::vector< jack_port_t *> Ports;
+class JackProcess {
+public:
+ virtual void jack_process(jack_nframes_t nframes) = 0;
+};
class JackClient {
public:
- JackClient(DrumKit *drumkit);
+ JackClient();
~JackClient();
- void activate();
+ void addJackProcess(JackProcess *process);
+ void removeJackProcess(JackProcess *process);
- // Callbacks
- void shutdown();
+ void activate();
int process(jack_nframes_t nframes);
- void thread_init();
- void freewheel_mode(int freewheel_mode);
- int buffer_size(jack_nframes_t nframes);
- int sample_rate(jack_nframes_t nframes);
- void port_registration(jack_port_id_t port, int i);
- int graph_order();
- int xrun();
-private:
jack_client_t *jack_client;
- // Ports input_ports;
- Ports output_ports;
- jack_port_t *midi_port;
-
- Events events;
- DrumKit *drumkit;
+ // Sort of private...
+ int refcnt;
- MidiMapper midimapper;
- std::vector< BeatMapper* > beatmappers;
+private:
+ std::set<JackProcess *> jack_processes;
+ bool active;
};
+extern JackClient *jackclient;
+
+JackClient *init_jack_client();
+void close_jack_client();
+
#endif/*__DRUMGIZMO_JACKCLIENT_H__*/
diff --git a/drumgizmo/input/jackmidi/jackmidi.cc b/drumgizmo/input/jackmidi/jackmidi.cc
new file mode 100644
index 0000000..f9faabd
--- /dev/null
+++ b/drumgizmo/input/jackmidi/jackmidi.cc
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * jackmidi.cc
+ *
+ * Sat Apr 30 21:11:54 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <event.h>
+#include <string>
+
+#include <stdio.h>
+
+#define NOTE_ON 0x90
+
+#include "jackclient.h"
+
+#include <jack/midiport.h>
+
+class JackMidi : public JackProcess {
+public:
+ JackMidi();
+ ~JackMidi();
+
+ bool init(int instruments, char *inames[]);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+
+ void jack_process(jack_nframes_t nframes);
+
+private:
+ void loadMap(std::string map) {}
+
+ JackClient *jackclient;
+ jack_port_t *midi_port;
+
+ size_t pos;
+
+ event_t *list;
+ size_t listsize;
+};
+
+JackMidi::JackMidi()
+{
+ jackclient = init_jack_client();
+ jackclient->addJackProcess(this);
+ pos = 0;
+
+ list = (event_t *)malloc(sizeof(event_t) * 1000);
+ listsize = 0;
+}
+
+JackMidi::~JackMidi()
+{
+ jackclient->removeJackProcess(this);
+ close_jack_client();
+}
+
+bool JackMidi::init(int instruments, char *inames[])
+{
+ midi_port = jack_port_register(jackclient->jack_client,
+ "drumgizmo_midiin",
+ JACK_DEFAULT_MIDI_TYPE,
+ JackPortIsInput,// | JackPortIsTerminal,
+ 0);
+
+ return true;
+}
+
+void JackMidi::setParm(std::string parm, std::string value)
+{
+ if(parm == "map") loadMap(value);
+}
+
+bool JackMidi::start()
+{
+ jackclient->activate();
+ return true;
+}
+
+void JackMidi::stop()
+{
+}
+
+void JackMidi::pre()
+{
+}
+
+event_t *JackMidi::run(size_t pos, size_t len, size_t *nevents)
+{
+ *nevents = listsize;
+ event_t *l = list;
+ list = (event_t *)malloc(sizeof(event_t) * 1000);
+ listsize = 0;
+ return l;
+}
+
+void JackMidi::jack_process(jack_nframes_t nframes)
+{
+ void *midibuffer = jack_port_get_buffer(midi_port, nframes);
+
+ jack_nframes_t midievents = jack_midi_get_event_count(midibuffer);
+
+ for(jack_nframes_t i = 0; i < midievents; i++) {
+ jack_midi_event_t event;
+ jack_midi_event_get(&event, midibuffer, i);
+
+ if(event.size != 3) continue;
+ if((event.buffer[0] & NOTE_ON) != NOTE_ON) continue;
+
+ int key = event.buffer[1];
+ int velocity = event.buffer[2];
+
+ printf("Event key:%d vel:%d\n", key, velocity);
+
+ if(velocity) {
+ list[listsize].type = TYPE_ONSET;
+ list[listsize].instrument = key;
+ list[listsize].velocity = velocity / 127.0;
+ list[listsize].offset = event.time;
+ listsize++;
+ }
+ }
+
+ jack_midi_clear_buffer(midibuffer);
+
+ pos += nframes;
+}
+
+
+void JackMidi::post()
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new JackMidi();
+ }
+
+ void destroy(void *h)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ delete jackmidi;
+ }
+
+ bool init(void *h, int i, char *inames[])
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ return jackmidi->init(i, inames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ jackmidi->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ return jackmidi->start();
+ }
+
+ void stop(void *h)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ jackmidi->stop();
+ }
+
+ void pre(void *h)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ jackmidi->pre();
+ }
+
+ event_t *run(void *h, size_t pos, size_t len, size_t *nev)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ return jackmidi->run(pos, len, nev);
+ }
+
+ void post(void *h)
+ {
+ JackMidi *jackmidi = (JackMidi*)h;
+ jackmidi->post();
+ }
+}
+
+#ifdef TEST_AUDIOINPUTENGINEJACKMIDI
+//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_AUDIOINPUTENGINEJACKMIDI*/
diff --git a/drumgizmo/input/midifile/Makefile.am b/drumgizmo/input/midifile/Makefile.am
new file mode 100644
index 0000000..30a2db4
--- /dev/null
+++ b/drumgizmo/input/midifile/Makefile.am
@@ -0,0 +1,27 @@
+
+midifilesources = \
+ midifile.cc \
+ midimap.cc
+
+if HAVE_INPUT_MIDIFILE
+
+midifileltlibs = libmidifile.la
+midifilebuildsources = $(midifilesources)
+
+else
+
+midifileltlibs =
+midifilebuildsources =
+
+endif
+
+EXTRA_DIST = $(midifilesources)
+
+lib_LTLIBRARIES = $(midifileltlibs)
+
+libdir = $(INPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/include $(SMF_CFLAGS)
+libmidifile_la_LDFLAGS = $(SMF_LIBS)
+libmidifile_la_LIBADD =
+libmidifile_la_SOURCES = $(midifilebuildsources)
diff --git a/src/audioinputenginemidifile.cc b/drumgizmo/input/midifile/audioinputenginemidifile.cc
index 878ca1b..878ca1b 100644
--- a/src/audioinputenginemidifile.cc
+++ b/drumgizmo/input/midifile/audioinputenginemidifile.cc
diff --git a/src/audioinputenginemidifile.h b/drumgizmo/input/midifile/audioinputenginemidifile.h
index fbdeffa..6bb9ff6 100644
--- a/src/audioinputenginemidifile.h
+++ b/drumgizmo/input/midifile/audioinputenginemidifile.h
@@ -34,7 +34,7 @@ public:
AudioInputEngineMidiFile() {}
~AudioInputEngineMidiFile() {}
- bool init(EventQueue *eventqueue) { return true; }
+ bool init(EventQueue *eventqueue, DrumKit *drumkit) { return true; }
void run(size_t pos, size_t len) {}
};
diff --git a/drumgizmo/input/midifile/midifile.cc b/drumgizmo/input/midifile/midifile.cc
new file mode 100644
index 0000000..7b17028
--- /dev/null
+++ b/drumgizmo/input/midifile/midifile.cc
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * dummy.cc
+ *
+ * Sat Apr 30 21:11:54 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <string>
+#include <event.h>
+
+#include <smf.h>
+
+#include "midimap.h"
+
+#define NOTE_ON 0x90
+
+class MidiFile {
+public:
+ MidiFile();
+ ~MidiFile() {}
+
+ bool init(int instruments, char *inames[]);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+
+private:
+ smf_t *smf;
+ smf_event_t *cur_event;
+
+ MidiMap mmap;
+
+ // Parameters
+ std::string filename;
+ float speed;
+ int track;
+ std::string midimapfile;
+};
+
+MidiFile::MidiFile()
+{
+ cur_event = NULL;
+ smf = NULL;
+
+ filename = "";
+ speed = 1.0;
+ track = 0;
+}
+
+bool MidiFile::init(int instruments, char *inames[])
+{
+ smf = smf_load(filename.c_str());
+
+ mmap.load(midimapfile);
+
+ return true;
+}
+
+void MidiFile::setParm(std::string parm, std::string value)
+{
+ if(parm == "file") filename = value;
+ if(parm == "speed") speed = atof(value.c_str());
+ if(parm == "track") track = atoi(value.c_str());
+ if(parm == "midimap") midimapfile = value;
+}
+
+bool MidiFile::start()
+{
+ return true;
+}
+
+void MidiFile::stop()
+{
+}
+
+void MidiFile::pre()
+{
+}
+
+event_t *MidiFile::run(size_t pos, size_t len, size_t *nevents)
+{
+ event_t *evs = NULL;
+ size_t nevs = 0;
+
+ double cur_max_time = (double)(pos + len) / (44100.0 / speed);
+ // double cur_min_time = (double)(pos) / (44100.0 / speed);
+
+ if(!cur_event) cur_event = smf_get_next_event(smf);
+
+ while(cur_event && cur_event->time_seconds < cur_max_time) {
+ if(!smf_event_is_metadata(cur_event)) {
+ if( (cur_event->midi_buffer_length == 3) &&
+ ((cur_event->midi_buffer[0] & NOTE_ON) == NOTE_ON) &&
+ cur_event->track_number == track && cur_event->midi_buffer[2] > 0) {
+
+ if(evs == NULL) evs = (event_t *)malloc(sizeof(event_t) * 1000);
+
+ int key = cur_event->midi_buffer[1];
+ int velocity = cur_event->midi_buffer[2];
+
+ evs[nevs].type = TYPE_ONSET;
+ size_t evpos = cur_event->time_seconds * (44100.0 / speed);
+ evs[nevs].offset = evpos - pos;
+ /*
+ printf("evpos: %d, sec: %f, pos: %d, len: %d, max_time: %f\n",
+ evpos, cur_event->time_seconds, pos, len, cur_max_time);
+ */
+ evs[nevs].instrument = mmap.lookup(key);
+ evs[nevs].velocity = velocity / 127.0;
+
+ nevs++;
+ if(nevs > 999) {
+ printf("PANIC!\n");
+ break;
+ }
+ }
+ }
+
+ cur_event = smf_get_next_event(smf);
+ }
+
+ if(!cur_event) {
+ if(evs == NULL) evs = (event_t *)malloc(sizeof(event_t) * 1000);
+ evs[nevs].type = TYPE_STOP;
+ evs[nevs].offset = len - 1;
+ nevs++;
+ }
+
+ *nevents = nevs;
+
+ return evs;
+}
+
+void MidiFile::post()
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new MidiFile();
+ }
+
+ void destroy(void *h)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ delete midifile;
+ }
+
+ bool init(void *h, int i, char *inames[])
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ return midifile->init(i, inames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ midifile->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ return midifile->start();
+ }
+
+ void stop(void *h)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ midifile->stop();
+ }
+
+ void pre(void *h)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ midifile->pre();
+ }
+
+ event_t *run(void *h, size_t pos, size_t len, size_t *nev)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ return midifile->run(pos, len, nev);
+ }
+
+ void post(void *h)
+ {
+ MidiFile *midifile = (MidiFile*)h;
+ midifile->post();
+ }
+}
+
+#ifdef TEST_AUDIOINPUTENGINEMIDIFILE
+//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_AUDIOINPUTENGINEMIDIFILE*/
diff --git a/drumgizmo/input/midifile/midimap.cc b/drumgizmo/input/midifile/midimap.cc
new file mode 100644
index 0000000..ccb9b3c
--- /dev/null
+++ b/drumgizmo/input/midifile/midimap.cc
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * midimap.cc
+ *
+ * Mon Jun 13 21:36:30 CEST 2011
+ * Copyright 2011 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 "midimap.h"
+
+/*
+
+ 35 = 1
+ 36-51 = 2 - TODO!
+ 51, 53 = 3 - TODO!
+ 54, 56-59, 62 = 4 - TODO!
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+MidiMap::MidiMap()
+{
+}
+
+bool MidiMap::load(std::string file)
+{
+ FILE *fp = fopen(file.c_str(), "r");
+ if(!fp) return false;
+
+ std::string line;
+ while(!feof(fp)) {
+ int c = fgetc(fp);
+ // printf("[%c]\n", c);
+ if(c == '\n') {
+ if(line != "") {
+ int from = atoi(line.substr(0, line.find('=')).c_str());
+ int to = atoi(line.substr(line.find('=')+1,
+ line.length()-line.find('=')+1).c_str());
+ map[from] = to;
+ // printf("Line: '%s', from: %d to: %d\n", line.c_str(), from, to);
+
+ }
+ line = "";
+ } else {
+ if((c >= '0' && c <= '9') || c == ',' || c == '-' || c == '=') {
+ line += (char)c;
+ } else {
+ if(c != '\t' && c != ' ') return false; // Parse error.
+ }
+ }
+ }
+
+ return true;
+}
+
+int MidiMap::lookup(int note)
+{
+ return map[note];
+}
+
+#ifdef TEST_MIDIMAP
+//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_MIDIMAP*/
diff --git a/src/audiooutputenginesndfile.h b/drumgizmo/input/midifile/midimap.h
index adfbe96..183d2d3 100644
--- a/src/audiooutputenginesndfile.h
+++ b/drumgizmo/input/midifile/midimap.h
@@ -1,9 +1,9 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * audiooutputenginesndfile.h
+ * midimap.h
*
- * Tue Sep 21 09:31:29 CEST 2010
- * Copyright 2010 Bent Bisballe Nyeng
+ * Mon Jun 13 21:36:29 CEST 2011
+ * Copyright 2011 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,28 +24,20 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __DRUMGIZMO_AUDIOOUTPUTENGINESNDFILE_H__
-#define __DRUMGIZMO_AUDIOOUTPUTENGINESNDFILE_H__
+#ifndef __DRUMGIZMO_MIDIMAP_H__
+#define __DRUMGIZMO_MIDIMAP_H__
+#include <map>
#include <string>
-#include <sndfile.h>
-
-#include "audiooutputengine.h"
-
-class AudioOutputEngineSndFile : public AudioOutputEngine {
+class MidiMap {
public:
- AudioOutputEngineSndFile(std::string filename);
- ~AudioOutputEngineSndFile();
-
- bool init(Channels *channels);
+ MidiMap();
+ bool load(std::string file);
+ int lookup(int note);
- void run(DrumGizmo *drumgizmo);
-
private:
- std::string filename;
- SF_INFO sf_info;
- SNDFILE *fh;
+ std::map<int, int> map;
};
-#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINESNDFILE_H__*/
+#endif/*__DRUMGIZMO_MIDIMAP_H__*/
diff --git a/drumgizmo/input/test/Makefile.am b/drumgizmo/input/test/Makefile.am
new file mode 100644
index 0000000..ca45de0
--- /dev/null
+++ b/drumgizmo/input/test/Makefile.am
@@ -0,0 +1,26 @@
+
+testsources = \
+ test.cc
+
+if HAVE_INPUT_TEST
+
+testltlibs = libtest.la
+testbuildsources = $(testsources)
+
+else
+
+testltlibs =
+testbuildsources =
+
+endif
+
+EXTRA_DIST = $(testsources)
+
+lib_LTLIBRARIES = $(testltlibs)
+
+libdir = $(INPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/include
+libtest_la_LDFLAGS =
+libtest_la_LIBADD =
+libtest_la_SOURCES = $(testbuildsources)
diff --git a/drumgizmo/input/test/test.cc b/drumgizmo/input/test/test.cc
new file mode 100644
index 0000000..457733f
--- /dev/null
+++ b/drumgizmo/input/test/test.cc
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audioinputenginedummy.cc
+ *
+ * Sat Apr 30 21:11:54 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <event.h>
+#include <string>
+
+class Test {
+public:
+ Test() { p = 0.1; instr = -1; }
+ ~Test() {}
+
+ bool init(int instruments, char *inames[]);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+
+private:
+ float p;
+ int instr;
+};
+
+bool Test::init(int instruments, char *inames[])
+{
+ return true;
+}
+
+void Test::setParm(std::string parm, std::string value)
+{
+ if(parm == "p") p = atof(value.c_str());
+ if(parm == "instr") instr = atoi(value.c_str());
+}
+
+bool Test::start()
+{
+ return true;
+}
+
+void Test::stop()
+{
+}
+
+void Test::pre()
+{
+}
+
+event_t *Test::run(size_t pos, size_t len, size_t *nevents)
+{
+ if((float)rand() / (float)RAND_MAX > p) {
+ *nevents = 0;
+ return NULL;
+ }
+
+ *nevents = 1;
+ event_t *evs = (event_t *)malloc(sizeof(event_t));
+ evs[0].type = TYPE_ONSET;
+
+ if(instr != -1) evs[0].instrument = instr;
+ else evs[0].instrument = rand() % 32;
+
+ evs[0].velocity = (float)rand()/(float)RAND_MAX;
+ evs[0].offset = len?rand()%len:0;
+ return evs;
+}
+
+void Test::post()
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new Test();
+ }
+
+ void destroy(void *h)
+ {
+ Test *test = (Test*)h;
+ delete test;
+ }
+
+ bool init(void *h, int i, char *inames[])
+ {
+ Test *test = (Test*)h;
+ return test->init(i, inames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ Test *test = (Test*)h;
+ test->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ Test *test = (Test*)h;
+ return test->start();
+ }
+
+ void stop(void *h)
+ {
+ Test *test = (Test*)h;
+ test->stop();
+ }
+
+ void pre(void *h)
+ {
+ Test *test = (Test*)h;
+ test->pre();
+ }
+
+ event_t *run(void *h, size_t pos, size_t len, size_t *nev)
+ {
+ Test *test = (Test*)h;
+ return test->run(pos, len, nev);
+ }
+
+ void post(void *h)
+ {
+ Test *test = (Test*)h;
+ test->post();
+ }
+}
+
+#ifdef TEST_AUDIOINPUTENGINETEST
+//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_AUDIOINPUTENGINETEST*/
diff --git a/drumgizmo/output/Makefile.am b/drumgizmo/output/Makefile.am
new file mode 100644
index 0000000..14ff00b
--- /dev/null
+++ b/drumgizmo/output/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = @OUTPUT_PLUGINS@
diff --git a/drumgizmo/output/alsa/Makefile.am b/drumgizmo/output/alsa/Makefile.am
new file mode 100644
index 0000000..d35cb21
--- /dev/null
+++ b/drumgizmo/output/alsa/Makefile.am
@@ -0,0 +1,26 @@
+
+alsasources = \
+ alsa.cc
+
+if HAVE_OUTPUT_ALSA
+
+alsaltlibs = libalsa.la
+alsabuildsources = $(alsasources)
+
+else
+
+alsaltlibs =
+alsabuildsources =
+
+endif
+
+EXTRA_DIST = $(alsasources)
+
+lib_LTLIBRARIES = $(alsaltlibs)
+
+libdir = $(OUTPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include $(ALSA_CFLAGS)
+libalsa_la_LDFLAGS = $(ALSA_LIBS)
+libalsa_la_LIBADD =
+libalsa_la_SOURCES = $(alsabuildsources)
diff --git a/drumgizmo/output/alsa/alsa.cc b/drumgizmo/output/alsa/alsa.cc
new file mode 100644
index 0000000..7b3a395
--- /dev/null
+++ b/drumgizmo/output/alsa/alsa.cc
@@ -0,0 +1,230 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputenginedummy.cc
+ *
+ * Sat Apr 30 21:12:02 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <audiotypes.h>
+#include <string>
+
+// Use the newer ALSA API
+#define ALSA_PCM_NEW_HW_PARAMS_API
+
+#include <asoundlib.h>
+
+#define T(x, msg) if(x < 0) { printf("%s failed: %s\n", msg, snd_strerror(x)); fflush(stdout); return false; }
+
+#define BUFSZ 40960
+
+class Alsa {
+public:
+ Alsa();
+ ~Alsa();
+ bool init(int channels, char *cnames[]);
+ void setParm(std::string parm, std::string value);
+ bool start();
+ void stop();
+ void pre(size_t size);
+ void run(int channel, sample_t* data, size_t size);
+ void post(size_t size);
+
+private:
+ snd_pcm_t *handle;
+ snd_pcm_hw_params_t *params;
+ sample_t *data;
+ size_t channels;
+
+ // Parameters
+ std::string device;
+ unsigned int srate;
+ snd_pcm_uframes_t frames;
+};
+
+Alsa::Alsa()
+{
+ handle = NULL;
+ data = NULL;
+
+ device = "default";
+ srate = 44100;
+ frames = 32;
+}
+
+Alsa::~Alsa()
+{
+ if(handle) snd_pcm_close(handle);
+ if(data) free(data);
+}
+
+bool Alsa::init(int channels, char *cnames[])
+{
+ int rc;
+
+ rc = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
+ T(rc, "snd_pcm_open");
+
+ this->channels = channels;
+ if(!handle) {
+ printf("No handle!\n");
+ return false;
+ }
+
+ // Allocate a hardware parameters object.
+ snd_pcm_hw_params_alloca(&params);
+ // if(rc < 0) return false;
+
+ // Fill it in with default values.
+ rc = snd_pcm_hw_params_any(handle, params);
+ T(rc, "snd_pcm_hw_params_any");
+
+ rc = snd_pcm_hw_params_set_access(handle, params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ T(rc, "snd_pcm_hw_params_set_access");
+
+ rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT);
+ T(rc, "snd_pcm_hw_params_set_format");
+
+ rc = snd_pcm_hw_params_set_channels(handle, params, channels);
+ T(rc, "snd_pcm_hw_params_set_channels");
+
+ rc = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
+ T(rc, "snd_pcm_hw_params_set_rate_near");
+
+ rc = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0);
+ T(rc, "snd_pcm_hw_params_set_period_size_near");
+
+ rc = snd_pcm_hw_params(handle, params);
+ T(rc, "snd_pcm_hw_params");
+
+ data = (sample_t*)malloc(sizeof(sample_t) * BUFSZ * channels);
+
+ return true;
+}
+
+void Alsa::setParm(std::string parm, std::string value)
+{
+ if(parm == "dev") device = value;
+ if(parm == "frames") frames = atoi(value.c_str());
+ if(parm == "srate") srate = atoi(value.c_str());
+}
+
+bool Alsa::start()
+{
+ return true;
+}
+
+void Alsa::stop()
+{
+}
+
+void Alsa::pre(size_t size)
+{
+}
+
+void Alsa::run(int channel, sample_t* cdata, size_t csize)
+{
+ // Write channel data in interleaved buffer.
+ for(size_t i = 0; i < csize; i++) {
+ data[i * channels + channel] = cdata[i];
+ }
+}
+
+void Alsa::post(size_t size)
+{
+ // Write the interleaved buffer to the soundcard
+ snd_pcm_writei(handle, data, size);
+}
+
+extern "C" {
+ void *create()
+ {
+ return new Alsa();
+ }
+
+ void destroy(void *h)
+ {
+ Alsa *alsa = (Alsa*)h;
+ delete alsa;
+ }
+
+ bool init(void *h, int cs, char *cnames[])
+ {
+ Alsa *alsa = (Alsa*)h;
+ return alsa->init(cs, cnames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ Alsa *alsa = (Alsa*)h;
+ alsa->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ Alsa *alsa = (Alsa*)h;
+ return alsa->start();
+ }
+
+ void stop(void *h)
+ {
+ Alsa *alsa = (Alsa*)h;
+ alsa->stop();
+ }
+
+ void pre(void *h, size_t s)
+ {
+ Alsa *alsa = (Alsa*)h;
+ alsa->pre(s);
+ }
+
+ void run(void *h, int ch, sample_t *data, size_t size)
+ {
+ Alsa *alsa = (Alsa*)h;
+ alsa->run(ch, data, size);
+ }
+
+ void post(void *h, size_t s)
+ {
+ 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*/
diff --git a/drumgizmo/output/dummy/Makefile.am b/drumgizmo/output/dummy/Makefile.am
new file mode 100644
index 0000000..ff68319
--- /dev/null
+++ b/drumgizmo/output/dummy/Makefile.am
@@ -0,0 +1,26 @@
+
+dummysources = \
+ dummy.cc
+
+if HAVE_OUTPUT_DUMMY
+
+dummyltlibs = libdummy.la
+dummybuildsources = $(dummysources)
+
+else
+
+dummyltlibs =
+dummybuildsources =
+
+endif
+
+EXTRA_DIST = $(dummysources)
+
+lib_LTLIBRARIES = $(dummyltlibs)
+
+libdir = $(OUTPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include
+libdummy_la_LDFLAGS =
+libdummy_la_LIBADD =
+libdummy_la_SOURCES = $(dummybuildsources)
diff --git a/drumgizmo/output/dummy/dummy.cc b/drumgizmo/output/dummy/dummy.cc
new file mode 100644
index 0000000..cd210dc
--- /dev/null
+++ b/drumgizmo/output/dummy/dummy.cc
@@ -0,0 +1,156 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * audiooutputenginedummy.cc
+ *
+ * Sat Apr 30 21:12:02 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <audiotypes.h>
+#include <string>
+
+class Dummy {
+public:
+ Dummy();
+ ~Dummy();
+ bool init(int channels, char *cnames[]);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre(size_t size);
+ void run(int channel, sample_t* data, size_t size);
+ void post(size_t size);
+};
+
+Dummy::Dummy()
+{
+}
+
+Dummy::~Dummy()
+{
+}
+
+bool Dummy::init(int channels, char *cnames[])
+{
+ return true;
+}
+
+void Dummy::setParm(std::string parm, std::string value)
+{
+}
+
+bool Dummy::start()
+{
+ return true;
+}
+
+void Dummy::stop()
+{
+}
+
+void Dummy::pre(size_t size)
+{
+}
+
+void Dummy::run(int channel, sample_t* data, size_t size)
+{
+}
+
+void Dummy::post(size_t size)
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new Dummy();
+ }
+
+ void destroy(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ delete dummy;
+ }
+
+ bool init(void *h, int cs, char *cnames[])
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->init(cs, cnames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ return dummy->start();
+ }
+
+ void stop(void *h)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->stop();
+ }
+
+ void pre(void *h, size_t size)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->pre(size);
+ }
+
+ void run(void *h, int ch, sample_t *data, size_t size)
+ {
+ Dummy *dummy = (Dummy*)h;
+ dummy->run(ch, data, size);
+ }
+
+ void post(void *h, size_t size)
+ {
+ 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*/
diff --git a/drumgizmo/output/wavfile/Makefile.am b/drumgizmo/output/wavfile/Makefile.am
new file mode 100644
index 0000000..14ffed3
--- /dev/null
+++ b/drumgizmo/output/wavfile/Makefile.am
@@ -0,0 +1,26 @@
+
+wavfilesources = \
+ wavfile.cc
+
+if HAVE_OUTPUT_WAVFILE
+
+wavfileltlibs = libwavfile.la
+wavfilebuildsources = $(wavfilesources)
+
+else
+
+wavfileltlibs =
+wavfilebuildsources =
+
+endif
+
+EXTRA_DIST = $(wavfilesources)
+
+lib_LTLIBRARIES = $(wavfileltlibs)
+
+libdir = $(OUTPUT_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SNDFILE_CFLAGS)
+libwavfile_la_LDFLAGS = $(SNDFILE_LIBS)
+libwavfile_la_LIBADD =
+libwavfile_la_SOURCES = $(wavfilebuildsources)
diff --git a/drumgizmo/output/wavfile/wavfile.cc b/drumgizmo/output/wavfile/wavfile.cc
new file mode 100644
index 0000000..03d8a7c
--- /dev/null
+++ b/drumgizmo/output/wavfile/wavfile.cc
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * wavfile.cc
+ *
+ * Sat Apr 30 21:12:02 CEST 2011
+ * Copyright 2011 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 <stdlib.h>
+
+#include <audiotypes.h>
+#include <string>
+
+#include <sndfile.h>
+
+#define T(x, msg) if(x < 0) { printf("%s failed: %s\n", msg, snd_strerror(x)); fflush(stdout); return false; }
+
+class WavFile {
+public:
+ WavFile();
+ ~WavFile();
+ bool init(int channels, char *cnames[]);
+ void setParm(std::string parm, std::string value);
+ bool start();
+ void stop();
+ void pre(size_t size);
+ void run(int channel, sample_t* data, size_t size);
+ void post(size_t size);
+
+private:
+ SF_INFO sf_info;
+ SNDFILE **fh;
+ size_t channels;
+
+ // Parameters
+ std::string filename;
+};
+
+WavFile::WavFile()
+{
+ fh = NULL;
+ filename = "output";
+}
+
+WavFile::~WavFile()
+{
+ if(fh == NULL) return;
+
+ for(size_t i = 0; i < channels; i++) {
+ if(fh[i]) sf_close(fh[i]);
+ }
+
+ if(fh) free(fh);
+}
+
+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);
+
+ for(size_t i = 0; i < this->channels; i++) fh[i] = NULL;
+
+ for(size_t i = 0; i < this->channels; i++) {
+ char fname[512];
+
+ sprintf(fname, "%s%s-%d.wav", filename.c_str(), cnames[i], i);
+ // printf("[%s]\n", fname);
+
+ fh[i] = sf_open(fname, SFM_WRITE, &sf_info);
+ if(!fh[i]) {
+ printf("Write error...\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void WavFile::setParm(std::string parm, std::string value)
+{
+ if(parm == "file") filename = value;
+}
+
+bool WavFile::start()
+{
+ return true;
+}
+
+void WavFile::stop()
+{
+}
+
+void WavFile::pre(size_t size)
+{
+}
+
+void WavFile::run(int channel, sample_t* cdata, size_t csize)
+{
+ if(channel < (int)channels) sf_writef_float(fh[channel], cdata, csize);
+}
+
+void WavFile::post(size_t size)
+{
+}
+
+extern "C" {
+ void *create()
+ {
+ return new WavFile();
+ }
+
+ void destroy(void *h)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ delete sndfile;
+ }
+
+ bool init(void *h, int cs, char *cnames[])
+ {
+ WavFile *sndfile = (WavFile*)h;
+ return sndfile->init(cs, cnames);
+ }
+
+ void setparm(void *h, const char *parm, const char *value)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ sndfile->setParm(parm, value);
+ }
+
+ bool start(void *h)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ return sndfile->start();
+ }
+
+ void stop(void *h)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ sndfile->stop();
+ }
+
+ void pre(void *h, size_t s)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ sndfile->pre(s);
+ }
+
+ void run(void *h, int ch, sample_t *data, size_t size)
+ {
+ WavFile *sndfile = (WavFile*)h;
+ sndfile->run(ch, data, size);
+ }
+
+ void post(void *h, size_t s)
+ {
+ 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*/
diff --git a/lv2/Makefile.am b/lv2/Makefile.am
new file mode 100644
index 0000000..69c2457
--- /dev/null
+++ b/lv2/Makefile.am
@@ -0,0 +1,44 @@
+lv2sources = \
+ lv2.cc \
+ input_lv2.cc \
+ output_lv2.cc \
+ $(top_srcdir)/src/audiofile.cc \
+ $(top_srcdir)/src/channel.cc \
+ $(top_srcdir)/src/channelmixer.cc \
+ $(top_srcdir)/src/drumgizmo.cc \
+ $(top_srcdir)/src/drumkit.cc \
+ $(top_srcdir)/src/drumkitparser.cc \
+ $(top_srcdir)/src/events.cc \
+ $(top_srcdir)/src/instrument.cc \
+ $(top_srcdir)/src/instrumentparser.cc \
+ $(top_srcdir)/src/midimapper.cc \
+ $(top_srcdir)/src/mutex.cc \
+ $(top_srcdir)/src/path.cc \
+ $(top_srcdir)/src/sample.cc \
+ $(top_srcdir)/src/saxparser.cc \
+ $(top_srcdir)/src/thread.cc \
+ $(top_srcdir)/src/velocity.cc
+
+if WITH_LV2
+
+lv2ltlibs = liblv2.la
+lv2buildsources = $(lv2sources)
+
+else
+
+lv2ltlibs =
+lv2buildsources =
+
+endif
+
+EXTRA_DIST = $(lv2sources)
+
+lib_LTLIBRARIES = $(lv2ltlibs)
+
+libdir = $(LV2_PLUGIN_DIR)
+
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SNDFILE_CXXFLAGS) \
+ $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS)
+liblv2_la_LDFLAGS = $(SNDFILE_LIBS) $(EXPAT_CFLAGS)
+liblv2_la_LIBADD =
+liblv2_la_SOURCES = $(lv2buildsources)
diff --git a/lv2/drumgizmo.ttl b/lv2/drumgizmo.ttl
new file mode 100644
index 0000000..97d3542
--- /dev/null
+++ b/lv2/drumgizmo.ttl
@@ -0,0 +1,130 @@
+# LV2 DrumGizmo Plugin
+# Copyright 2011 Bent Bisballe Nyeng <deva@aasimon.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .
+
+<http://drumgizmo.org/lv2>
+ a lv2:Plugin ;
+ doap:name "DrumGizmo" ;
+ doap:license <http://opensource.org/licenses/isc-license> ;
+ lv2:requiredFeature <http://lv2plug.in/ns/ext/uri-map>;
+ lv2:optionalFeature <http://lv2plug.in/ns/ext/event>;
+ lv2:port [
+ a lv2:InputPort ,
+ lv2ev:EventPort ;
+ lv2ev:supportsEvent <http://lv2plug.in/ns/ext/midi#MidiEvent> ;
+ lv2:index 0 ;
+ lv2:symbol "control" ;
+ lv2:name "Control"
+ ] , [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 1 ;
+ lv2:symbol "out1" ;
+ lv2:name "Out1"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 2 ;
+ lv2:symbol "out2" ;
+ lv2:name "Out2"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 3 ;
+ lv2:symbol "out3" ;
+ lv2:name "Out3"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 4 ;
+ lv2:symbol "out4" ;
+ lv2:name "Out4"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 5 ;
+ lv2:symbol "out5" ;
+ lv2:name "Out5"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 6 ;
+ lv2:symbol "out6" ;
+ lv2:name "Out6"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 7 ;
+ lv2:symbol "out7" ;
+ lv2:name "Out7"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 8 ;
+ lv2:symbol "out8" ;
+ lv2:name "Out8"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 9 ;
+ lv2:symbol "out9" ;
+ lv2:name "Out9"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 10 ;
+ lv2:symbol "out10" ;
+ lv2:name "Out10"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 11 ;
+ lv2:symbol "out11" ;
+ lv2:name "Out11"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 12 ;
+ lv2:symbol "out12" ;
+ lv2:name "Out12"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 13 ;
+ lv2:symbol "out13" ;
+ lv2:name "Out13"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 14 ;
+ lv2:symbol "out14" ;
+ lv2:name "Out14"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 15 ;
+ lv2:symbol "out15" ;
+ lv2:name "Out15"
+ ], [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 16 ;
+ lv2:symbol "out16" ;
+ lv2:name "Out16"
+ ] .
diff --git a/lv2/input_lv2.cc b/lv2/input_lv2.cc
new file mode 100644
index 0000000..d670505
--- /dev/null
+++ b/lv2/input_lv2.cc
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * input_lv2.cc
+ *
+ * Wed Jul 13 14:27:02 CEST 2011
+ * Copyright 2011 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 "input_lv2.h"
+
+InputLV2::InputLV2()
+{
+ eventPort = NULL;
+}
+
+InputLV2::~InputLV2()
+{
+}
+
+bool InputLV2::init(Instruments &instruments)
+{
+ return true;
+}
+
+void InputLV2::setParm(std::string parm, std::string value)
+{
+}
+
+bool InputLV2::start()
+{
+ return true;
+}
+
+void InputLV2::stop()
+{
+}
+
+void InputLV2::pre()
+{
+}
+event_t *InputLV2::run(size_t pos, size_t len, size_t *nevents)
+{
+ event_t *list;
+ size_t listsize;
+
+ list = (event_t *)malloc(sizeof(event_t) * 1000);
+ listsize = 0;
+
+ LV2_Event_Iterator iterator;
+ for(lv2_event_begin(&iterator, eventPort);
+ lv2_event_is_valid(&iterator);
+ lv2_event_increment(&iterator)) {
+
+ LV2_Event* ev = lv2_event_get(&iterator, NULL);
+
+ uint8_t* const data = (uint8_t* const)(ev + 1);
+
+ if ((data[0] & 0xF0) == 0x90) {
+
+ int key = data[1];
+ int velocity = data[2];
+
+ //printf("Event key:%d vel:%d\n", key, velocity);
+
+ if(velocity) {
+ list[listsize].type = TYPE_ONSET;
+ list[listsize].instrument = key;
+ list[listsize].velocity = velocity / 127.0;
+ list[listsize].offset = ev->frames;
+ listsize++;
+ }
+ /*
+ start_frame = ev->frames;
+ plugin->frame = 0;
+ plugin->play = true;
+ */
+ }
+ }
+
+ *nevents = listsize;
+ return list;
+}
+
+void InputLV2::post()
+{
+}
+
+#ifdef TEST_INPUT_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_INPUT_LV2*/
diff --git a/lv2/input_lv2.h b/lv2/input_lv2.h
new file mode 100644
index 0000000..9e1fcac
--- /dev/null
+++ b/lv2/input_lv2.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * input_lv2.h
+ *
+ * Wed Jul 13 14:27:02 CEST 2011
+ * Copyright 2011 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_INPUT_LV2_H__
+#define __DRUMGIZMO_INPUT_LV2_H__
+
+#include <audioinputengine.h>
+
+#include <lv2/lv2plug.in/ns/ext/event/event-helpers.h>
+
+class InputLV2 : public AudioInputEngine {
+public:
+ InputLV2();
+ ~InputLV2();
+
+ bool init(Instruments &instruments);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre();
+ event_t *run(size_t pos, size_t len, size_t *nevents);
+ void post();
+
+ LV2_Event_Buffer *eventPort;
+};
+
+#endif/*__DRUMGIZMO_INPUT_LV2_H__*/
diff --git a/lv2/lv2.cc b/lv2/lv2.cc
new file mode 100644
index 0000000..8a8d7a3
--- /dev/null
+++ b/lv2/lv2.cc
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * lv2.cc
+ *
+ * Wed Jul 13 13:50:33 CEST 2011
+ * Copyright 2011 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 <lv2/lv2plug.in/ns/lv2core/lv2.h>
+
+#include <stdlib.h>
+
+#include <drumgizmo.h>
+
+#include "input_lv2.h"
+#include "output_lv2.h"
+
+#define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
+
+typedef struct {
+ InputLV2 *in;
+ OutputLV2 *out;
+ DrumGizmo *dg;
+ sample_t *buffer;
+ size_t buffer_size;
+} DGLV2;
+
+/** A globally unique, case-sensitive identifier for this plugin type.
+ *
+ * All plugins with the same URI MUST be compatible in terms of 'port
+ * signature', meaning they have the same number of ports, same port
+ * shortnames, and roughly the same functionality. URIs should
+ * probably contain a version number (or similar) for this reason.
+ *
+ * Rationale: When serializing session/patch/etc files, hosts MUST
+ * refer to a loaded plugin by the plugin URI only. In the future
+ * loading a plugin with this URI MUST yield a plugin with the
+ * same ports (etc) which is 100% compatible. */
+#define DRUMGIZMO_URI "http://drumgizmo.org/lv2"
+
+/** Function pointer that instantiates a plugin.
+ *
+ * A handle is returned indicating the new plugin instance. The
+ * instantiation function accepts a sample rate as a parameter as well
+ * as the plugin descriptor from which this instantiate function was
+ * found. This function must return NULL if instantiation fails.
+ *
+ * bundle_path is a string of the path to the LV2 bundle which contains
+ * this plugin binary. It MUST include the trailing directory separator
+ * (e.g. '/') so that BundlePath + filename gives the path to a file
+ * in the bundle.
+ *
+ * features is a NULL terminated array of LV2_Feature structs which
+ * represent the features the host supports. Plugins may refuse to
+ * instantiate if required features are not found here (however hosts
+ * SHOULD NOT use this as a discovery mechanism, instead reading the
+ * data file before attempting to instantiate the plugin). This array
+ * must always exist; if a host has no features, it MUST pass a single
+ * element array containing NULL (to simplify plugins).
+ *
+ * Note that instance initialisation should generally occur in
+ * activate() rather than here. If a host calls instantiate, it MUST
+ * call cleanup() at some point in the future. */
+LV2_Handle instantiate(const struct _LV2_Descriptor *descriptor,
+ double sample_rate,
+ const char *bundle_path,
+ const LV2_Feature *const *features)
+{
+ DGLV2 *dglv2 = new DGLV2;
+
+ dglv2->in = new InputLV2();
+ dglv2->out = new OutputLV2();
+
+ dglv2->buffer = NULL;
+ dglv2->buffer_size = 0;
+
+ dglv2->dg = new DrumGizmo(dglv2->out, dglv2->in);
+ dglv2->dg->loadkit("/home/deva/docs/c/drumgizmo/kits/test/test.xml");
+ dglv2->dg->init(true);
+
+ return (LV2_Handle)dglv2;
+}
+
+/** Function pointer that connects a port on a plugin instance to a memory
+ * location where the block of data for the port will be read/written.
+ *
+ * The data location is expected to be of the type defined in the
+ * plugin's data file (e.g. an array of float for an lv2:AudioPort).
+ * Memory issues are managed by the host. The plugin must read/write
+ * the data at these locations every time run() is called, data
+ * present at the time of this connection call MUST NOT be
+ * considered meaningful.
+ *
+ * The host MUST NOT try to connect a data buffer to a port index
+ * that is not defined in the RDF data for the plugin. If it does,
+ * the plugin's behaviour is undefined.
+ *
+ * connect_port() may be called more than once for a plugin instance
+ * to allow the host to change the buffers that the plugin is reading
+ * or writing. These calls may be made before or after activate()
+ * or deactivate() calls. Note that there may be realtime constraints
+ * on connect_port (see lv2:hardRTCapable in lv2.ttl).
+ *
+ * connect_port() MUST be called at least once for each port before
+ * run() is called. The plugin must pay careful attention to the block
+ * size passed to the run function as the block allocated may only just
+ * be large enough to contain the block of data (typically samples), and
+ * is not guaranteed to be constant.
+ *
+ * Plugin writers should be aware that the host may elect to use the
+ * same buffer for more than one port and even use the same buffer for
+ * both input and output (see lv2:inPlaceBroken in lv2.ttl).
+ * However, overlapped buffers or use of a single buffer for both
+ * audio and control data may result in unexpected behaviour.
+ *
+ * If the plugin has the feature lv2:hardRTCapable then there are
+ * various things that the plugin MUST NOT do within the connect_port()
+ * function (see lv2.ttl). */
+void connect_port(LV2_Handle instance,
+ uint32_t port,
+ void *data_location)
+{
+ DGLV2 *dglv2 = (DGLV2 *)instance;
+
+ if(port == 0) {// MIDI in
+ dglv2->in->eventPort = (LV2_Event_Buffer*)data_location;
+ } else {// Audio Port
+ if(port - 1 < NUM_OUTPUTS)
+ dglv2->out->outputPort[port - 1] = (sample_t*)data_location;
+ }
+}
+
+/** Function pointer that initialises a plugin instance and activates
+ * it for use.
+ *
+ * This is separated from instantiate() to aid real-time support and so
+ * that hosts can reinitialise a plugin instance by calling deactivate()
+ * and then activate(). In this case the plugin instance must reset all
+ * state information dependent on the history of the plugin instance
+ * except for any data locations provided by connect_port(). If there
+ * is nothing for activate() to do then the plugin writer may provide
+ * a NULL rather than an empty function.
+ *
+ * When present, hosts MUST call this function once before run()
+ * is called for the first time. This call SHOULD be made as close
+ * to the run() call as possible and indicates to real-time plugins
+ * that they are now live, however plugins MUST NOT rely on a prompt
+ * call to run() after activate(). activate() may not be called again
+ * unless deactivate() is called first (after which activate() may be
+ * called again, followed by deactivate, etc. etc.). If a host calls
+ * activate, it MUST call deactivate at some point in the future.
+ *
+ * Note that connect_port() may be called before or after a call to
+ * activate(). */
+void activate(LV2_Handle instance)
+{
+ DGLV2 *dglv2 = (DGLV2 *)instance;
+ //dglv2->dg->run();
+ (void)dglv2;
+}
+
+/** Function pointer that runs a plugin instance for a block.
+ *
+ * Two parameters are required: the first is a handle to the particular
+ * instance to be run and the second indicates the block size (in
+ * samples) for which the plugin instance may run.
+ *
+ * Note that if an activate() function exists then it must be called
+ * before run(). If deactivate() is called for a plugin instance then
+ * the plugin instance may not be reused until activate() has been
+ * called again.
+ *
+ * If the plugin has the feature lv2:hardRTCapable then there are
+ * various things that the plugin MUST NOT do within the run()
+ * function (see lv2.ttl). */
+void run(LV2_Handle instance,
+ uint32_t sample_count)
+{
+ static size_t pos = 0;
+ DGLV2 *dglv2 = (DGLV2 *)instance;
+
+ if(dglv2->buffer_size != sample_count) {
+ if(dglv2->buffer) free(dglv2->buffer);
+ dglv2->buffer_size = sample_count;
+ dglv2->buffer = (sample_t*)malloc(sizeof(sample_t) * dglv2->buffer_size);
+ }
+
+ dglv2->dg->run(pos, dglv2->buffer, dglv2->buffer_size);
+
+ pos += sample_count;
+}
+
+/** This is the counterpart to activate() (see above). If there is
+ * nothing for deactivate() to do then the plugin writer may provide
+ * a NULL rather than an empty function.
+ *
+ * Hosts must deactivate all activated units after they have been run()
+ * for the last time. This call SHOULD be made as close to the last
+ * run() call as possible and indicates to real-time plugins that
+ * they are no longer live, however plugins MUST NOT rely on prompt
+ * deactivation. Note that connect_port() may be called before or
+ * after a call to deactivate().
+ *
+ * Note that deactivation is not similar to pausing as the plugin
+ * instance will be reinitialised when activate() is called to reuse it.
+ * Hosts MUST NOT call deactivate() unless activate() was previously
+ * called. */
+void deactivate(LV2_Handle instance)
+{
+ DGLV2 *dglv2 = (DGLV2 *)instance;
+ dglv2->dg->stop();
+}
+
+/** This is the counterpart to instantiate() (see above). Once an instance
+ * of a plugin has been finished with it can be deleted using this
+ * function. The instance handle passed ceases to be valid after
+ * this call.
+ *
+ * If activate() was called for a plugin instance then a corresponding
+ * call to deactivate() MUST be made before cleanup() is called.
+ * Hosts MUST NOT call cleanup() unless instantiate() was previously
+ * called. */
+void cleanup(LV2_Handle instance)
+{
+ DGLV2 *dglv2 = (DGLV2 *)instance;
+ delete dglv2->dg;
+ delete dglv2->in;
+ delete dglv2->out;
+}
+
+/** Function pointer that can be used to return additional instance data for
+ * a plugin defined by some extenion (e.g. a struct containing additional
+ * function pointers).
+ *
+ * The actual type and meaning of the returned object MUST be specified
+ * precisely by the extension if it defines any extra data. If a particular
+ * extension does not define extra instance data, this function MUST return
+ * NULL for that extension's URI. If a plugin does not support any
+ * extensions that define extra instance data, this function pointer may be
+ * set to NULL rather than providing an empty function.
+ *
+ * The only parameter is the URI of the extension. The plugin MUST return
+ * NULL if it does not support the extension, but hosts SHOULD NOT use this
+ * as a discovery method (e.g. hosts should only call this function for
+ * extensions known to be supported by the plugin from the data file).
+ *
+ * The host is never responsible for freeing the returned value.
+ *
+ * NOTE: This function should return a struct (likely containing function
+ * pointers) and NOT a direct function pointer. Standard C and C++ do not
+ * allow type casts from void* to a function pointer type. To provide
+ * additional functions a struct should be returned containing the extra
+ * function pointers (which is valid standard code, and a much better idea
+ * for extensibility anyway). */
+const void* extension_data(const char *uri)
+{
+ return NULL;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const LV2_Descriptor descriptor = {
+ DRUMGIZMO_URI,
+ instantiate,
+ connect_port,
+ activate,
+ run,
+ deactivate,
+ cleanup,
+ extension_data
+};
+
+LV2_SYMBOL_EXPORT
+const LV2_Descriptor* lv2_descriptor(uint32_t index)
+{
+ switch (index) {
+ case 0:
+ return &descriptor;
+ default:
+ return NULL;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lv2/manifest.ttl b/lv2/manifest.ttl
new file mode 100644
index 0000000..65a8953
--- /dev/null
+++ b/lv2/manifest.ttl
@@ -0,0 +1,7 @@
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<http://drumgizmo.org/lv2>
+ a lv2:Plugin ;
+ lv2:binary <drumgizmo.so> ;
+ rdfs:seeAlso <drumgizmo.ttl> .
diff --git a/src/event.cc b/lv2/output_lv2.cc
index 717fa12..226b92a 100644
--- a/src/event.cc
+++ b/lv2/output_lv2.cc
@@ -1,9 +1,9 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * event.cc
+ * output_lv2.cc
*
- * Sat Sep 18 22:02:16 CEST 2010
- * Copyright 2010 Bent Bisballe Nyeng
+ * Wed Jul 13 14:27:06 CEST 2011
+ * Copyright 2011 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,27 +24,66 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include "event.h"
+#include "output_lv2.h"
-void EventQueue::post(Event *event, timepos_t time)
+#include <string.h>
+
+OutputLV2::OutputLV2()
+{
+ for(size_t i = 0; i < NUM_OUTPUTS; i++) outputPort[i] = NULL;
+}
+
+OutputLV2::~OutputLV2()
+{
+}
+
+bool OutputLV2::init(Channels channels)
+{
+ return true;
+}
+
+void OutputLV2::setParm(std::string parm, std::string value)
+{
+}
+
+bool OutputLV2::start()
+{
+ return true;
+}
+
+void OutputLV2::stop()
+{
+}
+
+void OutputLV2::pre(size_t nsamples)
{
- MutexAutolock lock(mutex);
- event->offset = time;
- queue.insert(std::pair<timepos_t, Event*>(time, event));
}
-Event *EventQueue::take(timepos_t time)
+void OutputLV2::run(int ch, sample_t *samples, size_t nsamples)
{
- MutexAutolock lock(mutex);
- std::multimap<timepos_t, Event*>::iterator i = queue.find(time);
- if(i == queue.end()) return NULL;
- Event *event = i->second;
- queue.erase(i);
- return event;
+ if(ch < NUM_OUTPUTS) {
+ if(outputPort[ch])
+ memcpy(outputPort[ch], samples, nsamples * sizeof(sample_t));
+ }
}
-bool EventQueue::hasEvent(timepos_t time)
+void OutputLV2::post(size_t nsamples)
{
- MutexAutolock lock(mutex);
- return queue.find(time) != queue.end();
}
+
+#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/lv2/output_lv2.h b/lv2/output_lv2.h
new file mode 100644
index 0000000..9a313f4
--- /dev/null
+++ b/lv2/output_lv2.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * output_lv2.h
+ *
+ * Wed Jul 13 14:27:06 CEST 2011
+ * Copyright 2011 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_OUTPUT_LV2_H__
+#define __DRUMGIZMO_OUTPUT_LV2_H__
+
+#include <audiooutputengine.h>
+
+#define NUM_OUTPUTS 16
+
+class OutputLV2 : public AudioOutputEngine {
+public:
+ OutputLV2();
+ ~OutputLV2();
+
+ bool init(Channels channels);
+
+ void setParm(std::string parm, std::string value);
+
+ bool start();
+ void stop();
+
+ void pre(size_t nsamples);
+ void run(int ch, sample_t *samples, size_t nsamples);
+ void post(size_t nsamples);
+
+ sample_t *outputPort[NUM_OUTPUTS];
+};
+
+#endif/*__DRUMGIZMO_OUTPUT_LV2_H__*/
diff --git a/src/Makefile.am b/src/Makefile.am
index df904db..897732c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,70 +1,10 @@
-bin_PROGRAMS = drumgizmo
-
-drumgizmo_LDADD = $(ALSA_LIBS) $(JACK_LIBS) $(SNDFILE_LIBS) $(SMF_LIBS) \
- $(PTHREAD_CFLAGS)
-
-drumgizmo_CXXFLAGS = $(ALSA_CFLAGS) $(JACK_CXXFLAGS) $(SNDFILE_CXXFLAGS) \
- $(SMF_CFLAGS) $(PTHREAD_LIBS)
-
-drumgizmo_SOURCES = \
- audioinputengine.cc \
- audioinputenginejackmidi.cc \
- audiooutputengine.cc \
- audiooutputenginealsa.cc \
- audiooutputenginejack.cc \
- audiooutputenginesndfile.cc \
- audiofile.cc \
- cli.cc \
- channel.cc \
- channelmixer.cc \
- drumgizmo.cc \
- drumkitparser.cc \
- event.cc \
- instrument.cc \
- midimapper.cc \
- midiplayer.cc \
- mutex.cc \
- sample.cc \
- saxparser.cc \
- thread.cc \
- velocity.cc
-
-# beatmapper.cc
-
-EXTRA_DIST = \
- audio.h \
- audioinputengine.h \
- audioinputenginejackmidi.h \
- audiooutputengine.h \
- audiooutputenginealsa.h \
- audiooutputenginejack.h \
- audiooutputenginesndfile.h \
- audiofile.h \
- channel.h \
- channelmixer.h \
- drumgizmo.h \
- drumkit.h \
- drumkitparser.h \
- event.h \
- instrument.h \
- midimapper.h \
- midiplayer.h \
- mutex.h \
- rangemap.h \
- sample.h \
- saxparser.h \
- thread.h \
- velocity.h
-
-# beatmapper.h
-
################
# Test Section #
################
-TEST_SOURCE_DEPS = ${drumgizmo_SOURCES} ${EXTRA_DIST}
+TEST_SOURCE_DEPS = ${EXTRA_DIST}
TEST_SCRIPT_DIR = $(top_srcdir)/tools
include ${TEST_SCRIPT_DIR}/Makefile.am.test
-include Makefile.am.test \ No newline at end of file
+include Makefile.am.test
diff --git a/src/audio.h b/src/audio.h
index 85a84a0..dc890cc 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -27,14 +27,6 @@
#ifndef __DRUMGIZMO_AUDIO_H__
#define __DRUMGIZMO_AUDIO_H__
-typedef unsigned int channels_t;
-typedef unsigned int channel_t;
-
-#define ALL_CHANNELS ((channel_t)0xffffffff)
-#define NO_CHANNEL ((channel_t)0xfffffffe)
-
-typedef float sample_t;
-
-typedef float level_t;
+#include <audiotypes.h>
#endif/*__DRUMGIZMO_AUDIO_H__*/
diff --git a/src/audiofile.cc b/src/audiofile.cc
index 2533b33..61b49e9 100644
--- a/src/audiofile.cc
+++ b/src/audiofile.cc
@@ -37,6 +37,8 @@ AudioFile::AudioFile(std::string filename)
data = NULL;
size = 0;
+
+ load();
}
AudioFile::~AudioFile()
diff --git a/src/audiofile.h b/src/audiofile.h
index a3d607d..53fe2a7 100644
--- a/src/audiofile.h
+++ b/src/audiofile.h
@@ -43,7 +43,6 @@ public:
sample_t *data;
size_t size;
-private:
std::string filename;
};
diff --git a/src/audioinputengine.cc b/src/audioinputengine.cc
index 201d851..95c7c13 100644
--- a/src/audioinputengine.cc
+++ b/src/audioinputengine.cc
@@ -26,19 +26,6 @@
*/
#include "audioinputengine.h"
-#include "audioinputenginejackmidi.h"
-#include "audioinputenginemidifile.h"
-
-AudioInputEngine *createAudioInputEngine(std::string engine)
-{
- AudioInputEngine *e = NULL;
-
- if(engine == "jackmidi") e = new AudioInputEngineJackMidi();
- if(engine == "midifile") e = new AudioInputEngineMidiFile();
-
- return e;
-}
-
#ifdef TEST_AUDIOINPUTENGINE
//Additional dependency files
//deps:
diff --git a/src/audioinputengine.h b/src/audioinputengine.h
index d10a31c..c17b964 100644
--- a/src/audioinputengine.h
+++ b/src/audioinputengine.h
@@ -29,18 +29,22 @@
#include <string>
-#include "event.h"
+#include <event.h>
+
+#include "instrument.h"
class AudioInputEngine {
public:
- AudioInputEngine() {}
- virtual ~AudioInputEngine() {}
+ virtual bool init(Instruments &instruments) = 0;
- virtual bool init(EventQueue *e) = 0;
+ virtual void setParm(std::string parm, std::string value) = 0;
- virtual void run(size_t pos, size_t len) = 0;
-};
+ virtual bool start() = 0;
+ virtual void stop() = 0;
-AudioInputEngine *createAudioInputEngine(std::string engine);
+ virtual void pre() = 0;
+ virtual event_t *run(size_t pos, size_t len, size_t *nevents) = 0;
+ virtual void post() = 0;
+};
#endif/*__DRUMGIZMO_AUDIOINPUTENGINE_H__*/
diff --git a/src/audiooutputengine.cc b/src/audiooutputengine.cc
index 73ef355..7070222 100644
--- a/src/audiooutputengine.cc
+++ b/src/audiooutputengine.cc
@@ -26,17 +26,3 @@
*/
#include "audiooutputengine.h"
-#include "audiooutputenginealsa.h"
-#include "audiooutputenginejack.h"
-#include "audiooutputenginesndfile.h"
-
-AudioOutputEngine *createAudioOutputEngine(std::string engine)
-{
- AudioOutputEngine *e = NULL;
-
- if(engine == "alsa") e = new AudioOutputEngineAlsa();
- if(engine == "jack") e = new AudioOutputEngineJack();
- if(engine == "sndfile") e = new AudioOutputEngineSndFile("out.wav");
-
- return e;
-}
diff --git a/src/audiooutputengine.h b/src/audiooutputengine.h
index 09dcbd7..864ecc5 100644
--- a/src/audiooutputengine.h
+++ b/src/audiooutputengine.h
@@ -28,24 +28,23 @@
#define __DRUMGIZMO_AUDIOOUTPUTENGINE_H__
#include <string>
+#include <stdlib.h>
+#include <audiotypes.h>
#include "channel.h"
-class DrumGizmo;
-
class AudioOutputEngine {
public:
- AudioOutputEngine() {}
- virtual ~AudioOutputEngine() {}
+ virtual bool init(Channels channels) = 0;
- virtual bool init(Channels *channels) = 0;
+ virtual void setParm(std::string parm, std::string value) = 0;
- virtual void run(DrumGizmo *drumgizmo) = 0;
+ virtual bool start() = 0;
+ virtual void stop() = 0;
-protected:
- Channels *channels;
+ virtual void pre(size_t nsamples) = 0;
+ virtual void run(int ch, sample_t *samples, size_t nsamples) = 0;
+ virtual void post(size_t nsamples) = 0;
};
-AudioOutputEngine *createAudioOutputEngine(std::string engine);
-
#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINE_H__*/
diff --git a/src/audiooutputenginealsa.cc b/src/audiooutputenginealsa.cc
deleted file mode 100644
index 635cf70..0000000
--- a/src/audiooutputenginealsa.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * audiooutputenginealsa.cc
- *
- * Thu Sep 16 11:22:52 CEST 2010
- * Copyright 2010 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 "audiooutputenginealsa.h"
-
-#include "drumgizmo.h"
-
-#include <string>
-#include <math.h>
-#include <sys/time.h>
-
-#define T(x, msg) if(x < 0) { printf("%s failed: %s\n", msg, snd_strerror(x)); fflush(stdout); return false; }
-#define T_(x, msg) if(x < 0) { printf("%s failed: %s\n", msg, snd_strerror(x)); fflush(stdout); return; }
-
-AudioOutputEngineAlsa::AudioOutputEngineAlsa()
-{
- printf("AudioOutputEngineAlsa\n");
- int rc;
-
- std::string pcmname = "default";
-
- rc = snd_pcm_open(&handle, pcmname.c_str(),
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
- T_(rc, "snd_pcm_open");
-}
-
-AudioOutputEngineAlsa::~AudioOutputEngineAlsa()
-{
- printf("~AudioOutputEngineAlsa\n");
- if(handle) snd_pcm_close(handle);
-}
-
-bool AudioOutputEngineAlsa::init(Channels *channels)
-{
- this->channels = channels;
-
- if(!handle) {
- printf("No handle!\n");
- return false;
- }
-
- int rc;
- unsigned int srate = 44100;
- snd_pcm_uframes_t frames = 32;
-
- // Allocate a hardware parameters object.
- snd_pcm_hw_params_alloca(&params);
- // if(rc < 0) return false;
-
- // Fill it in with default values.
- rc = snd_pcm_hw_params_any(handle, params);
- T(rc, "snd_pcm_hw_params_any");
-
- rc = snd_pcm_hw_params_set_access(handle, params,
- SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
- T(rc, "snd_pcm_hw_params_set_access");
-
- rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT);
- T(rc, "snd_pcm_hw_params_set_format");
-
- rc = snd_pcm_hw_params_set_channels(handle, params, channels->size());
- T(rc, "snd_pcm_hw_params_set_channels");
-
- rc = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
- T(rc, "snd_pcm_hw_params_set_rate_near");
-
- rc = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0);
- T(rc, "snd_pcm_hw_params_set_period_size_near");
-
- rc = snd_pcm_hw_params(handle, params);
- T(rc, "snd_pcm_hw_params");
-
- // SW Params:
- /*
- rc = snd_pcm_sw_params_current(pcm, sw);
- rc = snd_pcm_sw_params_set_start_threshold(pcm, sw, ~0U);
- rc = snd_pcm_sw_params_set_stop_threshold(pcm, sw, ~0U);
- rc = snd_pcm_sw_params(pcm, sw);
- rc = snd_pcm_hw_params_get_buffer_size(hw, &buffer_size);
- */
-
- channels_t nchannels;
- rc = snd_pcm_hw_params_get_channels(params, &nchannels);
- printf("channels: %d rc: %d\n", nchannels, rc);
- T(rc, "snd_pcm_hw_params_get_channels");
- if(nchannels != channels->size()) return false;
-
- channel_t c = 0;
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
- i->num = c;
-
- i++;
- c++;
- }
-
- return true;
-}
-
-#define MICRO 1000000
-void AudioOutputEngineAlsa::run(DrumGizmo *drumgizmo)
-{
- int rc;
-
- snd_pcm_uframes_t nframes;
-
- while(drumgizmo->isRunning()) {
- timeval tim;
- gettimeofday(&tim, NULL);
- useconds_t t1 = tim.tv_sec * MICRO + tim.tv_usec;
-
- snd_pcm_uframes_t offset = 0;
-
- // unsigned int nchannels = 2;
- // rc = snd_pcm_hw_params_get_channels(params, &nchannels);
- // printf("channels: %d rc: %d\n", nchannels, rc);
- // T_(rc, "snd_pcm_hw_params_get_channels");
- nframes = snd_pcm_avail_update(handle);
- // printf("%d\n", rc);
- // T_(rc, "snd_pcm_avail_update");
-
- // rc = snd_pcm_hw_params_get_buffer_size(params, &nframes);
- // T_(rc, "nd_pcm_hw_params_get_buffer_size");
-
- // nframes = 960;
-
- const snd_pcm_channel_area_t *areas;
- rc = snd_pcm_mmap_begin(handle, &areas, &offset, &nframes);
- T_(rc, "snd_pcm_mmap_begin");
-
- drumgizmo->pre((size_t)nframes);
-
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
- const snd_pcm_channel_area_t *a = &areas[i->num];
- sample_t *p = (sample_t*)a->addr + offset;
- memset(p, 0, nframes * sizeof(sample_t));
- drumgizmo->getSamples(&(*i), p, (size_t)nframes);
-
- i++;
- }
- drumgizmo->post((size_t)nframes);
-
- switch(snd_pcm_state(handle)) {
- case SND_PCM_STATE_PREPARED:
- rc = snd_pcm_mmap_commit(handle, offset, nframes);
- T_(rc, "snd_pcm_mmap_commit");
- rc = snd_pcm_start(handle);
- T_(rc, "snd_pcm_start");
- break;
- case SND_PCM_STATE_RUNNING:
- rc = snd_pcm_mmap_commit(handle, offset, nframes);
- T_(rc, "snd_pcm_mmap_commit");
- break;
- default:
- break;
- }
-
- useconds_t msec = ((useconds_t)nframes * MICRO)/44100;
-
- gettimeofday(&tim, NULL);
- useconds_t t2 = tim.tv_sec * MICRO + tim.tv_usec;
-
- struct timespec slp;
- slp.tv_sec = 0;
- slp.tv_nsec = (msec - (t2 - t1)) * 1000;
-
- nanosleep(&slp, NULL);
-
- }
-}
diff --git a/src/audiooutputenginejack.cc b/src/audiooutputenginejack.cc
deleted file mode 100644
index f29404d..0000000
--- a/src/audiooutputenginejack.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * audiooutputenginejack.cc
- *
- * Thu Sep 16 10:28:37 CEST 2010
- * Copyright 2010 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 "audiooutputenginejack.h"
-
-#include <string.h>
-#include "drumgizmo.h"
-
-extern "C" {
- static int _wrap_jack_process(jack_nframes_t nframes, void *arg){
- return ((AudioOutputEngineJack*)arg)->process(nframes);}
-}
-
-AudioOutputEngineJack::AudioOutputEngineJack()
-{
- jack_status_t status;
-
- jack_client = jack_client_open("DrumGizmo", JackNullOption, &status);
- jack_set_process_callback(jack_client, _wrap_jack_process, this);
-}
-
-AudioOutputEngineJack::~AudioOutputEngineJack()
-{
- jack_client_close(jack_client);
-}
-
-bool AudioOutputEngineJack::init(Channels *channels)
-{
- this->channels = channels;
-
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
-
- jack_port_t *port =
- jack_port_register(jack_client,
- i->name.c_str(),
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput | JackPortIsTerminal,
- 0);
-
- output_ports.push_back(port);
- i->num = output_ports.size() - 1;
-
- i++;
- }
-
- return true;
-}
-
-void AudioOutputEngineJack::run(DrumGizmo *drumgizmo)
-{
- gizmo = drumgizmo;
-
- jack_activate(jack_client);
-
- jack_connect(jack_client, "DrumGizmo:port0", "system:playback_1");
- jack_connect(jack_client, "DrumGizmo:port1", "system:playback_2");
-
- while(drumgizmo->isRunning()) {
- sleep(1);
- }
-}
-
-int AudioOutputEngineJack::process(jack_nframes_t nframes)
-{
- gizmo->pre(nframes);
-
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
- jack_port_t *port = output_ports[i->num];
- jack_default_audio_sample_t *buffer;
- buffer = (jack_default_audio_sample_t *)jack_port_get_buffer(port, nframes);
-
- memset(buffer, 0, nframes * sizeof(sample_t));
- gizmo->getSamples(&(*i), buffer, nframes);
-
- i++;
- }
-
- gizmo->post(nframes);
-
- return 0;
-}
diff --git a/src/audiooutputenginesndfile.cc b/src/audiooutputenginesndfile.cc
deleted file mode 100644
index f311180..0000000
--- a/src/audiooutputenginesndfile.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * audiooutputenginesndfile.cc
- *
- * Tue Sep 21 09:31:30 CEST 2010
- * Copyright 2010 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 "audiooutputenginesndfile.h"
-
-#include "drumgizmo.h"
-
-AudioOutputEngineSndFile::AudioOutputEngineSndFile(std::string file)
-{
- filename = file;
-}
-
-AudioOutputEngineSndFile::~AudioOutputEngineSndFile()
-{
- if(fh) sf_close(fh);
-}
-
-bool AudioOutputEngineSndFile::init(Channels *channels)
-{
- this->channels = channels;
-
- sf_info.channels = channels->size();
- sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
- sf_info.samplerate = 44100;
-
- fh = sf_open(filename.c_str(), SFM_WRITE, &sf_info);
- if(!fh) {
- printf("Load error...\n");
- return false;
- }
-
- channel_t c = 0;
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
- i->num = c;
- i++;
- c++;
- }
-
- return true;
-}
-
-void AudioOutputEngineSndFile::run(DrumGizmo *gizmo)
-{
- sample_t s[channels->size()];
-
- while(gizmo->isRunning()) {
-
- gizmo->pre(1);
- Channels::iterator i = channels->begin();
- while(i != channels->end()) {
- s[i->num] = 0.0;
- gizmo->getSamples(&(*i), &(s[i->num]), 1);
- i++;
- }
-
- gizmo->post(1);
-
- sf_writef_float(fh, s, 1);
- }
-}
diff --git a/src/channel.h b/src/channel.h
index 7aadc3c..2484d92 100644
--- a/src/channel.h
+++ b/src/channel.h
@@ -32,6 +32,9 @@
#include "audio.h"
+#define ALL_CHANNELS ((channel_t)0xffffffff)
+#define NO_CHANNEL ((channel_t)0xfffffffe)
+
class Channel {
public:
Channel(std::string name = "");
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 161517e..de8e610 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -29,83 +29,178 @@
#include <math.h>
#include <stdio.h>
+#include <event.h>
+#include <audiotypes.h>
+
+#include <string.h>
+
#include "drumkitparser.h"
-#include "audiooutputengine.h"
-#include "audioinputengine.h"
-#include "event.h"
-
-DrumGizmo::DrumGizmo(AudioOutputEngine &o,
- AudioInputEngine &i,
- ChannelMixer &m)
- : mixer(m), oe(o), ie(i)
+
+DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i)
+ : oe(o), ie(i)
{
- time = 0;
- Channel c1; c1.num = 0; c1.name="left";
- Channel c2; c2.num = 1; c2.name="right";
- channels.push_back(c1);
- channels.push_back(c2);
}
DrumGizmo::~DrumGizmo()
{
+ /*
AudioFiles::iterator i = audiofiles.begin();
while(i != audiofiles.end()) {
AudioFile *audiofile = i->second;
delete audiofile;
i++;
}
+ */
}
bool DrumGizmo::loadkit(const std::string &kitfile)
{
- /*
DrumKitParser parser(kitfile, kit);
if(parser.parse()) return false;
+ /*
+ Instruments::iterator i = kit.instruments.begin();
+ while(i != kit.instruments.end()) {
+ Instrument &instr = i->second;
+ InstrumentParser iparser(instr.file, instr);
+ if(iparser.parse()) return false;
+ i++;
+ }
*/
-
return true;
}
bool DrumGizmo::init(bool preload)
{
if(preload) {
+ /*
AudioFiles::iterator i = audiofiles.begin();
while(i != audiofiles.end()) {
AudioFile *audiofile = i->second;
audiofile->load();
i++;
}
+ */
}
- if(!oe.init(&channels)) return false;
-
- if(!ie.init(&eventqueue)) return false;
+ if(!ie->init(kit.instruments)) return false;
+ if(!oe->init(kit.channels)) return false;
return true;
}
-void DrumGizmo::run()
+void DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
{
- is_running = true;
- oe.run(this);
+ ie->pre();
+ oe->pre(nsamples);
+
+
+ //
+ // Read new events
+ //
+
+ size_t nev;
+ event_t *evs = ie->run(pos, nsamples, &nev);
+
+ for(size_t e = 0; e < nev; e++) {
+ /*
+ printf("Event: type: %d\tinstrument: %d\tvelocity: %f\toffset: %d\n",
+ evs[e].type,
+ evs[e].instrument,
+ evs[e].velocity,
+ evs[e].offset);
+ */
+ if(evs[e].type == TYPE_ONSET) {
+ Instrument *i = NULL;
+ int d = evs[e].instrument;
+ /*
+ Instruments::iterator it = kit.instruments.begin();
+ while(d-- && it != kit.instruments.end()) {
+ i = &(it->second);
+ it++;
+ }
+ */
+
+ if(d < (int)kit.instruments.size()) {
+ i = &kit.instruments[d];
+ }
+
+ if(i == NULL) {
+ printf("Missing Instrument %d.\n", evs[e].instrument);
+ continue;
+ }
+
+ Sample *s = i->sample(evs[e].velocity);
+
+ if(s == NULL) {
+ printf("Missing Sample.\n");
+ continue;
+ }
+
+ Channels::iterator j = kit.channels.begin();
+ while(j != kit.channels.end()) {
+ Channel &ch = *j;
+ AudioFile *af = s->getAudioFile(&ch);
+ if(af == NULL) {
+ //printf("Missing AudioFile.\n");
+ } else {
+ printf("Adding event %d.\n", evs[e].offset);
+ Event *evt = new EventSample(ch.num, 1.0, af);
+ evt->offset = evs[e].offset + pos;
+ activeevents[ch.num].push_back(evt);
+ }
+ j++;
+ }
+ }
+
+ if(evs[e].type == TYPE_STOP) {
+ printf("Stoooooop!\n");
+ // running = false;
+ }
+
+ }
+
+ free(evs);
+
+
+ //
+ // Write audio
+ //
+
+ for(size_t c = 0; c < kit.channels.size(); c++) {
+ memset(samples, 0, nsamples * sizeof(sample_t));
+ getSamples(c, pos, samples, nsamples);
+ oe->run(c, samples, nsamples);
+ }
+
+ ie->post();
+ oe->post(nsamples);
+
+ pos += nsamples;
}
-void DrumGizmo::pre(size_t sz)
+void DrumGizmo::run()
{
- ie.run(time, sz);
+ ie->start();
+ oe->start();
- for(size_t n = 0; n < sz; n++) {
- while(eventqueue.hasEvent(time + n)) {
- Event *event = eventqueue.take(time + n);
- activeevents[event->channel].push_back(event);
- }
+ size_t pos = 0;
+ size_t nsamples = 512;
+ sample_t samples[nsamples];
+
+ bool running = true;
+
+ while(running) {
+ run(pos, samples, nsamples);
}
+
+ ie->stop();
+ oe->stop();
}
-void DrumGizmo::getSamples(Channel *c, sample_t *s, size_t sz)
+void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz)
{
- for(std::list< Event* >::iterator i = activeevents[c->num].begin();
- i != activeevents[c->num].end();
+ for(std::list< Event* >::iterator i = activeevents[ch].begin();
+ i != activeevents[ch].end();
i++) {
bool removeevent = false;
@@ -113,59 +208,15 @@ void DrumGizmo::getSamples(Channel *c, sample_t *s, size_t sz)
Event::type_t type = event->type();
switch(type) {
- case Event::sine:
- {
- EventSine *evt = (EventSine *)event;
- for(size_t n = 0; n < sz; n++) {
-
- if(evt->offset > (time + n)) continue;
-
- if(evt->t > evt->len) {
- removeevent = true;
- break;
- }
-
- float x = (float)evt->t / 44100.0;
- float gain = evt->gain;
- gain *= 1.0 - ((float)evt->t / (float)evt->len);
- sample_t val = gain * sin(2.0 * M_PI * evt->freq * x);
- s[n] += val;
-
- evt->t++;
- }
- }
- break;
-
- case Event::noise:
- {
- EventNoise *evt = (EventNoise *)event;
- for(size_t n = 0; n < sz; n++) {
-
- if(evt->offset > (time + n)) continue;
-
- if(evt->t > evt->len) {
- removeevent = true;
- break;
- }
-
- float gain = evt->gain;
- gain *= 1.0 - ((float)evt->t / (float)evt->len);
- sample_t val = (float)rand() / (float)RAND_MAX;
- s[n] += val * gain;
- evt->t++;
- }
- }
- break;
-
case Event::sample:
{
- /*
EventSample *evt = (EventSample *)event;
- AudioFile *af = audiofiles[evt->file];
+ AudioFile *af = evt->file;
af->load(); // Make sure it is loaded.
+ // printf("playing: %s (%d)\n", af->filename.c_str(), sz);
for(size_t n = 0; n < sz; n++) {
- if(evt->offset > (time + n)) continue;
+ if(evt->offset > (pos + n)) continue;
if(evt->t > af->size) {
removeevent = true;
@@ -178,24 +229,16 @@ void DrumGizmo::getSamples(Channel *c, sample_t *s, size_t sz)
s[n] += val * gain;
evt->t++;
}
- */
}
break;
}
-
+
if(removeevent) {
delete event;
- i = activeevents[c->num].erase(i);
- if(activeevents[0].size() +
- activeevents[1].size() +
- eventqueue.size() == 0) {/*is_running = false;*/}
+ i = activeevents[ch].erase(i);
}
- }
-}
-void DrumGizmo::post(size_t sz)
-{
- time += sz;
+ }
}
void DrumGizmo::stop()
diff --git a/src/drumgizmo.h b/src/drumgizmo.h
index 4c6683b..1bdb5b5 100644
--- a/src/drumgizmo.h
+++ b/src/drumgizmo.h
@@ -30,20 +30,19 @@
#include <string>
#include <list>
-#include "drumkit.h"
-#include "audio.h"
-#include "event.h"
+#include "audiooutputengine.h"
+#include "audioinputengine.h"
-#include "channelmixer.h"
+#include "events.h"
+#include "audiofile.h"
+#include "drumkit.h"
-class AudioOutputEngine;
-class AudioInputEngine;
+#define MAX_NUM_CHANNELS 512
class DrumGizmo {
public:
- DrumGizmo(AudioOutputEngine &outputengine,
- AudioInputEngine &inputengine,
- ChannelMixer &mixer);
+ DrumGizmo(AudioOutputEngine *outputengine,
+ AudioInputEngine *inputengine);
~DrumGizmo();
bool loadkit(const std::string &kitfile);
@@ -51,29 +50,22 @@ public:
bool init(bool preload = true);
void run();
+ void run(size_t pos, sample_t *samples, size_t nsamples);
void stop();
- void pre(size_t sz);
- void getSamples(Channel *c, sample_t *s, size_t sz);
- void post(size_t sz);
+ void getSamples(int ch, int pos, sample_t *s, size_t sz);
bool isRunning() { return is_running; }
- Channels channels;
- ChannelMixer mixer;
-
- EventQueue eventqueue;
-
private:
bool is_running;
- AudioOutputEngine &oe;
- AudioInputEngine &ie;
+ AudioOutputEngine *oe;
+ AudioInputEngine *ie;
- std::list< Event* > activeevents[100];
- timepos_t time;
+ std::list< Event* > activeevents[MAX_NUM_CHANNELS];
- AudioFiles audiofiles;
+ std::map<std::string, AudioFile *> audiofiles;
#ifdef TEST_DRUMGIZMO
public:
diff --git a/src/drumkit.h b/src/drumkit.h
index d79a3e4..f9883b6 100644
--- a/src/drumkit.h
+++ b/src/drumkit.h
@@ -2,8 +2,8 @@
/***************************************************************************
* drumkit.h
*
- * Tue Jul 22 16:29:16 CEST 2008
- * Copyright 2008 Bent Bisballe Nyeng
+ * Wed Mar 9 15:27:26 CET 2011
+ * Copyright 2011 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -32,13 +32,20 @@
#include "channel.h"
#include "instrument.h"
-#include "midimap.h"
+class DrumKitParser;
class DrumKit {
+ friend class DrumKitParser;
public:
- std::string name;
- std::string description;
+ std::string name();
+ std::string description();
+
Instruments instruments;
+ Channels channels;
+
+private:
+ std::string _name;
+ std::string _description;
};
#endif/*__DRUMGIZMO_DRUMKIT_H__*/
diff --git a/src/drumkitparser.cc b/src/drumkitparser.cc
index 499b78c..1c16574 100644
--- a/src/drumkitparser.cc
+++ b/src/drumkitparser.cc
@@ -29,12 +29,19 @@
#include <string.h>
#include <stdio.h>
-#define DIR_SEPERATOR '/'
+#include "instrumentparser.h"
+#include "path.h"
DrumKitParser::DrumKitParser(const std::string &kitfile, DrumKit &k)
: kit(k)
{
+ // instr = NULL;
+ path = getPath(kitfile);
+
fd = fopen(kitfile.c_str(), "r");
+
+ printf("Parsing drumkit in %s\n", kitfile.c_str());
+
if(!fd) return;
}
@@ -44,38 +51,93 @@ DrumKitParser::~DrumKitParser()
}
void DrumKitParser::startTag(std::string name,
- std::map< std::string, std::string> attributes)
+ std::map< std::string, std::string> attr)
{
if(name == "drumkit") {
- kit.name = attributes["name"];
- kit.description = attributes["description"];
+ if(attr.find("name") != attr.end())
+ kit._name = attr["name"];
+
+ if(attr.find("description") != attr.end())
+ kit._description = attr["description"];
}
if(name == "channels") {}
if(name == "channel") {
- // Channel *c = new Channel(attributes["name"]);
- // dk->channels[attributes["name"]] = c;
+ if(attr.find("name") == attr.end()) {
+ printf("Missing channel name.\n");
+ return;
+ }
+ Channel c(attr["name"]);
+ c.num = kit.channels.size();
+ kit.channels.push_back(c);
}
if(name == "instruments") {
}
if(name == "instrument") {
+ if(attr.find("name") == attr.end()) {
+ printf("Missing name in instrument tag.\n");
+ return;
+ }
+ if(attr.find("file") == attr.end()) {
+ printf("Missing file in instrument tag.\n");
+ return;
+ }
+ Instrument i;
+ InstrumentParser parser(path + "/" + attr["file"], i);
+ parser.parse();
+ kit.instruments.push_back(i);//[attr["name"]] = i;
+
+ // Assign kit channel numbers to instruments channels.
+ std::vector<InstrumentChannel*>::iterator ic = parser.channellist.begin();
+ while(ic != parser.channellist.end()) {
+ InstrumentChannel *c = *ic;
+
+ for(size_t cnt = 0; cnt < kit.channels.size(); cnt++) {
+ if(kit.channels[cnt].name == c->name) c->num = kit.channels[cnt].num;
+ }
+ if(c->num == NO_CHANNEL) {
+ printf("Missing channel '%s' in instrument '%s'\n",
+ c->name.c_str(), i.name().c_str());
+ } else {
+ printf("Assigned channel '%s' to number %d in instrument '%s'\n",
+ c->name.c_str(), c->num, i.name().c_str());
+ }
+ ic++;
+ }
+
+ //instr = &kit.instruments[attr["name"]];
}
-
+ /*
if(name == "channelmap") {
+ if(instr == NULL) {
+ printf("Missing instrument.\n");
+ return;
+ }
+
+ if(attr.find("in") == attr.end()) {
+ printf("Missing 'in' in channelmap tag.\n");
+ return;
+ }
+
+ if(attr.find("out") == attr.end()) {
+ printf("Missing 'out' in channelmap tag.\n");
+ return;
+ }
+ instr->channelmap[attr["in"]] = attr["out"];
}
-
- if(name == "midimaps") {
- }
-
- if(name == "midimap") {
- }
+ */
}
void DrumKitParser::endTag(std::string name)
{
+ /*
+ if(name == "instrument") {
+ instr = NULL;
+ }
+ */
}
int DrumKitParser::readData(char *data, size_t size)
@@ -84,3 +146,92 @@ int DrumKitParser::readData(char *data, size_t size)
return fread(data, 1, size, fd);
}
+#ifdef TEST_DRUMKITPARSER
+//deps: drumkit.cc saxparser.cc instrument.cc sample.cc audiofile.cc channel.cc
+//cflags: $(EXPAT_CFLAGS) $(SNDFILE_CFLAGS)
+//libs: $(EXPAT_LIBS) $(SNDFILE_LIBS)
+#include "test.h"
+
+const char xml[] =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<drumkit name=\"The Aasimonster\"\n"
+" description=\"A large deathmetal drumkit\">\n"
+" <channels>\n"
+" <channel name=\"Alesis\"/>\n"
+" <channel name=\"Kick-L\"/>\n"
+" <channel name=\"Kick-R\"/>\n"
+" <channel name=\"SnareTop\"/>\n"
+" <channel name=\"SnareTrigger\"/>\n"
+" <channel name=\"SnareBottom\"/>\n"
+" <channel name=\"OH-L\"/>\n"
+" <channel name=\"OH-R\"/>\n"
+" <channel name=\"Hihat\"/>\n"
+" <channel name=\"Ride\"/>\n"
+" <channel name=\"Tom1\"/>\n"
+" <channel name=\"Tom2\"/>\n"
+" <channel name=\"Tom3\"/>\n"
+" <channel name=\"Tom4\"/>\n"
+" <channel name=\"Amb-R\"/>\n"
+" <channel name=\"Amb-L\"/>\n"
+" </channels>\n"
+" <instruments>\n"
+" <instrument name=\"Ride\" file=\"ride.xml\">\n"
+" <channelmap in=\"Alesis\" out=\"Alesis\" gain=\"1.5\"/>\n"
+" <channelmap in=\"Kick-L\" out=\"Kick-L\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Kick-R\" out=\"Kick-R\"/>\n"
+" <channelmap in=\"SnareTop\" out=\"SnareTop\" gain=\"0.5\"/>\n"
+" <channelmap in=\"SnareTrigger\" out=\"SnareTrigger\" gain=\"0.5\"/>\n"
+" <channelmap in=\"SnareBottom\" out=\"SnareBottom\" gain=\"0.5\"/>\n"
+" <channelmap in=\"OH-L\" out=\"OH-L\"/>\n"
+" <channelmap in=\"OH-R\" out=\"OH-R\"/>\n"
+" <channelmap in=\"Hihat\" out=\"Hihat\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Ride\" out=\"Ride\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom1\" out=\"Tom1\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom2\" out=\"Tom2\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom3\" out=\"Tom3\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom4\" out=\"Tom4\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Amb-R\" out=\"Amb-R\"/>\n"
+" <channelmap in=\"Amb-L\" out=\"Amb-L\"/>\n"
+" </instrument>\n"
+" <instrument name=\"Snare\" file=\"snare.xml\">\n"
+" <channelmap in=\"Alesis\" out=\"Alesis\" gain=\"1.5\"/>\n"
+" <channelmap in=\"Kick-L\" out=\"Kick-L\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Kick-R\" out=\"Kick-R\"/>\n"
+" <channelmap in=\"SnareTop\" out=\"SnareTop\" gain=\"0.5\"/>\n"
+" <channelmap in=\"SnareTrigger\" out=\"SnareTrigger\" gain=\"0.5\"/>\n"
+" <channelmap in=\"SnareBottom\" out=\"SnareBottom\" gain=\"0.5\"/>\n"
+" <channelmap in=\"OH-L\" out=\"OH-L\"/>\n"
+" <channelmap in=\"OH-R\" out=\"OH-R\"/>\n"
+" <channelmap in=\"Hihat\" out=\"Hihat\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Ride\" out=\"Ride\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom1\" out=\"Tom1\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom2\" out=\"Tom2\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom3\" out=\"Tom3\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Tom4\" out=\"Tom4\" gain=\"0.5\"/>\n"
+" <channelmap in=\"Amb-R\" out=\"Amb-R\"/>\n"
+" <channelmap in=\"Amb-L\" out=\"Amb-L\"/>\n"
+" </instrument>\n"
+" </instruments>\n"
+"</drumkit>\n"
+ ;
+
+#define FNAME "/tmp/drumkittest.xml"
+
+TEST_BEGIN;
+
+FILE *fp = fopen(FNAME, "w");
+fprintf(fp, "%s", xml);
+fclose(fp);
+
+DrumKit kit;
+DrumKitParser p(FNAME, kit);
+TEST_EQUAL_INT(p.parse(), 0, "Parsing went well?");
+
+TEST_EQUAL_STR(kit.name(), "The Aasimonster", "Compare name");
+TEST_EQUAL_INT(kit.instruments.size(), 2, "How many instruments?");
+
+unlink(FNAME);
+
+TEST_END;
+
+#endif/*TEST_DRUMKITPARSER*/
diff --git a/src/drumkitparser.h b/src/drumkitparser.h
index 783ed5f..f585043 100644
--- a/src/drumkitparser.h
+++ b/src/drumkitparser.h
@@ -45,6 +45,8 @@ protected:
private:
FILE *fd;
DrumKit &kit;
+ // Instrument *instr;
+ std::string path;
};
#endif/*__DRUMGIZMO_DRUMKITPARSER_H__*/
diff --git a/src/event.h b/src/event.h
deleted file mode 100644
index 2128386..0000000
--- a/src/event.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * event.h
- *
- * Sat Sep 18 22:02:16 CEST 2010
- * Copyright 2010 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_EVENT_H__
-#define __DRUMGIZMO_EVENT_H__
-
-#include <map>
-#include <stdio.h>
-#include <string>
-#include <sndfile.h>
-
-#include "audio.h"
-#include "mutex.h"
-
-typedef unsigned int timepos_t;
-
-class Event {
-public:
- typedef enum {
- sine,
- noise,
- sample
- } type_t;
-
- virtual type_t type() = 0;
-
- channel_t channel;
- timepos_t offset;
-};
-
-class EventSine : public Event {
-public:
- EventSine(channel_t c, float f, float g, timepos_t l)
- {
- channel = c;
- freq = f;
- gain = g;
- len = l;
- t = 0;
- }
- Event::type_t type() { return Event::sine; }
-
- float freq;
- float gain;
- timepos_t len;
-
- unsigned int t;
-};
-
-class EventNoise : public Event {
-public:
- EventNoise(channel_t c, float g, timepos_t l)
- {
- channel = c;
- gain = g;
- len = l;
- t = 0;
- }
- Event::type_t type() { return Event::noise; }
-
- float gain;
- timepos_t len;
-
- unsigned int t;
-};
-
-class EventSample : public Event {
-public:
- EventSample(channel_t c, float g, std::string f)
- {
- channel = c;
- gain = g;
- t = 0;
- file = f;
- }
-
- Event::type_t type() { return Event::sample; }
-
- float gain;
-
- unsigned int t;
-
- std::string file;
-};
-
-
-
-class EventQueue {
-public:
- void post(Event *event, timepos_t time);
- Event *take(timepos_t time);
- bool hasEvent(timepos_t time);
- size_t size() { return queue.size(); }
-
-private:
- std::multimap< timepos_t, Event* > queue;
- Mutex mutex;
-};
-
-#endif/*__DRUMGIZMO_EVENT_H__*/
diff --git a/src/instrument.cc b/src/instrument.cc
index b710757..1b3c31a 100644
--- a/src/instrument.cc
+++ b/src/instrument.cc
@@ -27,14 +27,17 @@
#include "instrument.h"
#include <stdlib.h>
+#include <stdio.h>
-Instrument::Instrument(std::string name)
+#include "sample.h"
+
+Instrument::Instrument()
{
- this->name = name;
}
Sample *Instrument::sample(level_t level)
{
+ // printf("Find level %f\n", level);
std::vector<Sample*> s = samples.get(level);
if(s.size() == 0) return NULL;
size_t idx = rand()%(s.size());
@@ -46,6 +49,16 @@ void Instrument::addSample(level_t a, level_t b, Sample *s)
samples.insert(a, b, s);
}
+std::string Instrument::name()
+{
+ return _name;
+}
+
+std::string Instrument::description()
+{
+ return _description;
+}
+
#ifdef TEST_INSTRUMENT
//deps: channel.cc sample.cc audiofile.cc
//cflags: $(SNDFILE_CFLAGS)
diff --git a/src/instrument.h b/src/instrument.h
index b01379f..fb8aeac 100644
--- a/src/instrument.h
+++ b/src/instrument.h
@@ -31,59 +31,34 @@
#include <vector>
#include "rangemap.h"
+
#include "sample.h"
+class InstrumentParser;
class Instrument {
+ friend class InstrumentParser;
public:
- Instrument(std::string name);
+ Instrument();
Sample *sample(level_t level);
- void addSample(level_t a, level_t b, Sample *s);
+ std::string name();
+ std::string description();
+
+ // std::map<std::string, std::string> channelmap;
+
+ std::vector<AudioFile*> audiofiles;
private:
- std::string name;
+ std::string _name;
+ std::string _description;
RangeMap<level_t, Sample*> samples;
-};
+ void addSample(level_t a, level_t b, Sample *s);
-typedef std::map< std::string, Instrument > Instruments;
+ std::vector<Sample*> samplelist;
+};
-/*
- * <?xml version='1.0' encoding='UTF-8'?>
- * <instrument name="kick-r">
- * <samples>
- * <sample name="kick-r-1">
- * <audiofile channel="Alesis-3" file="samples/1-kick-r-Alesis-3.wav"/>
- * <audiofile channel="Amb L-3" file="samples/1-kick-r-Amb L-3.wav"/>
- * <audiofile channel="Amb R-3" file="samples/1-kick-r-Amb R-3.wav"/>
- * <audiofile channel="Kick L-3" file="samples/1-kick-r-Kick L-3.wav"/>
- * <audiofile channel="Kick R-3" file="samples/1-kick-r-Kick R-3.wav"/>
- * </sample>
- * <sample name="kick-r-2">
- * <audiofile channel="Alesis-3" file="samples/2-kick-r-Alesis-3.wav"/>
- * <audiofile channel="Amb L-3" file="samples/2-kick-r-Amb L-3.wav"/>
- * <audiofile channel="Amb R-3" file="samples/2-kick-r-Amb R-3.wav"/>
- * <audiofile channel="Kick L-3" file="samples/2-kick-r-Kick L-3.wav"/>
- * <audiofile channel="Kick R-3" file="samples/2-kick-r-Kick R-3.wav"/>
- * </sample>
- * <sample name="kick-r-3">
- * <audiofile channel="Alesis-3" file="samples/3-kick-r-Alesis-3.wav"/>
- * <audiofile channel="Amb L-3" file="samples/3-kick-r-Amb L-3.wav"/>
- * <audiofile channel="Amb R-3" file="samples/3-kick-r-Amb R-3.wav"/>
- * <audiofile channel="Kick L-3" file="samples/3-kick-r-Kick L-3.wav"/>
- * <audiofile channel="Kick R-3" file="samples/3-kick-r-Kick R-3.wav"/>
- * </sample>
- * </samples>
- * <velocities>
- * <velocity lower="0" upper="99">
- * <sampleref name="kick-r-1"/>
- * <sampleref name="kick-r-2"/>
- * </velocity>
- * <velocity lower="100" upper="127">
- * <sampleref name="kick-r-3"/>
- * </velocity>
- * </velocities>
- * </instrument>
- */
+//typedef std::map< std::string, Instrument > Instruments;
+typedef std::vector< Instrument > Instruments;
#endif/*__DRUMGIZMO_INSTRUMENT_H__*/
diff --git a/src/instrumentparser.cc b/src/instrumentparser.cc
new file mode 100644
index 0000000..5198959
--- /dev/null
+++ b/src/instrumentparser.cc
@@ -0,0 +1,219 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * instrumentparser.cc
+ *
+ * Wed Mar 9 13:22:24 CET 2011
+ * Copyright 2011 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 "instrumentparser.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "path.h"
+
+InstrumentParser::InstrumentParser(const std::string &file, Instrument &i)
+ : instrument(i)
+{
+ s = NULL;
+ printf("Parsing instrument in %s\n", file.c_str());
+ path = getPath(file);
+ fd = fopen(file.c_str(), "r");
+ if(!fd) return;
+}
+
+InstrumentParser::~InstrumentParser()
+{
+ if(fd) fclose(fd);
+}
+
+void InstrumentParser::startTag(std::string name,
+ std::map< std::string, std::string> attr)
+{
+ if(name == "instrument") {
+ if(attr.find("name") != attr.end())
+ instrument._name = attr["name"];
+
+ if(attr.find("description") != attr.end())
+ instrument._description = attr["description"];
+ }
+
+ if(name == "samples") {
+ }
+
+ if(name == "sample") {
+ if(attr.find("name") == attr.end()) {
+ printf("Missing required attribute 'name'.\n");
+ return;
+ }
+ s = new Sample(attr["name"]);
+ }
+
+ if(name == "audiofile") {
+ if(s == NULL) {
+ printf("Missing Sample!\n");
+ return;
+ }
+
+ if(attr.find("file") == attr.end()) {
+ printf("Missing required attribute 'file'.\n");
+ return;
+ }
+
+ if(attr.find("channel") == attr.end()) {
+ printf("Missing required attribute 'channel'.\n");
+ return;
+ }
+
+ AudioFile *af = new AudioFile(path + "/" + attr["file"]);
+ InstrumentChannel *ch = new InstrumentChannel(attr["channel"]);
+ channellist.push_back(ch);
+ s->addAudioFile(ch, af);
+ instrument.audiofiles.push_back(af);
+ }
+
+ if(name == "velocities") {
+ }
+
+ if(name == "velocity") {
+ if(attr.find("lower") == attr.end()) {
+ printf("Missing required attribute 'lower'.\n");
+ return;
+ }
+
+ if(attr.find("upper") == attr.end()) {
+ printf("Missing required attribute 'upper'.\n");
+ return;
+ }
+
+ lower = atof(attr["lower"].c_str());
+ upper = atof(attr["upper"].c_str());
+ }
+
+ if(name == "sampleref") {
+ if(attr.find("name") == attr.end()) {
+ printf("Missing required attribute 'name'.\n");
+ return;
+ }
+
+ Sample *sample = NULL;
+ std::vector<Sample *>::iterator i = instrument.samplelist.begin();
+ while(i != instrument.samplelist.end()) {
+ if((*i)->name == attr["name"]) {
+ sample = *i;
+ break;
+ }
+ i++;
+ }
+
+ if(sample == NULL) {
+ printf("Samplref pointed at non-existing sample.\n");
+ return;
+ }
+
+ instrument.addSample(lower, upper, sample);
+ }
+}
+
+void InstrumentParser::endTag(std::string name)
+{
+ if(name == "sample") {
+ if(s == NULL) {
+ printf("Missing Sample.\n");
+ return;
+ }
+
+ instrument.samplelist.push_back(s);
+ s = NULL;
+ }
+}
+
+int InstrumentParser::readData(char *data, size_t size)
+{
+ if(!fd) return -1;
+ return fread(data, 1, size, fd);
+}
+
+
+#ifdef TEST_INSTRUMENTPARSER
+//deps: saxparser.cc instrument.cc sample.cc audiofile.cc channel.cc
+//cflags: $(EXPAT_CFLAGS) $(SNDFILE_CFLAGS)
+//libs: $(EXPAT_LIBS) $(SNDFILE_LIBS)
+#include "test.h"
+
+const char xml[] =
+"<?xml version='1.0' encoding='UTF-8'?>\n"
+"<instrument name=\"kick-r\">\n"
+" <samples>\n"
+" <sample name=\"kick-r-1\">\n"
+" <audiofile channel=\"Alesis\" file=\"samples/1-kick-r-Alesis-3.wav\"/>\n"
+" <audiofile channel=\"Amb L\" file=\"samples/1-kick-r-Amb L-3.wav\"/>\n"
+" <audiofile channel=\"Amb R\" file=\"samples/1-kick-r-Amb R-3.wav\"/>\n"
+" <audiofile channel=\"Kick L\" file=\"samples/1-kick-r-Kick L-3.wav\"/>\n"
+" <audiofile channel=\"Kick R\" file=\"samples/1-kick-r-Kick R-3.wav\"/>\n"
+" </sample>\n"
+" <sample name=\"kick-r-2\">\n"
+" <audiofile channel=\"Alesis\" file=\"samples/2-kick-r-Alesis-3.wav\"/>\n"
+" <audiofile channel=\"Amb L\" file=\"samples/2-kick-r-Amb L-3.wav\"/>\n"
+" <audiofile channel=\"Amb R\" file=\"samples/2-kick-r-Amb R-3.wav\"/>\n"
+" <audiofile channel=\"Kick L\" file=\"samples/2-kick-r-Kick L-3.wav\"/>\n"
+" <audiofile channel=\"Kick R\" file=\"samples/2-kick-r-Kick R-3.wav\"/>\n"
+" </sample>\n"
+" <sample name=\"kick-r-3\">\n"
+" <audiofile channel=\"Alesis\" file=\"samples/3-kick-r-Alesis-3.wav\"/>\n"
+" <audiofile channel=\"Amb L\" file=\"samples/3-kick-r-Amb L-3.wav\"/>\n"
+" <audiofile channel=\"Amb R\" file=\"samples/3-kick-r-Amb R-3.wav\"/>\n"
+" <audiofile channel=\"Kick L\" file=\"samples/3-kick-r-Kick L-3.wav\"/>\n"
+" <audiofile channel=\"Kick R\" file=\"samples/3-kick-r-Kick R-3.wav\"/>\n"
+" </sample>\n"
+" </samples>\n"
+" <velocities>\n"
+" <velocity lower=\"0\" upper=\"0.7\">\n"
+" <sampleref name=\"kick-r-1\"/>\n"
+" <sampleref name=\"kick-r-2\"/>\n"
+" </velocity>\n"
+" <velocity lower=\"0.7\" upper=\"1.0\">\n"
+" <sampleref name=\"kick-r-3\"/>\n"
+" </velocity>\n"
+" </velocities>\n"
+"</instrument>\n"
+ ;
+
+#define FNAME "/tmp/instrtest.xml"
+
+TEST_BEGIN;
+
+FILE *fp = fopen(FNAME, "w");
+fprintf(fp, "%s", xml);
+fclose(fp);
+
+Instrument instr;
+InstrumentParser p(FNAME, instr);
+TEST_EQUAL_INT(p.parse(), 0, "Parsing went well?");
+
+TEST_EQUAL_STR(instr.name(), "kick-r", "Compare name");
+
+unlink(FNAME);
+
+TEST_END;
+
+#endif/*TEST_INSTRUMENTPARSER*/
diff --git a/src/audiooutputenginejack.h b/src/instrumentparser.h
index 41d9964..2a7a9c9 100644
--- a/src/audiooutputenginejack.h
+++ b/src/instrumentparser.h
@@ -1,9 +1,9 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * audiooutputenginejack.h
+ * instrumentparser.h
*
- * Thu Sep 16 10:28:37 CEST 2010
- * Copyright 2010 Bent Bisballe Nyeng
+ * Wed Mar 9 13:22:24 CET 2011
+ * Copyright 2011 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,36 +24,37 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __DRUMGIZMO_AUDIOOUTPUTENGINEJACK_H__
-#define __DRUMGIZMO_AUDIOOUTPUTENGINEJACK_H__
+#ifndef __DRUMGIZMO_INSTRUMENTPARSER_H__
+#define __DRUMGIZMO_INSTRUMENTPARSER_H__
-#include <vector>
-
-#include <jack/jack.h>
+#include "saxparser.h"
+#include "instrument.h"
-#include "audiooutputengine.h"
+#include <vector>
-class AudioOutputEngineJack : public AudioOutputEngine {
+class InstrumentParser : public SAXParser {
public:
- AudioOutputEngineJack();
- ~AudioOutputEngineJack();
+ InstrumentParser(const std::string &instrfile, Instrument &instrument);
+ ~InstrumentParser();
- bool init(Channels *channels);
+ void startTag(std::string name,
+ std::map< std::string, std::string> attributes);
+ void endTag(std::string name);
- void run(DrumGizmo *drumgizmo);
+ std::vector<InstrumentChannel *> channellist;
- // Internal callback method. *must* be public.
- int process(jack_nframes_t nframes);
+protected:
+ int readData(char *data, size_t size);
private:
- jack_client_t *jack_client;
- std::vector< jack_port_t *> output_ports;
+ FILE *fd;
+ Instrument &instrument;
+ Sample *s;
- jack_port_t *port0;
- jack_port_t *port1;
+ std::string path;
- DrumGizmo *gizmo;
+ level_t lower;
+ level_t upper;
};
-
-#endif/*__DRUMGIZMO_AUDIOOUTPUTENGINEJACK_H__*/
+#endif/*__DRUMGIZMO_INSTRUMENTPARSER_H__*/
diff --git a/src/jackclient.cc b/src/jackclient.cc
deleted file mode 100644
index cac1b74..0000000
--- a/src/jackclient.cc
+++ /dev/null
@@ -1,260 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * jackclient.cc
- *
- * Sun Jul 20 21:48:44 CEST 2008
- * Copyright 2008 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 "jackclient.h"
-
-extern "C"
-{
- void _wrap_jack_shutdown(void *arg){
- ((JackClient*)arg)->shutdown();}
- int _wrap_jack_process(jack_nframes_t nframes, void *arg){
- return ((JackClient*)arg)->process(nframes);}
- void _wrap_jack_thread_init(void *arg){
- ((JackClient*)arg)->thread_init();}
- void _wrap_jack_freewheel_mode(int freewheel_mode, void *arg){
- ((JackClient*)arg)->freewheel_mode(freewheel_mode);}
- int _wrap_jack_buffer_size(jack_nframes_t nframes, void *arg){
- return ((JackClient*)arg)->buffer_size(nframes);}
- int _wrap_jack_sample_rate(jack_nframes_t nframes, void *arg){
- return ((JackClient*)arg)->sample_rate(nframes);}
- void _wrap_jack_port_registration(jack_port_id_t port, int i, void *arg){
- ((JackClient*)arg)->port_registration(port, i);}
- int _wrap_jack_graph_order(void *arg){
- return ((JackClient*)arg)->graph_order();}
- int _wrap_jack_xrun(void *arg){
- return ((JackClient*)arg)->xrun();}
-} // extern "C"
-
-JackClient::JackClient(DrumKit *drumkit)
- : midimapper(drumkit)
-{
- this->drumkit = drumkit;
-
- jack_status_t status;
-
- jack_client = jack_client_open("DrumGizmo", JackNullOption, &status);
-
- // Setup input port
- midi_port = jack_port_register(jack_client,
- "midi_in",
- JACK_DEFAULT_MIDI_TYPE,
- JackPortIsInput,// | JackPortIsTerminal,
- 0);
-
- // Setup input ports
- Instruments::iterator ii = drumkit->instruments.begin();
- while(ii != drumkit->instruments.end()) {
- Instrument *instrument = ii->second;
- instrument->port = jack_port_register(jack_client,
- instrument->name.c_str(),
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsInput | JackPortIsTerminal,
- 0);
-
- BeatMapper *beatmapper = new BeatMapper(instrument);
- beatmappers.push_back(beatmapper);
-
- // input_ports.push_back(instrument->port);
- ii++;
- }
-
- // Setup output ports
- Channels::iterator ci = drumkit->channels.begin();
- while(ci != drumkit->channels.end()) {
- Channel *channel = ci->second;
- channel->port = jack_port_register(jack_client,
- channel->name.c_str(),
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput | JackPortIsTerminal,
- 0);
- output_ports.push_back(channel->port);
- ci++;
- }
-
- //jack_on_shutdown(jack_client, _wrap_jack_shutdown, this);
- jack_set_process_callback(jack_client, _wrap_jack_process, this);
- //jack_set_thread_init_callback(jack_client, _wrap_jack_thread_init, this);
- //jack_set_freewheel_callback(jack_client, _wrap_jack_freewheel_mode, this);
- //jack_set_buffer_size_callback(jack_client, _wrap_jack_buffer_size, this);
- //jack_set_sample_rate_callback(jack_client, _wrap_jack_sample_rate, this);
- //jack_set_port_registration_callback(jack_client, _wrap_jack_port_registration, this);
- //jack_set_graph_order_callback(jack_client, _wrap_jack_graph_order, this);
- //jack_set_xrun_callback(jack_client, _wrap_jack_xrun, this);
-}
-
-JackClient::~JackClient()
-{
- jack_client_close(jack_client);
-}
-
-void JackClient::activate()
-{
- jack_activate(jack_client);
-}
-
-void JackClient::shutdown()
-{
-}
-
-int JackClient::process(jack_nframes_t nframes)
-{
- //
- // Look for midi input
- //
- void *midibuffer = jack_port_get_buffer(midi_port, nframes);
- jack_nframes_t midievents = jack_midi_get_event_count(midibuffer);
- for(jack_nframes_t i = 0; i < midievents; i++) {
- jack_midi_event_t midi_event;
- jack_midi_event_get(&midi_event, midibuffer, i);
-
- Sample *sample = midimapper.map(midi_event);
- if(!sample) continue;
-
- AudioFiles::iterator ai = sample->audiofiles.begin();
- while(ai != sample->audiofiles.end()) {
- AudioFile *audiofile = ai->second;
- audiofile->load();
-
- if(drumkit->channels.find(audiofile->channel) != drumkit->channels.end()) {
- Channel *channel = drumkit->channels[audiofile->channel];
- Event event(channel->port, audiofile, midi_event.time);
- events.insert(event);
- }
- ai++;
- }
-
- }
- jack_midi_clear_buffer(midibuffer);
-
- //
- // Look for audio trigger input
- //
- // std::vector< BeatMapper >::iterator bi = beatmappers.begin();
- // while(bi != beatmappers.end()) {
- for(size_t bi = 0; bi < beatmappers.size(); bi++) {
- BeatMapper *beatmapper = beatmappers[bi];//*bi;
-
- Sample *sample = beatmapper->map(nframes);
- if(!sample) continue;
-
- AudioFiles::iterator ai = sample->audiofiles.begin();
- while(ai != sample->audiofiles.end()) {
- AudioFile *audiofile = ai->second;
- audiofile->load();
-
- if(drumkit->channels.find(audiofile->channel) != drumkit->channels.end()) {
- Channel *channel = drumkit->channels[audiofile->channel];
- Event event(channel->port, audiofile, 0);
- events.insert(event);
- }
- ai++;
- }
-
- //bi++;
- }
-
- //
- // Reset ports
- //
- Ports::iterator pi = output_ports.begin();
- while(pi != output_ports.end()) {
-
- jack_default_audio_sample_t *buffer;
- buffer = (jack_default_audio_sample_t *)jack_port_get_buffer(*pi, nframes);
-
- for(size_t j = 0; j < nframes; j++) {
- buffer[j] = 0;
- }
-
- pi++;
- }
-
- Events nextevents;
-
- //
- // Handle events
- //
- Events::iterator ei = events.begin();
- while(ei != events.end()) {
-
- Event event = *ei;
-
- jack_default_audio_sample_t *buffer;
- buffer = (jack_default_audio_sample_t *)jack_port_get_buffer(event.port, nframes);
-
- size_t dtime = nframes - event.time; // how much buffer is left?
- size_t size = event.sample->size - event.duration; // how much audio is left?
- if(size > dtime) size = dtime;
-
- for(size_t j = event.time; j < event.time + size; j++) {
- buffer[j] += event.sample->data[event.duration + j - event.time];
- }
-
- if(event.duration + size < event.sample->size) {
- Event e(event.port, event.sample, 0, event.duration + size);
- nextevents.insert(e);
- }
-
- ei++;
- }
-
- // Remove all dead events
- events = nextevents;
-
- return 0;
-}
-
-void JackClient::thread_init()
-{
-}
-
-void JackClient::freewheel_mode(int freewheel_mode)
-{
-}
-
-int JackClient::buffer_size(jack_nframes_t nframes)
-{
- return 0;
-}
-
-int JackClient::sample_rate(jack_nframes_t nframes)
-{
- return 0;
-}
-
-void JackClient::port_registration(jack_port_id_t port, int i)
-{
-}
-
-int JackClient::graph_order()
-{
- return 0;
-}
-
-int JackClient::xrun()
-{
- return 0;
-}
diff --git a/src/path.cc b/src/path.cc
new file mode 100644
index 0000000..3812b87
--- /dev/null
+++ b/src/path.cc
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * path.cc
+ *
+ * Tue May 3 14:42:47 CEST 2011
+ * Copyright 2011 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 "path.h"
+
+#include <libgen.h>
+#include <string.h>
+#include <stdlib.h>
+
+std::string getPath(std::string file)
+{
+ char *b = strdup(file.c_str());
+ std::string p = dirname(b);
+ free(b);
+ return p;
+}
+
+#ifdef TEST_PATH
+//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;
+
+std::string a = "../dir/file";
+TEST_EQUAL_STR(getPath(a), "../dir", "relative path");
+
+std::string b = "/abs/path/file";
+TEST_EQUAL_STR(getPath(b), "/abs/path", "absolute path");
+
+
+TEST_END;
+
+#endif/*TEST_PATH*/
diff --git a/src/cli.h b/src/path.h
index a5c42be..bdad0a5 100644
--- a/src/cli.h
+++ b/src/path.h
@@ -1,9 +1,9 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
- * cli.h
+ * path.h
*
- * Thu Sep 16 10:23:22 CEST 2010
- * Copyright 2010 Bent Bisballe Nyeng
+ * Tue May 3 14:42:46 CEST 2011
+ * Copyright 2011 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,6 +24,11 @@
* along with DrumGizmo; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __DRUMGIZMO_CLI_H__
-#define __DRUMGIZMO_CLI_H__
-#endif/*__DRUMGIZMO_CLI_H__*/
+#ifndef __DRUMGIZMO_PATH_H__
+#define __DRUMGIZMO_PATH_H__
+
+#include <string>
+
+std::string getPath(std::string file);
+
+#endif/*__DRUMGIZMO_PATH_H__*/
diff --git a/src/sample.cc b/src/sample.cc
index f0bb099..be897c7 100644
--- a/src/sample.cc
+++ b/src/sample.cc
@@ -47,8 +47,19 @@ void Sample::addAudioFile(Channel *c, AudioFile *a)
AudioFile *Sample::getAudioFile(Channel *c)
{
+ /*
if(audiofiles.find(c) == audiofiles.end()) return NULL;
return audiofiles[c];
+ */
+
+ AudioFiles::iterator i = audiofiles.begin();
+ while(i != audiofiles.end()) {
+ Channel *ch = i->first;
+ if(c->num == ch->num) return i->second;
+ i++;
+ }
+
+ return NULL;
}
#ifdef TEST_SAMPLE
diff --git a/src/sample.h b/src/sample.h
index c4d82f8..70cfee2 100644
--- a/src/sample.h
+++ b/src/sample.h
@@ -35,15 +35,18 @@
typedef std::map< Channel*, AudioFile* > AudioFiles;
+class InstrumentParser;
class Sample {
+ friend class InstrumentParser;
public:
- Sample(std::string name = "");
+ Sample(std::string name);
~Sample();
- void addAudioFile(InstrumentChannel *c, AudioFile *a);
AudioFile *getAudioFile(InstrumentChannel *c);
private:
+ void addAudioFile(InstrumentChannel *c, AudioFile *a);
+
std::string name;
AudioFiles audiofiles;
};
diff --git a/tools/Makefile.am.test b/tools/Makefile.am.test
new file mode 100644
index 0000000..5c5e8c7
--- /dev/null
+++ b/tools/Makefile.am.test
@@ -0,0 +1,14 @@
+Makefile.am.test: ${TEST_SOURCE_DEPS}
+ ${TEST_SCRIPT_DIR}/testlist > Makefile.am.test
+ @touch Makefile.am
+
+test: Makefile.am.test $(TESTFILES)
+ @echo "All tests done."
+
+test_clean:
+ rm -f $(TESTFILES) $(TESTLOGS)
+
+TESTLOGS = `for F in ${TESTFILES}; do echo $$F.log; done`
+
+CLEANFILES = $(TESTFILES) $(TESTLOGS) Makefile.am.test *~
+
diff --git a/tools/add_file b/tools/add_file
index f95f241..4825943 100755
--- a/tools/add_file
+++ b/tools/add_file
@@ -41,6 +41,23 @@ function ccfile() {
echo -n $hf >> $1;
echo '"' >> $1;
echo '' >> $1;
+ local hn=`echo $1 | cut -d'.' -f1 | tr 'a-z.' 'A-Z_'`
+ echo "#ifdef TEST_${hn}" >> $1;
+ echo "//Additional dependency files" >> $1;
+ echo "//deps:" >> $1;
+ echo "//Required cflags (autoconf vars may be used)" >> $1;
+ echo "//cflags:" >> $1;
+ echo "//Required link options (autoconf vars may be used)" >> $1;
+ echo "//libs:" >> $1;
+ echo "#include \"test.h\"" >> $1;
+ echo "" >> $1;
+ echo "TEST_BEGIN;" >> $1;
+ echo "" >> $1;
+ echo "// TODO: Put some testcode here (see test.h for usable macros)." >> $1;
+ echo "" >> $1;
+ echo "TEST_END;" >> $1;
+ echo "" >> $1;
+ echo "#endif/*TEST_${hn}*/" >> $1;
}
function hfile() {
diff --git a/tools/test b/tools/test
new file mode 100755
index 0000000..a52609d
--- /dev/null
+++ b/tools/test
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+TEST=`echo -n $1 | cut -d'.' -f1`
+UPPER=`echo $TEST | tr 'a-z.' 'A-Z_'`
+OUTPUT=test_$TEST
+DEFINE=TEST_$UPPER
+
+SCRIPTDIR=`dirname $0`
+
+COMPILE="g++ -DHAVE_CONFIG_H -I$SCRIPTDIR -g -Wall -Werror -D$DEFINE -o $OUTPUT $*"
+
+echo -e "\033[0;2mTesting $TEST:"
+echo Testing $TEST: > $OUTPUT.log
+
+echo -n "* Compiling $TEST test"
+echo Compiling $TEST test: > $OUTPUT.log
+echo ${COMPILE} >> $OUTPUT.log
+
+if ${COMPILE} >> ${OUTPUT}.log 2>&1; then
+ echo -e "\r\t\t\t\t\t\t[\033[1;32mSuccess\033[0;2m]"
+ echo "[Success]" >> $OUTPUT.log
+
+ echo -n "* Running $TEST test"
+ echo Running $TEST test: >> $OUTPUT.log
+ if ./$OUTPUT >> $OUTPUT.log 2>&1; then
+ echo -e "\r\t\t\t\t\t\t[\033[1;32mSuccess\033[0;2m]"
+ echo "[Success]" >> $OUTPUT.log
+ else
+ echo -e "\r\t\t\t\t\t\t[\033[1;31mFailure\033[0;2m]"
+ echo "[Failure]" >> $OUTPUT.log
+ rm -f $OUTPUT
+ fi
+else
+ echo -e "\r\t\t\t\t\t\t[\033[1;31mFailure\033[0;2m]"
+ echo "[Failure]" >> $OUTPUT.log
+fi
+
+echo \ No newline at end of file
diff --git a/tools/test.h b/tools/test.h
new file mode 100644
index 0000000..f470162
--- /dev/null
+++ b/tools/test.h
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * test.h
+ *
+ * Wed Dec 16 12:33:19 CET 2009
+ * Copyright 2009 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_TEST_H__
+#define __PRACRO_TEST_H__
+
+#include <stdio.h>
+
+#define TEST_REPORT { \
+ fprintf(stderr, "\nTest report:\n%d tests\n%d test failed.\n", \
+ TEST_num_tests, TEST_num_fails); \
+ }
+
+#define TEST_BEGIN \
+ int main() { \
+ int TEST_num_fails = 0; \
+ int TEST_num_tests = 0; \
+ {}
+
+#define TEST_END { \
+ TEST_REPORT; \
+ return TEST_num_fails != 0; \
+ } }
+
+#define TEST_OK(m) { \
+ fprintf(stderr, " OK: "m"\n"); \
+ }
+
+#define TEST_FAIL(m) { \
+ fprintf(stderr, " FAIL: "m"\t\t\t<------------\n"); \
+ TEST_num_fails++; \
+ }
+
+#define TEST_FATAL(m) { \
+ fprintf(stderr, "FATAL: %s\t\t\t<============\n", m); \
+ TEST_num_fails++; \
+ { TEST_END; }
+
+#define TEST_MSG(fmt...) { \
+ fprintf(stderr, "\n"); \
+ fprintf(stderr, fmt); \
+ fprintf(stderr, " (line %d)\n", __LINE__); \
+ }
+
+#define TEST_BASE(fmt...) { \
+ TEST_num_tests++; \
+ TEST_MSG(fmt); \
+ }
+
+#define TEST_TRUE(x, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x) { TEST_OK(#x" is true.") } \
+ else { TEST_FAIL(#x" is not true.") } \
+ }
+
+#define TEST_FALSE(x, fmt...) { \
+ TEST_BASE(fmt); \
+ if(!x) { TEST_OK(#x" is false.") } \
+ else { TEST_FAIL(#x" is not false.") } \
+ }
+
+#define TEST_EQUAL(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x == y) { TEST_OK(#x" and "#y" are equal.") } \
+ else { TEST_FAIL(#x" and "#y" are not equal.") } \
+ }
+
+#define TEST_NOTEQUAL(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x != y) { TEST_OK(#x" and "#y" are not equal.") } \
+ else { TEST_FAIL(#x" and "#y" are equal.") } \
+ }
+
+#define TEST_GREATER_THAN(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x > y) { TEST_OK(#x" are greater than "#y".") } \
+ else { TEST_FAIL(#x" are not greater than "#y".") } \
+ }
+
+#define TEST_LESS_THAN(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ if(x < y) { TEST_OK(#x" are less than "#y".") } \
+ else { TEST_FAIL(#x" are not less than "#y".") } \
+ }
+
+#define TEST_EQUAL_STR(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ std::string s1 = x; \
+ std::string s2 = y; \
+ fprintf(stderr, "Comparing: \"%s\" == \"%s\"\n", \
+ s1.c_str(), s2.c_str()); \
+ if(s1 == s2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_STR(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ std::string s1 = x; \
+ std::string s2 = y; \
+ fprintf(stderr, "Comparing: \"%s\" != \"%s\"\n", \
+ s1.c_str(), s2.c_str()); \
+ if(s1 != s2) { \
+ TEST_OK(#x" and "#y" not are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_EQUAL_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" == \"%d\"\n", i1, i2); \
+ if(i1 == i2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" != \"%d\"\n", i1, i2); \
+ if(i1 != i2) { \
+ TEST_OK(#x" and "#y" are not equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_EQUAL_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" == \"%f\"\n", d1, d2); \
+ if(d1 == d2) { \
+ TEST_OK(#x" and "#y" are equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are not equal."); \
+ } \
+ }
+
+#define TEST_NOTEQUAL_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" != \"%f\"\n", d1, d2); \
+ if(d1 != d2) { \
+ TEST_OK(#x" and "#y" are not equal."); \
+ } else { \
+ TEST_FAIL(#x" and "#y" are equal."); \
+ } \
+ }
+
+#define TEST_GREATER_THAN_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" > \"%d\"\n", i1, i2); \
+ if(i1 > i2) { \
+ TEST_OK(#x" are greater than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not greater than "#y"."); \
+ } \
+ }
+
+#define TEST_LESS_THAN_INT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ int i1 = x; \
+ int i2 = y; \
+ fprintf(stderr, "Comparing: \"%d\" < \"%d\"\n", i1, i2); \
+ if(i1 < i2) { \
+ TEST_OK(#x" are less than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not less than "#y"."); \
+ } \
+ }
+
+#define TEST_GREATER_THAN_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" > \"%f\"\n", d1, d2); \
+ if(d1 > d2) { \
+ TEST_OK(#x" are greater than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not greater than "#y"."); \
+ } \
+ }
+
+#define TEST_LESS_THAN_FLOAT(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ double d1 = x; \
+ double d2 = y; \
+ fprintf(stderr, "Comparing: \"%f\" < \"%f\"\n", d1, d2); \
+ if(d1 < d2) { \
+ TEST_OK(#x" are less than "#y"."); \
+ } else { \
+ TEST_FAIL(#x" are not less than "#y"."); \
+ } \
+ }
+
+#define TEST_EXCEPTION(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_FAIL("Exception "#y" was not trown."); \
+ } catch( y &e ) { \
+ TEST_OK("Exception "#y" was thrown as expected."); \
+ } \
+ }
+
+#define TEST_NOTEXCEPTION(x, y, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_OK("Exception "#y" was not trown as expected"); \
+ } catch( y &e ) { \
+ TEST_FAIL("Exception "#y" was thrown."); \
+ } \
+ }
+
+#define TEST_NOEXCEPTION(x, fmt...) { \
+ TEST_BASE(fmt); \
+ try { \
+ x; \
+ TEST_OK("Exception was not trown as expected"); \
+ } catch( ... ) { \
+ TEST_FAIL("Exception was thrown."); \
+ } \
+ }
+
+#endif/*__PRACRO_TEST_H__*/
diff --git a/tools/testlist b/tools/testlist
new file mode 100755
index 0000000..c42824f
--- /dev/null
+++ b/tools/testlist
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+SCRIPTDIR=`dirname $0`
+
+grep -l "TEST_BEGIN" *.cc > tmp
+
+echo -n "TESTFILES="
+while read LINE
+do
+ FILE=$LINE
+ NAME=`echo $FILE | cut -d'.' -f1`
+ TEST=test_$NAME
+ echo -ne "$TEST "
+done < tmp
+echo ""
+echo ""
+
+while read LINE
+do
+ FILE=$LINE
+ NAME=`echo $FILE | cut -d'.' -f1`
+ DEPS=`cat $FILE | grep "deps:" | cut -d':' -f2`
+ LIBS=`cat $FILE | grep "libs:" | cut -d':' -f2`
+ CFLAGS=`cat $FILE | grep "cflags:" | cut -d':' -f2`
+ TEST=test_$NAME
+ echo "$TEST: $FILE $DEPS"
+ echo -e "\t@${SCRIPTDIR}/test $FILE $DEPS $CFLAGS $LIBS"
+ echo ""
+done < tmp
+
+rm -f tmp \ No newline at end of file