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:
parent
7eea9fac9d
commit
084dda86a7
@ -59,6 +59,7 @@
|
|||||||
#include "midi_time_axis.h"
|
#include "midi_time_axis.h"
|
||||||
#include "midi_time_axis.h"
|
#include "midi_time_axis.h"
|
||||||
#include "midi_util.h"
|
#include "midi_util.h"
|
||||||
|
#include "note_player.h"
|
||||||
#include "public_editor.h"
|
#include "public_editor.h"
|
||||||
#include "rgb_macros.h"
|
#include "rgb_macros.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
@ -91,6 +92,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
|
|||||||
, _step_edit_cursor (0)
|
, _step_edit_cursor (0)
|
||||||
, _step_edit_cursor_width (1.0)
|
, _step_edit_cursor_width (1.0)
|
||||||
, _step_edit_cursor_position (0.0)
|
, _step_edit_cursor_position (0.0)
|
||||||
|
, _earliest_selected_time (Evoral::MaxMusicalTime)
|
||||||
, _mouse_state(None)
|
, _mouse_state(None)
|
||||||
, _pressed_button(0)
|
, _pressed_button(0)
|
||||||
, _sort_needed (true)
|
, _sort_needed (true)
|
||||||
@ -115,6 +117,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
|
|||||||
, _diff_command(0)
|
, _diff_command(0)
|
||||||
, _ghost_note(0)
|
, _ghost_note(0)
|
||||||
, _drag_rect (0)
|
, _drag_rect (0)
|
||||||
|
, _earliest_selected_time (Evoral::MaxMusicalTime)
|
||||||
, _mouse_state(None)
|
, _mouse_state(None)
|
||||||
, _pressed_button(0)
|
, _pressed_button(0)
|
||||||
, _sort_needed (true)
|
, _sort_needed (true)
|
||||||
@ -138,6 +141,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
|
|||||||
, _diff_command(0)
|
, _diff_command(0)
|
||||||
, _ghost_note(0)
|
, _ghost_note(0)
|
||||||
, _drag_rect (0)
|
, _drag_rect (0)
|
||||||
|
, _earliest_selected_time (Evoral::MaxMusicalTime)
|
||||||
, _mouse_state(None)
|
, _mouse_state(None)
|
||||||
, _pressed_button(0)
|
, _pressed_button(0)
|
||||||
, _sort_needed (true)
|
, _sort_needed (true)
|
||||||
@ -165,6 +169,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
|
|||||||
, _diff_command(0)
|
, _diff_command(0)
|
||||||
, _ghost_note(0)
|
, _ghost_note(0)
|
||||||
, _drag_rect (0)
|
, _drag_rect (0)
|
||||||
|
, _earliest_selected_time (Evoral::MaxMusicalTime)
|
||||||
, _mouse_state(None)
|
, _mouse_state(None)
|
||||||
, _pressed_button(0)
|
, _pressed_button(0)
|
||||||
, _sort_needed (true)
|
, _sort_needed (true)
|
||||||
@ -1308,6 +1313,7 @@ MidiRegionView::extend_active_notes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiRegionView::play_midi_note(boost::shared_ptr<NoteType> note)
|
MidiRegionView::play_midi_note(boost::shared_ptr<NoteType> note)
|
||||||
{
|
{
|
||||||
@ -1321,36 +1327,34 @@ MidiRegionView::play_midi_note(boost::shared_ptr<NoteType> note)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
route_ui->midi_track()->write_immediate_event(
|
NotePlayer* np = new NotePlayer (route_ui->midi_track());
|
||||||
note->on_event().size(), note->on_event().buffer());
|
np->add (note);
|
||||||
|
np->play ();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
MidiRegionView::play_midi_note_off(boost::shared_ptr<NoteType> note)
|
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);
|
RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
|
||||||
|
|
||||||
if (!route_ui || !route_ui->midi_track()) {
|
if (!route_ui || !route_ui->midi_track()) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
route_ui->midi_track()->write_immediate_event(
|
NotePlayer* np = new NotePlayer (route_ui->midi_track());
|
||||||
note->off_event().size(), note->off_event().buffer());
|
|
||||||
|
|
||||||
return false;
|
for (vector<boost::shared_ptr<NoteType> >::iterator n = notes.begin(); n != notes.end(); ++n) {
|
||||||
|
np->add (*n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
np->play ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MidiRegionView::note_in_region_range(const boost::shared_ptr<NoteType> note, bool& visible) const
|
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();
|
_selection.clear();
|
||||||
|
_earliest_selected_time = Evoral::MaxMusicalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1932,9 +1937,25 @@ MidiRegionView::remove_from_selection (CanvasNoteEvent* ev)
|
|||||||
ev->set_selected (false);
|
ev->set_selected (false);
|
||||||
ev->hide_velocity ();
|
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()) {
|
if (_selection.empty()) {
|
||||||
PublicEditor& editor (trackview.editor());
|
PublicEditor& editor (trackview.editor());
|
||||||
editor.get_selection().remove (this);
|
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) {
|
if (_selection.insert (ev).second) {
|
||||||
ev->set_selected (true);
|
ev->set_selected (true);
|
||||||
play_midi_note ((ev)->note());
|
play_midi_note ((ev)->note());
|
||||||
|
|
||||||
|
if (ev->note()->time() < _earliest_selected_time) {
|
||||||
|
_earliest_selected_time = ev->note()->time();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_mrv_selection) {
|
if (add_mrv_selection) {
|
||||||
@ -1961,12 +1986,33 @@ MidiRegionView::add_to_selection (CanvasNoteEvent* ev)
|
|||||||
void
|
void
|
||||||
MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
|
MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
|
||||||
{
|
{
|
||||||
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
|
typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
|
||||||
(*i)->move_event(dx, dy);
|
PossibleChord to_play;
|
||||||
|
|
||||||
if (dy) {
|
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
|
||||||
boost::shared_ptr<NoteType>
|
if (Evoral::musical_time_equal ((*i)->note()->time(), _earliest_selected_time)) {
|
||||||
moved_note (new NoteType (*((*i)->note())));
|
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);
|
moved_note->set_note (moved_note->note() + cumulative_dy);
|
||||||
play_midi_note (moved_note);
|
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;
|
beat_delta = (*mcb.notes().begin())->time() - paste_pos_beats;
|
||||||
paste_pos_beats = 0;
|
paste_pos_beats = 0;
|
||||||
|
|
||||||
_selection.clear ();
|
clear_selection ();
|
||||||
|
|
||||||
for (int n = 0; n < (int) times; ++n) {
|
for (int n = 0; n < (int) times; ++n) {
|
||||||
|
|
||||||
|
@ -308,6 +308,7 @@ class MidiRegionView : public RegionView
|
|||||||
* and schedule the playback of the corresponding NoteOff event.
|
* and schedule the playback of the corresponding NoteOff event.
|
||||||
*/
|
*/
|
||||||
void play_midi_note(boost::shared_ptr<NoteType> note);
|
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
|
/** Play the NoteOff-Event of the given note immediately
|
||||||
* (scheduled by @ref play_midi_note()).
|
* (scheduled by @ref play_midi_note()).
|
||||||
@ -371,6 +372,7 @@ class MidiRegionView : public RegionView
|
|||||||
ArdourCanvas::SimpleRect* _step_edit_cursor;
|
ArdourCanvas::SimpleRect* _step_edit_cursor;
|
||||||
Evoral::MusicalTime _step_edit_cursor_width;
|
Evoral::MusicalTime _step_edit_cursor_width;
|
||||||
Evoral::MusicalTime _step_edit_cursor_position;
|
Evoral::MusicalTime _step_edit_cursor_position;
|
||||||
|
Evoral::MusicalTime _earliest_selected_time;
|
||||||
|
|
||||||
MouseState _mouse_state;
|
MouseState _mouse_state;
|
||||||
int _pressed_button;
|
int _pressed_button;
|
||||||
|
60
gtk2_ardour/note_player.cc
Normal file
60
gtk2_ardour/note_player.cc
Normal 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
34
gtk2_ardour/note_player.h
Normal 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__ */
|
@ -146,6 +146,7 @@ gtk2_ardour_sources = [
|
|||||||
'mixer_ui.cc',
|
'mixer_ui.cc',
|
||||||
'monitor_section.cc',
|
'monitor_section.cc',
|
||||||
'nag.cc',
|
'nag.cc',
|
||||||
|
'note_player.cc',
|
||||||
'option_editor.cc',
|
'option_editor.cc',
|
||||||
'opts.cc',
|
'opts.cc',
|
||||||
'panner.cc',
|
'panner.cc',
|
||||||
|
Loading…
Reference in New Issue
Block a user