summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-09-15 18:54:04 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-09-15 18:54:04 +0000
commit084dda86a7c4391aba4e9f37f752af4846ded15d (patch)
tree067abd6a4ad767958bc3a391c96f5486f8e3462f
parent7eea9fac9d23cdb2a6b39c2fbd4b680fafb40a5c (diff)
when there is a chord at the beginning of a note selection, play the whole chord during drags, not just the first note. seems to be able to send a bank swap message - probably an existingbug
git-svn-id: svn://localhost/ardour2/branches/3.0@7784 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/midi_region_view.cc98
-rw-r--r--gtk2_ardour/midi_region_view.h4
-rw-r--r--gtk2_ardour/note_player.cc60
-rw-r--r--gtk2_ardour/note_player.h34
-rw-r--r--gtk2_ardour/wscript1
5 files changed, 170 insertions, 27 deletions
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index cd26a0c81f..f3e1b2cd98 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -59,6 +59,7 @@
#include "midi_time_axis.h"
#include "midi_time_axis.h"
#include "midi_util.h"
+#include "note_player.h"
#include "public_editor.h"
#include "rgb_macros.h"
#include "selection.h"
@@ -91,6 +92,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
, _step_edit_cursor (0)
, _step_edit_cursor_width (1.0)
, _step_edit_cursor_position (0.0)
+ , _earliest_selected_time (Evoral::MaxMusicalTime)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
@@ -115,6 +117,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
+ , _earliest_selected_time (Evoral::MaxMusicalTime)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
@@ -138,6 +141,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
+ , _earliest_selected_time (Evoral::MaxMusicalTime)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
@@ -165,6 +169,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
, _diff_command(0)
, _ghost_note(0)
, _drag_rect (0)
+ , _earliest_selected_time (Evoral::MaxMusicalTime)
, _mouse_state(None)
, _pressed_button(0)
, _sort_needed (true)
@@ -1308,6 +1313,7 @@ MidiRegionView::extend_active_notes()
}
}
+
void
MidiRegionView::play_midi_note(boost::shared_ptr<NoteType> note)
{
@@ -1321,36 +1327,34 @@ MidiRegionView::play_midi_note(boost::shared_ptr<NoteType> note)
return;
}
- route_ui->midi_track()->write_immediate_event(
- note->on_event().size(), note->on_event().buffer());
-
- const double note_length_beats = (note->off_event().time() - note->on_event().time());
- nframes_t note_length_ms = beats_to_frames(note_length_beats)
- * (1000 / (double)route_ui->session()->nominal_frame_rate());
-
- /* note: we probably should not be binding a shared_ptr<NoteType>
- here. Since its a one-shot timeout, its sort of OK, but ...
- */
-
- Glib::signal_timeout().connect(sigc::bind(sigc::mem_fun(this, &MidiRegionView::play_midi_note_off), note),
- note_length_ms, G_PRIORITY_DEFAULT);
+ NotePlayer* np = new NotePlayer (route_ui->midi_track());
+ np->add (note);
+ np->play ();
}
-bool
-MidiRegionView::play_midi_note_off(boost::shared_ptr<NoteType> note)
+void
+MidiRegionView::play_midi_chord (vector<boost::shared_ptr<NoteType> > notes)
{
- RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
+ if (no_sound_notes || !trackview.editor().sound_notes()) {
+ return;
+ }
+ RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
+
if (!route_ui || !route_ui->midi_track()) {
- return false;
+ return;
}
- route_ui->midi_track()->write_immediate_event(
- note->off_event().size(), note->off_event().buffer());
+ NotePlayer* np = new NotePlayer (route_ui->midi_track());
- return false;
+ for (vector<boost::shared_ptr<NoteType> >::iterator n = notes.begin(); n != notes.end(); ++n) {
+ np->add (*n);
+ }
+
+ np->play ();
}
+
bool
MidiRegionView::note_in_region_range(const boost::shared_ptr<NoteType> note, bool& visible) const
{
@@ -1691,6 +1695,7 @@ MidiRegionView::clear_selection_except(ArdourCanvas::CanvasNoteEvent* ev)
}
_selection.clear();
+ _earliest_selected_time = Evoral::MaxMusicalTime;
}
void
@@ -1932,9 +1937,25 @@ MidiRegionView::remove_from_selection (CanvasNoteEvent* ev)
ev->set_selected (false);
ev->hide_velocity ();
+
+ if (Evoral::musical_time_equal (ev->note()->time(), _earliest_selected_time)) {
+
+ _earliest_selected_time = Evoral::MaxMusicalTime;
+
+ /* compute new earliest time */
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ if (!Evoral::musical_time_equal ((*i)->note()->time(), _earliest_selected_time) &&
+ (*i)->note()->time() < _earliest_selected_time) {
+ _earliest_selected_time = (*i)->note()->time();
+ }
+ }
+ }
+
if (_selection.empty()) {
PublicEditor& editor (trackview.editor());
editor.get_selection().remove (this);
+ _earliest_selected_time = Evoral::MaxMusicalTime;
}
}
@@ -1950,7 +1971,11 @@ MidiRegionView::add_to_selection (CanvasNoteEvent* ev)
if (_selection.insert (ev).second) {
ev->set_selected (true);
play_midi_note ((ev)->note());
- }
+
+ if (ev->note()->time() < _earliest_selected_time) {
+ _earliest_selected_time = ev->note()->time();
+ }
+ }
if (add_mrv_selection) {
PublicEditor& editor (trackview.editor());
@@ -1961,16 +1986,37 @@ MidiRegionView::add_to_selection (CanvasNoteEvent* ev)
void
MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
{
+ typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+ PossibleChord to_play;
+
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ if (Evoral::musical_time_equal ((*i)->note()->time(), _earliest_selected_time)) {
+ to_play.push_back ((*i)->note());
+ }
(*i)->move_event(dx, dy);
+ }
+
+ if (dy && !_selection.empty() && !no_sound_notes && trackview.editor().sound_notes()) {
+
+ if (to_play.size() > 1) {
+
+ PossibleChord shifted;
+
+ for (PossibleChord::iterator n = to_play.begin(); n != to_play.end(); ++n) {
+ boost::shared_ptr<NoteType> moved_note (new NoteType (**n));
+ moved_note->set_note (moved_note->note() + cumulative_dy);
+ shifted.push_back (moved_note);
+ }
- if (dy) {
- boost::shared_ptr<NoteType>
- moved_note (new NoteType (*((*i)->note())));
+ play_midi_chord (shifted);
+
+ } else if (!to_play.empty()) {
+
+ boost::shared_ptr<NoteType> moved_note (new NoteType (*to_play.front()));
moved_note->set_note (moved_note->note() + cumulative_dy);
play_midi_note (moved_note);
}
- }
+ }
}
void
@@ -2755,7 +2801,7 @@ MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
beat_delta = (*mcb.notes().begin())->time() - paste_pos_beats;
paste_pos_beats = 0;
- _selection.clear ();
+ clear_selection ();
for (int n = 0; n < (int) times; ++n) {
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index b0cc505aee..baf67928c8 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -308,6 +308,7 @@ class MidiRegionView : public RegionView
* and schedule the playback of the corresponding NoteOff event.
*/
void play_midi_note(boost::shared_ptr<NoteType> note);
+ void play_midi_chord (std::vector<boost::shared_ptr<NoteType> > notes);
/** Play the NoteOff-Event of the given note immediately
* (scheduled by @ref play_midi_note()).
@@ -371,7 +372,8 @@ class MidiRegionView : public RegionView
ArdourCanvas::SimpleRect* _step_edit_cursor;
Evoral::MusicalTime _step_edit_cursor_width;
Evoral::MusicalTime _step_edit_cursor_position;
-
+ Evoral::MusicalTime _earliest_selected_time;
+
MouseState _mouse_state;
int _pressed_button;
diff --git a/gtk2_ardour/note_player.cc b/gtk2_ardour/note_player.cc
new file mode 100644
index 0000000000..3c577633b1
--- /dev/null
+++ b/gtk2_ardour/note_player.cc
@@ -0,0 +1,60 @@
+#include <sigc++/bind.h>
+#include <glibmm/main.h>
+
+#include "ardour/midi_track.h"
+#include "ardour/session.h"
+
+#include "note_player.h"
+
+using namespace ARDOUR;
+using namespace std;
+
+NotePlayer::NotePlayer (boost::shared_ptr<MidiTrack> mt)
+ : track (mt)
+{
+}
+
+void
+NotePlayer::add (boost::shared_ptr<NoteType> note)
+{
+ notes.push_back (note);
+}
+
+void
+NotePlayer::play ()
+{
+ Evoral::MusicalTime longest_duration_beats = 0;
+
+ /* note: if there is more than 1 note, we will silence them all at the same time
+ */
+
+ for (NoteList::iterator n = notes.begin(); n != notes.end(); ++n) {
+ track->write_immediate_event ((*n)->on_event().size(), (*n)->on_event().buffer());
+ if ((*n)->length() > longest_duration_beats) {
+ longest_duration_beats = (*n)->length();
+ }
+ }
+
+ uint32_t note_length_ms = 350;
+ /* beats_to_frames (longest_duration_beats)
+ * (1000 / (double)track->session().nominal_frame_rate()); */
+
+ Glib::signal_timeout().connect(sigc::bind (sigc::ptr_fun (&NotePlayer::_off), this),
+ note_length_ms, G_PRIORITY_DEFAULT);
+}
+
+bool
+NotePlayer::_off (NotePlayer* np)
+{
+ np->off ();
+ delete np;
+ return false;
+}
+
+void
+NotePlayer::off ()
+{
+ for (NoteList::iterator n = notes.begin(); n != notes.end(); ++n) {
+ track->write_immediate_event((*n)->off_event().size(), (*n)->off_event().buffer());
+ }
+}
diff --git a/gtk2_ardour/note_player.h b/gtk2_ardour/note_player.h
new file mode 100644
index 0000000000..7df4af4445
--- /dev/null
+++ b/gtk2_ardour/note_player.h
@@ -0,0 +1,34 @@
+#ifndef __gtk2_ardour_note_player_h__
+#define __gtk2_ardour_note_player_h__
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <sigc++/trackable.h>
+
+#include "evoral/Note.hpp"
+
+namespace ARDOUR {
+ class MidiTrack;
+}
+
+class NotePlayer : public sigc::trackable {
+ public:
+ typedef Evoral::Note<Evoral::MusicalTime> NoteType;
+
+ NotePlayer (boost::shared_ptr<ARDOUR::MidiTrack>);
+ ~NotePlayer () {}
+
+ void add (boost::shared_ptr<NoteType>);
+ void play ();
+ void off ();
+
+ static bool _off (NotePlayer*);
+
+ private:
+ typedef std::vector<boost::shared_ptr<NoteType> > NoteList;
+
+ boost::shared_ptr<ARDOUR::MidiTrack> track;
+ NoteList notes;
+};
+
+#endif /* __gtk2_ardour_note_player_h__ */
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index f4cf401d5a..bd5ef56690 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -146,6 +146,7 @@ gtk2_ardour_sources = [
'mixer_ui.cc',
'monitor_section.cc',
'nag.cc',
+ 'note_player.cc',
'option_editor.cc',
'opts.cc',
'panner.cc',