diff options
author | deva <deva> | 2011-07-15 13:02:33 +0000 |
---|---|---|
committer | deva <deva> | 2011-07-15 13:02:33 +0000 |
commit | cd0e36773992e26985bdec1f7a5341f83fa3e521 (patch) | |
tree | 4710fb3f2465f4b464f5f6176261a67cfde2e46e | |
parent | e190d38057892b69246391841b234a368bc2b4ad (diff) |
New input/output plugin architecture. New LV2 plugin.
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(¶ms); + // 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(¶ms); - // 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*/ @@ -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 |