* first working version of editing MIDI channels of individual notes, see: http://www.flickr.com/photos/24012642@N02/2412142661/

git-svn-id: svn://localhost/ardour2/branches/3.0@3252 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Hans Baier 2008-04-14 06:23:11 +00:00
parent 2656e0a43b
commit 8b3d298f6b
9 changed files with 239 additions and 13 deletions

View file

@ -192,6 +192,7 @@ midi_region_view.cc
midi_scroomer.cc
midi_streamview.cc
midi_time_axis.cc
midi_channel_selector.cc
mixer_strip.cc
mixer_ui.cc
new_session_dialog.cc

View file

@ -36,6 +36,7 @@ CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item,
: _region(region)
, _item(item)
, _text(0)
, _channel_selector_widget()
, _state(None)
, _note(note)
, _selected(false)
@ -43,6 +44,12 @@ CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item,
_text = new Text(*(item->property_parent()));
}
CanvasMidiEvent::~CanvasMidiEvent()
{
if(_text) delete _text;
if(_channel_selector_widget) delete _channel_selector_widget;
}
void
CanvasMidiEvent::move_event(double dx, double dy)
{
@ -71,6 +78,50 @@ CanvasMidiEvent::hide_velocity(void)
_text->hide();
}
void
CanvasMidiEvent::on_channel_change(uint8_t channel)
{
_region.note_selected(this, true);
hide_channel_selector();
_region.change_channel(channel);
}
void
CanvasMidiEvent::show_channel_selector(void)
{
if(_channel_selector_widget == 0) {
cerr << "Note has channel: " << int(_note->channel()) << endl;
SingleMidiChannelSelector* _channel_selector = new SingleMidiChannelSelector(_note->channel());
_channel_selector->show_all();
_channel_selector->channel_selected.connect(
sigc::mem_fun(this, &CanvasMidiEvent::on_channel_change));
_channel_selector_widget =
new Widget(*(_item->property_parent()),
x1(),
y2() + 2,
(Gtk::Widget &) *_channel_selector);
_channel_selector_widget->hide();
_channel_selector_widget->property_height() = 100;
_channel_selector_widget->property_width() = 100;
_channel_selector_widget->raise_to_top();
_channel_selector_widget->show();
} else {
hide_channel_selector();
}
}
void
CanvasMidiEvent::hide_channel_selector(void)
{
if(_channel_selector_widget) {
_channel_selector_widget->hide();
delete _channel_selector_widget;
_channel_selector_widget = 0;
}
}
void
CanvasMidiEvent::selected(bool yn)
{
@ -120,7 +171,6 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
}
return true;
} else if(ev->scroll.direction == GDK_SCROLL_DOWN) {
_region.note_selected(this, true);
if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
// TODO: absolute velocity
@ -164,6 +214,8 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
case GDK_BUTTON_PRESS:
if (ev->button.button == 1) {
_state = Pressed;
} else if (ev->button.button == 3) {
show_channel_selector();
}
return true;
@ -236,7 +288,11 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
event_x = ev->button.x;
event_y = ev->button.y;
_item->property_parent().get_value()->w2i(event_x, event_y);
if(ev->button.button == 3) {
return true;
}
switch (_state) {
case Pressed: // Clicked
if (_region.midi_view()->editor.current_midi_edit_mode() == Editing::MidiEditSelect) {

View file

@ -21,7 +21,9 @@
#define __gtk_ardour_canvas_midi_event_h__
#include "simplerect.h"
#include "midi_channel_selector.h"
#include <libgnomecanvasmm/text.h>
#include <libgnomecanvasmm/widget.h>
#include <ardour/midi_model.h>
class Editor;
@ -49,7 +51,7 @@ public:
Item* item,
const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>());
virtual ~CanvasMidiEvent() { if(_text) delete _text; }
virtual ~CanvasMidiEvent();
bool on_event(GdkEvent* ev);
@ -60,6 +62,15 @@ public:
void show_velocity();
void hide_velocity();
/**
* This slot is called, when a new channel is selected for the event
* */
void on_channel_change(uint8_t channel);
void show_channel_selector();
void hide_channel_selector();
virtual void set_outline_color(uint32_t c) = 0;
virtual void set_fill_color(uint32_t c) = 0;
@ -76,7 +87,8 @@ protected:
MidiRegionView& _region;
Item* const _item;
Text* _text;
Text* _text;
Widget* _channel_selector_widget;
State _state;
const boost::shared_ptr<ARDOUR::Note> _note;
bool _own_note;

View file

@ -47,8 +47,8 @@ CanvasNote::on_event(GdkEvent* ev)
last_x = event_x;
return true;
}
}
case GDK_MOTION_NOTIFY:
event_x = ev->motion.x;

View file

@ -433,12 +433,12 @@ CrossfadeEditor::canvas_event (GdkEvent* event)
case GDK_BUTTON_PRESS:
add_control_point ((event->button.x - canvas_border)/effective_width(),
1.0 - ((event->button.y - canvas_border)/effective_height()));
return TRUE;
return true;
break;
default:
break;
}
return FALSE;
return false;
}
CrossfadeEditor::Point::~Point()

View file

@ -0,0 +1,65 @@
#include "midi_channel_selector.h"
#include <sstream>
using namespace std;
MidiChannelSelector::MidiChannelSelector() :
Gtk::Table(4,4,true)
{
property_column_spacing() = 0;
property_row_spacing() = 0;
uint8_t channel_nr = 0;
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());
_button_labels[row][column].set_justify(Gtk::JUSTIFY_RIGHT);
_buttons[row][column].add(_button_labels[row][column]);
_buttons[row][column].signal_toggled().connect(
sigc::bind(
sigc::mem_fun(this, &MidiChannelSelector::button_toggled),
&_buttons[row][column],
channel_nr - 1));
attach(_buttons[row][column], column, column + 1, row, row + 1);
}
}
}
MidiChannelSelector::~MidiChannelSelector()
{
}
SingleMidiChannelSelector::SingleMidiChannelSelector(uint8_t active_channel)
: MidiChannelSelector()
{
_active_button = 0;
Gtk::ToggleButton *button = &_buttons[active_channel / 4][active_channel % 4];
button->set_active(true);
_active_button = button;
_active_channel = active_channel;
}
void
SingleMidiChannelSelector::button_toggled(Gtk::ToggleButton *button, uint8_t channel)
{
if(button->get_active()) {
if(_active_button) {
_active_button->set_active(false);
}
_active_button = button;
_active_channel = channel;
channel_selected.emit(channel);
}
}
void
MidiMultipleChannelSelector::button_toggled(Gtk::ToggleButton *button, uint8_t channel)
{
if(button->get_active()) {
_selected_channels.insert(channel);
} else {
_selected_channels.erase(channel);
}
}

View file

@ -0,0 +1,49 @@
#ifndef __ardour_ui_midi_channel_selector_h__
#define __ardour_ui_midi_channel_selector_h__
#include "gtkmm/table.h"
#include "sigc++/trackable.h"
#include "gtkmm/togglebutton.h"
#include "gtkmm/label.h"
#include <set>
class MidiChannelSelector : public Gtk::Table
{
public:
MidiChannelSelector();
virtual ~MidiChannelSelector() = 0;
protected:
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr) = 0;
Gtk::Label _button_labels[4][4];
Gtk::ToggleButton _buttons[4][4];
};
class SingleMidiChannelSelector : public MidiChannelSelector
{
public:
SingleMidiChannelSelector(uint8_t active_channel = 0);
const uint8_t get_active_channel() const { return _active_channel; }
sigc::signal<void, uint8_t> channel_selected;
protected:
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
Gtk::ToggleButton *_active_button;
uint8_t _active_channel;
};
class MidiMultipleChannelSelector : public MidiChannelSelector
{
public:
const std::set<uint8_t>& get_selected_channels() const { return _selected_channels; }
protected:
virtual void button_toggled(Gtk::ToggleButton *button, uint8_t button_nr);
std::set<uint8_t> _selected_channels;
};
#endif /*__ardour_ui_midi_channel_selector_h__*/

View file

@ -184,10 +184,15 @@ MidiRegionView::canvas_event(GdkEvent* ev)
return false;
case GDK_BUTTON_PRESS:
if (_mouse_state != SelectTouchDragging && _mouse_state != EraseTouchDragging)
if (_mouse_state != SelectTouchDragging &&
_mouse_state != EraseTouchDragging &&
ev->button.button == 1 ) {
_pressed_button = ev->button.button;
_mouse_state = Pressed;
return true;
}
_pressed_button = ev->button.button;
return true;
return false;
case GDK_ENTER_NOTIFY:
/* FIXME: do this on switch to note tool, too, if the pointer is already in */
@ -306,6 +311,10 @@ MidiRegionView::canvas_event(GdkEvent* ev)
group->ungrab(ev->button.time);
event_frame = trackview.editor.pixel_to_frame(event_x);
if(_pressed_button != 1) {
return false;
}
switch (_mouse_state) {
case Pressed: // Clicked
switch (trackview.editor.current_midi_edit_mode()) {
@ -328,8 +337,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
case AddDragging: // Add drag done
_mouse_state = None;
if (drag_rect->property_x2() > drag_rect->property_x1() + 2) {
const double x = drag_rect->property_x1()
+ trackview.editor.frame_to_pixel(_region->start());
const double x = drag_rect->property_x1();
const double length = trackview.editor.pixel_to_frame(
drag_rect->property_x2() - drag_rect->property_x1());
@ -365,6 +373,7 @@ MidiRegionView::create_note_at(double x, double y, double duration)
nframes_t new_note_time = trackview.editor.pixel_to_frame (x);
assert(new_note_time >= 0);
new_note_time += _region->start();
/*
const Meter& m = trackview.session().tempo_map().meter_at(new_note_time);
@ -1161,6 +1170,34 @@ MidiRegionView::change_velocity(uint8_t velocity, bool relative)
apply_command();
}
void
MidiRegionView::change_channel(uint8_t channel)
{
start_delta_command(_("change channel"));
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
Selection::iterator next = i;
++next;
CanvasMidiEvent *event = *i;
const boost::shared_ptr<Note> copy(new Note(*(event->note().get())));
copy->set_channel(channel);
command_remove_note(event);
command_add_note(copy);
_marked_for_selection.insert(copy);
i = next;
}
// dont keep notes selected if tweaking a single note
if(_marked_for_selection.size() == 1) {
_marked_for_selection.clear();
}
apply_command();
}
void
MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)

View file

@ -165,11 +165,17 @@ class MidiRegionView : public RegionView
/**
* This function is called while the user adjusts the velocity on a selection of notes
* @param velocity the relative or absolute velocity, dependin on the value of relative
* @param velocity the relative or absolute velocity, depending on the value of relative
* @param relative true if the given velocity represents a delta to be applied to all notes, false
* if the absolute value of the note shoud be set
*/
void change_velocity(uint8_t velocity, bool relative=false);
/**
* This function is called when the user adjusts the midi channel of a selection of notes
* @param channel - the channel number of the new channel, zero-based
*/
void change_channel(uint8_t channel);
enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
MouseState mouse_state() const { return _mouse_state; }