From 41b6ef4642b25c22e47e5f89f113b502d3a4321c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Gl=C3=B6ckner?= Date: Mon, 25 Jan 2016 12:32:09 +0100 Subject: added JackMidiInputEngine + additional minor changes --- drumgizmo/Makefile.am | 5 ++ drumgizmo/enginefactory.cc | 12 +++- drumgizmo/enginefactory.h | 5 +- drumgizmo/input/jackmidi.cc | 145 ++++++++++++++++++++++++++++++++++++++++++ drumgizmo/input/jackmidi.h | 67 +++++++++++++++++++ drumgizmo/input/midifile.cc | 4 +- drumgizmo/input/midifile.h | 6 +- drumgizmo/jackclient.cc | 22 +++---- drumgizmo/jackclient.h | 22 ++++--- drumgizmo/output/jackaudio.cc | 35 ++++++---- drumgizmo/output/jackaudio.h | 15 +++-- 11 files changed, 289 insertions(+), 49 deletions(-) create mode 100644 drumgizmo/input/jackmidi.cc create mode 100644 drumgizmo/input/jackmidi.h (limited to 'drumgizmo') diff --git a/drumgizmo/Makefile.am b/drumgizmo/Makefile.am index 4eb770c..4c34f6c 100644 --- a/drumgizmo/Makefile.am +++ b/drumgizmo/Makefile.am @@ -41,6 +41,11 @@ drumgizmo_SOURCES += input/midifile.cc drumgizmo_CXXFLAGS += -DHAVE_INPUT_MIDIFILE endif # HAVE_INPUT_MIDIFILE +if HAVE_INPUT_JACKMIDI +drumgizmo_SOURCES += input/jackmidi.cc +drumgizmo_CXXFLAGS += -DHAVE_INPUT_JACKMIDI +endif # HAVE_INPUT_JACKMIDI + if HAVE_OUTPUT_DUMMY drumgizmo_SOURCES += output/outputdummy.cc drumgizmo_CXXFLAGS += -DHAVE_OUTPUT_DUMMY diff --git a/drumgizmo/enginefactory.cc b/drumgizmo/enginefactory.cc index cb332ed..06f8141 100644 --- a/drumgizmo/enginefactory.cc +++ b/drumgizmo/enginefactory.cc @@ -26,6 +26,7 @@ */ #include +#include "cpp11fix.h" // required for c++11 #include "enginefactory.h" EngineFactory::EngineFactory() @@ -42,6 +43,9 @@ EngineFactory::EngineFactory() #ifdef HAVE_INPUT_MIDIFILE input.push_back("midifile"); #endif +#ifdef HAVE_INPUT_JACKMIDI + input.push_back("jackmidi"); +#endif // list available output engines #ifdef HAVE_OUTPUT_DUMMY @@ -85,6 +89,12 @@ std::unique_ptr EngineFactory::createInput(std::string const & return std::make_unique(); } #endif +#ifdef HAVE_INPUT_JACKMIDI + if (name == "jackmidi") { + prepareJack(); + return std::make_unique(*jack); + } +#endif // todo: add more engines @@ -111,7 +121,7 @@ std::unique_ptr EngineFactory::createOutput(std::string const #ifdef HAVE_OUTPUT_JACKAUDIO if (name == "jackaudio") { prepareJack(); - return std::make_unique(*jack); + return std::make_unique(*jack); } #endif diff --git a/drumgizmo/enginefactory.h b/drumgizmo/enginefactory.h index 6457ed1..f00df99 100644 --- a/drumgizmo/enginefactory.h +++ b/drumgizmo/enginefactory.h @@ -28,7 +28,6 @@ #include #include #include -#include "cpp11fix.h" // required for c++11 #include "audioinputengine.h" #include "audiooutputengine.h" @@ -46,6 +45,10 @@ #include "input/midifile.h" #endif +#ifdef HAVE_INPUT_JACKMIDI + #include "input/jackmidi.h" +#endif + #ifdef HAVE_OUTPUT_DUMMY #include "output/outputdummy.h" #endif diff --git a/drumgizmo/input/jackmidi.cc b/drumgizmo/input/jackmidi.cc new file mode 100644 index 0000000..2d399c2 --- /dev/null +++ b/drumgizmo/input/jackmidi.cc @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * jackmidi.cc + * + * Mo 25. Jan 11:26:06 CET 2016 + * Copyright 2016 Christian Glöckner + * cgloeckner@freenet.de + ****************************************************************************/ + +/* + * 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 +#include + +#include "cpp11fix.h" // required for c++11 +#include "jackmidi.h" + +int const NOTE_ON = 0x90; + +JackMidiInputEngine::JackMidiInputEngine(JackClient& client) + : AudioInputEngine{} + , JackProcess{} + , client{client} + , port{nullptr} + , midimap{} + , midi_mapper{} + , list{nullptr} + , pos{0u} { + client.add(*this); +} + +JackMidiInputEngine::~JackMidiInputEngine() { + client.remove(*this); +} + +bool JackMidiInputEngine::isMidiEngine() { + return true; +} + +bool JackMidiInputEngine::init(Instruments& instruments) { + if (midimap == "") { + std::cerr << "[JackMidiInputEngine] Missing midimap filename\n"; + return false; + } + MidiMapParser p{midimap}; + if (p.parse()) { + std::cerr << "[JackmidiInputEngine] Failed to parse midimap '" + << midimap << "'\n"; + return false; + } + midi_mapper.midimap = p.midimap; + for (auto i = 0u; i < instruments.size(); ++i) { + auto name = instruments[i]->name(); + midi_mapper.instrmap[name] = i; + } + port = std::make_unique(client, "drumgizmo_midiin", + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput); + return true; +} + +void JackMidiInputEngine::setParm(std::string parm, std::string value) { + if (parm == "midimap") { + // apply midimap filename + midimap = value; + + } else { + std::cerr << "[JackMidiInputEngine] Unsupported parameter '" + << parm << "'\n"; + } +} + +bool JackMidiInputEngine::start() { + client.activate(); + return true; +} + +void JackMidiInputEngine::stop() { +} + +void JackMidiInputEngine::pre() { +} + +event_t* JackMidiInputEngine::run(size_t pos, size_t len, size_t* nevents) { + *nevents = listsize; + event_t* l = list; + printf("Owning raw pointer at drumgizmo/input/jackmidiinput.cc - GET RID OF THEM!\n"); + list = (event_t *)malloc(sizeof(event_t) * 1000); + listsize = 0; + return l; +} + +void JackMidiInputEngine::post() { +} + +void JackMidiInputEngine::process(jack_nframes_t num_frames) { + assert(port != nullptr); + void* buffer = port->getBuffer(num_frames); + jack_nframes_t num_events = jack_midi_get_event_count(buffer); + + for(jack_nframes_t i = 0; i < num_events; ++i) { + jack_midi_event_t event; + jack_midi_event_get(&event, buffer, 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); + int k = midi_mapper.lookup(key); + if(k != -1 && velocity) { + list[listsize].type = TYPE_ONSET; + list[listsize].instrument = k; + list[listsize].velocity = velocity / 127.0; + list[listsize].offset = event.time; + ++listsize; + } + } + jack_midi_clear_buffer(buffer); + pos += num_frames; +} + +/* + DrumKit* kit; + size_t pos; + EventQueue *eventqueue; +*/ + diff --git a/drumgizmo/input/jackmidi.h b/drumgizmo/input/jackmidi.h new file mode 100644 index 0000000..3c64f2d --- /dev/null +++ b/drumgizmo/input/jackmidi.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * jackmidi.h + * + * Mo 25. Jan 11:26:06 CET 2016 + * Copyright 2016 Christian Glöckner + * cgloeckner@freenet.de + ****************************************************************************/ + +/* + * 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. + */ +#pragma once +#include +#include +#include + +#include "audioinputengine.h" +#include "midimapper.h" +#include "midimapparser.h" +#include "../jackclient.h" + +class JackMidiInputEngine + : public AudioInputEngine + , public JackProcess { + public: + JackMidiInputEngine(JackClient& client); + ~JackMidiInputEngine(); + + // based on AudioInputEngine + bool isMidiEngine() override; + bool init(Instruments& instruments) override; + void setParm(std::string parm, std::string value) override; + bool start() override; + void stop() override; + void pre() override; + event_t* run(size_t pos, size_t len, size_t* nevents) override; + void post() override; + + // based on JackProcess + void process(jack_nframes_t num_frames) override; + + private: + JackClient& client; + std::unique_ptr port; + + std::string midimap; + MidiMapper midi_mapper; + std::size_t pos; + + event_t* list; + size_t listsize; +}; diff --git a/drumgizmo/input/midifile.cc b/drumgizmo/input/midifile.cc index 323a198..c9aeaf8 100644 --- a/drumgizmo/input/midifile.cc +++ b/drumgizmo/input/midifile.cc @@ -137,7 +137,7 @@ event_t* MidifileInputEngine::run(size_t pos, size_t len, size_t *nevents) { current_event->midi_buffer[2] > 0) { if(evs == nullptr) { - printf("Yet another raw owning pointer was generated by drumgizmo/input/midifile.cc - GET RID OF THEM!\n"); + printf("Owning raw pointer at drumgizmo/input/midifile.cc - GET RID OF THEM!\n"); evs = (event_t *)malloc(sizeof(event_t) * 1000); } @@ -171,7 +171,7 @@ event_t* MidifileInputEngine::run(size_t pos, size_t len, size_t *nevents) { offset += current_max_time; } else { if(evs == nullptr) { - printf("Yet another raw owning pointer was generated by drumgizmo/input/midifile.cc - GET RID OF THEM!\n"); + printf("Owning raw pointer at drumgizmo/input/midifile.cc - GET RID OF THEM!\n"); evs = (event_t *)malloc(sizeof(event_t) * 1000); } evs[num_events].type = TYPE_STOP; diff --git a/drumgizmo/input/midifile.h b/drumgizmo/input/midifile.h index 85abfc9..6749339 100644 --- a/drumgizmo/input/midifile.h +++ b/drumgizmo/input/midifile.h @@ -30,9 +30,9 @@ #include #include -#include -#include -#include +#include "audioinputengine.h" +#include "midimapper.h" +#include "midimapparser.h" class MidifileInputEngine : public AudioInputEngine { diff --git a/drumgizmo/jackclient.cc b/drumgizmo/jackclient.cc index 8d422cb..376f3fb 100644 --- a/drumgizmo/jackclient.cc +++ b/drumgizmo/jackclient.cc @@ -33,29 +33,23 @@ JackProcess::~JackProcess() { // -------------------------------------------------------------------- -JackChannel::JackChannel() - : samples{} - , client{nullptr} - , port{nullptr} { -} - -JackChannel::JackChannel(JackClient& client, std::size_t buffer_size, - std::string const & name) - : samples{} - , client{client.client} +JackPort::JackPort(JackClient& client, std::string const & name, const char * type, JackPortFlags flags) + : client{client.client} // register jack port for given client - , port{jack_port_register(this->client, name.c_str(), - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)} { - samples.resize(buffer_size); + , port{jack_port_register(this->client, name.c_str(), type, flags, 0)} { } -JackChannel::~JackChannel() { +JackPort::~JackPort() { if (port != nullptr) { assert(client != nullptr); jack_port_unregister(client, port); } } +void* JackPort::getBuffer(jack_nframes_t num_frames) { + return jack_port_get_buffer(port, num_frames); +} + // -------------------------------------------------------------------- int _wrap_jack_process(jack_nframes_t nframes, void* arg){ diff --git a/drumgizmo/jackclient.h b/drumgizmo/jackclient.h index ef7abf1..2574f18 100644 --- a/drumgizmo/jackclient.h +++ b/drumgizmo/jackclient.h @@ -43,21 +43,23 @@ class JackProcess { // -------------------------------------------------------------------- -struct JackChannel { - std::vector samples; - jack_client_t* const client; - jack_port_t* const port; - - JackChannel(); - JackChannel(JackClient& client, std::size_t buffer_size, - std::string const & name); - ~JackChannel(); +// RAII-wrapper for jack_port_t +class JackPort { + public: + JackPort(JackClient& client, std::string const & name, const char * type, JackPortFlags flags); + ~JackPort(); + + void* getBuffer(jack_nframes_t num_frames); + + private: + jack_client_t* const client; + jack_port_t* const port; }; // -------------------------------------------------------------------- class JackClient { - friend struct JackChannel; + friend struct JackPort; public: JackClient(); diff --git a/drumgizmo/output/jackaudio.cc b/drumgizmo/output/jackaudio.cc index 07ae4b5..634b7d1 100644 --- a/drumgizmo/output/jackaudio.cc +++ b/drumgizmo/output/jackaudio.cc @@ -29,17 +29,18 @@ #include "jackaudio.h" -JackaudioOutputEngine::JackaudioOutputEngine(JackClient& client) +JackAudioOutputEngine::JackAudioOutputEngine(JackClient& client) : client(client) // wanna use initializer braces here but jenkins fails , channels{} , sema{"jackaudio"} { client.add(*this); } -JackaudioOutputEngine::~JackaudioOutputEngine() { +JackAudioOutputEngine::~JackAudioOutputEngine() { + client.remove(*this); } -bool JackaudioOutputEngine::init(Channels data) { +bool JackAudioOutputEngine::init(Channels data) { channels.clear(); channels.reserve(data.size()); auto i = 0u; @@ -48,10 +49,10 @@ bool JackaudioOutputEngine::init(Channels data) { for (auto const & elem: data) { auto name = std::to_string(i) + "-" + elem.name; // initialize new channel - channels.emplace_back(client, buffer_size, name); + channels.emplace_back(client, name, buffer_size); if (channels.back().port == nullptr) { - std::cerr << "[JackaudioOutputEngine] Cannot create jack " + std::cerr << "[JackAudioOutputEngine] Cannot create jack " << "port for channel #" << i << "\n"; return false; } @@ -60,31 +61,31 @@ bool JackaudioOutputEngine::init(Channels data) { return true; } -void JackaudioOutputEngine::setParm(std::string parm, std::string value) { +void JackAudioOutputEngine::setParm(std::string parm, std::string value) { } -bool JackaudioOutputEngine::start() { +bool JackAudioOutputEngine::start() { client.activate(); return true; } -void JackaudioOutputEngine::stop() { +void JackAudioOutputEngine::stop() { } -void JackaudioOutputEngine::pre(size_t nsamples) { +void JackAudioOutputEngine::pre(size_t nsamples) { } -void JackaudioOutputEngine::run(int ch, sample_t* samples, size_t nsamples) { +void JackAudioOutputEngine::run(int ch, sample_t* samples, size_t nsamples) { for (auto i = 0u; i < nsamples; ++i) { channels[ch].samples[i] = samples[i]; } } -void JackaudioOutputEngine::post(size_t nsamples) { +void JackAudioOutputEngine::post(size_t nsamples) { sema.wait(); } -void JackaudioOutputEngine::process(jack_nframes_t num_frames) { +void JackAudioOutputEngine::process(jack_nframes_t num_frames) { assert(num_frames == getBufferSize()); for (auto& channel: channels) { @@ -97,10 +98,16 @@ void JackaudioOutputEngine::process(jack_nframes_t num_frames) { sema.post(); } -size_t JackaudioOutputEngine::getBufferSize() { +size_t JackAudioOutputEngine::getBufferSize() { return client.getBufferSize(); } -size_t JackaudioOutputEngine::samplerate() { +size_t JackAudioOutputEngine::samplerate() { return client.getSampleRate(); } + +JackAudioOutputEngine::Channel::Channel(JackClient& client, std::string const & name, std::size_t buffer_size) + : port{client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0} + , samples{} { + samples.resize(buffer_size); +} diff --git a/drumgizmo/output/jackaudio.h b/drumgizmo/output/jackaudio.h index 13ed75f..12539c5 100644 --- a/drumgizmo/output/jackaudio.h +++ b/drumgizmo/output/jackaudio.h @@ -31,12 +31,12 @@ #include "audiooutputengine.h" #include "../jackclient.h" -class JackaudioOutputEngine +class JackAudioOutputEngine : public AudioOutputEngine , public JackProcess { public: - JackaudioOutputEngine(JackClient& client); - ~JackaudioOutputEngine(); + JackAudioOutputEngine(JackClient& client); + ~JackAudioOutputEngine(); // based on AudioOutputEngine bool init(Channels chan) override; @@ -53,7 +53,14 @@ class JackaudioOutputEngine void process(jack_nframes_t num_frames) override; private: + struct Channel { + JackPort port; + std::vector samples; + + Channel(JackClient& client, std::string const & name, std::size_t buffer_size); + }; + JackClient& client; - std::vector channels; + std::vector channels; Semaphore sema; }; -- cgit v1.2.3