From 1ab61b8564f9934c533d1c1a229888bc7e2fd557 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 7 Aug 2013 22:22:11 -0400 Subject: [PATCH] major redesign of MIDI port heirarchy and management (part 2) --- gtk2_ardour/ardour_ui.cc | 42 ++-- gtk2_ardour/editor.cc | 3 +- gtk2_ardour/editor_drag.cc | 5 +- gtk2_ardour/gain_meter.cc | 1 - gtk2_ardour/generic_pluginui.cc | 2 - gtk2_ardour/level_meter.cc | 1 - gtk2_ardour/midi_tracer.cc | 45 ++++- gtk2_ardour/panner_ui.cc | 1 - gtk2_ardour/plugin_ui.cc | 2 - gtk2_ardour/port_group.cc | 28 +-- gtk2_ardour/rc_option_editor.cc | 2 - libs/ardour/ardour/audio_port.h | 4 +- libs/ardour/ardour/audioengine.h | 11 +- libs/ardour/ardour/debug.h | 1 + libs/ardour/ardour/jack_audiobackend.h | 2 + libs/ardour/ardour/midi_ui.h | 6 +- libs/ardour/ardour/midiport_manager.h | 10 +- libs/ardour/ardour/port_manager.h | 35 +++- libs/ardour/ardour/session.h | 2 +- libs/ardour/ardour/slave.h | 30 ++- libs/ardour/ardour/ticker.h | 49 +++-- libs/ardour/audioengine.cc | 138 +++++--------- libs/ardour/debug.cc | 1 + libs/ardour/globals.cc | 5 +- libs/ardour/jack_audiobackend.cc | 6 +- libs/ardour/jack_connection.cc | 5 +- libs/ardour/ladspa_plugin.cc | 2 - libs/ardour/midi_clock_slave.cc | 44 +++-- libs/ardour/midi_ui.cc | 40 ++-- libs/ardour/midiport_manager.cc | 40 +++- libs/ardour/mtc_slave.cc | 51 +++-- libs/ardour/port.cc | 1 + libs/ardour/port_manager.cc | 128 +++++++++++-- libs/ardour/rc_configuration.cc | 16 +- libs/ardour/session.cc | 20 +- libs/ardour/session_export.cc | 7 +- libs/ardour/session_midi.cc | 20 +- libs/ardour/session_process.cc | 6 +- libs/ardour/session_state.cc | 51 +++-- libs/ardour/session_transport.cc | 19 +- libs/ardour/ticker.cc | 180 +++++++++--------- libs/ardour/wscript | 2 + libs/midi++2/midi++/mmc.h | 5 +- libs/midi++2/midi++/parser.h | 4 +- libs/midi++2/midi++/port.h | 7 - libs/midi++2/mmc.cc | 15 +- libs/midi++2/parser.cc | 3 +- libs/midi++2/port.cc | 2 +- libs/midi++2/wscript | 2 - .../generic_midi_control_protocol.cc | 19 +- .../generic_midi_control_protocol.h | 18 +- libs/surfaces/generic_midi/midiaction.cc | 2 +- libs/surfaces/generic_midi/midiaction.h | 4 +- .../surfaces/generic_midi/midicontrollable.cc | 38 ++-- libs/surfaces/generic_midi/midicontrollable.h | 15 +- libs/surfaces/generic_midi/midifunction.cc | 2 +- libs/surfaces/generic_midi/midifunction.h | 3 +- libs/surfaces/generic_midi/midiinvokable.cc | 22 +-- libs/surfaces/generic_midi/midiinvokable.h | 7 +- libs/surfaces/mackie/surface.cc | 1 - libs/surfaces/mackie/surface_port.cc | 47 ++--- libs/surfaces/mackie/surface_port.h | 23 ++- 62 files changed, 741 insertions(+), 562 deletions(-) diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index a3ea2b1612..69e2a339dd 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -58,8 +58,6 @@ #include "gtkmm2ext/popup.h" #include "gtkmm2ext/window_title.h" -#include "midi++/manager.h" - #include "ardour/ardour.h" #include "ardour/audio_backend.h" #include "ardour/audioengine.h" @@ -1050,14 +1048,20 @@ ARDOUR_UI::update_sample_rate (framecnt_t) framecnt_t rate = engine->sample_rate(); - if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("JACK: %.1f kHz / %4.1f ms"), - (float) rate / 1000.0f, - (engine->usecs_per_cycle() / 1000.0f)); + if (rate == 0) { + /* no sample rate available */ + snprintf (buf, sizeof (buf), _("Audio: disconnected")); } else { - snprintf (buf, sizeof (buf), _("JACK: %" PRId64 " kHz / %4.1f ms"), - rate/1000, - (engine->usecs_per_cycle() * 1000.0f)); + + if (fmod (rate, 1000.0) != 0.0) { + snprintf (buf, sizeof (buf), _("Audio: %.1f kHz / %4.1f ms"), + (float) rate / 1000.0f, + (engine->usecs_per_cycle() / 1000.0f)); + } else { + snprintf (buf, sizeof (buf), _("Audio: %" PRId64 " kHz / %4.1f ms"), + rate/1000, + (engine->usecs_per_cycle() * 1000.0f)); + } } } @@ -1181,6 +1185,11 @@ ARDOUR_UI::update_disk_space() char buf[64]; framecnt_t fr = _session->frame_rate(); + if (fr == 0) { + /* skip update - no SR available */ + return; + } + if (!opt_frames) { /* Available space is unknown */ snprintf (buf, sizeof (buf), "%s", _("Disk: Unknown")); @@ -1662,10 +1671,17 @@ ARDOUR_UI::transport_goto_wallclock () time (&now); localtime_r (&now, &tmnow); + + int frame_rate = _session->frame_rate(); + + if (frame_rate == 0) { + /* no frame rate available */ + return; + } - frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate()); - frames += tmnow.tm_min * (60 * _session->frame_rate()); - frames += tmnow.tm_sec * _session->frame_rate(); + frames = tmnow.tm_hour * (60 * 60 * frame_rate); + frames += tmnow.tm_min * (60 * frame_rate); + frames += tmnow.tm_sec * frame_rate; _session->request_locate (frames, _session->transport_rolling ()); @@ -3802,7 +3818,7 @@ void ARDOUR_UI::disconnect_from_jack () { if (engine) { - if (engine->pause ()) { + if (engine->stop ()) { MessageDialog msg (*editor, _("Could not disconnect from JACK")); msg.run (); } diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 300e317a38..a0418892e7 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1258,7 +1258,8 @@ Editor::set_session (Session *t) /* These signals can all be emitted by a non-GUI thread. Therefore the handlers for them must not attempt to directly interact with the GUI, - but use Gtkmm2ext::UI::instance()->call_slot(); + but use PBD::Signal::connect() which accepts an event loop + ("context") where the handler will be asked to run. */ _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context()); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index b083e851c5..3389164f50 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -2372,8 +2372,9 @@ CursorDrag::fake_locate (framepos_t t) if (s->timecode_transmission_suspended ()) { framepos_t const f = _editor->playhead_cursor->current_frame; s->send_mmc_locate (f); - s->send_full_time_code (f); - s->send_song_position_pointer (f); + // XXX need to queue full time code and SPP messages somehow + // s->send_full_time_code (f); + // s->send_song_position_pointer (f); } show_verbose_cursor_time (t); diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index 10512b24d0..b2beb5b9a3 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -32,7 +32,6 @@ #include #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "pbd/stacktrace.h" diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 971dfc0e9b..4405d05c1c 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -37,8 +37,6 @@ #include #include -#include "midi++/manager.h" - #include "ardour/plugin.h" #include "ardour/plugin_insert.h" #include "ardour/session.h" diff --git a/gtk2_ardour/level_meter.cc b/gtk2_ardour/level_meter.cc index 6f48864992..bf9823518b 100644 --- a/gtk2_ardour/level_meter.cc +++ b/gtk2_ardour/level_meter.cc @@ -23,7 +23,6 @@ #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "ardour_ui.h" diff --git a/gtk2_ardour/midi_tracer.cc b/gtk2_ardour/midi_tracer.cc index 073fd9cc15..fee339d126 100644 --- a/gtk2_ardour/midi_tracer.cc +++ b/gtk2_ardour/midi_tracer.cc @@ -24,7 +24,10 @@ #include #include "midi++/parser.h" -#include "midi++/manager.h" + +#include "ardour/async_midi_port.h" +#include "ardour/midi_port.h" +#include "ardour/audioengine.h" #include "midi_tracer.h" #include "gui_thread.h" @@ -53,7 +56,8 @@ MidiTracer::MidiTracer () , collect_button (_("Enabled")) , delta_time_button (_("Delta times")) { - Manager::instance()->PortsChanged.connect (_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context()); + ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect + (_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context()); _last_receipt.tv_sec = 0; _last_receipt.tv_usec = 0; @@ -126,25 +130,50 @@ MidiTracer::ports_changed () { string const c = _port_combo.get_active_text (); _port_combo.clear (); + + ARDOUR::PortManager::PortList pl; + ARDOUR::AudioEngine::instance()->get_ports (ARDOUR::DataType::MIDI, pl); - boost::shared_ptr p = Manager::instance()->get_midi_ports (); - for (Manager::PortList::const_iterator i = p->begin(); i != p->end(); ++i) { + if (pl.empty()) { + _port_combo.set_active_text (""); + return; + } + + for (ARDOUR::PortManager::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { _port_combo.append_text ((*i)->name()); } - _port_combo.set_active_text (c); + if (c.empty()) { + _port_combo.set_active_text (pl.front()->name()); + } else { + _port_combo.set_active_text (c); + } } void MidiTracer::port_changed () { + using namespace ARDOUR; + disconnect (); - Port* p = Manager::instance()->port (_port_combo.get_active_text()); + boost::shared_ptr p = AudioEngine::instance()->get_port_by_name (_port_combo.get_active_text()); - if (p) { - p->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3)); + if (!p) { + std::cerr << "port not found\n"; + return; } + + boost::shared_ptr async = boost::dynamic_pointer_cast (p); + + if (!async) { + /* pure ARDOUR::MidiPort ... cannot currently attach to it because it + * has no Parser. + */ + return; + } + + async->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3)); } void diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 181664bb4e..c82a44f399 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -21,7 +21,6 @@ #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "ardour/pannable.h" diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index d9741f5e39..713b98cdaf 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -40,8 +40,6 @@ #include #include -#include "midi++/manager.h" - #include "ardour/session.h" #include "ardour/plugin.h" #include "ardour/plugin_insert.h" diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 5b4f151da8..f8c8e2bde2 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -21,7 +21,6 @@ #include #include -#include "midi++/manager.h" #include "midi++/mmc.h" #include "ardour/audioengine.h" @@ -29,9 +28,13 @@ #include "ardour/bundle.h" #include "ardour/control_protocol_manager.h" #include "ardour/io_processor.h" +#include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/session.h" #include "ardour/user_bundle.h" #include "ardour/port.h" +#include "ardour/syncport_manager.h" + #include "control_protocol/control_protocol.h" #include "gui_thread.h" @@ -452,37 +455,36 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp /* Ardour's sync ports */ - MIDI::Manager* midi_manager = MIDI::Manager::instance (); - if (midi_manager && (type == DataType::MIDI || type == DataType::NIL)) { + if ((type == DataType::MIDI || type == DataType::NIL)) { boost::shared_ptr sync (new Bundle (_("Sync"), inputs)); - MIDI::MachineControl* mmc = midi_manager->mmc (); - AudioEngine& ae = session->engine (); + AudioEngine* ae = AudioEngine::instance(); + MIDI::MachineControl& mmc (ae->mmc()); if (inputs) { sync->add_channel ( - _("MTC in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_input_port()->name()) + _("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_input_port()->name()) ); sync->add_channel ( - _("MIDI control in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_input_port()->name()) + _("MIDI control in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_input_port()->name()) ); sync->add_channel ( - _("MIDI clock in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_input_port()->name()) + _("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_input_port()->name()) ); sync->add_channel ( - _("MMC in"), DataType::MIDI, ae.make_port_name_non_relative (mmc->input_port()->name()) + _("MMC in"), DataType::MIDI, ae->make_port_name_non_relative (mmc.input_port()->name()) ); } else { sync->add_channel ( - _("MTC out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_output_port()->name()) + _("MTC out"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_output_port()->name()) ); sync->add_channel ( - _("MIDI control out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_output_port()->name()) + _("MIDI control out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_output_port()->name()) ); sync->add_channel ( - _("MIDI clock out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_output_port()->name()) + _("MIDI clock out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_output_port()->name()) ); sync->add_channel ( - _("MMC out"), DataType::MIDI, ae.make_port_name_non_relative (mmc->output_port()->name()) + _("MMC out"), DataType::MIDI, ae->make_port_name_non_relative (mmc.output_port()->name()) ); } diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 54b96bbb8d..ed9ffda4ef 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -31,8 +31,6 @@ #include "pbd/fpu.h" #include "pbd/cpus.h" -#include "midi++/manager.h" - #include "ardour/audioengine.h" #include "ardour/dB.h" #include "ardour/rc_configuration.h" diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index f5affb0580..f87b134e9e 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -49,9 +49,7 @@ class AudioPort : public Port friend class PortManager; AudioPort (std::string const &, PortFlags); - protected: - friend class AudioEngine; - /* special access for engine only (hah, C++) */ + /* special access for PortManager only (hah, C++) */ Sample* engine_get_whole_audio_buffer (); private: diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 6fb13b7ae0..509d330f12 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -36,13 +36,9 @@ #include "pbd/signals.h" #include "pbd/stacktrace.h" -#include -#include -#include -#include +#include "midi++/mmc.h" #include "ardour/ardour.h" - #include "ardour/data_type.h" #include "ardour/session_handle.h" #include "ardour/types.h" @@ -192,6 +188,8 @@ public: /* sets up the process callback thread */ static void thread_init_callback (void *); + MIDI::MachineControl& mmc() { return _mmc; } + private: AudioEngine (); @@ -206,16 +204,17 @@ public: gain_t session_removal_gain; gain_t session_removal_gain_step; bool _running; + bool _freewheeling; /// number of frames between each check for changes in monitor input framecnt_t monitor_check_interval; /// time of the last monitor check in frames framecnt_t last_monitor_check; /// the number of frames processed since start() was called framecnt_t _processed_frames; - bool _freewheeling; bool _pre_freewheel_mmc_enabled; Glib::Threads::Thread* m_meter_thread; ProcessThread* _main_thread; + MIDI::MachineControl _mmc; void meter_thread (); void start_metering_thread (); diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index 202d0cc424..5811f7a484 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -63,6 +63,7 @@ namespace PBD { extern uint64_t OrderKeys; extern uint64_t Automation; extern uint64_t WiimoteControl; + extern uint64_t Ports; } } diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 9fa3d0c1cc..ada7ce8e33 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -178,6 +178,8 @@ class JACKAudioBackend : public AudioBackend { typedef std::map DriverDeviceMap; mutable DriverDeviceMap all_devices; + + PBD::ScopedConnection disconnect_connection; }; } // namespace diff --git a/libs/ardour/ardour/midi_ui.h b/libs/ardour/ardour/midi_ui.h index 34e97494be..c15a530057 100644 --- a/libs/ardour/ardour/midi_ui.h +++ b/libs/ardour/ardour/midi_ui.h @@ -26,13 +26,11 @@ #include "pbd/signals.h" #include "pbd/stacktrace.h" -namespace MIDI { - class Port; -} namespace ARDOUR { class Session; +class AsyncMIDIPort; /* this is mostly a placeholder because I suspect that at some point we will want to add more members to accomodate @@ -67,7 +65,7 @@ class MidiControlUI : public AbstractUI ARDOUR::Session& _session; PBD::ScopedConnection rebind_connection; - bool midi_input_handler (Glib::IOCondition, MIDI::Port*); + bool midi_input_handler (Glib::IOCondition, AsyncMIDIPort*); void reset_ports (); void clear_ports (); diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h index 9c45e60341..df33038f2b 100644 --- a/libs/ardour/ardour/midiport_manager.h +++ b/libs/ardour/ardour/midiport_manager.h @@ -56,8 +56,10 @@ class MidiPortManager { * callback. */ - MIDI::Port* midi_input_port () { return _midi_input_port; } - MIDI::Port* midi_output_port () { return _midi_output_port; } + MIDI::Port* midi_input_port () const { return _midi_input_port; } + MIDI::Port* midi_output_port () const { return _midi_output_port; } + MIDI::Port* mmc_input_port () const { return _mmc_input_port; } + MIDI::Port* mmc_output_port () const { return _mmc_output_port; } /* Ports used for synchronization. These have their I/O handled inside the * process callback. @@ -76,8 +78,12 @@ class MidiPortManager { /* asynchronously handled ports: MIDI::Port */ MIDI::Port* _midi_input_port; MIDI::Port* _midi_output_port; + MIDI::Port* _mmc_input_port; + MIDI::Port* _mmc_output_port; boost::shared_ptr _midi_in; boost::shared_ptr _midi_out; + boost::shared_ptr _mmc_in; + boost::shared_ptr _mmc_out; /* synchronously handled ports: ARDOUR::MidiPort */ boost::shared_ptr _mtc_input_port; diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index 06e4939101..895294810e 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -32,15 +32,17 @@ #include "pbd/rcu.h" #include "ardour/chan_count.h" +#include "ardour/midiport_manager.h" #include "ardour/port.h" #include "ardour/port_engine.h" namespace ARDOUR { -class PortManager +class PortManager : public MidiPortManager { public: typedef std::map > Ports; + typedef std::list > PortList; PortManager (); virtual ~PortManager() {} @@ -53,8 +55,8 @@ class PortManager /* Port registration */ - boost::shared_ptr register_input_port (DataType, const std::string& portname); - boost::shared_ptr register_output_port (DataType, const std::string& portname); + boost::shared_ptr register_input_port (DataType, const std::string& portname, bool async = false); + boost::shared_ptr register_output_port (DataType, const std::string& portname, bool async = false); int unregister_port (boost::shared_ptr); /* Port connectivity */ @@ -87,7 +89,8 @@ class PortManager ChanCount n_physical_inputs () const; int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&); - + int get_ports (DataType, PortList&); + void remove_all_ports (); /* per-Port monitoring */ @@ -135,9 +138,31 @@ class PortManager SerializedRCUManager ports; bool _port_remove_in_progress; - boost::shared_ptr register_port (DataType type, const std::string& portname, bool input); + boost::shared_ptr register_port (DataType type, const std::string& portname, bool input, bool async = false); void port_registration_failure (const std::string& portname); + + /** List of ports to be used between ::cycle_start() and ::cycle_end() + */ + boost::shared_ptr _cycle_ports; + + void fade_out (gain_t, gain_t, pframes_t); + void silence (pframes_t nframes); + void check_monitoring (); + /** Signal the start of an audio cycle. + * This MUST be called before any reading/writing for this cycle. + * Realtime safe. + */ + void cycle_start (pframes_t nframes); + + /** Signal the end of an audio cycle. + * This signifies that the cycle began with @ref cycle_start has ended. + * This MUST be called at the end of each cycle. + * Realtime safe. + */ + void cycle_end (pframes_t nframes); }; + + } // namespace diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index a12f816c1e..a47c13046d 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -813,7 +813,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi boost::shared_ptr playlists; void send_mmc_locate (framepos_t); - int send_full_time_code (framepos_t); + int send_full_time_code (framepos_t, pframes_t nframes); void send_song_position_pointer (framepos_t); bool step_editing() const { return (_step_editors > 0); } diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 4408da2d25..adf425ea43 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -40,15 +40,12 @@ #define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") ) #define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" ) -namespace MIDI { - class Port; -} - namespace ARDOUR { class TempoMap; class Session; class AudioEngine; +class MidiPort; /** * @class Slave @@ -67,6 +64,15 @@ class Slave { Slave() { } virtual ~Slave() {} + /** The slave should read any incoming information in this method + * and use it adjust its current idea of reality. If no such + * processing is required, it does need to be implemented. + * + * @param nframes specifies the number of frames-worth of data that + * can be read from any ports used by the slave. + */ + virtual int process (pframes_t) { return 0; } + /** * This is the most important function to implement: * Each process cycle, Session::follow_slave will call this method. @@ -253,10 +259,11 @@ class TimecodeSlave : public Slave { class MTC_Slave : public TimecodeSlave { public: - MTC_Slave (Session&, MIDI::Port&); + MTC_Slave (Session&, MidiPort&); ~MTC_Slave (); - void rebind (MIDI::Port&); + void rebind (MidiPort&); + int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -274,7 +281,8 @@ class MTC_Slave : public TimecodeSlave { private: Session& session; - MIDI::Port* port; + MidiPort* port; + MIDI::Parser parser; PBD::ScopedConnectionList port_connections; PBD::ScopedConnection config_connection; bool can_notify_on_unknown_rate; @@ -405,13 +413,14 @@ public: class MIDIClock_Slave : public Slave { public: - MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24); + MIDIClock_Slave (Session&, MidiPort&, int ppqn = 24); /// Constructor for unit tests MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24); ~MIDIClock_Slave (); - void rebind (MIDI::Port&); + void rebind (MidiPort&); + int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -427,7 +436,8 @@ class MIDIClock_Slave : public Slave { protected: ISlaveSessionProxy* session; - MIDI::Port* port; + MidiPort* port; + MIDI::Parser parser; PBD::ScopedConnectionList port_connections; /// pulses per quarter note for one MIDI clock frame (default 24) diff --git a/libs/ardour/ardour/ticker.h b/libs/ardour/ardour/ticker.h index b6e5376c12..7f0d1987fc 100644 --- a/libs/ardour/ardour/ticker.h +++ b/libs/ardour/ardour/ticker.h @@ -27,17 +27,13 @@ #include "ardour/session_handle.h" -#ifndef TICKER_H_ -#define TICKER_H_ +#ifndef __libardour_ticker_h__ +#define __libardour_ticker_h__ -namespace MIDI { - class Port; -} - -namespace ARDOUR -{ +namespace ARDOUR { class Session; +class MidiPort; class MidiClockTicker : public SessionHandlePtr, boost::noncopyable { @@ -45,7 +41,7 @@ public: MidiClockTicker (); virtual ~MidiClockTicker(); - void tick (const framepos_t& transport_frames); + void tick (const framepos_t& transport_frames, pframes_t nframes); bool has_midi_port() const { return _midi_port != 0; } @@ -58,9 +54,6 @@ public: /// slot for the signal session::TransportStateChange void transport_state_changed(); - /// slot for the signal session::PositionChanged - void position_changed (framepos_t position); - /// slot for the signal session::TransportLooped void transport_looped(); @@ -70,23 +63,25 @@ public: /// pulses per quarter note (default 24) void set_ppqn(int ppqn) { _ppqn = ppqn; } -private: - MIDI::Port* _midi_port; - int _ppqn; - double _last_tick; + private: + boost::shared_ptr _midi_port; + int _ppqn; + double _last_tick; + bool _send_pos; + bool _send_state; - class Position; - boost::scoped_ptr _pos; + class Position; + boost::scoped_ptr _pos; + + double one_ppqn_in_frames (framepos_t transport_position); - double one_ppqn_in_frames (framepos_t transport_position); - - void send_midi_clock_event (pframes_t offset); - void send_start_event (pframes_t offset); - void send_continue_event (pframes_t offset); - void send_stop_event (pframes_t offset); - void send_position_event (uint32_t midi_clocks, pframes_t offset); + void send_midi_clock_event (pframes_t offset, pframes_t nframes); + void send_start_event (pframes_t offset, pframes_t nframes); + void send_continue_event (pframes_t offset, pframes_t nframes); + void send_stop_event (pframes_t offset, pframes_t nframes); + void send_position_event (uint32_t midi_clocks, pframes_t offset, pframes_t nframes); }; - } + // namespace -#endif /* TICKER_H_ */ +#endif /* __libardour_ticker_h__ */ diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 0c88e7c0fd..9c04529384 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -37,10 +37,9 @@ #include #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" -#include "midi++/manager.h" +#include "ardour/async_midi_port.h" #include "ardour/audio_port.h" #include "ardour/audio_backend.h" #include "ardour/audioengine.h" @@ -50,6 +49,7 @@ #include "ardour/internal_send.h" #include "ardour/meter.h" #include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/port.h" #include "ardour/process_thread.h" #include "ardour/session.h" @@ -66,10 +66,11 @@ AudioEngine* AudioEngine::_instance = 0; AudioEngine::AudioEngine () : session_remove_pending (false) , session_removal_countdown (-1) + , _running (false) + , _freewheeling (false) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) , _processed_frames (0) - , _freewheeling (false) , _pre_freewheel_mmc_enabled (false) , m_meter_thread (0) , _main_thread (0) @@ -117,7 +118,7 @@ _thread_init_callback (void * /*arg*/) SessionEvent::create_per_thread_pool (X_("Audioengine"), 512); - MIDI::JackMIDIPort::set_process_thread (pthread_self()); + AsyncMIDIPort::set_process_thread (pthread_self()); } void @@ -231,8 +232,8 @@ AudioEngine::process_callback (pframes_t nframes) if (_session == 0) { if (!_freewheeling) { - MIDI::Manager::instance()->cycle_start(nframes); - MIDI::Manager::instance()->cycle_end(); + PortManager::cycle_start (nframes); + PortManager::cycle_end (nframes); } _processed_frames = next_processed_frames; @@ -243,34 +244,22 @@ AudioEngine::process_callback (pframes_t nframes) /* tell all relevant objects that we're starting a new cycle */ InternalSend::CycleStart (nframes); - Port::set_global_port_buffer_offset (0); - Port::set_cycle_framecnt (nframes); /* tell all Ports that we're starting a new cycle */ - boost::shared_ptr p = ports.reader(); - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - i->second->cycle_start (nframes); - } + PortManager::cycle_start (nframes); /* test if we are freewheeling and there are freewheel signals connected. ardour should act normally even when freewheeling unless /it/ is - exporting + exporting (which is what Freewheel.empty() tests for). */ if (_freewheeling && !Freewheel.empty()) { - Freewheel (nframes); - } else { - MIDI::Manager::instance()->cycle_start(nframes); - if (_session) { _session->process (nframes); } - - MIDI::Manager::instance()->cycle_end(); } if (_freewheeling) { @@ -283,52 +272,18 @@ AudioEngine::process_callback (pframes_t nframes) } if (last_monitor_check + monitor_check_interval < next_processed_frames) { - - boost::shared_ptr p = ports.reader(); - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - bool x; - - if (i->second->last_monitor() != (x = i->second->monitoring_input ())) { - i->second->set_last_monitor (x); - /* XXX I think this is dangerous, due to - a likely mutex in the signal handlers ... - */ - i->second->MonitorInputChanged (x); /* EMIT SIGNAL */ - } - } + + PortManager::check_monitoring (); last_monitor_check = next_processed_frames; } if (_session->silent()) { - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - if (i->second->sends_output()) { - i->second->get_buffer(nframes).silence(nframes); - } - } + PortManager::silence (nframes); } if (session_remove_pending && session_removal_countdown) { - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - if (i->second->sends_output()) { - - boost::shared_ptr ap = boost::dynamic_pointer_cast (i->second); - if (ap) { - Sample* s = ap->engine_get_whole_audio_buffer (); - gain_t g = session_removal_gain; - - for (pframes_t n = 0; n < nframes; ++n) { - *s++ *= g; - g -= session_removal_gain_step; - } - } - } - } + PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes); if (session_removal_countdown > nframes) { session_removal_countdown -= nframes; @@ -339,11 +294,7 @@ AudioEngine::process_callback (pframes_t nframes) session_removal_gain -= (nframes * session_removal_gain_step); } - // Finalize ports - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - i->second->cycle_end (nframes); - } + PortManager::cycle_end (nframes); _processed_frames = next_processed_frames; @@ -574,7 +525,7 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons } drop_backend (); - + try { cerr << "Instantiate " << b->second->name << " with " << arg1 << " + " << arg2 << endl; @@ -603,31 +554,45 @@ AudioEngine::start () return -1; } - if (!_running) { + if (_running) { + return 0; + } - if (_session) { - BootMessage (_("Connect session to engine")); - _session->set_frame_rate (_backend->sample_rate()); - } + /* if we're still connected (i.e. previously paused), no need to + * re-register ports. + */ + + bool have_ports = (!ports.reader()->empty()); - _processed_frames = 0; + _processed_frames = 0; + last_monitor_check = 0; + + if (_backend->start() == 0) { + + _running = true; last_monitor_check = 0; + + if (_session) { + _session->set_frame_rate (_backend->sample_rate()); - if (_backend->start() == 0) { - _running = true; - last_monitor_check = 0; - - if (_session && _session->config.get_jack_time_master()) { + if (_session->config.get_jack_time_master()) { _backend->set_time_master (true); } - - Running(); /* EMIT SIGNAL */ - } else { - /* should report error? */ } - } - return _running ? 0 : -1; + if (!have_ports) { + PortManager::create_ports (); + } + + _mmc.set_ports (mmc_input_port(), mmc_output_port()); + + Running(); /* EMIT SIGNAL */ + + return 0; + } + + /* should report error ... */ + return -1; } int @@ -641,6 +606,7 @@ AudioEngine::stop () if (_backend->stop () == 0) { _running = false; + _processed_frames = 0; stop_metering_thread (); Stopped (); /* EMIT SIGNAL */ @@ -932,7 +898,7 @@ AudioEngine::thread_init_callback (void* arg) SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512); - MIDI::JackMIDIPort::set_process_thread (pthread_self()); + AsyncMIDIPort::set_process_thread (pthread_self()); if (arg) { AudioEngine* ae = static_cast (arg); @@ -964,10 +930,10 @@ void AudioEngine::freewheel_callback (bool onoff) { if (onoff) { - _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled (); - MIDI::Manager::instance()->mmc()->enable_send (false); + _pre_freewheel_mmc_enabled = _mmc.send_enabled (); + _mmc.enable_send (false); } else { - MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled); + _mmc.enable_send (_pre_freewheel_mmc_enabled); } } @@ -991,8 +957,6 @@ void AudioEngine::halted_callback (const char* why) { stop_metering_thread (); - - MIDI::JackMIDIPort::EngineHalted (); /* EMIT SIGNAL */ Halted (why); /* EMIT SIGNAL */ } diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index afd5da2169..fb122dd83c 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -60,5 +60,6 @@ uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap"); uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys"); uint64_t PBD::DEBUG::Automation = PBD::new_debug_bit ("automation"); uint64_t PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol"); +uint64_t PBD::DEBUG::Ports = PBD::new_debug_bit ("Ports"); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index d744368fe7..fbce336283 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -67,7 +67,6 @@ #include "pbd/basename.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "midi++/mmc.h" #include "ardour/analyser.h" @@ -80,6 +79,7 @@ #include "ardour/control_protocol_manager.h" #include "ardour/filesystem_paths.h" #include "ardour/midi_region.h" +#include "ardour/midiport_manager.h" #include "ardour/mix.h" #include "ardour/panner_manager.h" #include "ardour/plugin_manager.h" @@ -340,9 +340,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir void ARDOUR::init_post_engine () { - /* the MIDI Manager is needed by the ControlProtocolManager */ - MIDI::Manager::create (AudioEngine::instance()->port_engine()); - ControlProtocolManager::instance().discover_control_protocols (); XMLNode* node; diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index 19158aacc9..2e0d90202f 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -24,7 +24,8 @@ #include "pbd/error.h" -#include "midi++/manager.h" +#include "jack/jack.h" +#include "jack/thread.h" #include "ardour/audioengine.h" #include "ardour/types.h" @@ -57,6 +58,7 @@ JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptrDisconnected.connect_same_thread (disconnect_connection, boost::bind (&JACKAudioBackend::disconnected, this, _1)); } JACKAudioBackend::~JACKAudioBackend() @@ -897,8 +899,6 @@ JACKAudioBackend::jack_bufsize_callback (pframes_t nframes) void JACKAudioBackend::disconnected (const char* why) { - /* called from jack shutdown handler */ - bool was_running = _running; _running = false; diff --git a/libs/ardour/jack_connection.cc b/libs/ardour/jack_connection.cc index 57950b0e17..d48e3355b5 100644 --- a/libs/ardour/jack_connection.cc +++ b/libs/ardour/jack_connection.cc @@ -135,7 +135,10 @@ JackConnection::close () GET_PRIVATE_JACK_POINTER_RET (_jack, -1); if (_priv_jack) { - return jack_client_close (_priv_jack); + int ret = jack_client_close (_priv_jack); + _jack = 0; + Disconnected (""); /* EMIT SIGNAL */ + return ret; } return 0; diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index 5a6e577f2d..6a2636e4f4 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -36,8 +36,6 @@ #include "pbd/xml++.h" #include "pbd/stacktrace.h" -#include "midi++/manager.h" - #include "ardour/session.h" #include "ardour/ladspa_plugin.h" #include "ardour/buffer_set.h" diff --git a/libs/ardour/midi_clock_slave.cc b/libs/ardour/midi_clock_slave.cc index 6f54d17d02..752644e9f4 100644 --- a/libs/ardour/midi_clock_slave.cc +++ b/libs/ardour/midi_clock_slave.cc @@ -31,6 +31,8 @@ #include "midi++/port.h" #include "ardour/debug.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/slave.h" #include "ardour/tempo.h" @@ -41,13 +43,20 @@ using namespace ARDOUR; using namespace MIDI; using namespace PBD; -MIDIClock_Slave::MIDIClock_Slave (Session& s, MIDI::Port& p, int ppqn) +MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn) : ppqn (ppqn) , bandwidth (10.0 / 60.0) // 1 BpM = 1 / 60 Hz { session = (ISlaveSessionProxy *) new SlaveSessionProxy(s); rebind (p); reset (); + + parser.timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2)); + parser.start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2)); + parser.contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2)); + parser.stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2)); + parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3)); + } MIDIClock_Slave::MIDIClock_Slave (ISlaveSessionProxy* session_proxy, int ppqn) @@ -63,20 +72,33 @@ MIDIClock_Slave::~MIDIClock_Slave() delete session; } -void -MIDIClock_Slave::rebind (MIDI::Port& p) +int +MIDIClock_Slave::process (pframes_t nframes) { - port_connections.drop_connections(); + MidiBuffer& mb (port->get_midi_buffer (nframes)); + /* dump incoming MIDI to parser */ + + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + uint8_t* buf = (*b).buffer(); + + parser.set_timestamp ((*b).time()); + + uint32_t limit = (*b).size(); + + for (size_t n = 0; n < limit; ++n) { + parser.scanner (buf[n]); + } + } + + return 0; +} + +void +MIDIClock_Slave::rebind (MidiPort& p) +{ port = &p; - DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port->name())); - - port->parser()->timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2)); - port->parser()->start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2)); - port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2)); - port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2)); - port->parser()->position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3)); } void diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index 0d9ac17601..e75c05c593 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -22,11 +22,11 @@ #include "pbd/pthread_utils.h" -#include "midi++/manager.h" -#include "midi++/port.h" - +#include "ardour/async_midi_port.h" #include "ardour/debug.h" #include "ardour/audioengine.h" +#include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/midi_ui.h" #include "ardour/session.h" #include "ardour/session_event.h" @@ -48,7 +48,6 @@ MidiControlUI::MidiControlUI (Session& s) : AbstractUI (X_("midiui")) , _session (s) { - MIDI::Manager::instance()->PortsChanged.connect_same_thread (rebind_connection, boost::bind (&MidiControlUI::change_midi_ports, this)); _instance = this; } @@ -83,20 +82,10 @@ MidiControlUI::do_request (MidiUIRequest* req) } } -void -MidiControlUI::change_midi_ports () -{ - MidiUIRequest* req = get_request (PortChange); - if (req == 0) { - return; - } - send_request (req); -} - bool -MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port) +MidiControlUI::midi_input_handler (IOCondition ioc, AsyncMIDIPort* port) { - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", port->name())); + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", ((ARDOUR::Port*)port)->name())); if (ioc & ~IO_IN) { return false; @@ -106,7 +95,7 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port) CrossThreadChannel::drain (port->selectable()); - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name())); + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", ((ARDOUR::Port*)port)->name())); framepos_t now = _session.engine().sample_time(); port->parse (now); } @@ -128,22 +117,19 @@ MidiControlUI::clear_ports () void MidiControlUI::reset_ports () { - clear_ports (); + if (port_sources.empty()) { + AsyncMIDIPort* async = dynamic_cast (AudioEngine::instance()->midi_input_port()); - boost::shared_ptr plist = MIDI::Manager::instance()->get_midi_ports (); - - for (MIDI::Manager::PortList::const_iterator i = plist->begin(); i != plist->end(); ++i) { - - if (!(*i)->centrally_parsed()) { - continue; + if (!async) { + return; } int fd; - if ((fd = (*i)->selectable ()) >= 0) { + if ((fd = async->selectable ()) >= 0) { Glib::RefPtr psrc = IOSource::create (fd, IO_IN|IO_HUP|IO_ERR); - - psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), *i)); + + psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), async)); psrc->attach (_main_loop->get_context()); // glibmm hack: for now, store only the GSource* diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc index fb27800762..ec525fd9f8 100644 --- a/libs/ardour/midiport_manager.cc +++ b/libs/ardour/midiport_manager.cc @@ -66,11 +66,47 @@ MidiPortManager::port (string const & n) void MidiPortManager::create_ports () { - _midi_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MIDI control in"), true); - _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MIDI control out"), true); + /* this method is idempotent + */ + + if (_midi_in) { + return; + } + + _midi_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("control in"), true); + _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("control out"), true); + + _mmc_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("mmc in"), true); + _mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("mmc out"), true); + /* XXX nasty type conversion needed because of the mixed inheritance + * required to integrate MIDI::IPMidiPort and ARDOUR::AsyncMIDIPort. + * + * At some point, we'll move IPMidiPort into Ardour and make it + * inherit from ARDOUR::MidiPort not MIDI::Port, and then this + * mess can go away + */ + _midi_input_port = boost::dynamic_pointer_cast(_midi_in).get(); _midi_output_port = boost::dynamic_pointer_cast(_midi_out).get(); + + _mmc_input_port = boost::dynamic_pointer_cast(_mmc_in).get(); + _mmc_output_port = boost::dynamic_pointer_cast(_mmc_out).get(); + + /* Now register ports used for sync (MTC and MIDI Clock) + */ + + boost::shared_ptr p; + + p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("timecode in")); + _mtc_input_port = boost::dynamic_pointer_cast (p); + p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("timecode out")); + _mtc_output_port= boost::dynamic_pointer_cast (p); + + p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("clock in")); + _midi_clock_input_port = boost::dynamic_pointer_cast (p); + p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("clock out")); + _midi_clock_output_port= boost::dynamic_pointer_cast (p); } void diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 0f2761c350..b42b4989d2 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -25,11 +25,12 @@ #include "pbd/error.h" -#include "midi++/port.h" -#include "ardour/debug.h" -#include "ardour/slave.h" -#include "ardour/session.h" #include "ardour/audioengine.h" +#include "ardour/debug.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" +#include "ardour/session.h" +#include "ardour/slave.h" #include "i18n.h" @@ -48,8 +49,9 @@ using namespace Timecode; */ const int MTC_Slave::frame_tolerance = 2; -MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) +MTC_Slave::MTC_Slave (Session& s, MidiPort& p) : session (s) + , port (&p) { can_notify_on_unknown_rate = true; did_reset_tc_format = false; @@ -70,7 +72,11 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_Slave::parameter_changed, this, _1)); parse_timecode_offset(); reset (true); - rebind (p); + + parser.mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); + parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); + parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); + } MTC_Slave::~MTC_Slave() @@ -93,16 +99,35 @@ MTC_Slave::~MTC_Slave() } } +int +MTC_Slave::process (pframes_t nframes) +{ + MidiBuffer& mb (port->get_midi_buffer (nframes)); + + /* dump incoming MIDI to parser */ + + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + uint8_t* buf = (*b).buffer(); + + parser.set_timestamp ((*b).time()); + + uint32_t limit = (*b).size(); + + for (size_t n = 0; n < limit; ++n) { + parser.scanner (buf[n]); + } + } + + return 0; +} + void -MTC_Slave::rebind (MIDI::Port& p) +MTC_Slave::rebind (MidiPort& p) { port_connections.drop_connections (); port = &p; - port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); - port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); - port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); } void @@ -154,7 +179,7 @@ MTC_Slave::outside_window (framepos_t pos) const bool MTC_Slave::locked () const { - return port->parser()->mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; + return parser.mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; } bool @@ -446,7 +471,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now) DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n", mtc_frame, (4.0*qtr), session.frames_per_timecode_frame())); - switch (port->parser()->mtc_running()) { + switch (parser.mtc_running()) { case MTC_Backward: mtc_frame -= mtc_off; qtr *= -1.0; @@ -528,7 +553,7 @@ MTC_Slave::reset_window (framepos_t root) */ framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance); - switch (port->parser()->mtc_running()) { + switch (parser.mtc_running()) { case MTC_Forward: window_begin = root; transport_direction = 1; diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index 571d227711..7dc11c6d3d 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -390,6 +390,7 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const int Port::reestablish () { + DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name)); _port_handle = port_engine.register_port (_name, type(), _flags); if (_port_handle == 0) { diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc index 5c807a6979..41331fe3a5 100644 --- a/libs/ardour/port_manager.cc +++ b/libs/ardour/port_manager.cc @@ -19,11 +19,12 @@ #include "pbd/error.h" -#include "midi++/manager.h" - +#include "ardour/async_midi_port.h" +#include "ardour/debug.h" #include "ardour/port_manager.h" #include "ardour/audio_port.h" #include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "i18n.h" @@ -227,6 +228,18 @@ PortManager::port_renamed (const std::string& old_relative_name, const std::stri } } +int +PortManager::get_ports (DataType type, PortList& pl) +{ + boost::shared_ptr plist = ports.reader(); + for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) { + if (p->second->type() == type) { + pl.push_back (p->second); + } + } + return pl.size(); +} + int PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) { @@ -262,15 +275,25 @@ PortManager::port_registration_failure (const std::string& portname) } boost::shared_ptr -PortManager::register_port (DataType dtype, const string& portname, bool input) +PortManager::register_port (DataType dtype, const string& portname, bool input, bool async) { boost::shared_ptr newport; try { if (dtype == DataType::AUDIO) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n", + portname, input)); newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput))); } else if (dtype == DataType::MIDI) { - newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput))); + if (async) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n", + portname, input)); + newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput))); + } else { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n", + portname, input)); + newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput))); + } } else { throw PortRegistrationFailure("unable to create port (unknown type)"); } @@ -281,7 +304,6 @@ PortManager::register_port (DataType dtype, const string& portname, bool input) /* writer goes out of scope, forces update */ - return newport; } catch (PortRegistrationFailure& err) { @@ -292,18 +314,21 @@ PortManager::register_port (DataType dtype, const string& portname, bool input) } catch (...) { throw PortRegistrationFailure("unable to create port (unknown error)"); } + + DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this)); + return newport; } boost::shared_ptr -PortManager::register_input_port (DataType type, const string& portname) +PortManager::register_input_port (DataType type, const string& portname, bool async) { - return register_port (type, portname, true); + return register_port (type, portname, true, async); } boost::shared_ptr -PortManager::register_output_port (DataType type, const string& portname) +PortManager::register_output_port (DataType type, const string& portname, bool async) { - return register_port (type, portname, false); + return register_port (type, portname, false, async); } int @@ -410,6 +435,8 @@ PortManager::reestablish_ports () boost::shared_ptr p = ports.reader (); + DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size())); + for (i = p->begin(); i != p->end(); ++i) { if (i->second->reestablish ()) { break; @@ -422,8 +449,6 @@ PortManager::reestablish_ports () return -1; } - MIDI::Manager::instance()->reestablish (); - return 0; } @@ -434,12 +459,12 @@ PortManager::reconnect_ports () /* re-establish connections */ + DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size())); + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { i->second->reconnect (); } - MIDI::Manager::instance()->reconnect (); - return 0; } @@ -543,3 +568,80 @@ PortManager::graph_order_callback () return 0; } + +void +PortManager::cycle_start (pframes_t nframes) +{ + Port::set_global_port_buffer_offset (0); + Port::set_cycle_framecnt (nframes); + + _cycle_ports = ports.reader (); + + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->cycle_start (nframes); + } +} + +void +PortManager::cycle_end (pframes_t nframes) +{ + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->cycle_end (nframes); + } + + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->flush_buffers (nframes); + } + + _cycle_ports.reset (); + + /* we are done */ +} + +void +PortManager::silence (pframes_t nframes) +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + if (i->second->sends_output()) { + i->second->get_buffer(nframes).silence(nframes); + } + } +} + +void +PortManager::check_monitoring () +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + + bool x; + + if (i->second->last_monitor() != (x = i->second->monitoring_input ())) { + i->second->set_last_monitor (x); + /* XXX I think this is dangerous, due to + a likely mutex in the signal handlers ... + */ + i->second->MonitorInputChanged (x); /* EMIT SIGNAL */ + } + } +} + +void +PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes) +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + + if (i->second->sends_output()) { + + boost::shared_ptr ap = boost::dynamic_pointer_cast (i->second); + if (ap) { + Sample* s = ap->engine_get_whole_audio_buffer (); + gain_t g = base_gain; + + for (pframes_t n = 0; n < nframes; ++n) { + *s++ *= g; + g -= gain_step; + } + } + } + } +} diff --git a/libs/ardour/rc_configuration.cc b/libs/ardour/rc_configuration.cc index 8127267975..007d6041db 100644 --- a/libs/ardour/rc_configuration.cc +++ b/libs/ardour/rc_configuration.cc @@ -27,13 +27,12 @@ #include "pbd/xml++.h" #include "pbd/file_utils.h" -#include "midi++/manager.h" - #include "ardour/control_protocol_manager.h" #include "ardour/diskstream.h" #include "ardour/filesystem_paths.h" #include "ardour/rc_configuration.h" #include "ardour/session_metadata.h" +#include "ardour/midiport_manager.h" #include "i18n.h" @@ -177,15 +176,20 @@ RCConfiguration::get_state () root = new XMLNode("Ardour"); - MIDI::Manager* mm = MIDI::Manager::instance(); + /* XXX + * GET STATE OF MIDI::Port HERE + */ +#if 0 + MidiPortManager* mm = MidiPortManager::instance(); if (mm) { - boost::shared_ptr ports = mm->get_midi_ports(); + boost::shared_ptr ports = mm->get_midi_ports(); - for (MIDI::Manager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) { - root->add_child_nocopy((*i)->get_state()); + for (MidiPortManager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) { + // root->add_child_nocopy ((*i)->get_state()); } } +#endif root->add_child_nocopy (get_variables ()); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 9667bbcd2c..cc4a99b11f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -49,6 +49,7 @@ #include "ardour/amp.h" #include "ardour/analyser.h" +#include "ardour/async_midi_port.h" #include "ardour/audio_buffer.h" #include "ardour/audio_diskstream.h" #include "ardour/audio_port.h" @@ -66,6 +67,7 @@ #include "ardour/debug.h" #include "ardour/filename_extensions.h" #include "ardour/graph.h" +#include "ardour/midiport_manager.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" #include "ardour/operations.h" @@ -88,9 +90,7 @@ #include "ardour/utils.h" #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" -#include "midi++/manager.h" #include "i18n.h" @@ -584,7 +584,8 @@ Session::when_engine_running () as it will set states for ports which the ControlProtocolManager creates. */ - MIDI::Manager::instance()->set_port_states (Config->midi_port_states ()); + // XXX set state of MIDI::Port's + // MidiPortManager::instance()->set_port_states (Config->midi_port_states ()); /* And this must be done after the MIDI::Manager::set_port_states as * it will try to make connections whose details are loaded by set_port_states. @@ -874,7 +875,12 @@ Session::hookup_io () /* Tell all IO objects to connect themselves together */ IO::enable_connecting (); - MIDI::JackMIDIPort::MakeConnections (); + + /* Now tell all "floating" ports to connect to whatever + they should be connected to. + */ + + AudioEngine::instance()->reconnect_ports (); /* Anyone who cares about input state, wake up and do something */ @@ -1169,7 +1175,7 @@ Session::enable_record () if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) { _last_record_location = _transport_frame; - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { set_track_monitor_input_status (true); @@ -1190,7 +1196,7 @@ Session::disable_record (bool rt_context, bool force) if ((!Config->get_latched_record_enable () && !play_loop) || force) { g_atomic_int_set (&_record_status, Disabled); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); } else { if (rs == Recording) { g_atomic_int_set (&_record_status, Enabled); @@ -1244,7 +1250,7 @@ Session::maybe_enable_record () enable_record (); } } else { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); RecordStateChanged (); /* EMIT SIGNAL */ } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 0db4fc33bb..ab37e915bf 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -21,7 +21,6 @@ #include "pbd/error.h" #include -#include #include #include "ardour/audioengine.h" @@ -93,8 +92,8 @@ Session::pre_export () /* disable MMC output early */ - _pre_export_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled (); - MIDI::Manager::instance()->mmc()->enable_send (false); + _pre_export_mmc_enabled = AudioEngine::instance()->mmc().send_enabled (); + AudioEngine::instance()->mmc().enable_send (false); return 0; } @@ -237,7 +236,7 @@ Session::finalize_audio_export () export_freewheel_connection.disconnect(); - MIDI::Manager::instance()->mmc()->enable_send (_pre_export_mmc_enabled); + AudioEngine::instance()->mmc().enable_send (_pre_export_mmc_enabled); /* maybe write CUE/TOC */ diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index d137e5167c..07a34283e3 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -31,7 +31,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "pbd/error.h" #include "pbd/pthread_utils.h" @@ -41,6 +40,7 @@ #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/debug.h" +#include "ardour/midi_port.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" #include "ardour/session.h" @@ -349,7 +349,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) * @param t time to send. */ int -Session::send_full_time_code (framepos_t const t) +Session::send_full_time_code (framepos_t const t, pframes_t nframes) { /* This function could easily send at a given frame offset, but would * that be useful? Does ardour do sub-block accurate locating? [DR] */ @@ -424,10 +424,9 @@ Session::send_full_time_code (framepos_t const t) msg[8] = timecode.frames; // Send message at offset 0, sent time is for the start of this cycle - if (MIDI::Manager::instance()->mtc_output_port()->midimsg (msg, sizeof (msg), 0)) { - error << _("Session: could not send full MIDI time code") << endmsg; - return -1; - } + + MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer (nframes)); + mb.push_back (0, sizeof (msg), msg); _pframes_since_last_mtc = 0; return 0; @@ -470,7 +469,7 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f next_quarter_frame_to_send, quarter_frame_duration)); if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < _transport_frame) { - send_full_time_code (_transport_frame); + send_full_time_code (_transport_frame, nframes); return 0; } @@ -516,9 +515,10 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f pframes_t const out_stamp = (msg_time - start_frame) / _transport_speed; assert (out_stamp < nframes); - if (MIDI::Manager::instance()->mtc_output_port()->midimsg (mtc_msg, 2, out_stamp)) { + MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer(nframes)); + if (!mb.push_back (out_stamp, 2, mtc_msg)) { error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) - << endmsg; + << endmsg; return -1; } @@ -588,7 +588,7 @@ Session::mmc_step_timeout () void -Session::send_song_position_pointer (framepos_t t) +Session::send_song_position_pointer (framepos_t) { if (midi_clock) { /* Do nothing for the moment */ diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index cecbd88f65..6a24198bec 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -40,7 +40,6 @@ #include "ardour/ticker.h" #include "ardour/types.h" -#include "midi++/manager.h" #include "midi++/mmc.h" #include "i18n.h" @@ -85,7 +84,7 @@ Session::process (pframes_t nframes) try { if (!_engine.freewheeling() && Config->get_send_midi_clock() && transport_speed() == 1.0f && midi_clock->has_midi_port()) { - midi_clock->tick (transport_at_start); + midi_clock->tick (transport_at_start, nframes); } } catch (...) { /* don't bother with a message */ @@ -325,7 +324,7 @@ Session::process_with_events (pframes_t nframes) * and prepare for rolling) */ if (_send_timecode_update) { - send_full_time_code (_transport_frame); + send_full_time_code (_transport_frame, nframes); } if (!process_can_proceed()) { @@ -492,6 +491,7 @@ Session::follow_slave (pframes_t nframes) goto noroll; } + _slave->process (nframes); _slave->speed_and_position (slave_speed, slave_transport_frame); DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave position %1 speed %2\n", slave_transport_frame, slave_speed)); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index cae3b9720a..c4522f76e7 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -60,7 +60,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "evoral/SMF.hpp" @@ -359,11 +358,11 @@ Session::second_stage_init () BootMessage (_("Reset Remote Controls")); - send_full_time_code (0); + // send_full_time_code (0); _engine.transport_locate (0); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ())); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (Timecode::Time ())); MIDI::Name::MidiPatchManager::instance().set_session (this); @@ -3429,11 +3428,11 @@ Session::config_changed (std::string p, bool ours) } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") { - MIDI::Manager::instance()->mmc()->set_receive_device_id (Config->get_mmc_receive_device_id()); + AudioEngine::instance()->mmc().set_receive_device_id (Config->get_mmc_receive_device_id()); } else if (p == "mmc-send-id" || p == "mmc-send-device-id") { - MIDI::Manager::instance()->mmc()->set_send_device_id (Config->get_mmc_send_device_id()); + AudioEngine::instance()->mmc().set_send_device_id (Config->get_mmc_send_device_id()); } else if (p == "midi-control") { @@ -3496,7 +3495,7 @@ Session::config_changed (std::string p, bool ours) } else if (p == "send-mmc") { - MIDI::Manager::instance()->mmc()->enable_send (Config->get_send_mmc ()); + AudioEngine::instance()->mmc().enable_send (Config->get_send_mmc ()); } else if (p == "midi-feedback") { @@ -3554,13 +3553,13 @@ Session::config_changed (std::string p, bool ours) } else if (p == "initial-program-change") { - if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) { + if (AudioEngine::instance()->mmc().output_port() && Config->get_initial_program_change() >= 0) { MIDI::byte buf[2]; buf[0] = MIDI::program; // channel zero by default buf[1] = (Config->get_initial_program_change() & 0x7f); - MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf, sizeof (buf), 0); + AudioEngine::instance()->mmc().output_port()->midimsg (buf, sizeof (buf), 0); } } else if (p == "solo-mute-override") { // catch_up_on_solo_mute_override (); @@ -3624,27 +3623,27 @@ Session::load_diskstreams_2X (XMLNode const & node, int) void Session::setup_midi_machine_control () { - MIDI::MachineControl* mmc = MIDI::Manager::instance()->mmc (); + MIDI::MachineControl& mmc (AudioEngine::instance()->mmc ()); - mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); - mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); - mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); - mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); - mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); - mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); - mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); - mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); - mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); - mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); - mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); + mmc.Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + mmc.DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + mmc.Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); + mmc.FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); + mmc.Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); + mmc.Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); + mmc.RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); + mmc.RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); + mmc.RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); + mmc.Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); + mmc.Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); + mmc.Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); + mmc.TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); /* also handle MIDI SPP because its so common */ - mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); - mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); - mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); + mmc.SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); + mmc.SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); + mmc.SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); } boost::shared_ptr diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 08e9a89481..44a885cd1c 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -33,7 +33,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "ardour/audioengine.h" #include "ardour/auditioner.h" @@ -611,10 +610,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) have_looped = false; if (!_engine.freewheeling()) { - send_full_time_code (_transport_frame); + // need to queue this in the next RT cycle + _send_timecode_update = true; if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); send_mmc_locate (_transport_frame); } } @@ -1260,7 +1260,7 @@ Session::start_transport () Timecode::Time time; timecode_time_subframes (_transport_frame, time); if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); } } @@ -1338,8 +1338,9 @@ Session::use_sync_source (Slave* new_slave) _slave = new_slave; DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave)); - - send_full_time_code (_transport_frame); + + // need to queue this for next process() cycle + _send_timecode_update = true; boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -1380,7 +1381,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MTC_Slave (*this, *MIDI::Manager::instance()->mtc_input_port()); + new_slave = new MTC_Slave (*this, *AudioEngine::instance()->mtc_input_port()); } catch (failed_constructor& err) { @@ -1409,7 +1410,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MIDIClock_Slave (*this, *MIDI::Manager::instance()->midi_clock_input_port(), 24); + new_slave = new MIDIClock_Slave (*this, *AudioEngine::instance()->midi_clock_input_port(), 24); } catch (failed_constructor& err) { @@ -1636,7 +1637,7 @@ Session::send_mmc_locate (framepos_t t) if (!_engine.freewheeling()) { Timecode::Time time; timecode_time_subframes (t, time); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (time)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (time)); } } diff --git a/libs/ardour/ticker.cc b/libs/ardour/ticker.cc index f32cdf9415..0ed4427b72 100644 --- a/libs/ardour/ticker.cc +++ b/libs/ardour/ticker.cc @@ -19,13 +19,12 @@ #include "pbd/compose.h" #include "pbd/stacktrace.h" -#include "midi++/port.h" -#include "midi++/jack_midi_port.h" -#include "midi++/manager.h" - #include "evoral/midi_events.h" +#include "ardour/async_midi_port.h" #include "ardour/audioengine.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/ticker.h" #include "ardour/session.h" #include "ardour/tempo.h" @@ -95,16 +94,16 @@ public: MidiClockTicker::MidiClockTicker () - : _midi_port (0) - , _ppqn (24) + : _ppqn (24) , _last_tick (0.0) + , _send_pos (false) + , _send_state (false) { _pos.reset (new Position()); } MidiClockTicker::~MidiClockTicker() { - _midi_port = 0; _pos.reset (0); } @@ -115,7 +114,6 @@ MidiClockTicker::set_session (Session* s) if (_session) { _session->TransportStateChange.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::transport_state_changed, this)); - _session->PositionChanged.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::position_changed, this, _1)); _session->TransportLooped.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::transport_looped, this)); _session->Located.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::session_located, this)); @@ -139,41 +137,20 @@ MidiClockTicker::session_located() return; } - if (_pos->speed == 0.0f) { - uint32_t where = llrint (_pos->midi_beats); - send_position_event (where, 0); - } else if (_pos->speed == 1.0f) { -#if 1 - /* Experimental. To really do this and have accuracy, the - stop/locate/continue sequence would need queued to send immediately - before the next midi clock. */ - - send_stop_event (0); - - if (_pos->frame == 0) { - send_start_event (0); - } else { - uint32_t where = llrint (_pos->midi_beats); - send_position_event (where, 0); - send_continue_event (0); - } -#endif - } else { - /* Varispeed not supported */ - } + _send_pos = true; } void MidiClockTicker::session_going_away () { SessionHandlePtr::session_going_away(); - _midi_port = 0; + _midi_port.reset (); } void MidiClockTicker::update_midi_clock_port() { - _midi_port = MIDI::Manager::instance()->midi_clock_output_port(); + _midi_port = AudioEngine::instance()->midi_clock_output_port(); } void @@ -204,48 +181,11 @@ MidiClockTicker::transport_state_changed() return; } - if (_pos->speed == 1.0f) { - - if (_session->get_play_loop()) { - assert(_session->locations()->auto_loop_location()); - - if (_pos->frame == _session->locations()->auto_loop_location()->start()) { - send_start_event(0); - } else { - send_continue_event(0); - } - - } else if (_pos->frame == 0) { - send_start_event(0); - } else { - send_continue_event(0); - } - - // send_midi_clock_event (0); - - } else if (_pos->speed == 0.0f) { - send_stop_event (0); - send_position_event (llrint (_pos->midi_beats), 0); - } + _send_state = true; // tick (_pos->frame); } -void -MidiClockTicker::position_changed (framepos_t) -{ -#if 0 - const double speed = _session->transport_speed(); - DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Transport Position Change: %1, speed: %2\n", position, speed)); - - if (speed == 0.0f && Config->get_send_midi_clock()) { - send_position_event (position, 0); - } - - _last_tick = position; -#endif -} - void MidiClockTicker::transport_looped() { @@ -270,18 +210,68 @@ MidiClockTicker::transport_looped() } void -MidiClockTicker::tick (const framepos_t& /* transport_frame */) +MidiClockTicker::tick (const framepos_t& /* transport_frame */, pframes_t nframes) { if (!Config->get_send_midi_clock() || _session == 0 || _session->transport_speed() != 1.0f || _midi_port == 0) { return; } - MIDI::JackMIDIPort* mp = dynamic_cast (_midi_port); - if (! mp) { - return; + if (_send_pos) { + if (_pos->speed == 0.0f) { + uint32_t where = llrint (_pos->midi_beats); + send_position_event (where, 0, nframes); + } else if (_pos->speed == 1.0f) { +#if 1 + /* Experimental. To really do this and have accuracy, the + stop/locate/continue sequence would need queued to send immediately + before the next midi clock. */ + + send_stop_event (0, nframes); + + if (_pos->frame == 0) { + send_start_event (0, nframes); + } else { + uint32_t where = llrint (_pos->midi_beats); + send_position_event (where, 0, nframes); + send_continue_event (0, nframes); + } +#endif + } else { + /* Varispeed not supported */ + } + + _send_pos = true; } - const framepos_t end = _pos->frame + mp->nframes_this_cycle(); + if (_send_state) { + if (_pos->speed == 1.0f) { + if (_session->get_play_loop()) { + assert(_session->locations()->auto_loop_location()); + + if (_pos->frame == _session->locations()->auto_loop_location()->start()) { + send_start_event (0, nframes); + } else { + send_continue_event (0, nframes); + } + + } else if (_pos->frame == 0) { + send_start_event (0, nframes); + } else { + send_continue_event (0, nframes); + } + + // send_midi_clock_event (0); + + } else if (_pos->speed == 0.0f) { + send_stop_event (0, nframes); + send_position_event (llrint (_pos->midi_beats), 0, nframes); + } + + _send_state = false; + } + + + const framepos_t end = _pos->frame + nframes; double iter = _last_tick; while (true) { @@ -291,14 +281,14 @@ MidiClockTicker::tick (const framepos_t& /* transport_frame */) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Tick: iter: %1, last tick time: %2, next tick time: %3, offset: %4, cycle length: %5\n", - iter, _last_tick, next_tick, next_tick_offset, mp ? mp->nframes_this_cycle() : 0)); + iter, _last_tick, next_tick, next_tick_offset, nframes)); - if (!mp || (next_tick_offset >= mp->nframes_this_cycle())) { + if (next_tick_offset >= nframes) { break; } if (next_tick_offset >= 0) { - send_midi_clock_event (next_tick_offset); + send_midi_clock_event (next_tick_offset, nframes); } iter = next_tick; @@ -308,7 +298,6 @@ MidiClockTicker::tick (const framepos_t& /* transport_frame */) _pos->frame = end; } - double MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position) { @@ -322,7 +311,7 @@ MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position) } void -MidiClockTicker::send_midi_clock_event (pframes_t offset) +MidiClockTicker::send_midi_clock_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -330,12 +319,13 @@ MidiClockTicker::send_midi_clock_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Tick with offset %1\n", offset)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_CLOCK }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_CLOCK }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_start_event (pframes_t offset) +MidiClockTicker::send_start_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -343,12 +333,13 @@ MidiClockTicker::send_start_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Start %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_START }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_START }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_continue_event (pframes_t offset) +MidiClockTicker::send_continue_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -356,12 +347,13 @@ MidiClockTicker::send_continue_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Continue %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_CONTINUE }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_CONTINUE }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_stop_event (pframes_t offset) +MidiClockTicker::send_stop_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -369,12 +361,13 @@ MidiClockTicker::send_stop_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Stop %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_STOP }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_STOP }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset) +MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -391,7 +384,8 @@ MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset) msg[1] = midi_beats & 0x007f; msg[2] = midi_beats >> 7; - _midi_port->midimsg (msg, sizeof (msg), offset); + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 3, &msg[0]); DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Song Position Sent: %1\n", midi_beats)); } diff --git a/libs/ardour/wscript b/libs/ardour/wscript index d48a4d6d85..f13c4e5eef 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -21,6 +21,7 @@ path_prefix = 'libs/ardour/' libardour_sources = [ 'amp.cc', 'analyser.cc', + 'async_midi_port.cc', 'audio_buffer.cc', 'audio_diskstream.cc', 'audio_library.cc', @@ -126,6 +127,7 @@ libardour_sources = [ 'midi_stretch.cc', 'midi_track.cc', 'midi_ui.cc', + 'midiport_manager.cc', 'mix.cc', 'monitor_processor.cc', 'mtc_slave.cc', diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index 0f362678ce..01f8bf3b8a 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -38,7 +38,6 @@ namespace MIDI { class Port; class Parser; class MachineControlCommand; -class Manager; /** Class to handle incoming and outgoing MIDI machine control messages */ class MachineControl @@ -95,7 +94,9 @@ class MachineControl cmdResume = 0x7F }; - MachineControl (Manager *, ARDOUR::PortEngine&); + MachineControl (); + + void set_ports (MIDI::Port* input, MIDI::Port* output); Port* input_port() { return _input_port; } Port* output_port() { return _output_port; } diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h index f5f343e952..44897f9d8e 100644 --- a/libs/midi++2/midi++/parser.h +++ b/libs/midi++2/midi++/parser.h @@ -41,7 +41,7 @@ typedef PBD::Signal3 Signal; class Parser { public: - Parser (Port &p); + Parser (); ~Parser (); /* sets the time that will be reported for any MTC or MIDI Clock @@ -105,7 +105,6 @@ class Parser { const char *midi_event_type_name (MIDI::eventType); void trace (bool onoff, std::ostream *o, const std::string &prefix = ""); bool tracing() { return trace_stream != 0; } - Port &port() { return _port; } void set_offline (bool); bool offline() const { return _offline; } @@ -136,7 +135,6 @@ class Parser { void reset_mtc_state (); private: - Port&_port; /* tracing */ std::ostream *trace_stream; diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h index 599fabaa87..6d778beab2 100644 --- a/libs/midi++2/midi++/port.h +++ b/libs/midi++2/midi++/port.h @@ -51,13 +51,6 @@ class Port { virtual XMLNode& get_state () const; virtual void set_state (const XMLNode&); - // FIXME: make Manager a friend of port so these can be hidden? - - /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_start (pframes_t) {} - /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_end () {} - /** Write a message to port. * @param msg Raw MIDI message to send * @param msglen Size of @a msg diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc index 0a71463721..b93dc0f260 100644 --- a/libs/midi++2/mmc.cc +++ b/libs/midi++2/mmc.cc @@ -27,9 +27,7 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/parser.h" -#include "midi++/manager.h" using namespace std; using namespace MIDI; @@ -197,16 +195,21 @@ static void build_mmc_cmd_map () mmc_cmd_map.insert (newpair); } - -MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine) +MachineControl::MachineControl () { build_mmc_cmd_map (); _receive_device_id = 0x7f; _send_device_id = 0x7f; +} - _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, pengine)); - _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, pengine)); +void +MachineControl::set_ports (MIDI::Port* ip, MIDI::Port* op) +{ + port_connections.drop_connections (); + + _input_port = ip; + _output_port = op; _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3)); _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this)); diff --git a/libs/midi++2/parser.cc b/libs/midi++2/parser.cc index 8e3af64504..2f6b50899c 100644 --- a/libs/midi++2/parser.cc +++ b/libs/midi++2/parser.cc @@ -104,8 +104,7 @@ Parser::midi_event_type_name (eventType t) } } -Parser::Parser (Port &p) - : _port(p) +Parser::Parser () { trace_stream = 0; trace_prefix = ""; diff --git a/libs/midi++2/port.cc b/libs/midi++2/port.cc index 3e7896631a..1480202867 100644 --- a/libs/midi++2/port.cc +++ b/libs/midi++2/port.cc @@ -71,7 +71,7 @@ Port::init (string const & name, Flags flags) _tagname = name; _flags = flags; - _parser = new Parser (*this); + _parser = new Parser (); for (int i = 0; i < 16; i++) { _channel[i] = new Channel (i, *this); diff --git a/libs/midi++2/wscript b/libs/midi++2/wscript index 8a4f2f6c69..0abbab7d40 100644 --- a/libs/midi++2/wscript +++ b/libs/midi++2/wscript @@ -31,8 +31,6 @@ libmidi_sources = [ 'midi.cc', 'channel.cc', 'ipmidi_port.cc', - 'jack_midi_port.cc', - 'manager.cc', 'parser.cc', 'port.cc', 'midnam_patch.cc', diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 6da0192a8f..2820b069dc 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -32,13 +32,14 @@ #include "pbd/xml++.h" #include "midi++/port.h" -#include "midi++/manager.h" +#include "ardour/audioengine.h" #include "ardour/filesystem_paths.h" #include "ardour/session.h" #include "ardour/route.h" #include "ardour/midi_ui.h" #include "ardour/rc_configuration.h" +#include "ardour/midiport_manager.h" #include "generic_midi_control_protocol.h" #include "midicontrollable.h" @@ -59,8 +60,8 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) , _threshold (10) , gui (0) { - _input_port = MIDI::Manager::instance()->midi_input_port (); - _output_port = MIDI::Manager::instance()->midi_output_port (); + _input_port = AudioEngine::instance()->midi_input_port (); + _output_port = AudioEngine::instance()->midi_output_port (); do_feedback = false; _feedback_interval = 10000; // microseconds @@ -338,7 +339,7 @@ GenericMidiControlProtocol::start_learning (Controllable* c) } if (!mc) { - mc = new MIDIControllable (this, *_input_port, *c, false); + mc = new MIDIControllable (this, *_input_port->parser(), *c, false); } { @@ -435,7 +436,7 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, MIDI::byte value = control_number; // Create a MIDIControllable - MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false); // Remove any old binding for this midi channel/type/value pair // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information @@ -559,7 +560,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version) Controllable* c = Controllable::by_id (id); if (c) { - MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false); if (mc->set_state (**niter, version) == 0) { controllables.push_back (mc); @@ -754,7 +755,7 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) prop = node.property (X_("uri")); uri = prop->value(); - MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary); if (mc->init (uri)) { delete mc; @@ -892,7 +893,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node) prop = node.property (X_("function")); - MIDIFunction* mf = new MIDIFunction (*_input_port); + MIDIFunction* mf = new MIDIFunction (*_input_port->parser()); if (mf->setup (*this, prop->value(), argument, data, data_size)) { delete mf; @@ -988,7 +989,7 @@ GenericMidiControlProtocol::create_action (const XMLNode& node) prop = node.property (X_("action")); - MIDIAction* ma = new MIDIAction (*_input_port); + MIDIAction* ma = new MIDIAction (*_input_port->parser()); if (ma->init (*this, prop->value(), data, data_size)) { delete ma; diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index a7c420cc41..a4a51b7f99 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -22,14 +22,11 @@ #include #include + #include "ardour/types.h" #include "control_protocol/control_protocol.h" -namespace MIDI { - class Port; -} - namespace PBD { class Controllable; class ControllableDescriptor; @@ -37,6 +34,11 @@ namespace PBD { namespace ARDOUR { class Session; + class MidiPort; +} + +namespace MIDI { + class Port; } class MIDIControllable; @@ -51,8 +53,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { int set_active (bool yn); static bool probe() { return true; } - MIDI::Port* input_port () const { return _input_port; } - MIDI::Port* output_port () const { return _output_port; } + MIDI::Port* input_port () const { return _input_port; } + MIDI::Port* output_port () const { return _output_port; } void set_feedback_interval (ARDOUR::microseconds_t); int set_feedback (bool yn); @@ -97,8 +99,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { } private: - MIDI::Port* _input_port; - MIDI::Port* _output_port; + MIDI::Port* _input_port; + MIDI::Port* _output_port; ARDOUR::microseconds_t _feedback_interval; ARDOUR::microseconds_t last_feedback_time; diff --git a/libs/surfaces/generic_midi/midiaction.cc b/libs/surfaces/generic_midi/midiaction.cc index e1eed1a49e..e537122e9c 100644 --- a/libs/surfaces/generic_midi/midiaction.cc +++ b/libs/surfaces/generic_midi/midiaction.cc @@ -25,7 +25,7 @@ using namespace MIDI; -MIDIAction::MIDIAction (MIDI::Port& p) +MIDIAction::MIDIAction (MIDI::Parser& p) : MIDIInvokable (p) { } diff --git a/libs/surfaces/generic_midi/midiaction.h b/libs/surfaces/generic_midi/midiaction.h index 521f59f26d..e2a29143ad 100644 --- a/libs/surfaces/generic_midi/midiaction.h +++ b/libs/surfaces/generic_midi/midiaction.h @@ -36,8 +36,6 @@ namespace Gtk { } namespace MIDI { - class Channel; - class Port; class Parser; } @@ -46,7 +44,7 @@ class GenericMidiControlProtocol; class MIDIAction : public MIDIInvokable { public: - MIDIAction (MIDI::Port&); + MIDIAction (MIDI::Parser&); virtual ~MIDIAction (); int init (GenericMidiControlProtocol&, const std::string& action_name, MIDI::byte* sysex = 0, size_t ssize = 0); diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index d36ccefd44..d78dd5e644 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -27,9 +27,9 @@ #include "pbd/xml++.h" #include "pbd/stacktrace.h" -#include "midi++/port.h" #include "midi++/channel.h" +#include "ardour/async_midi_port.h" #include "ardour/automation_control.h" #include "ardour/midi_ui.h" #include "ardour/utils.h" @@ -42,11 +42,11 @@ using namespace MIDI; using namespace PBD; using namespace ARDOUR; -MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool m) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& p, bool m) : _surface (s) , controllable (0) , _descriptor (0) - , _port (p) + , _parser (p) , _momentary (m) { _learned = false; /* from URI */ @@ -59,10 +59,10 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool feedback = true; // for now } -MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, Controllable& c, bool m) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& p, Controllable& c, bool m) : _surface (s) , _descriptor (0) - , _port (p) + , _parser (p) , _momentary (m) { set_controllable (&c); @@ -149,7 +149,7 @@ void MIDIControllable::learn_about_external_control () { drop_external_control (); - _port.parser()->any.connect_same_thread (midi_learn_connection, boost::bind (&MIDIControllable::midi_receiver, this, _1, _2, _3)); + _parser.any.connect_same_thread (midi_learn_connection, boost::bind (&MIDIControllable::midi_receiver, this, _1, _2, _3)); } void @@ -357,12 +357,6 @@ MIDIControllable::midi_receiver (Parser &, byte *msg, size_t /*len*/) return; } - /* if the our port doesn't do input anymore, forget it ... */ - - if (!_port.parser()) { - return; - } - bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]); if (controllable) { @@ -381,49 +375,43 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) control_channel = chn; control_additional = additional; - if (_port.parser() == 0) { - return; - } - - Parser& p = *_port.parser(); - int chn_i = chn; switch (ev) { case MIDI::off: - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); /* if this is a togglee, connect to noteOn as well, and we'll toggle back and forth between the two. */ if (_momentary) { - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); } _control_description = "MIDI control: NoteOff"; break; case MIDI::on: - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); if (_momentary) { - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); } _control_description = "MIDI control: NoteOn"; break; case MIDI::controller: - p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_controller, this, _1, _2)); + _parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_controller, this, _1, _2)); snprintf (buf, sizeof (buf), "MIDI control: Controller %d", control_additional); _control_description = buf; break; case MIDI::program: - p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); + _parser.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); _control_description = "MIDI control: ProgramChange"; break; case MIDI::pitchbend: - p.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); + _parser.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); _control_description = "MIDI control: Pitchbend"; break; diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index dd9dc988b4..aeed05db4a 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -36,17 +36,20 @@ namespace PBD { namespace MIDI { class Channel; - class Port; class Parser; } class GenericMidiControlProtocol; +namespace ARDOUR { + class AsyncMIDIPort; +} + class MIDIControllable : public PBD::Stateful { public: - MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, PBD::Controllable&, bool momentary); - MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, bool momentary = false); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Parser&, PBD::Controllable&, bool momentary); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Parser&, bool momentary = false); virtual ~MIDIControllable (); int init (const std::string&); @@ -72,7 +75,7 @@ class MIDIControllable : public PBD::Stateful bool learned() const { return _learned; } - MIDI::Port& get_port() const { return _port; } + MIDI::Parser& get_parser() { return _parser; } PBD::Controllable* get_controllable() const { return controllable; } void set_controllable (PBD::Controllable*); const std::string& current_uri() const { return _current_uri; } @@ -98,8 +101,8 @@ class MIDIControllable : public PBD::Stateful GenericMidiControlProtocol* _surface; PBD::Controllable* controllable; PBD::ControllableDescriptor* _descriptor; - std::string _current_uri; - MIDI::Port& _port; + std::string _current_uri; + MIDI::Parser& _parser; bool setting; int last_value; float last_controllable_value; diff --git a/libs/surfaces/generic_midi/midifunction.cc b/libs/surfaces/generic_midi/midifunction.cc index 70e9337861..b0dc95e4fc 100644 --- a/libs/surfaces/generic_midi/midifunction.cc +++ b/libs/surfaces/generic_midi/midifunction.cc @@ -25,7 +25,7 @@ using namespace MIDI; -MIDIFunction::MIDIFunction (MIDI::Port& p) +MIDIFunction::MIDIFunction (MIDI::Parser& p) : MIDIInvokable (p) { } diff --git a/libs/surfaces/generic_midi/midifunction.h b/libs/surfaces/generic_midi/midifunction.h index 8f0b0218d0..88aff0ab0a 100644 --- a/libs/surfaces/generic_midi/midifunction.h +++ b/libs/surfaces/generic_midi/midifunction.h @@ -33,7 +33,6 @@ namespace MIDI { class Channel; - class Port; class Parser; } @@ -64,7 +63,7 @@ class MIDIFunction : public MIDIInvokable TrackSetSoloIsolate, }; - MIDIFunction (MIDI::Port&); + MIDIFunction (MIDI::Parser&); virtual ~MIDIFunction (); int setup (GenericMidiControlProtocol&, const std::string& function_name, const std::string& argument, MIDI::byte* sysex = 0, size_t ssize = 0); diff --git a/libs/surfaces/generic_midi/midiinvokable.cc b/libs/surfaces/generic_midi/midiinvokable.cc index 79835835a4..42c74553d8 100644 --- a/libs/surfaces/generic_midi/midiinvokable.cc +++ b/libs/surfaces/generic_midi/midiinvokable.cc @@ -25,8 +25,8 @@ using namespace MIDI; -MIDIInvokable::MIDIInvokable (MIDI::Port& p) - : _port (p) +MIDIInvokable::MIDIInvokable (MIDI::Parser& p) + : _parser (p) { data_size = 0; data = 0; @@ -127,12 +127,6 @@ MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) control_channel = chn; control_additional = additional; - if (_port.parser() == 0) { - return; - } - - Parser& p = *_port.parser(); - int chn_i = chn; /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use @@ -141,27 +135,27 @@ MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) switch (ev) { case MIDI::off: - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2)); break; case MIDI::on: - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2)); break; case MIDI::controller: - p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2)); + _parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2)); break; case MIDI::program: - p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2)); + _parser.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2)); break; case MIDI::sysex: - p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3)); + _parser.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3)); break; case MIDI::any: - p.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3)); + _parser.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3)); break; default: diff --git a/libs/surfaces/generic_midi/midiinvokable.h b/libs/surfaces/generic_midi/midiinvokable.h index 62cbab238c..f374a126a5 100644 --- a/libs/surfaces/generic_midi/midiinvokable.h +++ b/libs/surfaces/generic_midi/midiinvokable.h @@ -31,7 +31,6 @@ namespace MIDI { class Channel; - class Port; class Parser; } @@ -40,12 +39,12 @@ class GenericMidiControlProtocol; class MIDIInvokable : public PBD::Stateful { public: - MIDIInvokable (MIDI::Port&); + MIDIInvokable (MIDI::Parser&); virtual ~MIDIInvokable (); virtual int init (GenericMidiControlProtocol&, const std::string&, MIDI::byte* data = 0, size_t dsize = 0); - MIDI::Port& get_port() const { return _port; } + MIDI::Parser& get_parser() { return _parser; } void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte); MIDI::channel_t get_control_channel () { return control_channel; } @@ -55,7 +54,7 @@ class MIDIInvokable : public PBD::Stateful protected: GenericMidiControlProtocol* _ui; std::string _invokable_name; - MIDI::Port& _port; + MIDI::Parser& _parser; PBD::ScopedConnection midi_sense_connection[2]; MIDI::eventType control_type; MIDI::byte control_additional; diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 0c45a29378..23cef9d13c 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -24,7 +24,6 @@ #include #include "midi++/port.h" -#include "midi++/manager.h" #include "ardour/automation_control.h" #include "ardour/debug.h" diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc index 44db30ab1b..fd9feaff74 100644 --- a/libs/surfaces/mackie/surface_port.cc +++ b/libs/surfaces/mackie/surface_port.cc @@ -24,27 +24,27 @@ #include #include "midi++/types.h" -#include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/ipmidi_port.h" -#include "midi++/manager.h" +#include "ardour/async_midi_port.h" #include "ardour/debug.h" #include "ardour/rc_configuration.h" #include "ardour/session.h" #include "ardour/audioengine.h" +#include "ardour/async_midi_port.h" +#include "ardour/midiport_manager.h" #include "controls.h" #include "mackie_control_protocol.h" #include "surface.h" #include "surface_port.h" - #include "i18n.h" using namespace std; using namespace Mackie; using namespace PBD; +using namespace ARDOUR; /** @param input_port Input MIDI::Port; this object takes responsibility for * adding & removing it from the MIDI::Manager and destroying it. @param @@ -52,31 +52,16 @@ using namespace PBD; */ SurfacePort::SurfacePort (Surface& s) : _surface (&s) - , _input_port (0) - , _output_port (0) { if (_surface->mcp().device_info().uses_ipmidi()) { _input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number()); _output_port = _input_port; } else { - ARDOUR::PortEngine& port_engine (ARDOUR::AudioEngine::instance()->port_engine()); - - _input_port = new MIDI::JackMIDIPort (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, port_engine); - _output_port =new MIDI::JackMIDIPort (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, port_engine); - - /* MackieControl has its own thread for handling input from the input - * port, and we don't want anything handling output from the output - * port. This stops the Generic MIDI UI event loop in ardour from - * attempting to handle these ports. - */ - - _input_port->set_centrally_parsed (false); - _output_port->set_centrally_parsed (false); - - MIDI::Manager * mm = MIDI::Manager::instance(); - - mm->add_port (_input_port); - mm->add_port (_output_port); + _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, string_compose (_("%1 in"), _surface->name()), true); + _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, string_compose (_("%1 out"), _surface->name()), true); + + _input_port = boost::dynamic_pointer_cast(_async_in).get(); + _output_port = boost::dynamic_pointer_cast(_async_out).get(); } } @@ -86,17 +71,15 @@ SurfacePort::~SurfacePort() delete _input_port; } else { - MIDI::Manager* mm = MIDI::Manager::instance (); - - if (_input_port) { - mm->remove_port (_input_port); - delete _input_port; + if (_async_in) { + AudioEngine::instance()->unregister_port (_async_in); + _async_in.reset (); } - if (_output_port) { + if (_async_out) { _output_port->drain (10000); - mm->remove_port (_output_port); - delete _output_port; + AudioEngine::instance()->unregister_port (_async_out); + _async_out.reset (); } } } diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h index 7dc20a06f2..751ee848d7 100644 --- a/libs/surfaces/mackie/surface_port.h +++ b/libs/surfaces/mackie/surface_port.h @@ -21,16 +21,23 @@ #include #include "pbd/signals.h" + + #include "midi_byte_array.h" #include "types.h" namespace MIDI { - class Port; class Parser; + class Port; } class MackieControlProtocol; +namespace ARDOUR { + class AsyncMIDIPort; + class Port; +} + namespace Mackie { @@ -49,17 +56,17 @@ public: /// an easier way to output bytes via midi int write (const MidiByteArray&); - MIDI::Port& input_port() { return *_input_port; } - const MIDI::Port& input_port() const { return *_input_port; } - MIDI::Port& output_port() { return *_output_port; } - const MIDI::Port& output_port() const { return *_output_port; } + MIDI::Port& input_port() const { return *_input_port; } + MIDI::Port& output_port() const { return *_output_port; } protected: private: - Mackie::Surface* _surface; - MIDI::Port* _input_port; - MIDI::Port* _output_port; + Mackie::Surface* _surface; + MIDI::Port* _input_port; + MIDI::Port* _output_port; + boost::shared_ptr _async_in; + boost::shared_ptr _async_out; }; std::ostream& operator << (std::ostream& , const SurfacePort& port);