mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 06:44:57 +01:00
* implemented editing velocities (http://tracker.ardour.org/view.php?id=2148)
* added MIDI panic button (http://tracker.ardour.org/view.php?id=2118) * bugfix: moving notes above midi 127 or below 0 does not wrap around anymore * bugfix: deadlock on editing notes after playback (http://tracker.ardour.org/view.php?id=2140) due to unbalanced lock acquire/release * bugfix: First note off lost in playback (http://tracker.ardour.org/view.php?id=2132) * bugfix: Last note off lost in saving MIDI files (http://tracker.ardour.org/view.php?id=2132) * bandaid fix for http://tracker.ardour.org/view.php?id=1985 (Cannot reopen session because jack ports are not unregistered on session close) * bandaid fix: replaced conf.CheckPKGExists ('\"slv2 >= 0.6.0\"') by conf.CheckPKGExists ('slv2') in SConstruct, because the former would fail, even if SLV 0.6.0 was installed * added/enabled debugging output for debugging MIDI model (might be removed later) git-svn-id: svn://localhost/ardour2/branches/3.0@3211 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
6554200e66
commit
fbfe9a7983
22 changed files with 332 additions and 57 deletions
|
|
@ -534,7 +534,7 @@ if env['FFT_ANALYSIS']:
|
||||||
if env['LV2']:
|
if env['LV2']:
|
||||||
conf = env.Configure(custom_tests = { 'CheckPKGExists' : CheckPKGExists })
|
conf = env.Configure(custom_tests = { 'CheckPKGExists' : CheckPKGExists })
|
||||||
|
|
||||||
if conf.CheckPKGExists ('\"slv2 >= 0.6.0\"'):
|
if conf.CheckPKGExists ('slv2'):
|
||||||
libraries['slv2'] = LibraryInfo()
|
libraries['slv2'] = LibraryInfo()
|
||||||
libraries['slv2'].ParseConfig('pkg-config --cflags --libs slv2')
|
libraries['slv2'].ParseConfig('pkg-config --cflags --libs slv2')
|
||||||
env.Append (CCFLAGS="-DHAVE_LV2")
|
env.Append (CCFLAGS="-DHAVE_LV2")
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
|
||||||
|
|
||||||
auditioning_alert_button (_("AUDITION")),
|
auditioning_alert_button (_("AUDITION")),
|
||||||
solo_alert_button (_("SOLO")),
|
solo_alert_button (_("SOLO")),
|
||||||
|
midi_panic_button (_("Panic")),
|
||||||
shown_flag (false),
|
shown_flag (false),
|
||||||
error_log_button (_("Errors"))
|
error_log_button (_("Errors"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -479,6 +479,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
|
||||||
Gtk::ToggleButton auditioning_alert_button;
|
Gtk::ToggleButton auditioning_alert_button;
|
||||||
Gtk::ToggleButton solo_alert_button;
|
Gtk::ToggleButton solo_alert_button;
|
||||||
|
|
||||||
|
Gtk::ToggleButton midi_panic_button;
|
||||||
|
|
||||||
Gtk::VBox alert_box;
|
Gtk::VBox alert_box;
|
||||||
|
|
||||||
void solo_blink (bool);
|
void solo_blink (bool);
|
||||||
|
|
@ -490,6 +492,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
|
||||||
|
|
||||||
void solo_alert_toggle ();
|
void solo_alert_toggle ();
|
||||||
void audition_alert_toggle ();
|
void audition_alert_toggle ();
|
||||||
|
void midi_panic_toggle ();
|
||||||
|
|
||||||
void big_clock_value_changed ();
|
void big_clock_value_changed ();
|
||||||
void primary_clock_value_changed ();
|
void primary_clock_value_changed ();
|
||||||
|
|
|
||||||
|
|
@ -344,12 +344,15 @@ ARDOUR_UI::setup_transport ()
|
||||||
solo_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::solo_alert_toggle));
|
solo_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::solo_alert_toggle));
|
||||||
auditioning_alert_button.set_name ("TransportAuditioningAlert");
|
auditioning_alert_button.set_name ("TransportAuditioningAlert");
|
||||||
auditioning_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle));
|
auditioning_alert_button.signal_pressed().connect (mem_fun(*this,&ARDOUR_UI::audition_alert_toggle));
|
||||||
|
midi_panic_button.set_name("TransportMidiPanic");
|
||||||
|
midi_panic_button.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::midi_panic_toggle));
|
||||||
|
|
||||||
tooltips().set_tip (solo_alert_button, _("When active, something is soloed.\nClick to de-solo everything"));
|
tooltips().set_tip (solo_alert_button, _("When active, something is soloed.\nClick to de-solo everything"));
|
||||||
tooltips().set_tip (auditioning_alert_button, _("When active, auditioning is taking place\nClick to stop the audition"));
|
tooltips().set_tip (auditioning_alert_button, _("When active, auditioning is taking place\nClick to stop the audition"));
|
||||||
|
|
||||||
alert_box.pack_start (solo_alert_button, false, false);
|
alert_box.pack_start (solo_alert_button, false, false);
|
||||||
alert_box.pack_start (auditioning_alert_button, false, false);
|
alert_box.pack_start (auditioning_alert_button, false, false);
|
||||||
|
alert_box.pack_start (midi_panic_button, false, false);
|
||||||
|
|
||||||
transport_tearoff_hbox.set_border_width (3);
|
transport_tearoff_hbox.set_border_width (3);
|
||||||
|
|
||||||
|
|
@ -518,6 +521,16 @@ ARDOUR_UI::solo_alert_toggle ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ARDOUR_UI::midi_panic_toggle ()
|
||||||
|
{
|
||||||
|
if (session) {
|
||||||
|
session->midi_panic();
|
||||||
|
midi_panic_button.set_active (false);
|
||||||
|
midi_panic_button.set_state (STATE_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ARDOUR_UI::solo_blink (bool onoff)
|
ARDOUR_UI::solo_blink (bool onoff)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,12 +35,41 @@ CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item,
|
||||||
const boost::shared_ptr<ARDOUR::Note> note)
|
const boost::shared_ptr<ARDOUR::Note> note)
|
||||||
: _region(region)
|
: _region(region)
|
||||||
, _item(item)
|
, _item(item)
|
||||||
|
, _text(0)
|
||||||
, _state(None)
|
, _state(None)
|
||||||
, _note(note)
|
, _note(note)
|
||||||
, _selected(false)
|
, _selected(false)
|
||||||
{
|
{
|
||||||
|
_text = new Text(*(item->property_parent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasMidiEvent::move_event(double dx, double dy)
|
||||||
|
{
|
||||||
|
_item->move(dx, dy);
|
||||||
|
_text->move(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasMidiEvent::show_velocity(void)
|
||||||
|
{
|
||||||
|
_text->property_x() = (x1() + x2()) /2;
|
||||||
|
_text->property_y() = (y1() + y2()) /2;
|
||||||
|
ostringstream velo(ios::ate);
|
||||||
|
velo << int(_note->velocity());
|
||||||
|
_text->property_text() = velo.str();
|
||||||
|
_text->property_justification() = Gtk::JUSTIFY_CENTER;
|
||||||
|
_text->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get();
|
||||||
|
_text->show();
|
||||||
|
_text->lower_to_bottom();
|
||||||
|
_text->raise(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasMidiEvent::hide_velocity(void)
|
||||||
|
{
|
||||||
|
_text->hide();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CanvasMidiEvent::selected(bool yn)
|
CanvasMidiEvent::selected(bool yn)
|
||||||
|
|
@ -49,11 +78,13 @@ CanvasMidiEvent::selected(bool yn)
|
||||||
return;
|
return;
|
||||||
} else if (yn) {
|
} else if (yn) {
|
||||||
set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()),
|
set_fill_color(UINT_INTERPOLATE(note_fill_color(_note->velocity()),
|
||||||
ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.85));
|
ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get(), 0.1));
|
||||||
set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get());
|
set_outline_color(ARDOUR_UI::config()->canvasvar_MidiNoteSelectedOutline.get());
|
||||||
|
show_velocity();
|
||||||
} else {
|
} else {
|
||||||
set_fill_color(note_fill_color(_note->velocity()));
|
set_fill_color(note_fill_color(_note->velocity()));
|
||||||
set_outline_color(note_outline_color(_note->velocity()));
|
set_outline_color(note_outline_color(_note->velocity()));
|
||||||
|
hide_velocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
_selected = yn;
|
_selected = yn;
|
||||||
|
|
@ -70,11 +101,38 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
|
||||||
double event_x, event_y, dx, dy;
|
double event_x, event_y, dx, dy;
|
||||||
nframes_t event_frame;
|
nframes_t event_frame;
|
||||||
bool select_mod;
|
bool select_mod;
|
||||||
|
uint8_t d_velocity = 10;
|
||||||
|
|
||||||
if (_region.get_time_axis_view().editor.current_mouse_mode() != Editing::MouseNote)
|
if (_region.get_time_axis_view().editor.current_mouse_mode() != Editing::MouseNote)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (ev->type) {
|
switch (ev->type) {
|
||||||
|
case GDK_SCROLL:
|
||||||
|
if (Keyboard::modifier_state_equals (ev->scroll.state, Keyboard::Level4Modifier)) {
|
||||||
|
d_velocity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ev->scroll.direction == GDK_SCROLL_UP) {
|
||||||
|
_region.note_selected(this, true);
|
||||||
|
if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
|
||||||
|
// TODO: absolute velocity
|
||||||
|
} else {
|
||||||
|
_region.change_velocity(d_velocity, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if(ev->scroll.direction == GDK_SCROLL_DOWN) {
|
||||||
|
|
||||||
|
_region.note_selected(this, true);
|
||||||
|
if (_region.mouse_state() == MidiRegionView::SelectTouchDragging) {
|
||||||
|
// TODO: absolute velocity
|
||||||
|
} else {
|
||||||
|
_region.change_velocity(-d_velocity, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
case GDK_KEY_PRESS:
|
case GDK_KEY_PRESS:
|
||||||
if (_note && ev->key.keyval == GDK_Delete) {
|
if (_note && ev->key.keyval == GDK_Delete) {
|
||||||
selected(true);
|
selected(true);
|
||||||
|
|
@ -92,11 +150,15 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
|
||||||
case GDK_ENTER_NOTIFY:
|
case GDK_ENTER_NOTIFY:
|
||||||
_region.note_entered(this);
|
_region.note_entered(this);
|
||||||
_item->grab_focus();
|
_item->grab_focus();
|
||||||
|
show_velocity();
|
||||||
Keyboard::magic_widget_grab_focus();
|
Keyboard::magic_widget_grab_focus();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GDK_LEAVE_NOTIFY:
|
case GDK_LEAVE_NOTIFY:
|
||||||
Keyboard::magic_widget_drop_focus();
|
Keyboard::magic_widget_drop_focus();
|
||||||
|
if(! selected()) {
|
||||||
|
hide_velocity();
|
||||||
|
}
|
||||||
_region.get_canvas_group()->grab_focus();
|
_region.get_canvas_group()->grab_focus();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#define __gtk_ardour_canvas_midi_event_h__
|
#define __gtk_ardour_canvas_midi_event_h__
|
||||||
|
|
||||||
#include "simplerect.h"
|
#include "simplerect.h"
|
||||||
|
#include <libgnomecanvasmm/text.h>
|
||||||
#include <ardour/midi_model.h>
|
#include <ardour/midi_model.h>
|
||||||
|
|
||||||
class Editor;
|
class Editor;
|
||||||
|
|
@ -48,13 +49,18 @@ public:
|
||||||
Item* item,
|
Item* item,
|
||||||
const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>());
|
const boost::shared_ptr<ARDOUR::Note> note = boost::shared_ptr<ARDOUR::Note>());
|
||||||
|
|
||||||
virtual ~CanvasMidiEvent() {}
|
virtual ~CanvasMidiEvent() { if(_text) delete _text; }
|
||||||
|
|
||||||
bool on_event(GdkEvent* ev);
|
bool on_event(GdkEvent* ev);
|
||||||
|
|
||||||
bool selected() const { return _selected; }
|
bool selected() const { return _selected; }
|
||||||
void selected(bool yn);
|
void selected(bool yn);
|
||||||
|
|
||||||
|
void move_event(double dx, double dy);
|
||||||
|
|
||||||
|
void show_velocity();
|
||||||
|
void hide_velocity();
|
||||||
|
|
||||||
virtual void set_outline_color(uint32_t c) = 0;
|
virtual void set_outline_color(uint32_t c) = 0;
|
||||||
virtual void set_fill_color(uint32_t c) = 0;
|
virtual void set_fill_color(uint32_t c) = 0;
|
||||||
|
|
||||||
|
|
@ -63,9 +69,6 @@ public:
|
||||||
virtual double x2() = 0;
|
virtual double x2() = 0;
|
||||||
virtual double y2() = 0;
|
virtual double y2() = 0;
|
||||||
|
|
||||||
const Item* item() const { return _item; }
|
|
||||||
Item* item() { return _item; }
|
|
||||||
|
|
||||||
const boost::shared_ptr<ARDOUR::Note> note() { return _note; }
|
const boost::shared_ptr<ARDOUR::Note> note() { return _note; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -73,6 +76,7 @@ protected:
|
||||||
|
|
||||||
MidiRegionView& _region;
|
MidiRegionView& _region;
|
||||||
Item* const _item;
|
Item* const _item;
|
||||||
|
Text* _text;
|
||||||
State _state;
|
State _state;
|
||||||
const boost::shared_ptr<ARDOUR::Note> _note;
|
const boost::shared_ptr<ARDOUR::Note> _note;
|
||||||
bool _own_note;
|
bool _own_note;
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@
|
||||||
#include "control_point.h"
|
#include "control_point.h"
|
||||||
#include "canvas_impl.h"
|
#include "canvas_impl.h"
|
||||||
#include "simplerect.h"
|
#include "simplerect.h"
|
||||||
|
#include "canvas-midi-event.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -48,6 +49,7 @@ using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
using namespace Gtk;
|
using namespace Gtk;
|
||||||
|
using namespace ArdourCanvas;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Editor::track_canvas_scroll (GdkEventScroll* ev)
|
Editor::track_canvas_scroll (GdkEventScroll* ev)
|
||||||
|
|
@ -56,6 +58,7 @@ Editor::track_canvas_scroll (GdkEventScroll* ev)
|
||||||
double wx, wy;
|
double wx, wy;
|
||||||
nframes_t xdelta;
|
nframes_t xdelta;
|
||||||
int direction = ev->direction;
|
int direction = ev->direction;
|
||||||
|
CanvasMidiEvent *midi_event = dynamic_cast<CanvasMidiEvent *>(track_canvas->get_item_at(ev->x, ev->y));
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
|
|
@ -94,6 +97,9 @@ Editor::track_canvas_scroll (GdkEventScroll* ev)
|
||||||
current_stepping_trackview->step_height (true);
|
current_stepping_trackview->step_height (true);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
if(midi_event) {
|
||||||
|
return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
|
||||||
|
}
|
||||||
scroll_tracks_up_line ();
|
scroll_tracks_up_line ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +135,9 @@ Editor::track_canvas_scroll (GdkEventScroll* ev)
|
||||||
current_stepping_trackview->step_height (false);
|
current_stepping_trackview->step_height (false);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
if(midi_event) {
|
||||||
|
return midi_event->on_event(reinterpret_cast<GdkEvent *>(ev));
|
||||||
|
}
|
||||||
scroll_tracks_down_line ();
|
scroll_tracks_down_line ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -423,8 +423,22 @@ MidiRegionView::redisplay_model()
|
||||||
|
|
||||||
_model->read_lock();
|
_model->read_lock();
|
||||||
|
|
||||||
for (size_t i=0; i < _model->n_notes(); ++i)
|
/*
|
||||||
|
MidiModel::Notes notes = _model->notes();
|
||||||
|
cerr << endl << "Model contains " << notes.size() << " Notes:" << endl;
|
||||||
|
for(MidiModel::Notes::iterator i = notes.begin(); i != notes.end(); ++i) {
|
||||||
|
Note note = *(*i).get();
|
||||||
|
cerr << "MODEL: Note time: " << note.time() << " duration: " << note.duration()
|
||||||
|
<< " end-time: " << note.end_time()
|
||||||
|
<< " velocity: " << int(note.velocity())
|
||||||
|
//<< " Note-on: " << note.on_event().
|
||||||
|
//<< " Note-off: " << note.off_event()
|
||||||
|
<< endl;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
for (size_t i=0; i < _model->n_notes(); ++i) {
|
||||||
add_note(_model->note_at(i));
|
add_note(_model->note_at(i));
|
||||||
|
}
|
||||||
|
|
||||||
end_write();
|
end_write();
|
||||||
|
|
||||||
|
|
@ -538,11 +552,15 @@ MidiRegionView::set_y_position_and_height (double y, double h)
|
||||||
note->show();
|
note->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
note->hide_velocity();
|
||||||
note->property_y1() = y1;
|
note->property_y1() = y1;
|
||||||
note->property_y2() = y2;
|
note->property_y2() = y2;
|
||||||
|
if(note->selected()) {
|
||||||
|
note->show_velocity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_model->read_unlock();
|
_model->read_unlock();
|
||||||
}
|
}
|
||||||
|
|
@ -609,6 +627,7 @@ MidiRegionView::end_write()
|
||||||
{
|
{
|
||||||
delete[] _active_notes;
|
delete[] _active_notes;
|
||||||
_active_notes = NULL;
|
_active_notes = NULL;
|
||||||
|
_marked_for_selection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -657,6 +676,8 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
|
||||||
|
|
||||||
ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
|
ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
|
||||||
|
|
||||||
|
CanvasMidiEvent *event = 0;
|
||||||
|
|
||||||
if (midi_view()->note_mode() == Sustained) {
|
if (midi_view()->note_mode() == Sustained) {
|
||||||
|
|
||||||
//cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time()
|
//cerr << "MRV::add_note sustained " << note->note() << " @ " << note->time()
|
||||||
|
|
@ -687,6 +708,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
|
||||||
|
|
||||||
ev_rect->show();
|
ev_rect->show();
|
||||||
_events.push_back(ev_rect);
|
_events.push_back(ev_rect);
|
||||||
|
event = ev_rect;
|
||||||
|
|
||||||
MidiGhostRegion* gr;
|
MidiGhostRegion* gr;
|
||||||
|
|
||||||
|
|
@ -711,8 +733,18 @@ MidiRegionView::add_note(const boost::shared_ptr<Note> note)
|
||||||
ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity());
|
ev_diamond->property_fill_color_rgba() = note_fill_color(note->velocity());
|
||||||
ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity());
|
ev_diamond->property_outline_color_rgba() = note_outline_color(note->velocity());
|
||||||
_events.push_back(ev_diamond);
|
_events.push_back(ev_diamond);
|
||||||
|
event = ev_diamond;
|
||||||
|
} else {
|
||||||
|
event = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(event) {
|
||||||
|
Note *note = event->note().get();
|
||||||
|
|
||||||
|
if(_marked_for_selection.find(note) != _marked_for_selection.end()) {
|
||||||
|
note_selected(event, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -813,7 +845,7 @@ void
|
||||||
MidiRegionView::move_selection(double dx, double dy)
|
MidiRegionView::move_selection(double dx, double dy)
|
||||||
{
|
{
|
||||||
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i)
|
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i)
|
||||||
(*i)->item()->move(dx, dy);
|
(*i)->move_event(dx, dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -851,7 +883,6 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
|
||||||
// Make sure the note pitch does not exceed the MIDI standard range
|
// Make sure the note pitch does not exceed the MIDI standard range
|
||||||
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
|
if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
|
||||||
highest_note_difference = highest_note_in_selection - 127;
|
highest_note_difference = highest_note_in_selection - 127;
|
||||||
cerr << "Highest note difference: " << (int) highest_note_difference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_delta_command();
|
start_delta_command();
|
||||||
|
|
@ -868,9 +899,15 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
|
||||||
copy->set_time(0);
|
copy->set_time(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t new_pitch = (*i)->note()->note() + dnote - highest_note_difference;
|
uint8_t original_pitch = (*i)->note()->note();
|
||||||
if(new_pitch > 127) {
|
uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
|
||||||
new_pitch = 127;
|
|
||||||
|
// keep notes in standard midi range
|
||||||
|
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)) {
|
||||||
|
new_pitch = original_pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
|
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
|
||||||
|
|
@ -880,19 +917,16 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
|
||||||
|
|
||||||
command_add_note(copy);
|
command_add_note(copy);
|
||||||
|
|
||||||
_selection.erase(i);
|
_marked_for_selection.insert(copy.get());
|
||||||
i = next;
|
i = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_command();
|
apply_command();
|
||||||
|
|
||||||
//cerr << "new lowest note (selection): " << int(lowest_note_in_selection) << " new highest note(selection): " << int(highest_note_in_selection) << endl;
|
|
||||||
|
|
||||||
// care about notes being moved beyond the upper/lower bounds on the canvas
|
// 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()
|
highest_note_in_selection > midi_stream_view()->highest_note()
|
||||||
) {
|
) {
|
||||||
//cerr << "resetting note range" << endl;
|
|
||||||
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1031,12 +1065,15 @@ MidiRegionView::commit_resizing(CanvasNote::NoteEnd note_end, double event_x, bo
|
||||||
command_remove_note(canvas_note);
|
command_remove_note(canvas_note);
|
||||||
copy->on_event().time() = current_frame;
|
copy->on_event().time() = current_frame;
|
||||||
command_add_note(copy);
|
command_add_note(copy);
|
||||||
|
_marked_for_selection.insert(copy.get());
|
||||||
}
|
}
|
||||||
// resize end of note
|
// resize end of note
|
||||||
if (note_end == CanvasNote::NOTE_OFF && current_frame > copy->time()) {
|
if (note_end == CanvasNote::NOTE_OFF && current_frame > copy->time()) {
|
||||||
|
command_remove_note(canvas_note);
|
||||||
command_remove_note(canvas_note);
|
command_remove_note(canvas_note);
|
||||||
copy->off_event().time() = current_frame;
|
copy->off_event().time() = current_frame;
|
||||||
command_add_note(copy);
|
command_add_note(copy);
|
||||||
|
_marked_for_selection.insert(copy.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
delete resize_rect;
|
delete resize_rect;
|
||||||
|
|
@ -1045,9 +1082,45 @@ MidiRegionView::commit_resizing(CanvasNote::NoteEnd note_end, double event_x, bo
|
||||||
|
|
||||||
_resize_data.clear();
|
_resize_data.clear();
|
||||||
apply_command();
|
apply_command();
|
||||||
clear_selection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiRegionView::change_velocity(uint8_t velocity, bool relative)
|
||||||
|
{
|
||||||
|
start_delta_command();
|
||||||
|
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())));
|
||||||
|
|
||||||
|
if(relative) {
|
||||||
|
uint8_t new_velocity = copy->velocity() + velocity;
|
||||||
|
clamp_0_to_127(new_velocity);
|
||||||
|
|
||||||
|
copy->set_velocity(new_velocity);
|
||||||
|
} else { // absolute
|
||||||
|
copy->set_velocity(velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_remove_note(event);
|
||||||
|
command_add_note(copy);
|
||||||
|
|
||||||
|
_marked_for_selection.insert(copy.get());
|
||||||
|
i = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dont keep notes selected if tweaking a single note
|
||||||
|
if(_marked_for_selection.size() == 1) {
|
||||||
|
_marked_for_selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_command();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
|
MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ class MidiRegionView : public RegionView
|
||||||
|
|
||||||
void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
|
void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
|
||||||
if (_delta_command && ev->note()) {
|
if (_delta_command && ev->note()) {
|
||||||
|
_selection.erase(ev);
|
||||||
_delta_command->remove(ev->note());
|
_delta_command->remove(ev->note());
|
||||||
ev->selected(true);
|
ev->selected(true);
|
||||||
}
|
}
|
||||||
|
|
@ -162,6 +163,14 @@ class MidiRegionView : public RegionView
|
||||||
*/
|
*/
|
||||||
void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
|
void commit_resizing(ArdourCanvas::CanvasNote::NoteEnd note_end, double event_x, bool relative);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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);
|
||||||
|
|
||||||
enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
|
enum MouseState { None, Pressed, SelectTouchDragging, SelectRectDragging, AddDragging, EraseTouchDragging };
|
||||||
MouseState mouse_state() const { return _mouse_state; }
|
MouseState mouse_state() const { return _mouse_state; }
|
||||||
|
|
||||||
|
|
@ -221,9 +230,17 @@ class MidiRegionView : public RegionView
|
||||||
MouseState _mouse_state;
|
MouseState _mouse_state;
|
||||||
int _pressed_button;
|
int _pressed_button;
|
||||||
|
|
||||||
|
/// currently selected CanvasMidiEvents
|
||||||
typedef std::set<ArdourCanvas::CanvasMidiEvent*> Selection;
|
typedef std::set<ArdourCanvas::CanvasMidiEvent*> Selection;
|
||||||
Selection _selection;
|
Selection _selection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this enables vanilla notes to be marked for selection
|
||||||
|
* they are added to _selection when redisplay_model is called
|
||||||
|
* this is necessary for selecting notes during/after model manipulations
|
||||||
|
*/
|
||||||
|
std::set<ARDOUR::Note *> _marked_for_selection;
|
||||||
|
|
||||||
std::vector<NoteResizeData *> _resize_data;
|
std::vector<NoteResizeData *> _resize_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,5 +54,14 @@ inline static uint32_t note_fill_color(uint8_t vel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static void clamp_0_to_127(uint8_t &val)
|
||||||
|
{
|
||||||
|
if( (127 < val) && (val < 192) ) {
|
||||||
|
val = 127;
|
||||||
|
} else if( (192 <= val) && (val < 255) ) {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __gtk_ardour_midi_util_h__ */
|
#endif /* __gtk_ardour_midi_util_h__ */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ public:
|
||||||
MidiModel(Session& s, size_t size=0);
|
MidiModel(Session& s, size_t size=0);
|
||||||
|
|
||||||
// This is crap.
|
// This is crap.
|
||||||
void write_lock() { _lock.writer_lock(); _automation_lock.lock(); }
|
void write_lock();
|
||||||
void write_unlock() { _lock.writer_unlock(); _automation_lock.unlock(); }
|
void write_unlock();
|
||||||
void read_lock() const { _lock.reader_lock(); /*_automation_lock.lock();*/ }
|
void read_lock() const;
|
||||||
void read_unlock() const { _lock.reader_unlock(); /*_automation_lock.unlock();*/ }
|
void read_unlock() const;
|
||||||
|
|
||||||
void clear() { _notes.clear(); }
|
void clear() { _notes.clear(); }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,8 +280,8 @@ MidiRingBuffer::read_contents(size_t size, Byte* buf)
|
||||||
inline size_t
|
inline size_t
|
||||||
MidiRingBuffer::write(double time, size_t size, const Byte* buf)
|
MidiRingBuffer::write(double time, size_t size, const Byte* buf)
|
||||||
{
|
{
|
||||||
//printf("MRB - write %#X %d %d with time %lf\n",
|
printf("MRB - write %#X %d %d with time %lf\n",
|
||||||
// buf[0], buf[1], buf[2], time);
|
buf[0], buf[1], buf[2], time);
|
||||||
|
|
||||||
assert(size > 0);
|
assert(size > 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ public:
|
||||||
|
|
||||||
int set_state(const XMLNode& node);
|
int set_state(const XMLNode& node);
|
||||||
|
|
||||||
|
void midi_panic(void);
|
||||||
bool write_immediate_event(size_t size, const Byte* buf);
|
bool write_immediate_event(size_t size, const Byte* buf);
|
||||||
|
|
||||||
struct MidiControl : public AutomationControl {
|
struct MidiControl : public AutomationControl {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public:
|
||||||
const Note& operator=(const Note& copy);
|
const Note& operator=(const Note& copy);
|
||||||
|
|
||||||
inline bool operator==(const Note& other)
|
inline bool operator==(const Note& other)
|
||||||
{ return time() == other.time() && note() == other.note(); }
|
{ return time() == other.time() && note() == other.note() && duration() == other.duration(); }
|
||||||
|
|
||||||
inline double time() const { return _on_event.time(); }
|
inline double time() const { return _on_event.time(); }
|
||||||
inline double end_time() const { return _off_event.time(); }
|
inline double end_time() const { return _off_event.time(); }
|
||||||
|
|
|
||||||
|
|
@ -754,6 +754,7 @@ class Session : public PBD::StatefulDestructible
|
||||||
|
|
||||||
/* MIDI */
|
/* MIDI */
|
||||||
|
|
||||||
|
void midi_panic(void);
|
||||||
int set_mtc_port (string port_tag);
|
int set_mtc_port (string port_tag);
|
||||||
int set_mmc_port (string port_tag);
|
int set_mmc_port (string port_tag);
|
||||||
int set_midi_port (string port_tag);
|
int set_midi_port (string port_tag);
|
||||||
|
|
|
||||||
|
|
@ -527,7 +527,8 @@ AudioEngine::remove_session ()
|
||||||
session = 0;
|
session = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_all_ports ();
|
//FIXME: Preliminary bugfix for http://tracker.ardour.org/view.php?id=1985
|
||||||
|
//remove_all_ports ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -555,6 +556,7 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input,
|
||||||
{
|
{
|
||||||
Port* newport = 0;
|
Port* newport = 0;
|
||||||
|
|
||||||
|
cerr << "trying to register port with name " << portname << endl;
|
||||||
try {
|
try {
|
||||||
if (dtype == DataType::AUDIO) {
|
if (dtype == DataType::AUDIO) {
|
||||||
newport = new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput), publish, frames_per_cycle());
|
newport = new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput), publish, frames_per_cycle());
|
||||||
|
|
@ -564,11 +566,17 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input,
|
||||||
throw unknown_type();
|
throw unknown_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cerr << "successfully got port " << portname << " with address " << newport << endl;
|
||||||
|
|
||||||
RCUWriter<Ports> writer (ports);
|
RCUWriter<Ports> writer (ports);
|
||||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||||
|
cerr << "Address of ports list: " << ps << endl
|
||||||
|
<< "Ports set size before insert: " << ps->size() << endl;
|
||||||
ps->insert (ps->begin(), newport);
|
ps->insert (ps->begin(), newport);
|
||||||
|
cerr << "Ports set size after insert: " << ps->size() << endl;
|
||||||
/* writer goes out of scope, forces update */
|
/* writer goes out of scope, forces update */
|
||||||
|
|
||||||
|
|
||||||
return newport;
|
return newport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -608,22 +616,31 @@ AudioEngine::unregister_port (Port& port)
|
||||||
{
|
{
|
||||||
/* caller must hold process lock */
|
/* caller must hold process lock */
|
||||||
|
|
||||||
|
cerr << "about to unregister Port xx x" << &port << "\n";
|
||||||
|
|
||||||
if (!_running) {
|
if (!_running) {
|
||||||
/* probably happening when the engine has been halted by JACK,
|
/* probably happening when the engine has been halted by JACK,
|
||||||
in which case, there is nothing we can do here.
|
in which case, there is nothing we can do here.
|
||||||
*/
|
*/
|
||||||
|
cerr << "not running\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
cerr << "before getcopy\n";
|
||||||
|
|
||||||
RCUWriter<Ports> writer (ports);
|
RCUWriter<Ports> writer (ports);
|
||||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
||||||
|
|
||||||
|
cerr << "Ports set size: " << ps.get()->size() << endl;
|
||||||
|
|
||||||
for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
|
for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
|
||||||
|
cerr << "before delete" << endl;
|
||||||
if ((*i) == &port) {
|
if ((*i) == &port) {
|
||||||
|
cerr << "About to delete " << &port << endl;
|
||||||
delete *i;
|
delete *i;
|
||||||
ps->erase (i);
|
ps->erase (i);
|
||||||
|
cerr << "After erasing ports size: " << ps->size();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -631,6 +648,7 @@ AudioEngine::unregister_port (Port& port)
|
||||||
/* writer goes out of scope, forces update */
|
/* writer goes out of scope, forces update */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cerr << "before remove_connections\n";
|
||||||
remove_connections_for (port);
|
remove_connections_for (port);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset)
|
||||||
for (size_t i=0; i < msrc.size(); ++i) {
|
for (size_t i=0; i < msrc.size(); ++i) {
|
||||||
const MIDI::Event& ev = msrc[i];
|
const MIDI::Event& ev = msrc[i];
|
||||||
if (ev.time() >= offset && ev.time() < offset+nframes) {
|
if (ev.time() >= offset && ev.time() < offset+nframes) {
|
||||||
//cout << "MidiBuffer::read_from got event, " << ev.time() << endl;
|
cout << "MidiBuffer::read_from got event, " << int(ev.type()) << " time: " << ev.time() << " buffer size: " << _size << endl;
|
||||||
push_back(ev);
|
push_back(ev);
|
||||||
} else {
|
} else {
|
||||||
cerr << "MidiBuffer event out of range, " << ev.time() << endl;
|
cerr << "MidiBuffer event out of range, " << ev.time() << endl;
|
||||||
|
|
@ -148,7 +148,7 @@ MidiBuffer::push_back(const MIDI::Event& ev)
|
||||||
_events[_size].set_buffer(write_loc, false);
|
_events[_size].set_buffer(write_loc, false);
|
||||||
++_size;
|
++_size;
|
||||||
|
|
||||||
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
|
cerr << "MidiBuffer: pushed, size = " << _size << endl;
|
||||||
|
|
||||||
_silent = false;
|
_silent = false;
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ MidiBuffer::push_back(const jack_midi_event_t& ev)
|
||||||
_events[_size].set_buffer(write_loc, false);
|
_events[_size].set_buffer(write_loc, false);
|
||||||
++_size;
|
++_size;
|
||||||
|
|
||||||
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
|
cerr << "MidiBuffer: pushed, size = " << _size << endl;
|
||||||
|
|
||||||
_silent = false;
|
_silent = false;
|
||||||
|
|
||||||
|
|
@ -207,7 +207,7 @@ MidiBuffer::reserve(double time, size_t size)
|
||||||
_events[_size].set_buffer(write_loc, false);
|
_events[_size].set_buffer(write_loc, false);
|
||||||
++_size;
|
++_size;
|
||||||
|
|
||||||
//cerr << "MidiBuffer: reserved, size = " << _size << endl;
|
cerr << "MidiBuffer: reserved, size = " << _size << endl;
|
||||||
|
|
||||||
_silent = false;
|
_silent = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,34 @@ using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiModel::write_lock()
|
||||||
|
{
|
||||||
|
_lock.writer_lock();
|
||||||
|
_automation_lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiModel::write_unlock()
|
||||||
|
{
|
||||||
|
_lock.writer_unlock();
|
||||||
|
_automation_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiModel::read_lock() const
|
||||||
|
{
|
||||||
|
_lock.reader_lock();
|
||||||
|
/*_automation_lock.lock();*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiModel::read_unlock() const
|
||||||
|
{
|
||||||
|
_lock.reader_unlock();
|
||||||
|
/*_automation_lock.unlock();*/
|
||||||
|
}
|
||||||
|
|
||||||
// Read iterator (const_iterator)
|
// Read iterator (const_iterator)
|
||||||
|
|
||||||
MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
|
|
@ -51,7 +79,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
model.read_lock();
|
model.read_lock();
|
||||||
|
|
||||||
_note_iter = model.notes().end();
|
_note_iter = model.notes().end();
|
||||||
|
// find first note which begins after t
|
||||||
for (MidiModel::Notes::const_iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
|
for (MidiModel::Notes::const_iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
|
||||||
if ((*i)->time() >= t) {
|
if ((*i)->time() >= t) {
|
||||||
_note_iter = i;
|
_note_iter = i;
|
||||||
|
|
@ -95,6 +123,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
if (_note_iter != model.notes().end()) {
|
if (_note_iter != model.notes().end()) {
|
||||||
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
||||||
_active_notes.push(*_note_iter);
|
_active_notes.push(*_note_iter);
|
||||||
|
cerr << " new const iterator: size active notes: " << _active_notes.size() << " is empty: " << _active_notes.empty() << endl;
|
||||||
++_note_iter;
|
++_note_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,19 +135,22 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
|
||||||
if (_event.size() == 0) {
|
if (_event.size() == 0) {
|
||||||
//cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
|
//cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
|
||||||
_is_end = true;
|
_is_end = true;
|
||||||
|
if(_locked) {
|
||||||
_model->read_unlock();
|
_model->read_unlock();
|
||||||
_locked = false;
|
_locked = false;
|
||||||
} /*else {
|
}
|
||||||
|
} else {
|
||||||
printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
|
printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MidiModel::const_iterator::~const_iterator()
|
MidiModel::const_iterator::~const_iterator()
|
||||||
{
|
{
|
||||||
if (_locked)
|
if (_locked) {
|
||||||
_model->read_unlock();
|
_model->read_unlock();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const MidiModel::const_iterator&
|
const MidiModel::const_iterator&
|
||||||
|
|
@ -168,6 +200,7 @@ MidiModel::const_iterator::operator++()
|
||||||
t = (*_note_iter)->time();
|
t = (*_note_iter)->time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cerr << " operator++ before test: size active notes: " << _active_notes.size() << " is empty: " << _active_notes.empty() << endl;
|
||||||
// Use the next earliest note off iff it's earlier than the note on
|
// Use the next earliest note off iff it's earlier than the note on
|
||||||
if (_model->note_mode() == Sustained && (! _active_notes.empty())) {
|
if (_model->note_mode() == Sustained && (! _active_notes.empty())) {
|
||||||
if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
|
if (type == NIL || _active_notes.top()->end_time() <= (*_note_iter)->time()) {
|
||||||
|
|
@ -182,22 +215,20 @@ MidiModel::const_iterator::operator++()
|
||||||
type = CC;
|
type = CC;
|
||||||
|
|
||||||
if (type == NOTE_ON) {
|
if (type == NOTE_ON) {
|
||||||
//cerr << "********** MIDI Iterator = note on" << endl;
|
cerr << "********** MIDI Iterator = note on" << endl;
|
||||||
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
_event = MIDI::Event((*_note_iter)->on_event(), false);
|
||||||
_active_notes.push(*_note_iter);
|
_active_notes.push(*_note_iter);
|
||||||
++_note_iter;
|
++_note_iter;
|
||||||
} else if (type == NOTE_OFF) {
|
} else if (type == NOTE_OFF) {
|
||||||
//cerr << "********** MIDI Iterator = note off" << endl;
|
cerr << "********** MIDI Iterator = note off" << endl;
|
||||||
_event = MIDI::Event(_active_notes.top()->off_event(), false);
|
_event = MIDI::Event(_active_notes.top()->off_event(), false);
|
||||||
_active_notes.pop();
|
_active_notes.pop();
|
||||||
} else if (type == CC) {
|
} else if (type == CC) {
|
||||||
//cerr << "********** MIDI Iterator = CC" << endl;
|
cerr << "********** MIDI Iterator = CC" << endl;
|
||||||
_model->control_to_midi_event(_event, *_control_iter);
|
_model->control_to_midi_event(_event, *_control_iter);
|
||||||
} else {
|
} else {
|
||||||
//cerr << "********** MIDI Iterator = END" << endl;
|
cerr << "********** MIDI Iterator = END" << endl;
|
||||||
_is_end = true;
|
_is_end = true;
|
||||||
_model->read_unlock();
|
|
||||||
_locked = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(_is_end || _event.size() > 0);
|
assert(_is_end || _event.size() > 0);
|
||||||
|
|
@ -226,6 +257,7 @@ MidiModel::const_iterator::operator=(const const_iterator& other)
|
||||||
|
|
||||||
_model = other._model;
|
_model = other._model;
|
||||||
_event = other._event;
|
_event = other._event;
|
||||||
|
_active_notes = other._active_notes;
|
||||||
_is_end = other._is_end;
|
_is_end = other._is_end;
|
||||||
_locked = other._locked;
|
_locked = other._locked;
|
||||||
_note_iter = other._note_iter;
|
_note_iter = other._note_iter;
|
||||||
|
|
@ -234,9 +266,6 @@ MidiModel::const_iterator::operator=(const const_iterator& other)
|
||||||
|
|
||||||
assert( ! _event.owns_buffer());
|
assert( ! _event.owns_buffer());
|
||||||
|
|
||||||
if (_locked)
|
|
||||||
_model->read_lock();
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,16 +294,16 @@ MidiModel::MidiModel(Session& s, size_t size)
|
||||||
size_t
|
size_t
|
||||||
MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const
|
MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const
|
||||||
{
|
{
|
||||||
//cerr << this << " MM::read @ " << start << " * " << nframes << " + " << stamp_offset << endl;
|
cerr << this << " MM::read @ " << start << " * " << nframes << " + " << stamp_offset << endl;
|
||||||
//cerr << this << " MM # notes: " << n_notes() << endl;
|
cerr << this << " MM # notes: " << n_notes() << endl;
|
||||||
|
|
||||||
size_t read_events = 0;
|
size_t read_events = 0;
|
||||||
|
|
||||||
if (start != _next_read) {
|
if (start != _next_read) {
|
||||||
_read_iter = const_iterator(*this, (double)start);
|
_read_iter = const_iterator(*this, (double)start);
|
||||||
//cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
|
cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
|
||||||
} else {
|
} else {
|
||||||
//cerr << "Using cached iterator at " << _next_read << endl;
|
cerr << "Using cached iterator at " << _next_read << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
_next_read = start + nframes;
|
_next_read = start + nframes;
|
||||||
|
|
@ -282,7 +311,11 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes
|
||||||
while (_read_iter != end() && _read_iter->time() < start + nframes) {
|
while (_read_iter != end() && _read_iter->time() < start + nframes) {
|
||||||
assert(_read_iter->size() > 0);
|
assert(_read_iter->size() > 0);
|
||||||
dst.write(_read_iter->time() + stamp_offset, _read_iter->size(), _read_iter->buffer());
|
dst.write(_read_iter->time() + stamp_offset, _read_iter->size(), _read_iter->buffer());
|
||||||
//cerr << this << " MM::read event @ " << _read_iter->time() << endl;
|
cerr << this << " MM::read event @ " << _read_iter->time()
|
||||||
|
<< " type: " << hex << int(_read_iter->type()) << dec
|
||||||
|
<< " note: " << int(_read_iter->note())
|
||||||
|
<< " velocity: " << int(_read_iter->velocity())
|
||||||
|
<< endl;
|
||||||
++_read_iter;
|
++_read_iter;
|
||||||
++read_events;
|
++read_events;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ MidiSource::midi_read (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nfra
|
||||||
{
|
{
|
||||||
Glib::Mutex::Lock lm (_lock);
|
Glib::Mutex::Lock lm (_lock);
|
||||||
if (_model) {
|
if (_model) {
|
||||||
/*const size_t n_events = */_model->read(dst, start, cnt, stamp_offset);
|
const size_t n_events = _model->read(dst, start, cnt, stamp_offset);
|
||||||
//cout << "Read " << n_events << " events from model." << endl;
|
cout << "Read " << n_events << " events from model." << endl;
|
||||||
return cnt;
|
return cnt;
|
||||||
} else {
|
} else {
|
||||||
return read_unlocked (dst, start, cnt, stamp_offset);
|
return read_unlocked (dst, start, cnt, stamp_offset);
|
||||||
|
|
|
||||||
|
|
@ -697,6 +697,19 @@ MidiTrack::set_note_mode (NoteMode m)
|
||||||
midi_diskstream()->set_note_mode(m);
|
midi_diskstream()->set_note_mode(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiTrack::midi_panic()
|
||||||
|
{
|
||||||
|
for(uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||||
|
Byte ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
|
||||||
|
write_immediate_event(3, ev);
|
||||||
|
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
|
||||||
|
write_immediate_event(3, ev);
|
||||||
|
ev[1] = MIDI_CTL_RESET_CONTROLLERS;
|
||||||
|
write_immediate_event(3, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** \return true on success, false on failure (no buffer space left)
|
/** \return true on success, false on failure (no buffer space left)
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include <midi++/mmc.h>
|
#include <midi++/mmc.h>
|
||||||
#include <midi++/port.h>
|
#include <midi++/port.h>
|
||||||
#include <midi++/manager.h>
|
#include <midi++/manager.h>
|
||||||
|
|
@ -37,6 +39,7 @@
|
||||||
#include <ardour/audioengine.h>
|
#include <ardour/audioengine.h>
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
#include <ardour/audio_track.h>
|
#include <ardour/audio_track.h>
|
||||||
|
#include <ardour/midi_track.h>
|
||||||
#include <ardour/audio_diskstream.h>
|
#include <ardour/audio_diskstream.h>
|
||||||
#include <ardour/slave.h>
|
#include <ardour/slave.h>
|
||||||
#include <ardour/cycles.h>
|
#include <ardour/cycles.h>
|
||||||
|
|
@ -52,6 +55,22 @@ using namespace MIDI;
|
||||||
MachineControl::CommandSignature MMC_CommandSignature;
|
MachineControl::CommandSignature MMC_CommandSignature;
|
||||||
MachineControl::ResponseSignature MMC_ResponseSignature;
|
MachineControl::ResponseSignature MMC_ResponseSignature;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Session::midi_panic()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
boost::shared_ptr<RouteList> r = routes.reader ();
|
||||||
|
|
||||||
|
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||||
|
MidiTrack *track = dynamic_cast<MidiTrack*>((*i).get());
|
||||||
|
if (track != 0) {
|
||||||
|
track->midi_panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Session::use_config_midi_ports ()
|
Session::use_config_midi_ports ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ SMFSource::flush_header ()
|
||||||
|
|
||||||
_fd = freopen(path().c_str(), "r+", _fd);
|
_fd = freopen(path().c_str(), "r+", _fd);
|
||||||
assert(_fd);
|
assert(_fd);
|
||||||
fseek(_fd, 0, 0);
|
fseek(_fd, 0, SEEK_SET);
|
||||||
write_chunk("MThd", 6, data);
|
write_chunk("MThd", 6, data);
|
||||||
write_chunk_header("MTrk", _track_size);
|
write_chunk_header("MTrk", _track_size);
|
||||||
|
|
||||||
|
|
@ -204,9 +204,8 @@ SMFSource::flush_header ()
|
||||||
int
|
int
|
||||||
SMFSource::flush_footer()
|
SMFSource::flush_footer()
|
||||||
{
|
{
|
||||||
seek_to_end();
|
fseek(_fd, 0, SEEK_END);
|
||||||
write_footer();
|
write_footer();
|
||||||
seek_to_end();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -321,11 +320,11 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
|
||||||
if (event_size > 1)
|
if (event_size > 1)
|
||||||
fread((*buf) + 1, 1, *size - 1, _fd);
|
fread((*buf) + 1, 1, *size - 1, _fd);
|
||||||
|
|
||||||
/*printf("%s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
|
printf("%s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
|
||||||
for (size_t i=0; i < *size; ++i) {
|
for (size_t i=0; i < *size; ++i) {
|
||||||
printf("%X ", (*buf)[i]);
|
printf("%X ", (*buf)[i]);
|
||||||
}
|
}
|
||||||
printf("\n");*/
|
printf("\n");
|
||||||
|
|
||||||
return (int)*size;
|
return (int)*size;
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +333,7 @@ SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
|
||||||
nframes_t
|
nframes_t
|
||||||
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
|
||||||
{
|
{
|
||||||
//cerr << "SMF " << 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
|
// 64 bits ought to be enough for anybody
|
||||||
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
|
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
|
||||||
|
|
@ -349,7 +348,7 @@ SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, n
|
||||||
size_t scratch_size = 0; // keep track of scratch to minimize reallocs
|
size_t scratch_size = 0; // keep track of scratch to minimize reallocs
|
||||||
|
|
||||||
// FIXME: don't seek to start and search every read (brutal!)
|
// FIXME: don't seek to start and search every read (brutal!)
|
||||||
fseek(_fd, _header_size, 0);
|
fseek(_fd, _header_size, SEEK_SET);
|
||||||
|
|
||||||
// FIXME: assumes tempo never changes after start
|
// FIXME: assumes tempo never changes after start
|
||||||
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue