summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/midi_channel_selector.cc143
-rw-r--r--gtk2_ardour/midi_channel_selector.h25
-rw-r--r--gtk2_ardour/midi_region_view.cc14
-rw-r--r--gtk2_ardour/midi_region_view.h2
-rw-r--r--gtk2_ardour/midi_time_axis.cc4
-rw-r--r--gtk2_ardour/midi_time_axis.h8
-rw-r--r--libs/ardour/ardour/midi_diskstream.h12
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h50
-rw-r--r--libs/ardour/midi_diskstream.cc9
9 files changed, 230 insertions, 37 deletions
diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc
index b0bf73c2a1..b810268633 100644
--- a/gtk2_ardour/midi_channel_selector.cc
+++ b/gtk2_ardour/midi_channel_selector.cc
@@ -8,7 +8,7 @@ using namespace Gtk;
using namespace sigc;
MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_row, int start_column) :
- Table(no_rows, no_columns, true)
+ Table(no_rows, no_columns, true), _recursion_counter(0)
{
assert(no_rows >= 4);
assert(no_rows >= start_row + 4);
@@ -46,28 +46,37 @@ MidiChannelSelector::~MidiChannelSelector()
SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
: MidiChannelSelector()
{
- _active_button = 0;
+ _last_active_button = 0;
ToggleButton *button = &_buttons[active_channel / 4][active_channel % 4];
- button->set_active(true);
- _active_button = button;
_active_channel = active_channel;
+ button->set_active(true);
+ _last_active_button = button;
}
void
SingleMidiChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
-{
- if(button->get_active()) {
- if(_active_button) {
- _active_button->set_active(false);
+{
+ ++_recursion_counter;
+ if(_recursion_counter == 1) {
+ // if the current button is active it must
+ // be different from the first one
+ if(button->get_active()) {
+ if(_last_active_button) {
+ _last_active_button->set_active(false);
+ _active_channel = channel;
+ _last_active_button = button;
+ }
+ } else {
+ // if not, the user pressed the already active button
+ button->set_active(true);
+ _active_channel = channel;
}
- _active_button = button;
- _active_channel = channel;
- channel_selected.emit(channel);
- }
+ }
+ --_recursion_counter;
}
MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_selection)
- : MidiChannelSelector(4, 6, 0, 0)
+ : MidiChannelSelector(4, 6, 0, 0), _mode(FILTERING_MULTIPLE_CHANNELS)
{
_select_all.add(*manage(new Label(_("All"))));
_select_all.signal_clicked().connect(
@@ -82,6 +91,8 @@ MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_select
mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
_force_channel.add(*manage(new Label(_("Force"))));
+ _force_channel.signal_toggled().connect(
+ mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
set_homogeneous(false);
attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
@@ -91,10 +102,53 @@ MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_select
attach(_invert_selection, 5, 6, 2, 3);
attach(_force_channel, 5, 6, 3, 4);
- _selected_channels = 0;
+ set_selected_channels(initial_selection);
+}
+
+MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
+{
+ selection_changed.clear();
+ force_channel_changed.clear();
+}
+
+const int8_t
+MidiMultipleChannelSelector::get_force_channel() const
+{
+ if(_mode == FORCING_SINGLE_CHANNEL) {
+ for(int8_t i = 0; i < 16; i++) {
+ const ToggleButton *button = &_buttons[i / 4][i % 4];
+ if(button->get_active()) {
+ return i;
+ }
+ }
+
+ // this point should not be reached.
+ assert(false);
+ }
+
+ return -1;
+}
+
+const uint16_t
+MidiMultipleChannelSelector::get_selected_channels() const
+{
+ uint16_t selected_channels = 0;
+ for(uint16_t i = 0; i < 16; i++) {
+ const ToggleButton *button = &_buttons[i / 4][i % 4];
+ if(button->get_active()) {
+ selected_channels |= (1L << i);
+ }
+ }
+
+ return selected_channels;
+}
+
+void
+MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
+{
for(uint16_t i = 0; i < 16; i++) {
ToggleButton *button = &_buttons[i / 4][i % 4];
- if(initial_selection & (1L << i)) {
+ if(selected_channels & (1L << i)) {
button->set_active(true);
} else {
button->set_active(false);
@@ -105,23 +159,73 @@ MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_select
void
MidiMultipleChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
{
- _selected_channels = _selected_channels ^ (1L << channel);
- selection_changed.emit(_selected_channels);
+ ++_recursion_counter;
+ if(_recursion_counter == 1) {
+ if(_mode == FORCING_SINGLE_CHANNEL) {
+ set_selected_channels(1 << channel);
+ }
+
+ force_channel_changed.emit(get_force_channel());
+ selection_changed.emit(get_selected_channels());
+ }
+ --_recursion_counter;
+}
+
+void
+MidiMultipleChannelSelector::force_channels_button_toggled()
+{
+ if(_force_channel.get_active()) {
+ _mode = FORCING_SINGLE_CHANNEL;
+ bool found_first_active = false;
+ // leave only the first button enabled
+ for(int i = 0; i <= 15; i++) {
+ ToggleButton *button = &_buttons[i / 4][i % 4];
+ if(button->get_active()) {
+ if(found_first_active) {
+ ++_recursion_counter;
+ button->set_active(false);
+ --_recursion_counter;
+ } else {
+ found_first_active = true;
+ }
+ }
+ }
+
+ if(!found_first_active) {
+ _buttons[0][0].set_active(true);
+ }
+
+ _select_all.set_sensitive(false);
+ _select_none.set_sensitive(false);
+ _invert_selection.set_sensitive(false);
+ force_channel_changed.emit(get_force_channel());
+ selection_changed.emit(get_selected_channels());
+ } else {
+ _mode = FILTERING_MULTIPLE_CHANNELS;
+ _select_all.set_sensitive(true);
+ _select_none.set_sensitive(true);
+ _invert_selection.set_sensitive(true);
+ force_channel_changed.emit(get_force_channel());
+ selection_changed.emit(get_selected_channels());
+ }
}
void
MidiMultipleChannelSelector::select_all(bool on)
{
+ ++_recursion_counter;
for(uint16_t i = 0; i < 16; i++) {
ToggleButton *button = &_buttons[i / 4][i % 4];
button->set_active(on);
}
- selection_changed.emit(_selected_channels);
+ --_recursion_counter;
+ selection_changed.emit(get_selected_channels());
}
void
MidiMultipleChannelSelector::invert_selection(void)
{
+ ++_recursion_counter;
for(uint16_t i = 0; i < 16; i++) {
ToggleButton *button = &_buttons[i / 4][i % 4];
if(button->get_active()) {
@@ -130,6 +234,7 @@ MidiMultipleChannelSelector::invert_selection(void)
button->set_active(true);
}
}
- selection_changed.emit(_selected_channels);
+ --_recursion_counter;
+ selection_changed.emit(get_selected_channels());
}
diff --git a/gtk2_ardour/midi_channel_selector.h b/gtk2_ardour/midi_channel_selector.h
index 33eb3f6b75..901296903c 100644
--- a/gtk2_ardour/midi_channel_selector.h
+++ b/gtk2_ardour/midi_channel_selector.h
@@ -19,6 +19,7 @@ protected:
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr) = 0;
Gtk::Label _button_labels[4][4];
Gtk::ToggleButton _buttons[4][4];
+ int _recursion_counter;
};
class SingleMidiChannelSelector : public MidiChannelSelector
@@ -33,7 +34,7 @@ public:
protected:
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
- Gtk::ToggleButton *_active_button;
+ Gtk::ToggleButton *_last_active_button;
uint8_t _active_channel;
};
@@ -41,13 +42,30 @@ class MidiMultipleChannelSelector : public MidiChannelSelector
{
public:
MidiMultipleChannelSelector(uint16_t initial_selection = 1);
+ virtual ~MidiMultipleChannelSelector();
- const uint16_t get_selected_channels() const { return _selected_channels; }
+ /**
+ * @return each bit in the returned word represents a midi channel, eg.
+ * bit 0 represents channel 0 and bit 15 represents channel 15
+ *
+ */
+ const uint16_t get_selected_channels() const;
+ void set_selected_channels(uint16_t selected_channels);
sigc::signal<void, uint16_t> selection_changed;
-
+ sigc::signal<void, int8_t> force_channel_changed;
+
+ const int8_t get_force_channel() const;
protected:
+ enum Mode {
+ FILTERING_MULTIPLE_CHANNELS,
+ FORCING_SINGLE_CHANNEL
+ };
+
+ Mode _mode;
+
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
+ void force_channels_button_toggled();
void select_all(bool on);
void invert_selection(void);
@@ -56,7 +74,6 @@ protected:
Gtk::Button _select_none;
Gtk::Button _invert_selection;
Gtk::ToggleButton _force_channel;
- uint16_t _selected_channels;
};
#endif /*__ardour_ui_midi_channel_selector_h__*/
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 6fa98e0b96..36defd7a57 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -60,6 +60,7 @@ using namespace ArdourCanvas;
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color)
: RegionView (parent, tv, r, spu, basic_color)
+ , force_channel(-1)
, last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _active_notes(0)
@@ -76,6 +77,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
: RegionView (parent, tv, r, spu, basic_color, visibility)
+ , force_channel(-1)
, last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _active_notes(0)
@@ -131,6 +133,8 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
group->signal_event().connect (mem_fun (this, &MidiRegionView::canvas_event), false);
+ midi_view()->signal_force_channel_changed().connect(
+ mem_fun(this, &MidiRegionView::midi_force_channel_changed));
midi_view()->signal_channel_selection_changed().connect(
mem_fun(this, &MidiRegionView::midi_channel_selection_changed));
}
@@ -1234,8 +1238,18 @@ MidiRegionView::set_frame_color()
}
void
+MidiRegionView::midi_force_channel_changed(int8_t channel)
+{
+ force_channel = channel;
+}
+
+void
MidiRegionView::midi_channel_selection_changed(uint16_t selection)
{
+ if(force_channel >= 0) {
+ selection = 0xFFFF;
+ }
+
for(std::vector<ArdourCanvas::CanvasMidiEvent*>::iterator i = _events.begin();
i != _events.end();
++i) {
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index fdc37380f6..bc5639476f 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -238,6 +238,8 @@ class MidiRegionView : public RegionView
bool canvas_event(GdkEvent* ev);
bool note_canvas_event(GdkEvent* ev);
+ int8_t force_channel;
+ void midi_force_channel_changed(int8_t channel);
uint16_t last_channel_selection;
void midi_channel_selection_changed(uint16_t selection);
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index a199d2e676..16edd88f72 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -146,7 +146,9 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shar
controls_vbox.pack_end(_midi_expander, SHRINK, 0);
_channel_selector.selection_changed.connect(
mem_fun(*midi_track()->midi_diskstream(), &MidiDiskstream::set_channel_mask));
-
+ _channel_selector.force_channel_changed.connect(
+ mem_fun(*midi_track()->midi_diskstream(), &MidiDiskstream::set_force_channel));
+
}
MidiTimeAxisView::~MidiTimeAxisView ()
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 0702fb65f9..98cc5bb0b7 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -74,8 +74,12 @@ class MidiTimeAxisView : public RouteTimeAxisView
void update_range();
- sigc::signal<void, uint16_t>& signal_channel_selection_changed() { return _channel_selector.selection_changed; }
-
+ sigc::signal<void, uint16_t>& signal_channel_selection_changed()
+ { return _channel_selector.selection_changed; }
+
+ sigc::signal<void, int8_t>& signal_force_channel_changed()
+ { return _channel_selector.force_channel_changed; }
+
private:
void append_extra_display_menu_items ();
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 40df9cfc26..f52f66dc6d 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -102,6 +102,18 @@ class MidiDiskstream : public Diskstream
return playback_mask;
}
+ void set_force_channel(int8_t force_channel) {
+ _playback_buf->set_force_channel(force_channel);
+ _capture_buf->set_force_channel(force_channel);
+ }
+
+ int8_t get_force_channel() {
+ int8_t playback_force_channel = _playback_buf->get_force_channel();
+ int8_t capture_force_channel = _capture_buf->get_force_channel();
+ assert(playback_force_channel == capture_force_channel);
+ return playback_force_channel;
+ }
+
protected:
friend class Session;
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index 7f0e9f3b37..c6cde666a3 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -227,7 +227,7 @@ public:
/** @param size Size in bytes.
*/
MidiRingBuffer(size_t size)
- : MidiRingBufferBase<Byte>(size), _channel_mask(0xFFFF)
+ : MidiRingBufferBase<Byte>(size), _channel_mask(0xFFFF), _force_channel(-1)
{}
size_t write(double time, size_t size, const Byte* buf);
@@ -238,8 +238,21 @@ public:
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0);
- void set_channel_mask(uint16_t channel_mask) { _channel_mask = channel_mask; }
- uint16_t get_channel_mask() { return _channel_mask; }
+ /**
+ * @param channel_mask each bit in channel_mask represents a midi channel: bit 0 = channel 0,
+ * bit 1 = channel 1 etc. the read and write methods will only allow
+ * events to pass, whose channel bit is 1.
+ */
+ void set_channel_mask(uint16_t channel_mask) { g_atomic_int_set(&channel_mask, channel_mask); }
+ uint16_t get_channel_mask() { return g_atomic_int_get(&_channel_mask); }
+
+ /**
+ * @param channel if negative, forcing channels is deactivated and filtering channels
+ * is activated, if positive, the LSB of channel is the channel number
+ * of the channel all events are forced into and filtering is deactivated
+ */
+ void set_force_channel(int8_t channel) { g_atomic_int_set(&_force_channel, channel); }
+ int8_t get_force_channel() { return g_atomic_int_get(&_force_channel); }
protected:
inline bool is_channel_event(Byte event_type_byte) {
@@ -250,7 +263,8 @@ protected:
}
private:
- uint16_t _channel_mask;
+ volatile uint16_t _channel_mask;
+ volatile int8_t _force_channel;
};
@@ -296,13 +310,13 @@ MidiRingBuffer::write(double time, size_t size, const Byte* buf)
{
printf("MRB - write %#X %d %d with time %lf\n",
buf[0], buf[1], buf[2], time);
-
+
assert(size > 0);
- // filter events for channels
- if(is_channel_event(buf[0])) {
+ if(is_channel_event(buf[0]) && (g_atomic_int_get(&_force_channel) < 0)) {
+ // filter events for channels
Byte channel_nr = buf[0] & 0x0F;
- if( !(_channel_mask & (1L << channel_nr)) ) {
+ if( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) {
return 0;
}
}
@@ -312,7 +326,17 @@ MidiRingBuffer::write(double time, size_t size, const Byte* buf)
} else {
MidiRingBufferBase<Byte>::write(sizeof(double), (Byte*)&time);
MidiRingBufferBase<Byte>::write(sizeof(size_t), (Byte*)&size);
- MidiRingBufferBase<Byte>::write(size, buf);
+ if(is_channel_event(buf[0]) && (g_atomic_int_get(&_force_channel) >= 0)) {
+ assert(size == 3);
+ Byte tmp_buf[3];
+ //force event into channel
+ tmp_buf[0] = (buf[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F);
+ tmp_buf[1] = buf[1];
+ tmp_buf[2] = buf[2];
+ MidiRingBufferBase<Byte>::write(size, tmp_buf);
+ } else {
+ MidiRingBufferBase<Byte>::write(size, buf);
+ }
return size;
}
@@ -363,9 +387,10 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
}
// filter events for channels
- if(is_channel_event(first_event_byte)) {
+ // filtering is only active, if forcing channels is not active
+ if(is_channel_event(first_event_byte) && (g_atomic_int_get(&_force_channel) < 0)) {
Byte channel_nr = first_event_byte & 0x0F;
- if( !(_channel_mask & (1L << channel_nr)) ) {
+ if( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) {
return 0;
}
}
@@ -376,6 +401,9 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
success = MidiRingBufferBase<Byte>::full_read(ev.size(), write_loc);
if (success) {
+ if(is_channel_event(first_event_byte) && (g_atomic_int_get(&_force_channel) >= 0)) {
+ write_loc[0] = (write_loc[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F);
+ }
++count;
printf("MRB - read event at time %lf\n", ev.time());
} else {
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 51f093919c..3d9aaca93f 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -1226,6 +1226,9 @@ MidiDiskstream::get_state ()
snprintf (buf, sizeof(buf), "0x%x", _flags);
node->add_property ("flags", buf);
+ snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
+ node->add_property("channel_mask", buf);
+
node->add_property ("playlist", _playlist->name());
snprintf (buf, sizeof(buf), "%f", _visible_speed);
@@ -1303,6 +1306,12 @@ MidiDiskstream::set_state (const XMLNode& node)
if ((prop = node.property ("flags")) != 0) {
_flags = Flag (string_2_enum (prop->value(), _flags));
}
+
+ if ((prop = node.property ("channel_mask")) != 0) {
+ unsigned int channel_mask;
+ sscanf (prop->value().c_str(), "0x%x", &channel_mask);
+ set_channel_mask(channel_mask);
+ }
if ((prop = node.property ("channels")) != 0) {
nchans = atoi (prop->value().c_str());