diff options
-rw-r--r-- | configure.ac | 67 | ||||
-rw-r--r-- | src/libs/engine/AlsaMidiDriver.cpp | 364 | ||||
-rw-r--r-- | src/libs/engine/AlsaMidiDriver.h | 119 | ||||
-rw-r--r-- | src/libs/engine/Engine.cpp | 8 | ||||
-rw-r--r-- | src/libs/engine/Makefile.am | 6 |
5 files changed, 24 insertions, 540 deletions
diff --git a/configure.ac b/configure.ac index d2db800d..9682db70 100644 --- a/configure.ac +++ b/configure.ac @@ -134,17 +134,11 @@ AC_ARG_ENABLE([in-process-engine], [ if test x$enable_in_process_engine = xyes ; then build_in_process_engine=yes ; fi ]) # Jack MIDI support -build_jack_midi="no" +build_jack_midi="yes" AC_ARG_ENABLE(jack-midi, - [AS_HELP_STRING(--enable-jack-midi, [Enable Jack MIDI support (no)])], + [AS_HELP_STRING(--enable-jack-midi, [Enable Jack MIDI support (yes)])], [ if test x$enable_jack_midi = xyes ; then build_jack_midi=yes ; fi ]) -# ALSA support -build_alsa_midi="yes" -AC_ARG_ENABLE(alsa-midi, - [AS_HELP_STRING(--enable-alsa-midi, [Enable Alsa MIDI driver (yes)])], - [ if test x$enable_alsa_midi = xno ; then build_alsa_midi=no ; fi ]) - # LV2 support build_lv2="yes" AC_ARG_ENABLE(lv2, @@ -228,21 +222,6 @@ if test "$build_server" = "yes"; then fi fi - # Check for ALSA - if test "$build_alsa_midi" = "yes" -o "$build_dssi" = "yes"; then - PKG_CHECK_MODULES(ALSA, alsa >= 1.0.0, [have_alsa_midi="yes"], [have_alsa_midi="no"]) - fi - - if test "$build_alsa_midi" = "yes"; then - if test "$build_jack_midi" = "yes"; then - AC_MSG_WARN(["Only one MIDI driver can be built (for now). Alsa MIDI disabled."]) - build_alsa_midi="no" - fi - fi - if test "$build_alsa_midi" = "yes"; then - AC_DEFINE(HAVE_ALSA_MIDI, 1, [Has Alsa MIDI]) - fi - # Check for LADSPA if test "$build_ladspa" = "yes"; then build_ladspa="no" @@ -253,6 +232,28 @@ if test "$build_server" = "yes"; then AC_DEFINE(HAVE_LADSPA, 1, [Has ladspa.h]) fi + # Check for DSSI + if test "$build_dssi" = "yes"; then + if test "$build_ladspa" = "no"; then + AC_MSG_WARN([DSSI support requires LADSPA. DSSI support will not be built.]) + build_dssi="no" + fi + if test "$build_dssi" = "yes"; then + PKG_CHECK_MODULES(ALSA, alsa >= 1.0.0, [build_dssi="yes"], [build_dssi="no"]) + if test "$build_dssi" = "no"; then + AC_MSG_WARN([DSSI support requires Alsa. DSSI support will not be built.]) + fi + fi + if test "$build_dssi" = "yes"; then + build_dssi="no" + AC_CHECK_HEADER([dssi.h], [build_dssi="yes"], + [AC_MSG_WARN([You do not seem to have dssi.h, DSSI support will not be built.])]) + if test "$build_dssi" = "yes"; then + AC_DEFINE(HAVE_DSSI, 1, [Has dssi.h]) + fi + fi + fi + # Check for LV2 (libslv2) if test "$build_lv2" = "yes"; then build_lv2="no" @@ -262,24 +263,6 @@ if test "$build_server" = "yes"; then AC_DEFINE(HAVE_SLV2, 1, [Has libslv2]) fi - # Check for DSSI - if test "$build_ladspa" = "no"; then - AC_MSG_WARN([DSSI support requires LADSPA. DSSI support will not be built.]) - build_dssi="no" - fi - if test "$build_alsa" = "no"; then - AC_MSG_WARN([DSSI support requires Alsa. DSSI support will not be built.]) - build_dssi="no" - fi - if test "$build_dssi" = "yes"; then - build_dssi="no" - AC_CHECK_HEADER([dssi.h], [build_dssi="yes"], - [AC_MSG_WARN([You do not seem to have dssi.h, Ingen will be built without DSSI support])]) - if test "$build_dssi" = "yes"; then - AC_DEFINE(HAVE_DSSI, 1, [Has dssi.h]) - fi - fi - else AC_MSG_WARN([Engine will NOT be built! (Nothing you're building produces any sound itself)]) fi @@ -287,7 +270,6 @@ AM_CONDITIONAL(BUILD_SERVER, [test "$build_server" = "yes"]) AM_CONDITIONAL(BUILD_IN_PROCESS_ENGINE, [test "$build_in_process_engine" = "yes"]) AM_CONDITIONAL(BUILD_UNIT_TESTS, [test "$build_unit_tests" = "yes"]) AM_CONDITIONAL(WITH_JACK_MIDI, [test "$build_jack_midi" = "yes"]) -AM_CONDITIONAL(WITH_ALSA_MIDI, [test "$build_alsa_midi" = "yes"]) AM_CONDITIONAL(WITH_LADSPA, [test "$build_ladspa" = "yes"]) AM_CONDITIONAL(WITH_LV2, [test "$build_lv2" = "yes"]) AM_CONDITIONAL(WITH_DSSI, [test "$build_dssi" = "yes"]) @@ -381,7 +363,6 @@ AC_MSG_RESULT([]) AC_MSG_RESULT([Building engine: $build_engine]) AC_MSG_RESULT([ JACK in-process support: $build_in_process_engine]) AC_MSG_RESULT([ Jack MIDI support: $build_jack_midi]) -AC_MSG_RESULT([ ALSA MIDI support: $build_alsa_midi]) AC_MSG_RESULT([ LV2 Plugin support: $build_lv2]) AC_MSG_RESULT([ DSSI Plugin support: $build_dssi]) AC_MSG_RESULT([ LADSPA Plugin support: $build_ladspa]) diff --git a/src/libs/engine/AlsaMidiDriver.cpp b/src/libs/engine/AlsaMidiDriver.cpp deleted file mode 100644 index a1638077..00000000 --- a/src/libs/engine/AlsaMidiDriver.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 Dave Robillard <http://drobilla.net> - * - * Ingen 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. - * - * Ingen 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "AlsaMidiDriver.h" -#include <iostream> -#include <cstdlib> -#include <pthread.h> -#include "types.h" -#include <raul/Maid.h> -#include "ThreadManager.h" -#include "AudioDriver.h" -#include "MidiBuffer.h" -#include "DuplexPort.h" -#ifdef HAVE_LASH -#include "LashDriver.h" -#endif -using std::cout; using std::cerr; using std::endl; - -namespace Ingen { - - -//// AlsaMidiPort //// - -AlsaMidiPort::AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* patch_port) -: DriverPort(patch_port->is_input()), - Raul::ListNode<AlsaMidiPort*>(this), - _driver(driver), - _patch_port(patch_port), - _port_id(0), - _midi_pool(new unsigned char*[patch_port->buffer_size()]), - _events(1024) -{ - assert(patch_port->poly() == 1); - - if (patch_port->is_input()) { - if ((_port_id = snd_seq_create_simple_port(driver->seq_handle(), patch_port->path().c_str(), - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_APPLICATION)) < 0) - { - cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; - exit(EXIT_FAILURE); - } - } else { - if ((_port_id = snd_seq_create_simple_port(driver->seq_handle(), patch_port->path().c_str(), - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, - SND_SEQ_PORT_TYPE_APPLICATION)) < 0) - { - cerr << "[AlsaMidiPort] Error creating sequencer port." << endl; - exit(EXIT_FAILURE); - } - } - - /* Allocate event pool. This pool is used when preparing a block from the queue - * of Alsa events. The buffer member of the MidiMessage's in the patch port's - * buffer will be set directly to an element in this pool, then next cycle they - * will be overwritten (eliminating the need for any allocation/freeing). */ - for (size_t i=0; i < patch_port->buffer_size(); ++i) - _midi_pool[i] = new unsigned char[MAX_MIDI_EVENT_SIZE]; - - patch_port->buffer(0)->clear(); - patch_port->fixed_buffers(true); -} - - -AlsaMidiPort::~AlsaMidiPort() -{ - snd_seq_delete_simple_port(_driver->seq_handle(), _port_id); - - // Free event pool - for (size_t i=0; i < _patch_port->buffer_size(); ++i) - delete[] _midi_pool[i]; - - delete[] _midi_pool; -} - - -void -AlsaMidiPort::set_name(const string& name) -{ - snd_seq_port_info_t* info = NULL; - snd_seq_port_info_malloc(&info); - snd_seq_get_port_info(_driver->seq_handle(), _port_id, info); - snd_seq_port_info_set_name(info, name.c_str()); - snd_seq_set_port_info(_driver->seq_handle(), _port_id, info); - snd_seq_port_info_free(info); -} - - -void -AlsaMidiPort::event(snd_seq_event_t* const ev) -{ - // Abuse the tick field to hold the timestamp - ev->time.tick = _driver->audio_driver()->frame_time(); - - // Fix noteons with velocity 0 (required for DSSI spec) - if (ev->type == SND_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0) - ev->type = SND_SEQ_EVENT_NOTEOFF; - - _events.push(*ev); -} - - -/** Generates a flat array of MIDI events for patching. - * - * Prepares all events that occurred during the time interval passed - * (which ideally are the events from the previous cycle with an exact - * 1 cycle delay) and creates a flat port buffer for this cycle. - */ -void -AlsaMidiPort::prepare_block(const SampleCount block_start, const SampleCount block_end) -{ - assert(block_end >= block_start); - - const SampleCount nframes = block_end - block_start; - snd_seq_event_t* ev = NULL; - size_t num_events = 0; - size_t event_size = 0; // decoded length of Alsa event in bytes - int timestamp = 0; - - MidiBuffer* patch_buf = dynamic_cast<MidiBuffer*>(_patch_port->buffer(0)); - assert(patch_buf); - - patch_buf->prepare_write(nframes); - - while (!_events.empty() && _events.front().time.tick < block_end) { - assert(num_events < _patch_port->buffer_size()); - ev = &_events.front(); - - timestamp = ev->time.tick - block_start; - if (timestamp < 0) { - // FIXME: remove this (obviously not realtime safe) - cerr << "[AlsaMidiPort] Missed event by " << -timestamp << " samples!" << endl; - timestamp = 0; - } - assert(timestamp < (int)(block_end - block_start)); - - // Reset decoder so we don't get running status - snd_midi_event_reset_decode(_driver->event_coder()); - - // FIXME: is this realtime safe? - if ((event_size = snd_midi_event_decode(_driver->event_coder(), - _midi_pool[num_events], MAX_MIDI_EVENT_SIZE, ev)) > 0) { - - patch_buf->put_event(timestamp, event_size, _midi_pool[num_events]); - ++num_events; - - } else { - cerr << "[AlsaMidiPort] Unable to decode MIDI event" << endl; - } - - _events.pop(); - } -} - - - -//// AlsaMidiDriver //// - - -bool AlsaMidiDriver::_midi_thread_exit_flag = true; - - -AlsaMidiDriver::AlsaMidiDriver(AudioDriver* audio_driver) -: _audio_driver(audio_driver), - _seq_handle(NULL), - _event_coder(NULL), - _is_activated(false) -{ - if (snd_seq_open(&_seq_handle, "hw", SND_SEQ_OPEN_INPUT, 0) < 0) { - cerr << "[AlsaMidiDriver] Error opening ALSA sequencer." << endl; - exit(EXIT_FAILURE); - } else { - cout << "[AlsaMidiDriver] Successfully opened ALSA sequencer." << endl; - } - - if (snd_midi_event_new(3, &_event_coder)) { - cerr << "[AlsaMidiDriver] Failed to initialize ALSA MIDI event coder!"; - exit(EXIT_FAILURE); - } else { - snd_midi_event_reset_encode(_event_coder); - snd_midi_event_reset_decode(_event_coder); - } - - snd_seq_set_client_name(_seq_handle, "Ingen"); -} - - -AlsaMidiDriver::~AlsaMidiDriver() -{ - deactivate(); - snd_midi_event_free(_event_coder); - snd_seq_close(_seq_handle); -} - - -/** Launch and start the MIDI thread. - */ -void -AlsaMidiDriver::activate() -{ - // Just exit if already running - if (_midi_thread_exit_flag == false) - return; - - bool success = false; - _midi_thread_exit_flag = false; - - //if (Engine::instance().audio_driver()->is_realtime()) { - pthread_attr_t attr; - pthread_attr_init(&attr); - - if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { - cerr << "[AlsaMidiDriver] Unable to set realtime scheduling for MIDI thread." << endl; - } - - sched_param param; - param.sched_priority = 10; - - pthread_attr_setstacksize(&attr, 1500000); - - if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) - || pthread_attr_setschedparam(&attr, ¶m)) - cout << "[AlsaMidiDriver] Unable to set SCHED_FIFO priority " - << param.sched_priority << endl; - - if (!pthread_create(&_process_thread, &attr, process_midi_in, this)) { - cout << "[AlsaMidiDriver] Started realtime MIDI thread (SCHED_FIFO, priority " - << param.sched_priority << ")" << endl; - success = true; - } else { - cerr << "[AlsaMidiDriver] Unable to start realtime MIDI thread." << endl; - } - pthread_attr_destroy(&attr); - //} - - if (!success) { - // FIXME: check for success - pthread_create(&_process_thread, NULL, process_midi_in, this); - cout << "[AlsaMidiDriver] Started non-realtime MIDI thread." << endl; - } - -#ifdef HAVE_LASH - cerr << "FIXME: LASH + ALSA" << endl; - //Engine::instance().lash_driver()->set_alsa_client_id(snd_seq_client_id(_seq_handle)); -#endif - - _is_activated = true; -} - - -/** Terminate the MIDI thread. - */ -void -AlsaMidiDriver::deactivate() -{ - if (_is_activated) { - _midi_thread_exit_flag = true; - pthread_cancel(_process_thread); - pthread_join(_process_thread, NULL); - _is_activated = false; - } -} - - -/** Build flat arrays of events to be used as input for the given cycle. - */ -void -AlsaMidiDriver::prepare_block(const SampleCount block_start, const SampleCount block_end) -{ - for (Raul::List<AlsaMidiPort*>::iterator i = _in_ports.begin(); i != _in_ports.end(); ++i) - (*i)->prepare_block(block_start, block_end); -} - - -/** Add an Alsa MIDI port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ -void -AlsaMidiDriver::add_port(DriverPort* port) -{ - assert(ThreadManager::current_thread_id() == THREAD_PROCESS); - assert(dynamic_cast<AlsaMidiPort*>(port)); - - if (port->is_input()) - _in_ports.push_back((AlsaMidiPort*)port); - else - _out_ports.push_back((AlsaMidiPort*)port); -} - - -/** Remove an Alsa MIDI port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -DriverPort* -AlsaMidiDriver::remove_port(const Path& path) -{ - assert(ThreadManager::current_thread_id() == THREAD_PROCESS); - - // FIXME: duplex? - - for (Raul::List<AlsaMidiPort*>::iterator i = _in_ports.begin(); i != _in_ports.end(); ++i) - if ((*i)->patch_port()->path() == path) - return _in_ports.erase(i)->elem(); // FIXME: leak - - for (Raul::List<AlsaMidiPort*>::iterator i = _out_ports.begin(); i != _out_ports.end(); ++i) - if ((*i)->patch_port()->path() == path) - return _out_ports.erase(i)->elem(); // FIXME: leak - - cerr << "[AlsaMidiDriver::remove_port] WARNING: Failed to find Jack port to remove!" << endl; - return NULL; -} - - -/** MIDI thread. - */ -void* -AlsaMidiDriver::process_midi_in(void* alsa_driver) -{ - AlsaMidiDriver* ad = (AlsaMidiDriver*)alsa_driver; - - snd_seq_event_t* ev; - - int npfd = snd_seq_poll_descriptors_count(ad->_seq_handle, POLLIN); - struct pollfd pfd; - snd_seq_poll_descriptors(ad->_seq_handle, &pfd, npfd, POLLIN); - - while ( ! _midi_thread_exit_flag) - if (poll(&pfd, npfd, 100000) > 0) - while (snd_seq_event_input(ad->_seq_handle, &ev) > 0) - for (Raul::List<AlsaMidiPort*>::iterator i = ad->_in_ports.begin(); i != ad->_in_ports.end(); ++i) - if ((*i)->port_id() == ev->dest.port) - (*i)->event(ev); - - cout << "[AlsaMidiDriver] Exiting MIDI thread." << endl; - - return NULL; -} - - -} // namespace Ingen - diff --git a/src/libs/engine/AlsaMidiDriver.h b/src/libs/engine/AlsaMidiDriver.h deleted file mode 100644 index 88daf94a..00000000 --- a/src/libs/engine/AlsaMidiDriver.h +++ /dev/null @@ -1,119 +0,0 @@ -/* This file is part of Ingen. - * Copyright (C) 2007 Dave Robillard <http://drobilla.net> - * - * Ingen 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. - * - * Ingen 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 details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef ALSAMIDIDRIVER_H -#define ALSAMIDIDRIVER_H - -#include <boost/utility.hpp> -#include <alsa/asoundlib.h> -#include <raul/List.h> -#include <raul/SRSWQueue.h> -#include "MidiDriver.h" - - -namespace Ingen { - -class Node; -class SetPortValueEvent; -class AlsaMidiDriver; -class AudioDriver; -class DuplexPort; - -static const int MAX_MIDI_EVENT_SIZE = 3; - - -/** Representation of an ALSA MIDI port. - * - * \ingroup engine - */ -class AlsaMidiPort : public DriverPort, public Raul::ListNode<AlsaMidiPort*> -{ -public: - AlsaMidiPort(AlsaMidiDriver* driver, DuplexPort* port); - virtual ~AlsaMidiPort(); - - void event(snd_seq_event_t* const ev); - - void prepare_block(const SampleCount block_start, const SampleCount block_end); - - void set_name(const std::string& name); - - int port_id() const { return _port_id; } - DuplexPort* patch_port() const { return _patch_port; } - -private: - AlsaMidiDriver* _driver; - DuplexPort* _patch_port; - int _port_id; - unsigned char** _midi_pool; ///< Pool of raw MIDI events for MidiMessage::buffer - Raul::SRSWQueue<snd_seq_event_t> _events; -}; - - -/** Alsa MIDI driver. - * - * This driver reads Alsa MIDI events and dispatches them to the appropriate - * AlsaMidiPort for processing. - * - * \ingroup engine - */ -class AlsaMidiDriver : public MidiDriver -{ -public: - AlsaMidiDriver(AudioDriver* audio_driver); - ~AlsaMidiDriver(); - - void activate(); - void deactivate(); - - bool is_activated() const { return _is_activated; } - - void prepare_block(const SampleCount block_start, const SampleCount block_end); - - AudioDriver* audio_driver() { return _audio_driver; } - - DriverPort* create_port(DuplexPort* patch_port) - { return new AlsaMidiPort(this, patch_port); } - - void add_port(DriverPort* port); - DriverPort* remove_port(const Raul::Path& path); - - snd_seq_t* seq_handle() const { return _seq_handle; } - snd_midi_event_t* event_coder() const { return _event_coder; } - -private: - Raul::List<AlsaMidiPort*> _in_ports; - Raul::List<AlsaMidiPort*> _out_ports; - - friend class AlsaMidiPort; - - // MIDI thread - static void* process_midi_in(void* me); - - AudioDriver* _audio_driver; - snd_seq_t* _seq_handle; - snd_midi_event_t* _event_coder; - pthread_t _process_thread; - bool _is_activated; - static bool _midi_thread_exit_flag; -}; - - -} // namespace Ingen - - -#endif // ALSAMIDIDRIVER_H diff --git a/src/libs/engine/Engine.cpp b/src/libs/engine/Engine.cpp index ca813ed0..f76790ff 100644 --- a/src/libs/engine/Engine.cpp +++ b/src/libs/engine/Engine.cpp @@ -39,9 +39,6 @@ #ifdef HAVE_JACK_MIDI #include "JackMidiDriver.h" #endif -#ifdef HAVE_ALSA_MIDI -#include "AlsaMidiDriver.h" -#endif #ifdef HAVE_LASH #include "LashDriver.h" #endif @@ -196,8 +193,6 @@ Engine::activate() #ifdef HAVE_JACK_MIDI _midi_driver = new JackMidiDriver(((JackAudioDriver*)_audio_driver.get())->jack_client()); -#elif HAVE_ALSA_MIDI - _midi_driver = new AlsaMidiDriver(_audio_driver.get()); #else _midi_driver = new DummyMidiDriver(); #endif @@ -217,9 +212,6 @@ Engine::activate() _audio_driver->set_root_patch(root_patch); _audio_driver->activate(); -#ifdef HAVE_ALSA_MIDI - _midi_driver->activate(); -#endif _post_processor->start(); diff --git a/src/libs/engine/Makefile.am b/src/libs/engine/Makefile.am index d11609b9..32fa531b 100644 --- a/src/libs/engine/Makefile.am +++ b/src/libs/engine/Makefile.am @@ -169,12 +169,6 @@ libingen_engine_la_SOURCES += \ jack_compat.h endif -if WITH_ALSA_MIDI -libingen_engine_la_SOURCES += \ - AlsaMidiDriver.h \ - AlsaMidiDriver.cpp -endif - if WITH_LADSPA libingen_engine_la_SOURCES += \ LADSPANode.h \ |