13
0

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
This commit is contained in:
Paul Davis 2010-09-15 18:54:04 +00:00
parent 7eea9fac9d
commit 084dda86a7
5 changed files with 172 additions and 29 deletions

View File

@ -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)
{
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,6 +1971,10 @@ 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) {
@ -1961,12 +1986,33 @@ MidiRegionView::add_to_selection (CanvasNoteEvent* ev)
void
MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
{
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
(*i)->move_event(dx, dy);
typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
PossibleChord to_play;
if (dy) {
boost::shared_ptr<NoteType>
moved_note (new NoteType (*((*i)->note())));
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);
}
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);
}
@ -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) {

View File

@ -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,6 +372,7 @@ 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;

View File

@ -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());
}
}

34
gtk2_ardour/note_player.h Normal file
View File

@ -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__ */

View File

@ -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',