summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/async_midi_port.h6
-rw-r--r--libs/ardour/ardour/location.h11
-rw-r--r--libs/ardour/ardour/midi_scene_change.h63
-rw-r--r--libs/ardour/ardour/midi_scene_changer.h72
-rw-r--r--libs/ardour/ardour/midiport_manager.h12
-rw-r--r--libs/ardour/ardour/rc_configuration_vars.h1
-rw-r--r--libs/ardour/ardour/scene_changer.h56
-rw-r--r--libs/ardour/ardour/session.h50
-rw-r--r--libs/ardour/async_midi_port.cc19
-rw-r--r--libs/ardour/location.cc74
-rw-r--r--libs/ardour/midi_scene_change.cc144
-rw-r--r--libs/ardour/midi_scene_changer.cc279
-rw-r--r--libs/ardour/midi_ui.cc4
-rw-r--r--libs/ardour/midiport_manager.cc22
-rw-r--r--libs/ardour/session.cc4
-rw-r--r--libs/ardour/session_midi.cc24
-rw-r--r--libs/ardour/session_process.cc4
-rw-r--r--libs/ardour/session_state.cc12
-rw-r--r--libs/ardour/wscript3
-rw-r--r--libs/midi++2/channel.cc19
-rw-r--r--libs/midi++2/midi++/channel.h4
-rw-r--r--libs/midi++2/midi++/parser.h5
22 files changed, 852 insertions, 36 deletions
diff --git a/libs/ardour/ardour/async_midi_port.h b/libs/ardour/ardour/async_midi_port.h
index c5babf6135..26946e3016 100644
--- a/libs/ardour/ardour/async_midi_port.h
+++ b/libs/ardour/ardour/async_midi_port.h
@@ -22,6 +22,8 @@
#include <string>
#include <iostream>
+#include <boost/function.hpp>
+
#include "pbd/xml++.h"
#include "pbd/crossthread.h"
#include "pbd/signals.h"
@@ -64,6 +66,8 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
#endif
}
+ void set_timer (boost::function<framecnt_t (void)>&);
+
static void set_process_thread (pthread_t);
static pthread_t get_process_thread () { return _process_thread; }
static bool is_process_thread();
@@ -71,6 +75,8 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
private:
bool _currently_in_cycle;
MIDI::timestamp_t _last_write_timestamp;
+ bool have_timer;
+ boost::function<framecnt_t (void)> timer;
RingBuffer< Evoral::Event<double> > output_fifo;
Evoral::EventRingBuffer<MIDI::timestamp_t> input_fifo;
Glib::Threads::Mutex output_fifo_lock;
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index b0956eea36..6cea208f05 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -34,10 +34,13 @@
#include "pbd/statefuldestructible.h"
#include "ardour/ardour.h"
+#include "ardour/scene_change.h"
#include "ardour/session_handle.h"
namespace ARDOUR {
+class SceneChange;
+
class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDestructible
{
public:
@@ -93,6 +96,9 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
Flags flags () const { return _flags; }
+ boost::shared_ptr<SceneChange> scene_change() const { return _scene_change; }
+ void set_scene_change (boost::shared_ptr<SceneChange>);
+
PBD::Signal1<void,Location*> name_changed;
PBD::Signal1<void,Location*> end_changed;
PBD::Signal1<void,Location*> start_changed;
@@ -116,6 +122,8 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
void set_position_lock_style (PositionLockStyle ps);
void recompute_frames_from_bbt ();
+ static PBD::Signal0<void> scene_changed;
+
private:
std::string _name;
framepos_t _start;
@@ -125,6 +133,7 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
Flags _flags;
bool _locked;
PositionLockStyle _position_lock_style;
+ boost::shared_ptr<SceneChange> _scene_change;
void set_mark (bool yn);
bool set_flag_internal (bool yn, Flags flag);
@@ -161,6 +170,8 @@ class LIBARDOUR_API Locations : public SessionHandleRef, public PBD::StatefulDes
int set_current (Location *, bool want_lock = true);
Location *current () const { return current_location; }
+ Location* mark_at (framepos_t, framecnt_t slop = 0) const;
+
framepos_t first_mark_before (framepos_t, bool include_special_ranges = false);
framepos_t first_mark_after (framepos_t, bool include_special_ranges = false);
diff --git a/libs/ardour/ardour/midi_scene_change.h b/libs/ardour/ardour/midi_scene_change.h
new file mode 100644
index 0000000000..86793c57fb
--- /dev/null
+++ b/libs/ardour/ardour/midi_scene_change.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2014 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_midi_scene_change_h__
+#define __libardour_midi_scene_change_h__
+
+#include "evoral/PatchChange.hpp"
+
+#include "ardour/scene_change.h"
+
+namespace ARDOUR
+{
+
+class MidiPort;
+
+class MIDISceneChange : public SceneChange
+{
+ public:
+ MIDISceneChange (framepos_t time, int channel, int bank = -1, int program = -1);
+ MIDISceneChange (const XMLNode&, int version);
+ ~MIDISceneChange ();
+
+ void set_channel (int channel);
+ void set_program (int program);
+ void set_bank (int bank);
+
+ int channel () const { return _channel; }
+ int program () const { return _program; }
+ int bank () const { return _bank; }
+
+ size_t get_bank_msb_message (uint8_t* buf, size_t size) const;
+ size_t get_bank_lsb_message (uint8_t* buf, size_t size) const;
+ size_t get_program_message (uint8_t* buf, size_t size) const;
+
+ XMLNode& get_state();
+ int set_state (const XMLNode&, int version);
+
+ private:
+ int _bank;
+ int _program;
+ uint8_t _channel;
+};
+
+} /* namespace */
+
+
+#endif /* __libardour_scene_change_h__ */
diff --git a/libs/ardour/ardour/midi_scene_changer.h b/libs/ardour/ardour/midi_scene_changer.h
new file mode 100644
index 0000000000..2cc0464bec
--- /dev/null
+++ b/libs/ardour/ardour/midi_scene_changer.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2014 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_midi_scene_changer_h__
+#define __libardour_midi_scene_changer_h__
+
+#include "ardour/scene_changer.h"
+
+namespace ARDOUR
+{
+
+class MIDISceneChanger : public SceneChanger
+{
+ public:
+ MIDISceneChanger (Session&);
+ ~MIDISceneChanger ();
+
+ void run (framepos_t start, framepos_t end);
+ void set_input_port (MIDI::Port*);
+ void set_output_port (boost::shared_ptr<MidiPort>);
+
+ uint8_t bank_at (framepos_t, uint8_t channel);
+ uint8_t program_at (framepos_t, uint8_t channel);
+
+ void set_recording (bool);
+ void locate (framepos_t);
+
+ private:
+ typedef std::multimap<framepos_t,boost::shared_ptr<MIDISceneChange> > Scenes;
+
+ MIDI::Port* input_port;
+ boost::shared_ptr<MidiPort> output_port;
+ Scenes scenes;
+ bool _recording;
+ framepos_t last_bank_message_time;
+ framepos_t last_program_message_time;
+ unsigned short current_bank;
+ int last_delivered_program;
+ int last_delivered_bank;
+
+ void gather ();
+ bool recording () const;
+ void jump_to (int bank, int program);
+ void deliver (MidiBuffer&, framepos_t, boost::shared_ptr<MIDISceneChange>);
+
+ void bank_change_input (MIDI::Parser&, unsigned short);
+ void program_change_input (MIDI::Parser&, MIDI::byte);
+ void locations_changed (Locations::Change);
+
+ PBD::ScopedConnection incoming_bank_change_connection;
+ PBD::ScopedConnection incoming_program_change_connection;
+};
+
+} // namespace
+
+#endif /* __libardour_midi_scene_changer_h__ */
diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h
index b5b46e8510..5e87238c22 100644
--- a/libs/ardour/ardour/midiport_manager.h
+++ b/libs/ardour/ardour/midiport_manager.h
@@ -30,6 +30,7 @@
#include "midi++/port.h"
#include "ardour/libardour_visibility.h"
+#include "ardour/midi_port.h"
#include "ardour/types.h"
namespace ARDOUR {
@@ -56,7 +57,12 @@ class LIBARDOUR_API MidiPortManager {
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; }
+ MIDI::Port* scene_input_port () const { return _scene_input_port; }
+ MIDI::Port* scene_output_port () const { return _scene_output_port; }
+ boost::shared_ptr<MidiPort> scene_in() const { return boost::dynamic_pointer_cast<MidiPort>(_scene_in); }
+ boost::shared_ptr<MidiPort> scene_out() const { return boost::dynamic_pointer_cast<MidiPort>(_scene_out); }
+
/* Ports used for synchronization. These have their I/O handled inside the
* process callback.
*/
@@ -77,13 +83,17 @@ class LIBARDOUR_API MidiPortManager {
MIDI::Port* _midi_output_port;
MIDI::Port* _mmc_input_port;
MIDI::Port* _mmc_output_port;
- /* these point to the same objects as the 4 members above,
+ MIDI::Port* _scene_input_port;
+ MIDI::Port* _scene_output_port;
+ /* these point to the same objects as the members above,
but cast to their ARDOUR::Port base class
*/
boost::shared_ptr<Port> _midi_in;
boost::shared_ptr<Port> _midi_out;
boost::shared_ptr<Port> _mmc_in;
boost::shared_ptr<Port> _mmc_out;
+ boost::shared_ptr<Port> _scene_in;
+ boost::shared_ptr<Port> _scene_out;
/* synchronously handled ports: ARDOUR::MidiPort */
boost::shared_ptr<MidiPort> _mtc_input_port;
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index d290d8ebc8..4401b1f74c 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -44,6 +44,7 @@ CONFIG_VARIABLE (int32_t, mmc_receive_device_id, "mmc-receive-device-id", 0x7f)
CONFIG_VARIABLE (int32_t, mmc_send_device_id, "mmc-send-device-id", 0)
CONFIG_VARIABLE (int32_t, initial_program_change, "initial-program-change", -1)
CONFIG_VARIABLE (bool, first_midi_bank_is_zero, "display-first-midi-bank-as-zero", false)
+CONFIG_VARIABLE (int32_t, inter_scene_gap_msecs, "inter-scene-gap-msecs", 1)
/* Timecode and related */
diff --git a/libs/ardour/ardour/scene_changer.h b/libs/ardour/ardour/scene_changer.h
new file mode 100644
index 0000000000..d5ba984e92
--- /dev/null
+++ b/libs/ardour/ardour/scene_changer.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2014 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_scene_changer_h__
+#define __libardour_scene_changer_h__
+
+#include <map>
+
+#include "pbd/signals.h"
+
+#include "ardour/location.h"
+#include "ardour/midi_scene_change.h"
+#include "ardour/session_handle.h"
+#include "ardour/types.h"
+
+namespace MIDI
+{
+class Parser;
+class Port;
+}
+
+namespace ARDOUR
+{
+
+class Session;
+class AsyncMidiPort;
+
+class SceneChanger : public SessionHandleRef
+{
+ public:
+ SceneChanger (Session& s) : SessionHandleRef (s) {}
+ virtual ~SceneChanger () {};
+
+ virtual void run (framepos_t start, framepos_t end) = 0;
+};
+
+} /* namespace */
+
+
+#endif /* __libardour_scene_change_h__ */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 15af67ada7..40ada138a6 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -129,6 +129,7 @@ class Route;
class RouteGroup;
class SMFSource;
class Send;
+class SceneChanger;
class SessionDirectory;
class SessionMetadata;
class SessionPlaylists;
@@ -868,23 +869,31 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
*/
static PBD::Signal2<void,std::string,std::string> VersionMismatch;
+ SceneChanger* scene_changer() const { return _scene_changer; }
+
boost::shared_ptr<Port> ltc_input_port() const;
boost::shared_ptr<Port> ltc_output_port() const;
boost::shared_ptr<IO> ltc_input_io() { return _ltc_input; }
boost::shared_ptr<IO> ltc_output_io() { return _ltc_output; }
- MIDI::Port* midi_input_port () const;
- MIDI::Port* midi_output_port () const;
- MIDI::Port* mmc_output_port () const;
- MIDI::Port* mmc_input_port () const;
+ MIDI::Port* midi_input_port () const;
+ MIDI::Port* midi_output_port () const;
+ MIDI::Port* mmc_output_port () const;
+ MIDI::Port* mmc_input_port () const;
- boost::shared_ptr<MidiPort> midi_clock_output_port () const;
- boost::shared_ptr<MidiPort> midi_clock_input_port () const;
- boost::shared_ptr<MidiPort> mtc_output_port () const;
- boost::shared_ptr<MidiPort> mtc_input_port () const;
+ MIDI::Port* scene_input_port () const;
+ MIDI::Port* scene_output_port () const;
- MIDI::MachineControl& mmc() { return *_mmc; }
+ boost::shared_ptr<MidiPort> scene_in () const;
+ boost::shared_ptr<MidiPort> scene_out () const;
+
+ boost::shared_ptr<MidiPort> midi_clock_output_port () const;
+ boost::shared_ptr<MidiPort> midi_clock_input_port () const;
+ boost::shared_ptr<MidiPort> mtc_output_port () const;
+ boost::shared_ptr<MidiPort> mtc_input_port () const;
+
+ MIDI::MachineControl& mmc() { return *_mmc; }
protected:
friend class AudioEngine;
@@ -1607,16 +1616,19 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
void reconnect_ltc_input ();
void reconnect_ltc_output ();
- /* persistent, non-track related MIDI ports */
- MidiPortManager* _midi_ports;
- MIDI::MachineControl* _mmc;
-
- void setup_ltc ();
- void setup_click ();
- void setup_click_state (const XMLNode*);
- void setup_bundles ();
-
- static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath);
+ /* Scene Changing */
+ SceneChanger* _scene_changer;
+
+ /* persistent, non-track related MIDI ports */
+ MidiPortManager* _midi_ports;
+ MIDI::MachineControl* _mmc;
+
+ void setup_ltc ();
+ void setup_click ();
+ void setup_click_state (const XMLNode*);
+ void setup_bundles ();
+
+ static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath);
};
} // namespace ARDOUR
diff --git a/libs/ardour/async_midi_port.cc b/libs/ardour/async_midi_port.cc
index bd583328c3..21b59dec00 100644
--- a/libs/ardour/async_midi_port.cc
+++ b/libs/ardour/async_midi_port.cc
@@ -50,6 +50,7 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
, MIDI::Port (name, MIDI::Port::Flags (0))
, _currently_in_cycle (false)
, _last_write_timestamp (0)
+ , have_timer (false)
, output_fifo (512)
, input_fifo (1024)
#ifndef PLATFORM_WINDOWS
@@ -63,6 +64,13 @@ AsyncMIDIPort::~AsyncMIDIPort ()
}
void
+AsyncMIDIPort::set_timer (boost::function<framecnt_t (void)>& f)
+{
+ timer = f;
+ have_timer = true;
+}
+
+void
AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
{
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
@@ -113,9 +121,18 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes)
if (ARDOUR::Port::receives_input()) {
MidiBuffer& mb (get_midi_buffer (nframes));
- pframes_t when = AudioEngine::instance()->sample_time_at_cycle_start();
+ framecnt_t when;
+
+ if (have_timer) {
+ when = timer ();
+ } else {
+ when = AudioEngine::instance()->sample_time_at_cycle_start();
+ }
for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
+ if (!have_timer) {
+ when += (*b).time();
+ }
input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer());
}
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index 2a27fc318a..90265af4e4 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -30,6 +30,7 @@
#include "pbd/enumwriter.h"
#include "ardour/location.h"
+#include "ardour/midi_scene_change.h"
#include "ardour/session.h"
#include "ardour/audiofilesource.h"
#include "ardour/tempo.h"
@@ -42,6 +43,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
+PBD::Signal0<void> Location::scene_changed;
+
Location::Location (Session& s)
: SessionHandleRef (s)
, _start (0)
@@ -87,6 +90,8 @@ Location::Location (const Location& other)
assert (_start >= 0);
assert (_end >= 0);
+
+ /* scene change is NOT COPIED */
}
Location::Location (Session& s, const XMLNode& node)
@@ -134,6 +139,8 @@ Location::operator= (const Location& other)
_bbt_end = other._bbt_end;
_flags = other._flags;
_position_lock_style = other._position_lock_style;
+
+ /* XXX need to copy scene change */
/* copy is not locked even if original was */
@@ -431,11 +438,15 @@ Location::get_state ()
node->add_property ("locked", (_locked ? "yes" : "no"));
node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
+ if (_scene_change) {
+ node->add_child_nocopy (_scene_change->get_state());
+ }
+
return *node;
}
int
-Location::set_state (const XMLNode& node, int /*version*/)
+Location::set_state (const XMLNode& node, int version)
{
const XMLProperty *prop;
@@ -521,6 +532,16 @@ Location::set_state (const XMLNode& node, int /*version*/)
_position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
}
+ XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
+
+ if (scene_child) {
+ _scene_change = SceneChange::factory (*scene_child, version);
+
+ if (_scene_change) {
+ _scene_change->set_time (_start);
+ }
+ }
+
recompute_bbt_from_frames ();
changed (this); /* EMIT SIGNAL */
@@ -581,6 +602,14 @@ Location::unlock ()
LockChanged (this);
}
+void
+Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
+{
+ _scene_change = sc;
+
+ scene_changed (); /* EMIT SIGNAL */
+}
+
/*---------------------------------------------------------------------- */
Locations::Locations (Session& s)
@@ -675,6 +704,7 @@ Locations::clear ()
++tmp;
if (!(*i)->is_session_range()) {
+ delete *i;
locations.erase (i);
}
@@ -700,6 +730,7 @@ Locations::clear_markers ()
++tmp;
if ((*i)->is_mark() && !(*i)->is_session_range()) {
+ delete *i;
locations.erase (i);
}
@@ -723,6 +754,7 @@ Locations::clear_ranges ()
++tmp;
if (!(*i)->is_mark()) {
+ delete *i;
locations.erase (i);
}
@@ -779,6 +811,7 @@ Locations::remove (Location *loc)
for (i = locations.begin(); i != locations.end(); ++i) {
if ((*i) == loc) {
+ delete *i;
locations.erase (i);
was_removed = true;
if (current_location == loc) {
@@ -972,6 +1005,44 @@ Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
return -1;
}
+Location*
+Locations::mark_at (framepos_t pos, framecnt_t slop) const
+{
+ Glib::Threads::Mutex::Lock lm (lock);
+ Location* closest = 0;
+ frameoffset_t mindelta = max_framepos;
+ frameoffset_t delta;
+
+ /* locations are not necessarily stored in linear time order so we have
+ * to iterate across all of them to find the one closest to a give point.
+ */
+
+ for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
+
+ if ((*i)->is_mark()) {
+ if (pos > (*i)->start()) {
+ delta = pos - (*i)->start();
+ } else {
+ delta = (*i)->start() - pos;
+ }
+
+ if (slop == 0 && delta == 0) {
+ /* special case: no slop, and direct hit for position */
+ return *i;
+ }
+
+ if (delta <= slop) {
+ if (delta < mindelta) {
+ closest = *i;
+ mindelta = delta;
+ }
+ }
+ }
+ }
+
+ return closest;
+}
+
framepos_t
Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
{
@@ -1146,3 +1217,4 @@ Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll,
}
}
}
+
diff --git a/libs/ardour/midi_scene_change.cc b/libs/ardour/midi_scene_change.cc
new file mode 100644
index 0000000000..81a74911a9
--- /dev/null
+++ b/libs/ardour/midi_scene_change.cc
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2014 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "pbd/error.h"
+#include "pbd/compose.h"
+
+#include "ardour/midi_port.h"
+#include "ardour/midi_scene_change.h"
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+MIDISceneChange::MIDISceneChange (framepos_t time, int c, int b, int p)
+ : SceneChange (time)
+ , _bank (b)
+ , _program (p)
+ , _channel (c & 0xf)
+{
+ if (_bank > 16384) {
+ _bank = -1;
+ }
+
+ if (_program > 128) {
+ _program = -1;
+ }
+}
+
+MIDISceneChange::MIDISceneChange (const XMLNode& node, int version)
+ : SceneChange (0)
+ , _bank (-1)
+ , _program (-1)
+ , _channel (-1)
+{
+ set_state (node, version);
+}
+
+MIDISceneChange::~MIDISceneChange ()
+{
+}
+
+size_t
+MIDISceneChange::get_bank_msb_message (uint8_t* buf, size_t size) const
+{
+ if (size < 3 || _bank < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xB0 | (_channel & 0xf);
+ buf[1] = 0x0;
+ buf[2] = (_bank & 0xf700) >> 8;
+
+ return 3;
+}
+
+size_t
+MIDISceneChange::get_bank_lsb_message (uint8_t* buf, size_t size) const
+{
+ if (size < 3 || _bank < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xB0 | (_channel & 0xf);
+ buf[1] = 0x20;
+ buf[2] = (_bank & 0xf7);
+
+ return 3;
+}
+
+size_t
+MIDISceneChange::get_program_message (uint8_t* buf, size_t size) const
+{
+ if (size < 2 || _program < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xC0 | (_channel & 0xf);
+ buf[1] = _program & 0xf7;
+
+ return 2;
+}
+
+XMLNode&
+MIDISceneChange::get_state ()
+{
+ char buf[32];
+ XMLNode* node = new XMLNode (SceneChange::xml_node_name);
+
+ node->add_property (X_("type"), X_("MIDI"));
+ snprintf (buf, sizeof (buf), "%d", (int) _program);
+ node->add_property (X_("id"), id().to_s());
+ snprintf (buf, sizeof (buf), "%d", (int) _program);
+ node->add_property (X_("program"), buf);
+ snprintf (buf, sizeof (buf), "%d", (int) _bank);
+ node->add_property (X_("bank"), buf);
+ snprintf (buf, sizeof (buf), "%d", (int) _channel);
+ node->add_property (X_("channel"), buf);
+
+ return *node;
+}
+
+int
+MIDISceneChange::set_state (const XMLNode& node, int /* version-ignored */)
+{
+ if (!set_id (node)) {
+ return -1;
+ }
+
+ const XMLProperty* prop;
+
+ if ((prop = node.property (X_("program"))) == 0) {
+ return -1;
+ }
+ _program = atoi (prop->value());
+
+ if ((prop = node.property (X_("bank"))) == 0) {
+ return -1;
+ }
+ _bank = atoi (prop->value());
+
+ if ((prop = node.property (X_("channel"))) == 0) {
+ return -1;
+ }
+ _channel = atoi (prop->value());
+
+ return 0;
+}
diff --git a/libs/ardour/midi_scene_changer.cc b/libs/ardour/midi_scene_changer.cc
new file mode 100644
index 0000000000..49e835ca80
--- /dev/null
+++ b/libs/ardour/midi_scene_changer.cc
@@ -0,0 +1,279 @@
+/*
+ Copyright (C) 2014 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "evoral/MIDIEvent.hpp"
+#include "midi++/parser.h"
+#include "midi++/port.h"
+
+#include "ardour/event_type_map.h"
+#include "ardour/midi_port.h"
+#include "ardour/midi_scene_change.h"
+#include "ardour/midi_scene_changer.h"
+#include "ardour/session.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+
+MIDISceneChanger::MIDISceneChanger (Session& s)
+ : SceneChanger (s)
+ , _recording (true)
+ , last_bank_message_time (-1)
+ , last_program_message_time (-1)
+ , last_delivered_program (-1)
+ , last_delivered_bank (-1)
+
+{
+ _session.locations()->changed.connect_same_thread (*this, boost::bind (&MIDISceneChanger::locations_changed, this, _1));
+ Location::scene_changed.connect_same_thread (*this, boost::bind (&MIDISceneChanger::gather, this));
+}
+
+MIDISceneChanger::~MIDISceneChanger ()
+{
+}
+
+void
+MIDISceneChanger::locations_changed (Locations::Change)
+{
+ gather ();
+}
+
+/** Use the session's list of locations to collect all patch changes.
+ *
+ * This is called whenever the locations change in anyway.
+ */
+void
+MIDISceneChanger::gather ()
+{
+ const Locations::LocationList& locations (_session.locations()->list());
+ boost::shared_ptr<SceneChange> sc;
+
+ scenes.clear ();
+
+ for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) {
+
+ if ((sc = (*l)->scene_change()) != 0) {
+
+ boost::shared_ptr<MIDISceneChange> msc = boost::dynamic_pointer_cast<MIDISceneChange> (sc);
+
+ if (msc) {
+ scenes.insert (std::make_pair (msc->time(), msc));
+ }
+ }
+ }
+}
+
+void
+MIDISceneChanger::deliver (MidiBuffer& mbuf, framepos_t when, boost::shared_ptr<MIDISceneChange> msc)
+{
+ uint8_t buf[4];
+ size_t cnt;
+
+ if ((cnt = msc->get_bank_msb_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+
+ if ((cnt = msc->get_bank_lsb_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+ }
+
+ last_delivered_bank = msc->bank();
+ }
+
+ if ((cnt = msc->get_program_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+
+ last_delivered_program = msc->program();
+ }
+}
+
+
+void
+MIDISceneChanger::run (framepos_t start, framepos_t end)
+{
+ if (!output_port || recording()) {
+ return;
+ }
+
+ /* get lower bound of events to consider */
+
+ Scenes::const_iterator i = scenes.lower_bound (start);
+ MidiBuffer& mbuf (output_port->get_midi_buffer (end-start));
+
+ while (i != scenes.end()) {
+
+ if (i->first >= end) {
+ break;
+ }
+
+ deliver (mbuf, i->first - start, i->second);
+
+ ++i;
+ }
+}
+
+void
+MIDISceneChanger::locate (framepos_t pos)
+{
+ Scenes::const_iterator i = scenes.upper_bound (pos);
+
+ if (i == scenes.end()) {
+ return;
+ }
+
+ if (i->second->program() != last_delivered_program || i->second->bank() != last_delivered_bank) {
+ // MidiBuffer& mbuf (output_port->get_midi_buffer (end-start));
+ // deliver (mbuf, i->first, i->second);
+ }
+}
+
+void
+MIDISceneChanger::set_input_port (MIDI::Port* mp)
+{
+ input_port = mp;
+
+ incoming_bank_change_connection.disconnect ();
+ incoming_program_change_connection.disconnect ();
+
+ if (input_port) {
+
+ /* midi port is asynchronous. MIDI parsing will be carried out
+ * by the MIDI UI thread which will emit the relevant signals
+ * and thus invoke our callbacks as necessary.
+ */
+
+ input_port->parser()->bank_change.connect_same_thread (incoming_bank_change_connection, boost::bind (&MIDISceneChanger::bank_change_input, this, _1, _2));
+ input_port->parser()->program_change.connect_same_thread (incoming_program_change_connection, boost::bind (&MIDISceneChanger::program_change_input, this, _1, _2));
+ }
+}
+
+void
+MIDISceneChanger::set_output_port (boost::shared_ptr<MidiPort> mp)
+{
+ output_port = mp;
+}
+
+void
+MIDISceneChanger::set_recording (bool yn)
+{
+ _recording = yn;
+}
+
+bool
+MIDISceneChanger::recording() const
+{
+ return _session.transport_rolling() && _session.get_record_enabled();
+}
+
+void
+MIDISceneChanger::bank_change_input (MIDI::Parser& parser, unsigned short bank)
+{
+ if (!recording()) {
+ return;
+ }
+
+ last_bank_message_time = parser.get_timestamp ();
+ current_bank = bank;
+}
+
+void
+MIDISceneChanger::program_change_input (MIDI::Parser& parser, MIDI::byte program)
+{
+ framecnt_t time = parser.get_timestamp ();
+ frameoffset_t delta = time - last_program_message_time;
+
+ last_program_message_time = time;
+
+ if (!recording()) {
+ jump_to (current_bank, program);
+ return;
+ }
+
+ Locations* locations (_session.locations ());
+ Location* loc;
+ bool new_mark = false;
+ framecnt_t slop = (framecnt_t) floor ((Config->get_inter_scene_gap_msecs() / 1000.0) * _session.frame_rate());
+
+ /* check for marker at current location */
+
+ loc = locations->mark_at (time, slop);
+
+ if (!loc) {
+ /* create a new marker at the desired position */
+
+ std::string new_name;
+
+ if (!locations->next_available_name (new_name, _("Scene "))) {
+ std::cerr << "No new marker name available\n";
+ return;
+ }
+
+ loc = new Location (_session, time, time, new_name, Location::IsMark);
+ new_mark = true;
+ }
+
+ uint8_t bank;
+ uint8_t channel = (program & 0xf0) >> 8;
+
+ /* if we received a bank change message within the last 2 msec, use the
+ * current bank value, otherwise lookup the current bank number and use
+ * that.
+ */
+
+ if (time - last_bank_message_time < (2 * _session.frame_rate() / 1000.0)) {
+ bank = current_bank;
+ } else {
+ bank = -1;
+ }
+
+ MIDISceneChange* msc =new MIDISceneChange (loc->start(), channel, bank, program & 0x7f);
+
+ loc->set_scene_change (boost::shared_ptr<MIDISceneChange> (msc));
+
+ /* this will generate a "changed" signal to be emitted by locations,
+ and we will call ::gather() to update our list of MIDI events.
+ */
+
+ if (new_mark) {
+ locations->add (loc);
+ }
+}
+
+void
+MIDISceneChanger::jump_to (int bank, int program)
+{
+ const Locations::LocationList& locations (_session.locations()->list());
+ boost::shared_ptr<SceneChange> sc;
+ framepos_t where = max_framepos;
+
+ for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) {
+
+ if ((sc = (*l)->scene_change()) != 0) {
+
+ boost::shared_ptr<MIDISceneChange> msc = boost::dynamic_pointer_cast<MIDISceneChange> (sc);
+
+ if (msc->bank() == bank && msc->program() == program && (*l)->start() < where) {
+ where = (*l)->start();
+ }
+ }
+ }
+
+ if (where != max_framepos) {
+ _session.request_locate (where);
+ }
+}
diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc
index 97dfdce6bf..e00ec587ec 100644
--- a/libs/ardour/midi_ui.cc
+++ b/libs/ardour/midi_ui.cc
@@ -122,6 +122,10 @@ MidiControlUI::reset_ports ()
if ((p = dynamic_cast<AsyncMIDIPort*> (_session.mmc_input_port()))) {
ports.push_back (p);
}
+
+ if ((p = dynamic_cast<AsyncMIDIPort*> (_session.scene_input_port()))) {
+ ports.push_back (p);
+ }
if (ports.empty()) {
return;
diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc
index 6de0436586..b1699ca5ab 100644
--- a/libs/ardour/midiport_manager.cc
+++ b/libs/ardour/midiport_manager.cc
@@ -40,8 +40,14 @@ MidiPortManager::~MidiPortManager ()
if (_midi_in) {
AudioEngine::instance()->unregister_port (_midi_in);
}
- if (_midi_in) {
- AudioEngine::instance()->unregister_port (_midi_in);
+ if (_midi_out) {
+ AudioEngine::instance()->unregister_port (_midi_out);
+ }
+ if (_scene_in) {
+ AudioEngine::instance()->unregister_port (_scene_in);
+ }
+ if (_scene_out) {
+ AudioEngine::instance()->unregister_port (_scene_out);
}
if (_mtc_input_port) {
AudioEngine::instance()->unregister_port (_mtc_input_port);
@@ -73,7 +79,10 @@ MidiPortManager::create_ports ()
_mmc_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("MMC in"), true);
_mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("MMC out"), true);
-
+
+ _scene_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Scene in"), true);
+ _scene_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Scene out"), true);
+
/* XXX nasty type conversion needed because of the mixed inheritance
* required to integrate MIDI::IPMidiPort and ARDOUR::AsyncMIDIPort.
*
@@ -88,6 +97,9 @@ MidiPortManager::create_ports ()
_mmc_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_in).get();
_mmc_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_out).get();
+ _scene_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_scene_in).get();
+ _scene_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_scene_out).get();
+
/* Now register ports used for sync (MTC and MIDI Clock)
*/
@@ -129,6 +141,8 @@ MidiPortManager::set_midi_port_states (const XMLNodeList&nodes)
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
+ ports.insert (make_pair (_scene_output_port->name(), _scene_out));
+ ports.insert (make_pair (_scene_input_port->name(), _scene_in));
for (XMLNodeList::const_iterator n = nodes.begin(); n != nodes.end(); ++n) {
if ((prop = (*n)->property (X_("name"))) == 0) {
@@ -159,6 +173,8 @@ MidiPortManager::get_midi_port_states () const
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
+ ports.insert (make_pair (_scene_output_port->name(), _scene_out));
+ ports.insert (make_pair (_scene_input_port->name(), _scene_in));
for (PortMap::const_iterator p = ports.begin(); p != ports.end(); ++p) {
s.push_back (&p->second->get_state());
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 2aef745961..05fa883a9d 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -68,6 +68,7 @@
#include "ardour/filename_extensions.h"
#include "ardour/graph.h"
#include "ardour/midiport_manager.h"
+#include "ardour/scene_changer.h"
#include "ardour/midi_track.h"
#include "ardour/midi_ui.h"
#include "ardour/operations.h"
@@ -260,6 +261,7 @@ Session::Session (AudioEngine &eng,
, _speakers (new Speakers)
, _order_hint (0)
, ignore_route_processor_changes (false)
+ , _scene_changer (0)
, _midi_ports (0)
, _mmc (0)
{
@@ -547,6 +549,8 @@ Session::destroy ()
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();
+ delete _scene_changer; _scene_changer = 0;
+
delete _mmc; _mmc = 0;
delete _midi_ports; _midi_ports = 0;
delete _locations; _locations = 0;
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index ea6dfe81cf..93df1fc946 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -644,3 +644,27 @@ Session::mmc_input_port () const
{
return _midi_ports->mmc_input_port ();
}
+
+MIDI::Port*
+Session::scene_output_port () const
+{
+ return _midi_ports->scene_output_port ();
+}
+
+MIDI::Port*
+Session::scene_input_port () const
+{
+ return _midi_ports->scene_input_port ();
+}
+
+boost::shared_ptr<MidiPort>
+Session::scene_in () const
+{
+ return _midi_ports->scene_in ();
+}
+
+boost::shared_ptr<MidiPort>
+Session::scene_out () const
+{
+ return _midi_ports->scene_out ();
+}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index eb5c0de294..680f2861de 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -35,6 +35,7 @@
#include "ardour/graph.h"
#include "ardour/port.h"
#include "ardour/process_thread.h"
+#include "ardour/scene_changer.h"
#include "ardour/session.h"
#include "ardour/slave.h"
#include "ardour/ticker.h"
@@ -86,6 +87,9 @@ Session::process (pframes_t nframes)
if (!_silent && !_engine.freewheeling() && Config->get_send_midi_clock() && (transport_speed() == 1.0f || transport_speed() == 0.0f) && midi_clock->has_midi_port()) {
midi_clock->tick (transport_at_start, nframes);
}
+
+ _scene_changer->run (transport_at_start, transport_at_start + nframes);
+
} catch (...) {
/* don't bother with a message */
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 07f10e9bc1..6a06863e9e 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -77,6 +77,7 @@
#include "pbd/localtime_r.h"
#include "ardour/amp.h"
+#include "ardour/async_midi_port.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audio_track.h"
#include "ardour/audioengine.h"
@@ -92,6 +93,7 @@
#include "ardour/midi_model.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/midi_region.h"
+#include "ardour/midi_scene_changer.h"
#include "ardour/midi_source.h"
#include "ardour/midi_track.h"
#include "ardour/pannable.h"
@@ -207,6 +209,16 @@ Session::post_engine_init ()
BootMessage (_("Using configuration"));
_midi_ports = new MidiPortManager;
+
+ MIDISceneChanger* msc;
+
+ _scene_changer = msc = new MIDISceneChanger (*this);
+ msc->set_input_port (scene_input_port());
+ msc->set_output_port (scene_out());
+
+ boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
+ boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
+
setup_midi_machine_control ();
if (_butler->start_thread()) {
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index c12aec4ef8..0046e2eaec 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -119,6 +119,8 @@ libardour_sources = [
'midi_port.cc',
'midi_region.cc',
'midi_ring_buffer.cc',
+ 'midi_scene_change.cc',
+ 'midi_scene_changer.cc',
'midi_source.cc',
'midi_state_tracker.cc',
'midi_stretch.cc',
@@ -164,6 +166,7 @@ libardour_sources = [
'route_group.cc',
'route_group_member.cc',
'rb_effect.cc',
+ 'scene_change.cc',
'search_paths.cc',
'send.cc',
'session.cc',
diff --git a/libs/midi++2/channel.cc b/libs/midi++2/channel.cc
index ed8f4da5bc..190ea18568 100644
--- a/libs/midi++2/channel.cc
+++ b/libs/midi++2/channel.cc
@@ -115,7 +115,7 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
all changes *are* atomic.
*/
- if (tb->controller_number <= 31) { /* unsigned: no test for >= 0 */
+ if (tb->controller_number < 32) { /* unsigned: no test for >= 0 */
/* if this controller is already known to use 14 bits,
then treat this value as the MSB, and combine it
@@ -128,7 +128,7 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
cv = (unsigned short) _controller_val[tb->controller_number];
if (_controller_14bit[tb->controller_number]) {
- cv = ((tb->value << 7) | (cv & 0x7f));
+ cv = ((tb->value & 0x7f) << 7) | (cv & 0x7f);
} else {
cv = tb->value;
}
@@ -160,8 +160,14 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
cv = (cv & 0x3f80) | (tb->value & 0x7f);
}
- _controller_val[tb->controller_number] =
- (controller_value_t) cv;
+ /* update the 14 bit value */
+ _controller_val[cn] = (controller_value_t) cv;
+
+ /* also store the "raw" 7 bit value in the incoming controller
+ value store
+ */
+ _controller_val[tb->controller_number] = (controller_value_t) tb->value;
+
} else {
/* controller can only take 7 bit values */
@@ -173,12 +179,11 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
/* bank numbers are special, in that they have their own signal
*/
- if (tb->controller_number == 0) {
- _bank_number = (unsigned short) _controller_val[0];
+ if (tb->controller_number == 0 || tb->controller_number == 0x20) {
+ _bank_number = _controller_val[0];
_port.parser()->bank_change (*_port.parser(), _bank_number);
_port.parser()->channel_bank_change[_channel_number] (*_port.parser(), _bank_number);
}
-
}
void
diff --git a/libs/midi++2/midi++/channel.h b/libs/midi++2/midi++/channel.h
index 02c16e6729..f3ec434ca5 100644
--- a/libs/midi++2/midi++/channel.h
+++ b/libs/midi++2/midi++/channel.h
@@ -42,7 +42,7 @@ class LIBMIDIPP_API Channel : public PBD::ScopedConnectionList {
Port &midi_port() { return _port; }
byte channel() { return _channel_number; }
byte program() { return _program_number; }
- byte bank() { return _bank_number; }
+ unsigned short bank() { return _bank_number; }
byte pressure () { return _chanpress; }
byte poly_pressure (byte n) { return _polypress[n]; }
@@ -117,7 +117,7 @@ class LIBMIDIPP_API Channel : public PBD::ScopedConnectionList {
/* Current channel values */
byte _channel_number;
- byte _bank_number;
+ unsigned short _bank_number;
byte _program_number;
byte _rpn_msb;
byte _rpn_lsb;
diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h
index e4126b210b..420e7fcb7b 100644
--- a/libs/midi++2/midi++/parser.h
+++ b/libs/midi++2/midi++/parser.h
@@ -34,6 +34,7 @@ class Port;
class Parser;
typedef PBD::Signal1<void,Parser&> ZeroByteSignal;
+typedef PBD::Signal2<void,Parser&,unsigned short> BankSignal;
typedef PBD::Signal2<void,Parser&,framecnt_t> TimestampedSignal;
typedef PBD::Signal2<void,Parser&, byte> OneByteSignal;
typedef PBD::Signal2<void,Parser &, EventTwoBytes *> TwoByteSignal;
@@ -55,7 +56,7 @@ class LIBMIDIPP_API Parser {
/* signals that anyone can connect to */
- OneByteSignal bank_change;
+ BankSignal bank_change;
TwoByteSignal note_on;
TwoByteSignal note_off;
TwoByteSignal poly_pressure;
@@ -64,7 +65,7 @@ class LIBMIDIPP_API Parser {
PitchBendSignal pitchbend;
TwoByteSignal controller;
- OneByteSignal channel_bank_change[16];
+ BankSignal channel_bank_change[16];
TwoByteSignal channel_note_on[16];
TwoByteSignal channel_note_off[16];
TwoByteSignal channel_poly_pressure[16];