summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2015-02-19 18:05:53 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2015-02-19 18:05:53 +0100
commit7bdc1773013b90d8bf7adcf5907f7e096dd7be6f (patch)
tree3db301f8f33833226d8d4d732efbcbecb4717881
parentd38c843e13d411ab822b939a477dc6d6bc7fe5b2 (diff)
parentb16f9d793d6e3e4ab88efff112f2fca30ed87be5 (diff)
Merge branch 'master' into lv2opt
-rw-r--r--drumgizmo/Makefile.am1
-rw-r--r--drumgizmo/drumgizmoc.cc97
-rw-r--r--drumgizmo/drumgizmoc.h45
-rw-r--r--drumgizmo/output/wavfile/Makefile.am2
-rw-r--r--man/drumgizmo.1138
-rw-r--r--src/Makefile.am1
-rw-r--r--src/drumgizmo.cc34
-rw-r--r--src/drumgizmo.h13
-rw-r--r--src/instrumentparser.cc8
-rw-r--r--src/nolocale.h78
10 files changed, 324 insertions, 93 deletions
diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am
index b01b41f..5220ae3 100644
--- a/drumgizmo/Makefile.am
+++ b/drumgizmo/Makefile.am
@@ -27,6 +27,7 @@ drumgizmo_SOURCES = \
EXTRA_DIST = \
audioinputenginedl.h \
audiooutputenginedl.h \
+ drumgizmoc.h \
jackclient.h
endif
diff --git a/drumgizmo/drumgizmoc.cc b/drumgizmo/drumgizmoc.cc
index 61f8eaa..02e926e 100644
--- a/drumgizmo/drumgizmoc.cc
+++ b/drumgizmo/drumgizmoc.cc
@@ -30,8 +30,10 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include "drumgizmo.h"
+#include "drumgizmoc.h"
#include "audiooutputenginedl.h"
#include "audioinputenginedl.h"
@@ -54,17 +56,60 @@ static const char copyright_str[] =
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"
-" -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"
-" -e, --endpos Number of samples to process, -1: infinite.\n"
+" -a, --async-load Load drumkit in the background and start the engine immediately.\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|jackaudio|wavfile Use said audio output engine.\n"
+" -O, --outputparms parmlist Set output engine parameters.\n"
+" -e, --endpos Number of samples to process, -1: infinite.\n"
" -v, --version Print version information and exit.\n"
" -h, --help Print this message and exit.\n"
+"\n"
+"Input engine parameters:\n"
+" jackmidi: midimap=<midimapfile>\n"
+" midifile: file=<midifile>, speed=<tempo> (default 1.0),\n"
+" track=<miditrack> (default -1, all tracks)\n"
+" midimap=<midimapfile>, loop=<true|false>\n"
+" test: p=<hit_propability> (default 0.1)\n"
+" instr=<instrument> (default -1, random instrument)\n"
+" len=<seconds> (default -1, forever)\n"
+" dummy:\n"
+"\n"
+"Output engine parameters:\n"
+" alsa: dev=<device> (default 'default'), frames=<frames> (default 32)\n"
+" srate=<samplerate> (default 441000)\n"
+" wavfile: file=<filename> (default 'output'), srate=<samplerate> (default 44100)\n"
+" jackaudio:\n"
+" dummy:\n"
+"\n"
;
-int main(int argc, char *argv[])
+CliMain::CliMain() : MessageReceiver(MSGRCV_UI)
+{
+ loading = true; // Block by default
+}
+
+CliMain::~CliMain()
+{
+}
+
+void CliMain::handleMessage(Message *msg)
+{
+ switch(msg->type()) {
+ case Message::LoadStatus:
+ {
+ LoadStatusMessage *ls = (LoadStatusMessage*)msg;
+ if(ls->numer_of_files_loaded == ls->number_of_files) {
+ loading = false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int CliMain::run(int argc, char *argv[])
{
int c;
@@ -72,13 +117,13 @@ int main(int argc, char *argv[])
std::string inputengine;
std::string iparms;
std::string oparms;
- bool preload = false;
+ bool async = false;
int endpos = -1;
int option_index = 0;
while(1) {
static struct option long_options[] = {
- {"preload", no_argument, 0, 'p'},
+ {"async-load", no_argument, 0, 'a'},
{"inputengine", required_argument, 0, 'i'},
{"inputparms", required_argument, 0, 'I'},
{"outputengine", required_argument, 0, 'o'},
@@ -110,7 +155,7 @@ int main(int argc, char *argv[])
case 'o':
outputengine = optarg;
if(outputengine == "help") {
- printf("Available output engines: alsa, jack, sndfile.\n");
+ printf("Available output engines: alsa, jackaudio, wavfile.\n");
return 0;
}
break;
@@ -119,8 +164,8 @@ int main(int argc, char *argv[])
oparms = optarg;
break;
- case 'p':
- preload = true;
+ case 'a':
+ async = true;
break;
case 'e':
@@ -243,14 +288,30 @@ int main(int argc, char *argv[])
printf("Using kitfile: %s\n", kitfile.c_str());
DrumGizmo gizmo(oe, ie);
+
if(kitfile == "" || !gizmo.loadkit(kitfile)) {
printf("Failed to load \"%s\".\n", kitfile.c_str());
return 1;
}
+ printf("Loading drumkit, this may take a while...");
+ fflush(stdout);
+ loading = true;
+ while(async == false && loading) {
+#ifdef WIN32
+ SleepEx(500, FALSE);
+#else
+ usleep(500000);
+#endif/*WIN32*/
+ handleMessages();
+ printf(".");
+ fflush(stdout);
+ }
+ printf("done.\n");
+
gizmo.setSamplerate(oe->samplerate());
- if(!gizmo.init(preload)) {
+ if(!gizmo.init()) {
printf("Failed init engine.\n");
return 1;
}
@@ -264,3 +325,13 @@ int main(int argc, char *argv[])
return 0;
}
+
+int main(int argc, char *argv[])
+{
+ CliMain cli;
+
+ cli.run(argc, argv);
+
+ return 0;
+
+}
diff --git a/drumgizmo/drumgizmoc.h b/drumgizmo/drumgizmoc.h
new file mode 100644
index 0000000..4b6d4a1
--- /dev/null
+++ b/drumgizmo/drumgizmoc.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * drumgizmoc.h
+ *
+ * Mon Jan 12 00:36:37 CET 2015
+ * Copyright 2015 Sergey 'Jin' Bostandzhyan
+ * jin@mediatomb.cc
+ ****************************************************************************/
+
+/*
+ * 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 __DRUMGIZMOC_H__
+#define __DRUMGIZMOC_H__
+
+#include "messagereceiver.h"
+
+class CliMain : public MessageReceiver {
+public:
+ CliMain();
+ virtual ~CliMain();
+
+ int run(int argc, char *argv[]);
+ void handleMessage(Message *msg);
+private:
+ bool loading;
+};
+
+#endif//__DRUMGIZMOC_H__
+
diff --git a/drumgizmo/output/wavfile/Makefile.am b/drumgizmo/output/wavfile/Makefile.am
index ae0eb76..ad26294 100644
--- a/drumgizmo/output/wavfile/Makefile.am
+++ b/drumgizmo/output/wavfile/Makefile.am
@@ -26,4 +26,4 @@ wavfile_la_LIBADD =
wavfile_la_SOURCES = $(wavfilebuildsources)
install-exec-hook:
- rm -f $(DESTDIR)$(libdir)/alsa.la
+ rm -f $(DESTDIR)$(libdir)/wavfile.la
diff --git a/man/drumgizmo.1 b/man/drumgizmo.1
index 3472ddc..ad9b1f2 100644
--- a/man/drumgizmo.1
+++ b/man/drumgizmo.1
@@ -4,7 +4,7 @@
drumgizmo \- drum application
.SH SYNOPSIS
-\fBdrumgizmo\fR [OPTIONS] \fIdrumkitfile
+\fBdrumgizmo\fR [OPTIONS] drumkitfile
.SH "DESCRIPTION"
.PP
@@ -13,86 +13,104 @@ drumgizmo \- drum application
DrumGizmo uses an open drumkit file format, allowing the community to create their own drumkits. It has multichannel output, making it possible to mix it just the way you would a real drumkit. The optional built-in humanizer analyzes the midi notes, adjusting velocities on-the-fly. This client can be a stand-alone midi renderer, generating .wav files, 1 for each channel. Or use DrumGizmo as a software sampler for an electronic drumkit. There are also plugin versions available.
.SH "OPTIONS"
-.TP
-\fB-p, --preload
-Load entire kit audio files into memory (uses A LOT of memory).
-.TP
+.PD 0
+.RE
+.RS 7
\fB-i, --inputengine \fR{dummy|test|jackmidi|midifile}
+.RS 7
Use said event input engine.
-.TP
-\fB-I, --inputparms parmlist
+
+.RE
+\fB-I, --inputparms parmlist\fR
+.RS 7
Set input engine parameters.
-.TP
-.SS
-\fBjackmidi:
+
+\fBjackmidi:\fR
+.P
midimap=<midimapfile>
-.TP
-.SS
-\fBmidifile:
-file=<midifile>, speed=<tempo> (default 1.0)
-.br
+
+\fBmidifile:\fR
+.P
+file=<midifile>
+.P
+speed=<tempo> (default 1.0)
+.P
track=<miditrack> (default -1, all tracks)
-.br
-midimap=<midimapfile>, loop=<true|false>
-.TP
-.SS
-\fBtest:
+.P
+midimap=<midimapfile>
+.P
+loop=<true|false>
+
+\fBtest:\fR
+.P
p=<hit_propability> (default 0.1)
-.br
+.P
instr=<instrument> (default -1, random instrument)
-.br
+.P
len=<seconds> (default -1, forever)
-.TP
-.SS
-\fBdummy:
-.TP
+
+\fBdummy:\fR
+
+.RE
\fB-o, --outputengine \fR{dummy|alsa|jackaudio|wavfile}
+.RS 7
Use said audio output engine.
-.TP
-\fB-O, --outputparms parmlist
+
+.RE
+\fB-O, --outputparms parmlist\fR
+.RS 7
Set output engine parameters.
-.TP
-.SS
-\fBalsa:
+
+\fBalsa:\fR
+.P
dev=<device> (default 'default')
-.br
+.P
frames=<frames> (default 32)
-.br
+.P
srate=<samplerate> (default 441000)
-.TP
-.SS
-\fBwavfile:
+
+\fBwavfile:\fR
+.P
file=<filename> (default 'output')
-.br
+.P
srate=<samplerate> (default 44100)
-.TP
-.SS
-\fBjackaudio:
-.TP
-.SS
-\fBdummy:
-.TP
-\fB-e, --endpos
+
+\fBjackaudio:\fR
+
+\fBdummy:\fR
+
+.RE
+\fB-e, --endpos\fR
+.RS 7
Number of samples to process, -1: infinite.
-.TP
-\fB-v, --version
+
+.RE
+\fB-v, --version\fR
+.RS 7
Print drumgizmo version and exit.
-.TP
-\fB-h, --help
+
+.RE
+\fB-h, --help\fR
+.RS 7
Print command line help and exit.
-.TP
-\fB\fIdrumkitfile
+
+.RE
+\fBdrumkitfile\fR
+.RS 7
Load the drumkitfile.
-.El
-.Sh "EXAMPLES"
-Render midifile to wav files:
-.Bb -literal -offset indent -compact
-drumgizmo -p -i midifile -I file=file.mid,midimap=midimap.xml -o wavfile -O file=file.wav drumkit.xml
-.Ed
-Recieve midi from Jack and send audio output to speakers:
-drumgizmo -p -i jackmidi -I midimap=midimap.xml -o jackaudio drumkit.xml
+
+.RE
+.SH "EXAMPLES"
+\fBRender midifile to wav files:\fR
+.RS 7
+drumgizmo -i midifile -I file=file.mid,midimap=midimap.xml -o wavfile -O file=file.wav drumkit.xml
+.RE
+\fBRecieve midi from Jack and send audio output to speakers:\fR
+.RS 7
+drumgizmo -i jackmidi -I midimap=midimap.xml -o jackaudio drumkit.xml
+.RE
.SH "BUGS"
Report bugs to http://www.drumgizmo.org/wiki/doku.php?id=bugs.
.SH "ADDITIONAL INFORMATION"
-For further information, visit the website http://www.drumgizmo.org/.
+For further information, visit the website http://www.drumgizmo.org.
diff --git a/src/Makefile.am b/src/Makefile.am
index b9b0aae..df9f4ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ EXTRA_DIST = \
midimapparser.h \
midimapper.h \
mutex.h \
+ nolocale.h \
path.h \
powerlist.h \
rangemap.h \
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 71043af..6fd454e 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -43,10 +43,13 @@
#include "configuration.h"
#include "configparser.h"
+#include "nolocale.h"
+
DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i)
: MessageReceiver(MSGRCV_ENGINE),
loader(), oe(o), ie(i)
{
+ is_stopping = false;
}
DrumGizmo::~DrumGizmo()
@@ -84,10 +87,8 @@ bool DrumGizmo::loadkit(std::string file)
return true;
}
-bool DrumGizmo::init(bool preload)
+bool DrumGizmo::init()
{
- (void)preload;
-
if(!ie->init(kit.instruments)) return false;
if(!oe->init(kit.channels)) return false;
@@ -255,7 +256,23 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
}
if(evs[e].type == TYPE_STOP) {
- return false;
+ is_stopping = true;
+ }
+
+ if(is_stopping) {
+ // Count the number of active events.
+ int num_active_events = 0;
+ Channels::iterator j = kit.channels.begin();
+ while(j != kit.channels.end()) {
+ Channel &ch = *j;
+ num_active_events += activeevents[ch.num].size();
+ j++;
+ }
+
+ if(num_active_events == 0) {
+ // No more active events - now we can stop the engine.
+ return false;
+ }
}
}
@@ -409,12 +426,13 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz)
evt->rampdown--;
}
+ if(evt->rampdown == 0) {
+ removeevent = true; // Down ramp done. Remove event.
+ }
}
if(evt->t >= af->size) {
removeevent = true;
-// LAZYLOAD:
-// loader.reset(af);
}
}
@@ -455,7 +473,7 @@ void DrumGizmo::setSamplerate(int samplerate)
std::string float2str(float a)
{
char buf[256];
- sprintf(buf, "%f", a);
+ snprintf_nol(buf, sizeof(buf) - 1, "%f", a);
return buf;
}
@@ -467,7 +485,7 @@ std::string bool2str(bool a)
float str2float(std::string a)
{
if(a == "") return 0.0;
- return atof(a.c_str());
+ return atof_nol(a.c_str());
}
std::string DrumGizmo::configString()
diff --git a/src/drumgizmo.h b/src/drumgizmo.h
index 138e61c..f8d45f5 100644
--- a/src/drumgizmo.h
+++ b/src/drumgizmo.h
@@ -51,14 +51,13 @@
class DrumGizmo : public MessageReceiver {
public:
- DrumGizmo(AudioOutputEngine *outputengine,
- AudioInputEngine *inputengine);
+ DrumGizmo(AudioOutputEngine *outputengine, AudioInputEngine *inputengine);
virtual ~DrumGizmo();
bool loadkit(std::string kitfile);
- bool init(bool preload = true);
-
+ bool init();
+
/**
* @param endpos number of samples to process, -1 := never stop.
*/
@@ -68,8 +67,6 @@ public:
void getSamples(int ch, int pos, sample_t *s, size_t sz);
- bool isRunning() { return is_running; }
-
std::string configString();
bool setConfigString(std::string cfg);
@@ -77,12 +74,12 @@ public:
int samplerate();
void setSamplerate(int samplerate);
-
+
private:
DrumKitLoader loader;
Mutex mutex;
- bool is_running;
+ bool is_stopping; ///< Is set to true when a TYPE_STOP event has been seen.
AudioOutputEngine *oe;
AudioInputEngine *ie;
diff --git a/src/instrumentparser.cc b/src/instrumentparser.cc
index 0889d74..1f25bc7 100644
--- a/src/instrumentparser.cc
+++ b/src/instrumentparser.cc
@@ -33,6 +33,8 @@
#include "path.h"
+#include "nolocale.h"
+
InstrumentParser::InstrumentParser(const std::string &file, Instrument &i)
: instrument(i)
{
@@ -84,7 +86,7 @@ void InstrumentParser::startTag(std::string name,
if(attr.find("power") == attr.end()) {
power = -1;
} else {
- power = atof(attr["power"].c_str());
+ power = atof_nol(attr["power"].c_str());
DEBUG(instrparser, "Instrument power set to %f\n", power);
}
@@ -136,8 +138,8 @@ void InstrumentParser::startTag(std::string name,
return;
}
- lower = atof(attr["lower"].c_str());
- upper = atof(attr["upper"].c_str());
+ lower = atof_nol(attr["lower"].c_str());
+ upper = atof_nol(attr["upper"].c_str());
}
if(name == "sampleref") {
diff --git a/src/nolocale.h b/src/nolocale.h
new file mode 100644
index 0000000..816dd9c
--- /dev/null
+++ b/src/nolocale.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ * nolocale.h
+ *
+ * Fri Feb 13 12:48:10 CET 2015
+ * Copyright 2015 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_NOLOCALE_H__
+#define __DRUMGIZMO_NOLOCALE_H__
+
+#include <locale.h>
+#include <stdarg.h>
+
+static inline double atof_nol(const char *nptr)
+{
+ double res;
+
+ const char *locale = setlocale(LC_NUMERIC, "C");
+
+ res = atof(nptr);
+
+ setlocale(LC_NUMERIC, locale);
+
+ return res;
+}
+
+static inline int sprintf_nol(char *str, const char *format, ...)
+{
+ int ret;
+
+ const char *locale = setlocale(LC_NUMERIC, "C");
+
+ va_list vl;
+ va_start(vl, format);
+ ret = vsprintf(str, format, vl);
+ va_end(vl);
+
+ setlocale(LC_NUMERIC, locale);
+
+ return ret;
+}
+
+static inline int snprintf_nol(char *str, size_t size, const char *format, ...)
+{
+ int ret;
+
+ const char *locale = setlocale(LC_NUMERIC, "C");
+
+ va_list vl;
+ va_start(vl, format);
+ ret = vsnprintf(str, size, format, vl);
+ va_end(vl);
+
+ setlocale(LC_NUMERIC, locale);
+
+ return ret;
+}
+
+#endif/*__DRUMGIZMO_NOLOCALE_H__*/