* UI fixes for track channel selection
* implemented 'forcing midi events into a single channel' * see http://www.flickr.com/photos/24012642@N02/2430165889/ git-svn-id: svn://localhost/ardour2/branches/3.0@3273 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
e8c2b6f371
commit
f31abc5eaf
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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__*/
|
||||
|
@ -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));
|
||||
}
|
||||
@ -1233,9 +1237,19 @@ 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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 ()
|
||||
|
@ -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 ();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user