summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/canvas-note-event.cc1
-rw-r--r--gtk2_ardour/midi_channel_selector.cc163
-rw-r--r--gtk2_ardour/midi_channel_selector.h62
-rw-r--r--gtk2_ardour/midi_region_view.cc113
-rw-r--r--gtk2_ardour/midi_region_view.h9
-rw-r--r--gtk2_ardour/midi_time_axis.cc10
-rw-r--r--gtk2_ardour/midi_time_axis.h7
-rw-r--r--libs/ardour/ardour/midi_diskstream.h25
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h156
-rw-r--r--libs/ardour/ardour/types.h6
-rw-r--r--libs/ardour/enums.cc6
-rw-r--r--libs/ardour/midi_buffer.cc5
-rw-r--r--libs/ardour/midi_diskstream.cc27
-rw-r--r--libs/ardour/midi_model.cc3
-rw-r--r--libs/ardour/midi_track.cc22
-rw-r--r--libs/ardour/smf_source.cc6
-rw-r--r--libs/midi++2/jack_midiport.cc31
17 files changed, 353 insertions, 299 deletions
diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc
index bd402f8c08..0e758b5489 100644
--- a/gtk2_ardour/canvas-note-event.cc
+++ b/gtk2_ardour/canvas-note-event.cc
@@ -45,7 +45,6 @@ CanvasNoteEvent::CanvasNoteEvent(MidiRegionView& region, Item* item,
CanvasNoteEvent::~CanvasNoteEvent()
{
- cerr << "CanvasNoteEvent::~CanvasNoteEvent() " << int(_note->note()) << " velo " << int(_note->velocity()) << endl;
if (_text) {
_text->hide();
delete _text;
diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc
index 0018c169ab..281c6f5e2d 100644
--- a/gtk2_ardour/midi_channel_selector.cc
+++ b/gtk2_ardour/midi_channel_selector.cc
@@ -1,14 +1,34 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Hans Baier
+
+ 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 <sstream>
#include "midi_channel_selector.h"
#include "gtkmm/separator.h"
#include "i18n.h"
-#include <sstream>
using namespace std;
using namespace Gtk;
using namespace sigc;
+using namespace ARDOUR;
-MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_row, int start_column) :
- Table(no_rows, no_columns, true), _recursion_counter(0)
+MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_row, int start_column) : Table(no_rows, no_columns, true)
+ , _recursion_counter(0)
{
assert(no_rows >= 4);
assert(no_rows >= start_row + 4);
@@ -19,8 +39,8 @@ MidiChannelSelector::MidiChannelSelector(int no_rows, int no_columns, int start_
property_row_spacing() = 0;
uint8_t channel_nr = 0;
- for(int row = 0; row < 4; ++row) {
- for(int column = 0; column < 4; ++column) {
+ for (int row = 0; row < 4; ++row) {
+ for (int column = 0; column < 4; ++column) {
ostringstream channel;
channel << int(++channel_nr);
_button_labels[row][column].set_text(channel.str());
@@ -47,21 +67,21 @@ SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
: MidiChannelSelector()
{
_last_active_button = 0;
- ToggleButton *button = &_buttons[active_channel / 4][active_channel % 4];
+ ToggleButton* button = &_buttons[active_channel / 4][active_channel % 4];
_active_channel = active_channel;
button->set_active(true);
_last_active_button = button;
}
void
-SingleMidiChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
+SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
{
++_recursion_counter;
- if(_recursion_counter == 1) {
+ 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) {
+ if (button->get_active()) {
+ if (_last_active_button) {
_last_active_button->set_active(false);
_active_channel = channel;
_last_active_button = button;
@@ -76,8 +96,9 @@ SingleMidiChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
--_recursion_counter;
}
-MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_selection, int8_t force_channel)
- : MidiChannelSelector(4, 6, 0, 0), _mode(FILTERING_MULTIPLE_CHANNELS)
+MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
+ : MidiChannelSelector(4, 6, 0, 0)
+ , _channel_mode(mode)
{
_select_all.add(*manage(new Label(_("All"))));
_select_all.signal_clicked().connect(
@@ -103,58 +124,42 @@ MidiMultipleChannelSelector::MidiMultipleChannelSelector(uint16_t initial_select
attach(_invert_selection, 5, 6, 2, 3);
attach(_force_channel, 5, 6, 3, 4);
- set_selected_channels(initial_selection);
+ set_selected_channels(mask);
}
MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
{
- selection_changed.clear();
- force_channel_changed.clear();
+ mode_changed.clear();
}
-const int8_t
-MidiMultipleChannelSelector::get_force_channel() const
+void
+MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint8_t mask)
{
- 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;
- }
+ switch (mode) {
+ case AllChannels:
+ _force_channel.set_active(false);
+ set_selected_channels(0xFFFF);
+ break;
+ case FilterChannels:
+ _force_channel.set_active(false);
+ set_selected_channels(mask);
+ break;
+ case ForceChannel:
+ _force_channel.set_active(true);
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ button->set_active(i == mask);
}
-
- // this point should not be reached.
- assert(false);
- }
-
- return -1;
-}
-
-void
-MidiMultipleChannelSelector::set_force_channel(int8_t channel)
-{
- if(channel < 0) {
- // if forcing is already activated, deactivate
- if(_mode == FORCING_SINGLE_CHANNEL) {
- _force_channel.toggled();
- }
- // if not, nothing to do
- } else {
- // otherwise simulate activating force channels by pressing the
- // two buttons the user would press
- _force_channel.toggled();
- _buttons[channel / 4][channel % 4].toggled();
}
}
-
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()) {
+ for (uint16_t i = 0; i < 16; i++) {
+ const ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (button->get_active()) {
selected_channels |= (1L << i);
}
}
@@ -165,9 +170,9 @@ MidiMultipleChannelSelector::get_selected_channels() const
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(selected_channels & (1L << i)) {
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (selected_channels & (1L << i)) {
button->set_active(true);
} else {
button->set_active(false);
@@ -179,13 +184,13 @@ void
MidiMultipleChannelSelector::button_toggled(ToggleButton *button, uint8_t channel)
{
++_recursion_counter;
- if(_recursion_counter == 1) {
- if(_mode == FORCING_SINGLE_CHANNEL) {
+ if (_recursion_counter == 1) {
+ if (_channel_mode == ForceChannel) {
+ mode_changed.emit(_channel_mode, channel);
set_selected_channels(1 << channel);
+ } else {
+ mode_changed.emit(_channel_mode, get_selected_channels());
}
-
- force_channel_changed.emit(get_force_channel());
- selection_changed.emit(get_selected_channels());
}
--_recursion_counter;
}
@@ -193,67 +198,73 @@ MidiMultipleChannelSelector::button_toggled(ToggleButton *button, uint8_t channe
void
MidiMultipleChannelSelector::force_channels_button_toggled()
{
- if(_force_channel.get_active()) {
- _mode = FORCING_SINGLE_CHANNEL;
+ if (_force_channel.get_active()) {
+ _channel_mode = ForceChannel;
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) {
+ uint16_t active_channel = 0;
+ 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;
+ active_channel = i;
}
}
}
- if(!found_first_active) {
+ 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());
+ mode_changed.emit(_channel_mode, active_channel);
} else {
- _mode = FILTERING_MULTIPLE_CHANNELS;
+ _channel_mode = FilterChannels;
_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());
+ mode_changed.emit(FilterChannels, get_selected_channels());
}
}
void
MidiMultipleChannelSelector::select_all(bool on)
{
+ if (_channel_mode == ForceChannel)
+ return;
+
++_recursion_counter;
- for(uint16_t i = 0; i < 16; i++) {
- ToggleButton *button = &_buttons[i / 4][i % 4];
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
button->set_active(on);
}
--_recursion_counter;
- selection_changed.emit(get_selected_channels());
+ mode_changed.emit(_channel_mode, get_selected_channels());
}
void
MidiMultipleChannelSelector::invert_selection(void)
{
+ if (_channel_mode == ForceChannel)
+ return;
+
++_recursion_counter;
- for(uint16_t i = 0; i < 16; i++) {
- ToggleButton *button = &_buttons[i / 4][i % 4];
- if(button->get_active()) {
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (button->get_active()) {
button->set_active(false);
} else {
button->set_active(true);
}
}
--_recursion_counter;
- selection_changed.emit(get_selected_channels());
+ mode_changed.emit(_channel_mode, get_selected_channels());
}
diff --git a/gtk2_ardour/midi_channel_selector.h b/gtk2_ardour/midi_channel_selector.h
index 9ac95036d6..1f15f3eef5 100644
--- a/gtk2_ardour/midi_channel_selector.h
+++ b/gtk2_ardour/midi_channel_selector.h
@@ -1,13 +1,34 @@
+/*
+ Copyright (C) 2008 Paul Davis
+ Author: Hans Baier
+
+ 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 __ardour_ui_midi_channel_selector_h__
#define __ardour_ui_midi_channel_selector_h__
+#include <set>
#include "boost/shared_ptr.hpp"
-#include "gtkmm/table.h"
#include "sigc++/trackable.h"
+#include "gtkmm/table.h"
#include "gtkmm/button.h"
#include "gtkmm/togglebutton.h"
#include "gtkmm/label.h"
-#include <set>
+#include <ardour/types.h>
+
class MidiChannelSelector : public Gtk::Table
{
@@ -15,8 +36,10 @@ public:
MidiChannelSelector(int no_rows = 4, int no_columns = 4, int start_row = 0, int start_column = 0);
virtual ~MidiChannelSelector() = 0;
+ sigc::signal<void, ARDOUR::ChannelMode, uint16_t> mode_changed;
+
protected:
- virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr) = 0;
+ 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;
@@ -32,7 +55,7 @@ public:
sigc::signal<void, uint8_t> channel_selected;
protected:
- virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
+ virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr);
Gtk::ToggleButton* _last_active_button;
uint8_t _active_channel;
@@ -41,40 +64,35 @@ protected:
class MidiMultipleChannelSelector : public MidiChannelSelector
{
public:
- MidiMultipleChannelSelector(uint16_t initial_selection = 0xFFFF, int8_t force_channel = -1);
+ MidiMultipleChannelSelector(ARDOUR::ChannelMode mode = ARDOUR::FilterChannels,
+ uint16_t initial_selection = 0xFFFF);
+
virtual ~MidiMultipleChannelSelector();
+ void set_channel_mode(ARDOUR::ChannelMode mode, uint8_t mask);
+
/**
* @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;
+ void set_selected_channels(uint16_t selected_channels);
- const int8_t get_force_channel() const;
- void set_force_channel(int8_t force_channel);
protected:
- enum Mode {
- FILTERING_MULTIPLE_CHANNELS,
- FORCING_SINGLE_CHANNEL
- };
-
- Mode _mode;
+ ARDOUR::ChannelMode _channel_mode;
+ ARDOUR::NoteMode _note_mode;
- virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
+ 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);
- Gtk::Button _select_all;
- Gtk::Button _select_none;
- Gtk::Button _invert_selection;
- Gtk::ToggleButton _force_channel;
+ Gtk::Button _select_all;
+ Gtk::Button _select_none;
+ Gtk::Button _invert_selection;
+ Gtk::ToggleButton _force_channel;
};
#endif /*__ardour_ui_midi_channel_selector_h__*/
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index bc492b0e71..b83630e9fa 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -62,8 +62,8 @@ 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)
+ , _force_channel(-1)
+ , _last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
@@ -79,8 +79,8 @@ 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)
+ , _force_channel(-1)
+ , _last_channel_selection(0xFFFF)
, _default_note_length(0.0)
, _active_notes(0)
, _note_group(new ArdourCanvas::Group(*parent))
@@ -135,10 +135,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));
+ midi_view()->signal_channel_mode_changed().connect(
+ mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
}
bool
@@ -324,7 +322,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
group->ungrab(ev->button.time);
event_frame = trackview.editor.pixel_to_frame(event_x);
- if(_pressed_button != 1) {
+ if (_pressed_button != 1) {
return false;
}
@@ -458,18 +456,17 @@ MidiRegionView::redisplay_model()
clear_events();
_model->read_lock();
- MidiModel::Notes notes = _model->notes();
- cerr << endl << "Model contains " << notes.size() << " Notes:" << endl;
- for(MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
- cerr << "MODEL: Note time: " << (*i)->time()
- << " pitch: " << int((*i)->note())
- << " duration: " << (*i)->duration()
- << " end-time: " << (*i)->end_time()
- << " velocity: " << int((*i)->velocity())
- //<< " Note-on: " << note.on_event().
- //<< " Note-off: " << note.off_event()
+ /*MidiModel::Notes notes = _model->notes();
+ cerr << endl << _model->midi_source()->name() << " : redisplaying " << notes.size() << " notes:" << endl;
+ for (MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
+ cerr << "NOTE time: " << (*i)->time()
+ << " pitch: " << int((*i)->note())
+ << " duration: " << (*i)->duration()
+ << " end-time: " << (*i)->end_time()
+ << " velocity: " << int((*i)->velocity())
<< endl;
- }
+ }*/
+
for (size_t i = 0; i < _model->n_notes(); ++i) {
add_note(_model->note_at(i));
@@ -479,10 +476,10 @@ MidiRegionView::redisplay_model()
control = _model->controls().begin();
control != _model->controls().end(); ++control) {
- if( control->first.type() == MidiPgmChangeAutomation ) {
+ if ( control->first.type() == MidiPgmChangeAutomation ) {
Glib::Mutex::Lock list_lock (control->second->list()->lock());
- for(AutomationList::const_iterator event = control->second->list()->begin();
+ for (AutomationList::const_iterator event = control->second->list()->begin();
event != control->second->list()->end(); ++event) {
boost::shared_ptr<MIDI::Event> midi_event(new MIDI::Event());
MidiControlIterator iter(control->second->list(), (*event)->when, (*event)->value);
@@ -594,14 +591,14 @@ MidiRegionView::set_y_position_and_height (double y, double h)
}
event->hide_velocity();
- if(CanvasNote* note = dynamic_cast<CanvasNote*>(event)) {
+ if (CanvasNote* note = dynamic_cast<CanvasNote*>(event)) {
const double y1 = midi_stream_view()->note_to_y(event->note()->note());
const double y2 = y1 + floor(midi_stream_view()->note_height());
note->property_y1() = y1;
note->property_y2() = y2;
}
- if(CanvasHit* hit = dynamic_cast<CanvasHit*>(event)) {
+ if (CanvasHit* hit = dynamic_cast<CanvasHit*>(event)) {
double x = trackview.editor.frame_to_pixel((nframes_t)
event->note()->time() - _region->start());
const double diamond_size = midi_stream_view()->note_height() / 2.0;
@@ -612,7 +609,7 @@ MidiRegionView::set_y_position_and_height (double y, double h)
hit->move(x-hit->x1(), y-hit->y1());
hit->show();
}
- if(event->selected()) {
+ if (event->selected()) {
event->show_velocity();
}
}
@@ -732,7 +729,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
assert(midi_view()->note_mode() == Sustained || midi_view()->note_mode() == Percussive);
// dont display notes beyond the region bounds
- if(
+ if (
note->time() - _region->start() >= _region->length() ||
note->time() < _region->start() ||
note->note() < midi_stream_view()->lowest_note() ||
@@ -805,11 +802,11 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
event = 0;
}
- if(event) {
- if(_marked_for_selection.find(event->note()) != _marked_for_selection.end()) {
+ if (event) {
+ if (_marked_for_selection.find(event->note()) != _marked_for_selection.end()) {
note_selected(event, true);
}
- event->on_channel_selection_change(last_channel_selection);
+ event->on_channel_selection_change(_last_channel_selection);
}
}
@@ -819,7 +816,7 @@ MidiRegionView::add_pgm_change(boost::shared_ptr<MIDI::Event> event)
assert(event->time() >= 0);
// dont display notes beyond the region bounds
- if(
+ if (
event->time() - _region->start() >= _region->length() ||
event->time() < _region->start()
) {
@@ -997,7 +994,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
new_note_time += dt;
// keep notes inside region if dragged beyond left region bound
- if(new_note_time < _region->start()) {
+ if (new_note_time < _region->start()) {
new_note_time = _region->start();
}
@@ -1014,7 +1011,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
clamp_0_to_127(new_pitch);
//notes which are dragged beyond the standard midi range snap back to their original place
- if((original_pitch != 0 && new_pitch == 0) || (original_pitch != 127 && new_pitch == 127)) {
+ if ((original_pitch != 0 && new_pitch == 0) || (original_pitch != 127 && new_pitch == 127)) {
new_pitch = original_pitch;
}
@@ -1032,7 +1029,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
apply_command();
// care about notes being moved beyond the upper/lower bounds on the canvas
- if(lowest_note_in_selection < midi_stream_view()->lowest_note() ||
+ if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
highest_note_in_selection > midi_stream_view()->highest_note()
) {
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
@@ -1088,7 +1085,7 @@ MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
CanvasNote *note = dynamic_cast<CanvasNote *> (*i);
// only insert CanvasNotes into the map
- if(note) {
+ if (note) {
NoteResizeData *resize_data = new NoteResizeData();
resize_data->canvas_note = note;
@@ -1122,7 +1119,7 @@ MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
resize_data->resize_rect = resize_rect;
- if(note_end == CanvasNote::NOTE_ON) {
+ if (note_end == CanvasNote::NOTE_ON) {
resize_data->current_x = note->x1();
} else { // NOTE_OFF
resize_data->current_x = note->x2();
@@ -1142,7 +1139,7 @@ MidiRegionView::update_resizing(CanvasNote::NoteEnd note_end, double x, bool rel
const double region_start = get_position_pixels();
- if(relative) {
+ if (relative) {
(*i)->current_x = (*i)->current_x + x;
} else {
// x is in track relative, transform it to region relative
@@ -1151,7 +1148,7 @@ MidiRegionView::update_resizing(CanvasNote::NoteEnd note_end, double x, bool rel
double current_x = (*i)->current_x;
- if(note_end == CanvasNote::NOTE_ON) {
+ if (note_end == CanvasNote::NOTE_ON) {
resize_rect->property_x1() = snap_to_pixel(current_x);
resize_rect->property_x2() = canvas_note->x2();
} else {
@@ -1172,7 +1169,7 @@ MidiRegionView::commit_resizing(CanvasNote::NoteEnd note_end, double event_x, bo
double current_x = (*i)->current_x;
const double position = get_position_pixels();
- if(!relative) {
+ if (!relative) {
// event_x is in track relative, transform it to region relative
current_x = event_x - position;
}
@@ -1221,7 +1218,7 @@ MidiRegionView::change_velocity(uint8_t velocity, bool relative)
CanvasNoteEvent *event = *i;
const boost::shared_ptr<Note> copy(new Note(*(event->note().get())));
- if(relative) {
+ if (relative) {
uint8_t new_velocity = copy->velocity() + velocity;
clamp_0_to_127(new_velocity);
@@ -1238,7 +1235,7 @@ MidiRegionView::change_velocity(uint8_t velocity, bool relative)
}
// dont keep notes selected if tweaking a single note
- if(_marked_for_selection.size() == 1) {
+ if (_marked_for_selection.size() == 1) {
_marked_for_selection.clear();
}
@@ -1266,7 +1263,7 @@ MidiRegionView::change_channel(uint8_t channel)
}
// dont keep notes selected if tweaking a single note
- if(_marked_for_selection.size() == 1) {
+ if (_marked_for_selection.size() == 1) {
_marked_for_selection.clear();
}
@@ -1308,22 +1305,24 @@ 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)
+MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
{
- if(force_channel >= 0) {
- selection = 0xFFFF;
- }
-
- for(std::vector<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin();
- i != _events.end();
- ++i) {
- (*i)->on_channel_selection_change(selection);
+ switch (mode) {
+ case AllChannels:
+ case FilterChannels:
+ _force_channel = -1;
+ break;
+ case ForceChannel:
+ _force_channel = mask;
+ mask = 0xFFFF; // Show all notes as active (below)
+ };
+
+ // Update notes for selection
+ for (std::vector<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin();
+ i != _events.end(); ++i) {
+ (*i)->on_channel_selection_change(mask);
}
- last_channel_selection = selection;
+
+ _last_channel_selection = mask;
}
+
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 1a37205bef..4283483f04 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -241,16 +241,15 @@ 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);
+ void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
void clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev);
void clear_selection() { clear_selection_except(NULL); }
void update_drag_selection(double last_x, double x, double last_y, double y);
- double _default_note_length;
+ int8_t _force_channel;
+ uint16_t _last_channel_selection;
+ double _default_note_length;
boost::shared_ptr<ARDOUR::MidiModel> _model;
std::vector<ArdourCanvas::CanvasNoteEvent*> _events;
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 95b77abaf4..f6d2993cfe 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -144,13 +144,11 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shar
mem_fun(this, &MidiTimeAxisView::channel_selector_toggled));
controls_vbox.pack_end(_midi_expander, SHRINK, 0);
boost::shared_ptr<MidiDiskstream> diskstream = midi_track()->midi_diskstream();
+
// restore channel selector settings
- _channel_selector.set_selected_channels(diskstream->get_channel_mask());
- _channel_selector.set_force_channel(diskstream->get_force_channel());
- _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));
+ _channel_selector.set_channel_mode(diskstream->get_channel_mode(), diskstream->get_channel_mask());
+ _channel_selector.mode_changed.connect(
+ mem_fun(*midi_track()->midi_diskstream(), &MidiDiskstream::set_channel_mode));
}
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 98cc5bb0b7..cdbf6907e1 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -74,11 +74,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
void update_range();
- 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; }
+ sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed()
+ { return _channel_selector.mode_changed; }
private:
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index f52f66dc6d..3e8e9c4156 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -90,28 +90,27 @@ class MidiDiskstream : public Diskstream
void set_note_mode (NoteMode m);
- void set_channel_mask(uint16_t channel_mask) {
- _playback_buf->set_channel_mask(channel_mask);
- _capture_buf->set_channel_mask(channel_mask);
- }
-
uint16_t get_channel_mask() {
uint16_t playback_mask = _playback_buf->get_channel_mask();
+#ifndef NDEBUG
uint16_t capture_mask = _capture_buf->get_channel_mask();
assert(playback_mask == capture_mask);
+#endif
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);
+ void set_channel_mode(ChannelMode mode, uint16_t mask) {
+ _playback_buf->set_channel_mode(mode, mask);
+ _capture_buf->set_channel_mode(mode, mask);
}
- 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;
+ ChannelMode get_channel_mode() {
+ ChannelMode playback_mode = _playback_buf->get_channel_mode();
+#ifndef NDEBUG
+ ChannelMode capture_mode = _capture_buf->get_channel_mode();
+ assert(playback_mode == capture_mode);
+#endif
+ return playback_mode;
}
protected:
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index 680e2a7b61..ea0013fe46 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -75,7 +75,7 @@ public:
if (w > r) {
return ((r - w + _size) % _size) - 1;
- } else if(w < r) {
+ } else if (w < r) {
return (r - w) - 1;
} else {
return _size - 1;
@@ -101,15 +101,17 @@ public:
size_t read(size_t size, T* dst);
bool full_read(size_t size, T* dst);
+
+ bool skip(size_t size);
void write(size_t size, const T* src);
protected:
- mutable gint _write_ptr;
- mutable gint _read_ptr;
+ mutable int _write_ptr;
+ mutable int _read_ptr;
size_t _size; ///< Size (capacity) in bytes
- T* _buf; ///< size, event, size, event...
+ T* _buf; ///< size, event, size, event...
};
@@ -130,7 +132,7 @@ MidiRingBufferBase<T>::peek(size_t size, T* dst)
: _size - priv_read_ptr;
memcpy(dst, &_buf[priv_read_ptr], read_size);
-
+
return read_size;
}
@@ -168,7 +170,7 @@ MidiRingBufferBase<T>::read(size_t size, T* dst)
: _size - priv_read_ptr;
memcpy(dst, &_buf[priv_read_ptr], read_size);
-
+
g_atomic_int_set(&_read_ptr, (priv_read_ptr + read_size) % _size);
return read_size;
@@ -192,6 +194,23 @@ MidiRingBufferBase<T>::full_read(size_t size, T* dst)
template<typename T>
+bool
+MidiRingBufferBase<T>::skip(size_t size)
+{
+ if (read_space() < size) {
+ std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl;
+ return false;
+ }
+
+ const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+ g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size);
+
+ return true;
+}
+
+
+
+template<typename T>
inline void
MidiRingBufferBase<T>::write(size_t size, const T* src)
{
@@ -199,14 +218,14 @@ MidiRingBufferBase<T>::write(size_t size, const T* src)
if (priv_write_ptr + size <= _size) {
memcpy(&_buf[priv_write_ptr], src, size);
- g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
+ g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
} else {
const size_t this_size = _size - priv_write_ptr;
assert(this_size < size);
assert(priv_write_ptr + this_size <= _size);
memcpy(&_buf[priv_write_ptr], src, this_size);
memcpy(&_buf[0], src+this_size, size - this_size);
- g_atomic_int_set(&_write_ptr, size - this_size);
+ g_atomic_int_set(&_write_ptr, size - this_size);
}
}
@@ -223,11 +242,10 @@ MidiRingBufferBase<T>::write(size_t size, const T* src)
*/
class MidiRingBuffer : public MidiRingBufferBase<Byte> {
public:
-
/** @param size Size in bytes.
*/
MidiRingBuffer(size_t size)
- : MidiRingBufferBase<Byte>(size), _channel_mask(0xFFFF), _force_channel(-1)
+ : MidiRingBufferBase<Byte>(size), _channel_mask(0x0000FFFF)
{}
size_t write(double time, size_t size, const Byte* buf);
@@ -238,21 +256,24 @@ public:
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0);
- /**
- * @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.
+ /** Set the channel filtering mode.
+ * @param mask If mode is FilterChannels, each bit represents a midi channel:
+ * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
+ * process events whose channel bit is 1.
+ * If mode is ForceChannel, mask is simply a channel number which all events will
+ * be forced to while reading.
*/
- 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); }
+ void set_channel_mode(ChannelMode mode, uint16_t mask) {
+ g_atomic_int_set(&_channel_mask, ((uint16_t)mode << 16) | mask);
+ }
+
+ ChannelMode get_channel_mode() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16);
+ }
- /**
- * @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); }
+ uint16_t get_channel_mask() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0x0000FFFF));
+ }
protected:
inline bool is_channel_event(Byte event_type_byte) {
@@ -263,8 +284,7 @@ protected:
}
private:
- volatile uint16_t _channel_mask;
- volatile int8_t _force_channel;
+ volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
};
@@ -308,17 +328,18 @@ MidiRingBuffer::read_contents(size_t size, Byte* buf)
inline size_t
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);
+ /*fprintf(stderr, "MRB %p write (t = %f) ", this, time);
+ for (size_t i = 0; i < size; ++i)
+ fprintf(stderr, "%X", (char)buf[i]);
+ fprintf(stderr, "\n");*/
assert(size > 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( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) {
+ // Don't write event if it doesn't match channel filter
+ if (is_channel_event(buf[0]) && get_channel_mode() == FilterChannels) {
+ Byte channel = buf[0] & 0x0F;
+ if ( !(get_channel_mask() & (1L << channel)) )
return 0;
- }
}
if (write_space() < (sizeof(double) + sizeof(size_t) + size)) {
@@ -326,11 +347,11 @@ 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);
- if(is_channel_event(buf[0]) && (g_atomic_int_get(&_force_channel) >= 0)) {
+ if (is_channel_event(buf[0]) && get_channel_mode() == ForceChannel) {
assert(size == 3);
Byte tmp_buf[3];
- //force event into channel
- tmp_buf[0] = (buf[0] & 0xF0) | (g_atomic_int_get(&_force_channel) & 0x0F);
+ // Force event to channel
+ tmp_buf[0] = (buf[0] & 0xF0) | (get_channel_mask() & 0x0F);
tmp_buf[1] = buf[1];
tmp_buf[2] = buf[2];
MidiRingBufferBase<Byte>::write(size, tmp_buf);
@@ -354,22 +375,23 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
if (read_space() == 0)
return 0;
- MIDI::Event ev;
+ double ev_time;
+ uint32_t ev_size;
size_t count = 0;
- //printf("MRB - read %u .. %u + %u\n", start, end, offset);
+ //printf("---- MRB read %u .. %u + %u\n", start, end, offset);
while (read_space() > sizeof(double) + sizeof(size_t)) {
- full_peek(sizeof(double), (Byte*)&ev.time());
+ full_peek(sizeof(double), (Byte*)&ev_time);
- if (ev.time() > end)
+ if (ev_time > end)
break;
- bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev.time());
+ bool success = MidiRingBufferBase<Byte>::full_read(sizeof(double), (Byte*)&ev_time);
if (success) {
- success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev.size());
+ success = MidiRingBufferBase<Byte>::full_read(sizeof(size_t), (Byte*)&ev_size);
}
if (!success) {
@@ -377,51 +399,47 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
continue;
}
- Byte first_event_byte;
- if(success) {
- success = full_peek(sizeof(Byte), &first_event_byte);
- }
-
- // could this ever happen???
- if (!success) {
- std::cerr << "MRB: PEEK ERROR (first event byte)" << std::endl;
- continue;
- }
+ Byte status;
+ success = full_peek(sizeof(Byte), &status);
+ assert(success); // If this failed, buffer is corrupt, all hope is lost
- // filter events for channels
- // 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( !(g_atomic_int_get(&_channel_mask) & (1L << channel_nr)) ) {
+ // Ignore event if it doesn't match channel filter
+ if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
+ const Byte channel = status & 0x0F;
+ if ( !(get_channel_mask() & (1L << channel)) ) {
+ skip(ev_size); // Advance read pointer to next event
continue;
}
}
- if (ev.time() >= start) {
- ev.time() -= start;
- // TODO: Right now there come MIDI Events with empty buffer
- if(!ev.buffer()) {
- std::cerr << "MidiRingBuffer::read WARNING: Skipping MIDI Event with NULL buffer pointer "
- << " and length " << int(ev.size()) << std::endl;
+ if (ev_time >= start) {
+
+ /*std::cerr << "MRB " << this << " - Reading event, time = "
+ << ev_time << " - " << start << " => " << ev_time - start
+ << ", size = " << ev_size << std::endl;*/
+
+ ev_time -= start;
+
+ Byte* write_loc = dst.reserve(ev_time, ev_size);
+ if (write_loc == NULL) {
+ std::cerr << "MRB: Unable to reserve space in buffer, event skipped";
continue;
}
- Byte* write_loc = dst.reserve(ev.time(), ev.size());
-
- success = MidiRingBufferBase<Byte>::full_read(ev.size(), write_loc);
+ 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);
+ if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
+ write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
}
++count;
- //printf("MRB - read event at time %lf\n", ev.time());
+ //printf("MRB - read event at time %lf\n", ev_time);
} else {
std::cerr << "MRB: READ ERROR (data)" << std::endl;
}
} else {
- printf("MRB - SKIPPING EVENT AT TIME %f\n", ev.time());
+ printf("MRB (start %u) - Skipping event at (too early) time %f\n", start, ev_time);
}
}
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 9195b1075c..55655e9e26 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -135,6 +135,12 @@ namespace ARDOUR {
Sustained,
Percussive
};
+
+ enum ChannelMode {
+ AllChannels = 0, ///< Pass through all channel information unmodified
+ FilterChannels, ///< Ignore events on certain channels
+ ForceChannel ///< Force all events to a certain channel
+ };
enum EventTimeUnit {
Frames,
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index d64d3a2f99..71b699396b 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -46,6 +46,7 @@ setup_enum_writer ()
MeterPoint _MeterPoint;
TrackMode _TrackMode;
NoteMode _NoteMode;
+ ChannelMode _ChannelMode;
MeterFalloff _MeterFalloff;
MeterHold _MeterHold;
EditMode _EditMode;
@@ -140,6 +141,11 @@ setup_enum_writer ()
REGISTER_ENUM (Sustained);
REGISTER_ENUM (Percussive);
REGISTER (_NoteMode);
+
+ REGISTER_ENUM (AllChannels);
+ REGISTER_ENUM (FilterChannels);
+ REGISTER_ENUM (ForceChannel);
+ REGISTER (_ChannelMode);
REGISTER_ENUM (MeterFalloffOff);
REGISTER_ENUM (MeterFalloffSlowest);
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index 042f9529ad..4628de4a6a 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -195,7 +195,10 @@ MidiBuffer::push_back(const jack_midi_event_t& ev)
Byte*
MidiBuffer::reserve(double time, size_t size)
{
- assert(size <= MAX_EVENT_SIZE);
+ if (size > MAX_EVENT_SIZE) {
+ cerr << "WARNING: Failed to reserve " << size << " bytes for event";
+ return 0;
+ }
if (_size == _capacity)
return 0;
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 6efa1abbae..acc8f8117a 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -1227,11 +1227,10 @@ MidiDiskstream::get_state ()
snprintf (buf, sizeof(buf), "0x%x", _flags);
node->add_property ("flags", buf);
+ node->add_property("channel-mode", enum_2_string(get_channel_mode()));
+
snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
- node->add_property("channel_mask", buf);
-
- snprintf (buf, sizeof(buf), "%d", get_force_channel());
- node->add_property("force_channel", buf);
+ node->add_property("channel-mask", buf);
node->add_property ("playlist", _playlist->name());
@@ -1310,19 +1309,21 @@ 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);
+
+ ChannelMode channel_mode = AllChannels;
+ if ((prop = node.property ("channel-mode")) != 0) {
+ channel_mode = ChannelMode (string_2_enum(prop->value(), channel_mode));
}
- if ((prop = node.property ("force_channel")) != 0) {
- int force_channel;
- sscanf (prop->value().c_str(), "%d", &force_channel);
- set_force_channel(force_channel);
+ unsigned int channel_mask = 0xFFFF;
+ if ((prop = node.property ("channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &channel_mask);
+ if (channel_mask & 0xFFFF)
+ warning << _("MidiDiskstream: XML property channel-mask out of range") << endmsg;
}
+ set_channel_mode(channel_mode, channel_mask);
+
if ((prop = node.property ("channels")) != 0) {
nchans = atoi (prop->value().c_str());
}
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index 01f0ecc436..2b8755b0f9 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -491,9 +491,6 @@ void MidiModel::append(const MIDI::Event& ev)
write_lock();
_edited = true;
- cerr << "MidiModel append event type: "
- << hex << "0x" << (int)ev.type() << endl;
-
assert(_notes.empty() || ev.time() >= _notes.back()->time());
assert(_writing);
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index ab13ad410c..d22c2171e7 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -428,9 +428,6 @@ MidiTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_fram
passthru (start_frame, end_frame, nframes, offset, 0, (_meter_point == MeterInput));
}
- // stop all sounds
- midi_panic();
-
return 0;
}
@@ -571,10 +568,8 @@ MidiTrack::process_output_buffers (BufferSet& bufs,
IO::silence(nframes, offset);
} else {
- MidiBuffer& output_buf = bufs.get_midi(0);
- // TODO this crashes: (sends events with NULL buffer pointer)
- // Is this necessary anyway here? Dont know.
- //write_controller_messages(output_buf, start_frame, end_frame, nframes, offset);
+ // Write 'automation' controllers (e.g. CC events from a UI slider)
+ write_controller_messages(bufs.get_midi(0), start_frame, end_frame, nframes, offset);
deliver_output(bufs, start_frame, end_frame, nframes, offset);
}
@@ -706,13 +701,13 @@ MidiTrack::set_note_mode (NoteMode m)
void
MidiTrack::midi_panic()
{
- for(uint8_t channel = 0; channel <= 0xF; channel++) {
+ for (uint8_t channel = 0; channel <= 0xF; channel++) {
Byte ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
- write_immediate_event(3, ev);
+ write_immediate_event(3, ev);
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
- write_immediate_event(3, ev);
+ write_immediate_event(3, ev);
ev[1] = MIDI_CTL_RESET_CONTROLLERS;
- write_immediate_event(3, ev);
+ write_immediate_event(3, ev);
}
}
@@ -721,6 +716,11 @@ MidiTrack::midi_panic()
bool
MidiTrack::write_immediate_event(size_t size, const Byte* buf)
{
+ printf("Write immediate event: ");
+ for (size_t i=0; i < size; ++i) {
+ printf("%X ", buf[i]);
+ }
+ printf("\n");
return (_immediate_events.write(0, size, buf) == size);
}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index 4ab7a9b973..389224eb3b 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -361,11 +361,11 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
if (event_size > 1)
fread((*buf) + 1, 1, *size - 1, _fd);
- printf("SMFSource %s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
+ /*printf("SMFSource %s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
for (size_t i=0; i < *size; ++i) {
printf("%X ", (*buf)[i]);
}
- printf("\n");
+ printf("\n");*/
return (int)*size;
}
@@ -374,7 +374,7 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
nframes_t
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset, nframes_t negative_stamp_offset) const
{
- cerr << "SMF read_unlocked " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
+ //cerr << "SMF read_unlocked " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
// 64 bits ought to be enough for anybody
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc
index 311bbb98f6..0b49517212 100644
--- a/libs/midi++2/jack_midiport.cc
+++ b/libs/midi++2/jack_midiport.cc
@@ -95,24 +95,27 @@ JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
} else {
- assert(_currently_in_cycle);
assert(_jack_output_port);
assert(timestamp < _nframes_this_cycle);
- if (timestamp == 0) {
- timestamp = _last_write_timestamp;
- }
-
- if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle),
- timestamp, msg, msglen) == 0) {
- ret = msglen;
- _last_write_timestamp = timestamp;
-
+ if (_currently_in_cycle) {
+ if (timestamp == 0) {
+ timestamp = _last_write_timestamp;
+ }
+
+ if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle),
+ timestamp, msg, msglen) == 0) {
+ ret = msglen;
+ _last_write_timestamp = timestamp;
+
+ } else {
+ ret = 0;
+ cerr << "write of " << msglen << " failed, port holds "
+ << jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle))
+ << endl;
+ }
} else {
- ret = 0;
- cerr << "write of " << msglen << " failed, port holds "
- << jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle))
- << endl;
+ cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
}
}