mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
split out the logic behind step editing from MidiTimeAxisView as much as possible
git-svn-id: svn://localhost/ardour2/branches/3.0@7633 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
66ea8edc6e
commit
faca3e5f5d
7 changed files with 555 additions and 439 deletions
|
|
@ -80,8 +80,8 @@
|
||||||
#include "region_view.h"
|
#include "region_view.h"
|
||||||
#include "rgb_macros.h"
|
#include "rgb_macros.h"
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
|
#include "step_editor.h"
|
||||||
#include "simplerect.h"
|
#include "simplerect.h"
|
||||||
#include "step_entry.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include "ardour/midi_track.h"
|
#include "ardour/midi_track.h"
|
||||||
|
|
@ -116,7 +116,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
|
||||||
, _midi_thru_item (0)
|
, _midi_thru_item (0)
|
||||||
, default_channel_menu (0)
|
, default_channel_menu (0)
|
||||||
, controller_menu (0)
|
, controller_menu (0)
|
||||||
, step_editor (0)
|
|
||||||
{
|
{
|
||||||
subplugin_menu.set_name ("ArdourContextMenu");
|
subplugin_menu.set_name ("ArdourContextMenu");
|
||||||
|
|
||||||
|
|
@ -127,8 +126,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
|
||||||
mute_button->set_active (false);
|
mute_button->set_active (false);
|
||||||
solo_button->set_active (false);
|
solo_button->set_active (false);
|
||||||
|
|
||||||
step_edit_insert_position = 0;
|
|
||||||
|
|
||||||
if (is_midi_track()) {
|
if (is_midi_track()) {
|
||||||
controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
|
controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
|
||||||
_note_mode = midi_track()->note_mode();
|
_note_mode = midi_track()->note_mode();
|
||||||
|
|
@ -168,11 +165,6 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
|
||||||
_view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
|
_view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
|
||||||
_view->attach ();
|
_view->attach ();
|
||||||
|
|
||||||
midi_track()->PlaylistChanged.connect (*this, invalidator (*this),
|
|
||||||
boost::bind (&MidiTimeAxisView::playlist_changed, this),
|
|
||||||
gui_context());
|
|
||||||
playlist_changed ();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HBox* midi_controls_hbox = manage(new HBox());
|
HBox* midi_controls_hbox = manage(new HBox());
|
||||||
|
|
@ -235,35 +227,17 @@ MidiTimeAxisView::~MidiTimeAxisView ()
|
||||||
_range_scroomer = 0;
|
_range_scroomer = 0;
|
||||||
|
|
||||||
delete controller_menu;
|
delete controller_menu;
|
||||||
|
delete _step_editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::playlist_changed ()
|
MidiTimeAxisView::check_step_edit ()
|
||||||
{
|
{
|
||||||
step_edit_region_connection.disconnect ();
|
_step_editor->check_step_edit ();
|
||||||
midi_track()->playlist()->RegionRemoved.connect (step_edit_region_connection, invalidator (*this),
|
|
||||||
ui_bind (&MidiTimeAxisView::region_removed, this, _1),
|
|
||||||
gui_context());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::region_removed (boost::weak_ptr<Region> wr)
|
MidiTimeAxisView::model_changed()
|
||||||
{
|
|
||||||
boost::shared_ptr<Region> r (wr.lock());
|
|
||||||
|
|
||||||
if (!r) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_edit_region == r) {
|
|
||||||
step_edit_region.reset();
|
|
||||||
step_edit_region_view = 0;
|
|
||||||
// force a recompute of the insert position
|
|
||||||
step_edit_beat_pos = -1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiTimeAxisView::model_changed()
|
|
||||||
{
|
{
|
||||||
std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
|
std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
|
||||||
.custom_device_mode_names_by_model(_model_selector.get_active_text());
|
.custom_device_mode_names_by_model(_model_selector.get_active_text());
|
||||||
|
|
@ -892,360 +866,7 @@ MidiTimeAxisView::route_active_changed ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::start_step_editing ()
|
|
||||||
{
|
|
||||||
_step_edit_triplet_countdown = 0;
|
|
||||||
_step_edit_within_chord = 0;
|
|
||||||
_step_edit_chord_duration = 0.0;
|
|
||||||
step_edit_region.reset ();
|
|
||||||
step_edit_region_view = 0;
|
|
||||||
|
|
||||||
resync_step_edit_position ();
|
|
||||||
prepare_step_edit_region ();
|
|
||||||
reset_step_edit_beat_pos ();
|
|
||||||
|
|
||||||
assert (step_edit_region);
|
|
||||||
assert (step_edit_region_view);
|
|
||||||
|
|
||||||
if (step_editor == 0) {
|
|
||||||
step_editor = new StepEntry (*this);
|
|
||||||
step_editor->signal_delete_event().connect (sigc::mem_fun (*this, &MidiTimeAxisView::step_editor_hidden));
|
|
||||||
step_editor->signal_hide().connect (sigc::mem_fun (*this, &MidiTimeAxisView::step_editor_hide));
|
|
||||||
}
|
|
||||||
|
|
||||||
step_edit_region_view->show_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
step_edit_region_view->set_step_edit_cursor_width (step_editor->note_length());
|
|
||||||
|
|
||||||
step_editor->set_position (WIN_POS_MOUSE);
|
|
||||||
step_editor->present ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::resync_step_edit_position ()
|
|
||||||
{
|
|
||||||
step_edit_insert_position = _editor.get_preferred_edit_position ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::resync_step_edit_to_edit_point ()
|
|
||||||
{
|
|
||||||
resync_step_edit_position ();
|
|
||||||
if (step_edit_region) {
|
|
||||||
reset_step_edit_beat_pos ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::prepare_step_edit_region ()
|
|
||||||
{
|
|
||||||
boost::shared_ptr<Region> r = playlist()->top_region_at (step_edit_insert_position);
|
|
||||||
|
|
||||||
if (r) {
|
|
||||||
step_edit_region = boost::dynamic_pointer_cast<MidiRegion>(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_edit_region) {
|
|
||||||
RegionView* rv = view()->find_view (step_edit_region);
|
|
||||||
step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
step_edit_region = add_region (step_edit_insert_position);
|
|
||||||
RegionView* rv = view()->find_view (step_edit_region);
|
|
||||||
step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::reset_step_edit_beat_pos ()
|
|
||||||
{
|
|
||||||
assert (step_edit_region);
|
|
||||||
assert (step_edit_region_view);
|
|
||||||
|
|
||||||
framecnt_t frames_from_start = _editor.get_preferred_edit_position() - step_edit_region->position();
|
|
||||||
|
|
||||||
if (frames_from_start < 0) {
|
|
||||||
/* this can happen with snap enabled, and the edit point == Playhead. we snap the
|
|
||||||
position of the new region, and it can end up after the edit point.
|
|
||||||
*/
|
|
||||||
frames_from_start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
step_edit_beat_pos = step_edit_region_view->frames_to_beats (frames_from_start);
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MidiTimeAxisView::step_editor_hidden (GdkEventAny*)
|
|
||||||
{
|
|
||||||
step_editor_hide ();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_editor_hide ()
|
|
||||||
{
|
|
||||||
/* everything else will follow the change in the model */
|
|
||||||
midi_track()->set_step_editing (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::stop_step_editing ()
|
|
||||||
{
|
|
||||||
if (step_editor) {
|
|
||||||
step_editor->hide ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_edit_region_view) {
|
|
||||||
step_edit_region_view->hide_step_edit_cursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
step_edit_region.reset ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::check_step_edit ()
|
|
||||||
{
|
|
||||||
MidiRingBuffer<nframes_t>& incoming (midi_track()->step_edit_ring_buffer());
|
|
||||||
uint8_t* buf;
|
|
||||||
uint32_t bufsize = 32;
|
|
||||||
|
|
||||||
buf = new uint8_t[bufsize];
|
|
||||||
|
|
||||||
while (incoming.read_space()) {
|
|
||||||
nframes_t time;
|
|
||||||
Evoral::EventType type;
|
|
||||||
uint32_t size;
|
|
||||||
|
|
||||||
incoming.read_prefix (&time, &type, &size);
|
|
||||||
|
|
||||||
if (size > bufsize) {
|
|
||||||
delete [] buf;
|
|
||||||
bufsize = size;
|
|
||||||
buf = new uint8_t[bufsize];
|
|
||||||
}
|
|
||||||
|
|
||||||
incoming.read_contents (size, buf);
|
|
||||||
|
|
||||||
if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
|
|
||||||
step_add_note (buf[0] & 0xf, buf[1], buf[2], 0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
MidiTimeAxisView::step_add_bank_change (uint8_t channel, uint8_t bank)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
MidiTimeAxisView::step_add_program_change (uint8_t channel, uint8_t program)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_sustain (Evoral::MusicalTime beats)
|
|
||||||
{
|
|
||||||
if (step_edit_region_view) {
|
|
||||||
step_edit_region_view->step_sustain (beats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::move_step_edit_beat_pos (Evoral::MusicalTime beats)
|
|
||||||
{
|
|
||||||
if (beats > 0.0) {
|
|
||||||
step_edit_beat_pos = min (step_edit_beat_pos + beats,
|
|
||||||
step_edit_region_view->frames_to_beats (step_edit_region->length()));
|
|
||||||
} else if (beats < 0.0) {
|
|
||||||
if (beats < step_edit_beat_pos) {
|
|
||||||
step_edit_beat_pos += beats; // its negative, remember
|
|
||||||
} else {
|
|
||||||
step_edit_beat_pos = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
MidiTimeAxisView::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::MusicalTime beat_duration)
|
|
||||||
{
|
|
||||||
/* do these things in case undo removed the step edit region
|
|
||||||
*/
|
|
||||||
if (!step_edit_region) {
|
|
||||||
resync_step_edit_position ();
|
|
||||||
prepare_step_edit_region ();
|
|
||||||
reset_step_edit_beat_pos ();
|
|
||||||
step_edit_region_view->show_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
step_edit_region_view->set_step_edit_cursor_width (step_editor->note_length());
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (step_edit_region);
|
|
||||||
assert (step_edit_region_view);
|
|
||||||
|
|
||||||
if (beat_duration == 0.0) {
|
|
||||||
bool success;
|
|
||||||
beat_duration = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MidiStreamView* msv = midi_view();
|
|
||||||
|
|
||||||
/* make sure its visible on the vertical axis */
|
|
||||||
|
|
||||||
if (pitch < msv->lowest_note() || pitch > msv->highest_note()) {
|
|
||||||
msv->update_note_range (pitch);
|
|
||||||
msv->set_note_range (MidiStreamView::ContentsRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure its visible on the horizontal axis */
|
|
||||||
|
|
||||||
nframes64_t fpos = step_edit_region->position() +
|
|
||||||
step_edit_region_view->beats_to_frames (step_edit_beat_pos + beat_duration);
|
|
||||||
|
|
||||||
if (fpos >= (_editor.leftmost_position() + _editor.current_page_frames())) {
|
|
||||||
_editor.reset_x_origin (fpos - (_editor.current_page_frames()/4));
|
|
||||||
}
|
|
||||||
|
|
||||||
step_edit_region_view->step_add_note (channel, pitch, velocity, step_edit_beat_pos, beat_duration);
|
|
||||||
|
|
||||||
if (_step_edit_triplet_countdown > 0) {
|
|
||||||
_step_edit_triplet_countdown--;
|
|
||||||
|
|
||||||
if (_step_edit_triplet_countdown == 0) {
|
|
||||||
_step_edit_triplet_countdown = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_step_edit_within_chord) {
|
|
||||||
step_edit_beat_pos += beat_duration;
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
} else {
|
|
||||||
step_edit_beat_pos += 1.0/Meter::ticks_per_beat; // tiny, but no longer overlapping
|
|
||||||
_step_edit_chord_duration = max (_step_edit_chord_duration, beat_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::set_step_edit_cursor_width (Evoral::MusicalTime beats)
|
|
||||||
{
|
|
||||||
if (step_edit_region_view) {
|
|
||||||
step_edit_region_view->set_step_edit_cursor_width (beats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MidiTimeAxisView::step_edit_within_triplet() const
|
|
||||||
{
|
|
||||||
return _step_edit_triplet_countdown > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MidiTimeAxisView::step_edit_within_chord() const
|
|
||||||
{
|
|
||||||
return _step_edit_within_chord;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_toggle_triplet ()
|
|
||||||
{
|
|
||||||
if (_step_edit_triplet_countdown == 0) {
|
|
||||||
_step_edit_within_chord = false;
|
|
||||||
_step_edit_triplet_countdown = 3;
|
|
||||||
} else {
|
|
||||||
_step_edit_triplet_countdown = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_toggle_chord ()
|
|
||||||
{
|
|
||||||
if (_step_edit_within_chord) {
|
|
||||||
_step_edit_within_chord = false;
|
|
||||||
step_edit_beat_pos += _step_edit_chord_duration;
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
} else {
|
|
||||||
_step_edit_triplet_countdown = 0;
|
|
||||||
_step_edit_within_chord = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_rest (Evoral::MusicalTime beats)
|
|
||||||
{
|
|
||||||
bool success;
|
|
||||||
|
|
||||||
if (beats == 0.0) {
|
|
||||||
beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
|
|
||||||
} else {
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
step_edit_beat_pos += beats;
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_beat_sync ()
|
|
||||||
{
|
|
||||||
step_edit_beat_pos = ceil (step_edit_beat_pos);
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MidiTimeAxisView::step_edit_bar_sync ()
|
|
||||||
{
|
|
||||||
if (!_session || !step_edit_region_view || !step_edit_region) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
framepos_t fpos = step_edit_region->position() +
|
|
||||||
step_edit_region_view->beats_to_frames (step_edit_beat_pos);
|
|
||||||
fpos = _session->tempo_map().round_to_bar (fpos, 1);
|
|
||||||
step_edit_beat_pos = ceil (step_edit_region_view->frames_to_beats (fpos - step_edit_region->position()));
|
|
||||||
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<MidiRegion>
|
|
||||||
MidiTimeAxisView::add_region (framepos_t pos)
|
|
||||||
{
|
|
||||||
Editor* real_editor = dynamic_cast<Editor*> (&_editor);
|
|
||||||
|
|
||||||
real_editor->begin_reversible_command (_("create region"));
|
|
||||||
playlist()->clear_history ();
|
|
||||||
|
|
||||||
real_editor->snap_to (pos, 0);
|
|
||||||
const Meter& m = _session->tempo_map().meter_at(pos);
|
|
||||||
const Tempo& t = _session->tempo_map().tempo_at(pos);
|
|
||||||
double length = floor (m.frames_per_bar(t, _session->frame_rate()));
|
|
||||||
|
|
||||||
boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
|
|
||||||
view()->trackview().track()->name());
|
|
||||||
PropertyList plist;
|
|
||||||
|
|
||||||
plist.add (ARDOUR::Properties::start, 0);
|
|
||||||
plist.add (ARDOUR::Properties::length, length);
|
|
||||||
plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
|
|
||||||
|
|
||||||
boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
|
|
||||||
|
|
||||||
playlist()->add_region (region, pos);
|
|
||||||
_session->add_command (new StatefulDiffCommand (playlist()));
|
|
||||||
|
|
||||||
real_editor->commit_reversible_command();
|
|
||||||
|
|
||||||
return boost::dynamic_pointer_cast<MidiRegion>(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTimeAxisView::add_note_selection (uint8_t note)
|
MidiTimeAxisView::add_note_selection (uint8_t note)
|
||||||
|
|
@ -1380,3 +1001,52 @@ MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<MidiRegion>
|
||||||
|
MidiTimeAxisView::add_region (framepos_t pos)
|
||||||
|
{
|
||||||
|
Editor* real_editor = dynamic_cast<Editor*> (&_editor);
|
||||||
|
|
||||||
|
real_editor->begin_reversible_command (_("create region"));
|
||||||
|
playlist()->clear_history ();
|
||||||
|
|
||||||
|
real_editor->snap_to (pos, 0);
|
||||||
|
const Meter& m = _session->tempo_map().meter_at(pos);
|
||||||
|
const Tempo& t = _session->tempo_map().tempo_at(pos);
|
||||||
|
double length = floor (m.frames_per_bar(t, _session->frame_rate()));
|
||||||
|
|
||||||
|
boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
|
||||||
|
view()->trackview().track()->name());
|
||||||
|
PropertyList plist;
|
||||||
|
|
||||||
|
plist.add (ARDOUR::Properties::start, 0);
|
||||||
|
plist.add (ARDOUR::Properties::length, length);
|
||||||
|
plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
|
||||||
|
|
||||||
|
boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
|
||||||
|
|
||||||
|
playlist()->add_region (region, pos);
|
||||||
|
_session->add_command (new StatefulDiffCommand (playlist()));
|
||||||
|
|
||||||
|
real_editor->commit_reversible_command();
|
||||||
|
|
||||||
|
return boost::dynamic_pointer_cast<MidiRegion>(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiTimeAxisView::start_step_editing ()
|
||||||
|
{
|
||||||
|
if (!_step_editor) {
|
||||||
|
_step_editor = new StepEditor (_editor, midi_track(), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_step_editor->start_step_editing ();
|
||||||
|
|
||||||
|
}
|
||||||
|
void
|
||||||
|
MidiTimeAxisView::stop_step_editing ()
|
||||||
|
{
|
||||||
|
if (_step_editor) {
|
||||||
|
_step_editor->stop_step_editing ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class MidiStreamView;
|
||||||
class MidiScroomer;
|
class MidiScroomer;
|
||||||
class PianoRollHeader;
|
class PianoRollHeader;
|
||||||
class StepEntry;
|
class StepEntry;
|
||||||
|
class StepEditor;
|
||||||
|
|
||||||
class MidiTimeAxisView : public RouteTimeAxisView
|
class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
{
|
{
|
||||||
|
|
@ -87,28 +88,14 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
return _midi_patch_settings_changed;
|
return _midi_patch_settings_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_step_edit ();
|
|
||||||
void step_edit_rest (Evoral::MusicalTime beats);
|
|
||||||
void step_edit_beat_sync ();
|
|
||||||
void step_edit_bar_sync ();
|
|
||||||
int step_add_bank_change (uint8_t channel, uint8_t bank);
|
|
||||||
int step_add_program_change (uint8_t channel, uint8_t program);
|
|
||||||
int step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity,
|
|
||||||
Evoral::MusicalTime beat_duration);
|
|
||||||
void step_edit_sustain (Evoral::MusicalTime beats);
|
|
||||||
bool step_edit_within_triplet () const;
|
|
||||||
void step_edit_toggle_triplet ();
|
|
||||||
bool step_edit_within_chord () const;
|
|
||||||
void step_edit_toggle_chord ();
|
|
||||||
void reset_step_edit_beat_pos ();
|
|
||||||
void resync_step_edit_to_edit_point ();
|
|
||||||
void move_step_edit_beat_pos (Evoral::MusicalTime beats);
|
|
||||||
void set_step_edit_cursor_width (Evoral::MusicalTime beats);
|
|
||||||
|
|
||||||
const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
|
const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
|
||||||
|
|
||||||
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
|
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
|
||||||
|
|
||||||
|
StepEditor* step_editor() { return _step_editor; }
|
||||||
|
void check_step_edit ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void start_step_editing ();
|
void start_step_editing ();
|
||||||
void stop_step_editing ();
|
void stop_step_editing ();
|
||||||
|
|
@ -149,16 +136,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
Gtk::CheckMenuItem* _midi_thru_item;
|
Gtk::CheckMenuItem* _midi_thru_item;
|
||||||
Gtk::Menu* default_channel_menu;
|
Gtk::Menu* default_channel_menu;
|
||||||
|
|
||||||
nframes64_t step_edit_insert_position;
|
|
||||||
Evoral::MusicalTime step_edit_beat_pos;
|
|
||||||
boost::shared_ptr<ARDOUR::MidiRegion> step_edit_region;
|
|
||||||
MidiRegionView* step_edit_region_view;
|
|
||||||
uint8_t _step_edit_triplet_countdown;
|
|
||||||
bool _step_edit_within_chord;
|
|
||||||
Evoral::MusicalTime _step_edit_chord_duration;
|
|
||||||
void region_removed (boost::weak_ptr<ARDOUR::Region>);
|
|
||||||
void playlist_changed ();
|
|
||||||
PBD::ScopedConnection step_edit_region_connection;
|
|
||||||
|
|
||||||
Gtk::Menu* build_def_channel_menu();
|
Gtk::Menu* build_def_channel_menu();
|
||||||
void set_default_channel (int);
|
void set_default_channel (int);
|
||||||
|
|
@ -184,11 +161,7 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
/** parameter -> menu item map for the controller menu */
|
/** parameter -> menu item map for the controller menu */
|
||||||
ParameterMenuMap _controller_menu_map;
|
ParameterMenuMap _controller_menu_map;
|
||||||
|
|
||||||
StepEntry* step_editor;
|
StepEditor* _step_editor;
|
||||||
bool step_editor_hidden (GdkEventAny*);
|
|
||||||
void step_editor_hide ();
|
|
||||||
void resync_step_edit_position ();
|
|
||||||
void prepare_step_edit_region ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_midi_time_axis_h__ */
|
#endif /* __ardour_midi_time_axis_h__ */
|
||||||
|
|
|
||||||
395
gtk2_ardour/step_editor.cc
Normal file
395
gtk2_ardour/step_editor.cc
Normal file
|
|
@ -0,0 +1,395 @@
|
||||||
|
#include "ardour/midi_track.h"
|
||||||
|
#include "ardour/midi_region.h"
|
||||||
|
#include "ardour/tempo.h"
|
||||||
|
#include "ardour/types.h"
|
||||||
|
|
||||||
|
#include "gui_thread.h"
|
||||||
|
#include "midi_region_view.h"
|
||||||
|
#include "public_editor.h"
|
||||||
|
#include "step_editor.h"
|
||||||
|
#include "step_entry.h"
|
||||||
|
|
||||||
|
using namespace ARDOUR;
|
||||||
|
using namespace Gtk;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
StepEditor::StepEditor (PublicEditor& e, boost::shared_ptr<MidiTrack> t, MidiTimeAxisView& mtv)
|
||||||
|
: _editor (e)
|
||||||
|
, _track (t)
|
||||||
|
, step_editor (0)
|
||||||
|
, _mtv (mtv)
|
||||||
|
{
|
||||||
|
step_edit_insert_position = 0;
|
||||||
|
_step_edit_triplet_countdown = 0;
|
||||||
|
_step_edit_within_chord = 0;
|
||||||
|
_step_edit_chord_duration = 0.0;
|
||||||
|
step_edit_region_view = 0;
|
||||||
|
|
||||||
|
_track->PlaylistChanged.connect (*this, invalidator (*this),
|
||||||
|
boost::bind (&StepEditor::playlist_changed, this),
|
||||||
|
gui_context());
|
||||||
|
playlist_changed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
StepEditor::~StepEditor()
|
||||||
|
{
|
||||||
|
delete step_editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::start_step_editing ()
|
||||||
|
{
|
||||||
|
_step_edit_triplet_countdown = 0;
|
||||||
|
_step_edit_within_chord = 0;
|
||||||
|
_step_edit_chord_duration = 0.0;
|
||||||
|
step_edit_region.reset ();
|
||||||
|
step_edit_region_view = 0;
|
||||||
|
|
||||||
|
resync_step_edit_position ();
|
||||||
|
prepare_step_edit_region ();
|
||||||
|
reset_step_edit_beat_pos ();
|
||||||
|
|
||||||
|
assert (step_edit_region);
|
||||||
|
assert (step_edit_region_view);
|
||||||
|
|
||||||
|
if (step_editor == 0) {
|
||||||
|
step_editor = new StepEntry (*this);
|
||||||
|
step_editor->signal_delete_event().connect (sigc::mem_fun (*this, &StepEditor::step_editor_hidden));
|
||||||
|
step_editor->signal_hide().connect (sigc::mem_fun (*this, &StepEditor::step_editor_hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
step_edit_region_view->show_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
step_edit_region_view->set_step_edit_cursor_width (step_editor->note_length());
|
||||||
|
|
||||||
|
step_editor->set_position (WIN_POS_MOUSE);
|
||||||
|
step_editor->present ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::resync_step_edit_position ()
|
||||||
|
{
|
||||||
|
step_edit_insert_position = _editor.get_preferred_edit_position ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::resync_step_edit_to_edit_point ()
|
||||||
|
{
|
||||||
|
resync_step_edit_position ();
|
||||||
|
if (step_edit_region) {
|
||||||
|
reset_step_edit_beat_pos ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::prepare_step_edit_region ()
|
||||||
|
{
|
||||||
|
boost::shared_ptr<Region> r = _track->playlist()->top_region_at (step_edit_insert_position);
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
step_edit_region = boost::dynamic_pointer_cast<MidiRegion>(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_edit_region) {
|
||||||
|
RegionView* rv = _mtv.midi_view()->find_view (step_edit_region);
|
||||||
|
step_edit_region_view = dynamic_cast<MidiRegionView*> (rv);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
step_edit_region = _mtv.add_region (step_edit_insert_position);
|
||||||
|
RegionView* rv = _mtv.midi_view()->find_view (step_edit_region);
|
||||||
|
step_edit_region_view = dynamic_cast<MidiRegionView*>(rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::reset_step_edit_beat_pos ()
|
||||||
|
{
|
||||||
|
assert (step_edit_region);
|
||||||
|
assert (step_edit_region_view);
|
||||||
|
|
||||||
|
framecnt_t frames_from_start = _editor.get_preferred_edit_position() - step_edit_region->position();
|
||||||
|
|
||||||
|
if (frames_from_start < 0) {
|
||||||
|
/* this can happen with snap enabled, and the edit point == Playhead. we snap the
|
||||||
|
position of the new region, and it can end up after the edit point.
|
||||||
|
*/
|
||||||
|
frames_from_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
step_edit_beat_pos = step_edit_region_view->frames_to_beats (frames_from_start);
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StepEditor::step_editor_hidden (GdkEventAny*)
|
||||||
|
{
|
||||||
|
step_editor_hide ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_editor_hide ()
|
||||||
|
{
|
||||||
|
/* everything else will follow the change in the model */
|
||||||
|
_track->set_step_editing (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::stop_step_editing ()
|
||||||
|
{
|
||||||
|
if (step_editor) {
|
||||||
|
step_editor->hide ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_edit_region_view) {
|
||||||
|
step_edit_region_view->hide_step_edit_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
step_edit_region.reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::check_step_edit ()
|
||||||
|
{
|
||||||
|
MidiRingBuffer<nframes_t>& incoming (_track->step_edit_ring_buffer());
|
||||||
|
uint8_t* buf;
|
||||||
|
uint32_t bufsize = 32;
|
||||||
|
|
||||||
|
buf = new uint8_t[bufsize];
|
||||||
|
|
||||||
|
while (incoming.read_space()) {
|
||||||
|
nframes_t time;
|
||||||
|
Evoral::EventType type;
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
incoming.read_prefix (&time, &type, &size);
|
||||||
|
|
||||||
|
if (size > bufsize) {
|
||||||
|
delete [] buf;
|
||||||
|
bufsize = size;
|
||||||
|
buf = new uint8_t[bufsize];
|
||||||
|
}
|
||||||
|
|
||||||
|
incoming.read_contents (size, buf);
|
||||||
|
|
||||||
|
if ((buf[0] & 0xf0) == MIDI_CMD_NOTE_ON) {
|
||||||
|
step_add_note (buf[0] & 0xf, buf[1], buf[2], 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StepEditor::step_add_bank_change (uint8_t channel, uint8_t bank)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StepEditor::step_add_program_change (uint8_t channel, uint8_t program)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_sustain (Evoral::MusicalTime beats)
|
||||||
|
{
|
||||||
|
if (step_edit_region_view) {
|
||||||
|
step_edit_region_view->step_sustain (beats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::move_step_edit_beat_pos (Evoral::MusicalTime beats)
|
||||||
|
{
|
||||||
|
if (beats > 0.0) {
|
||||||
|
step_edit_beat_pos = min (step_edit_beat_pos + beats,
|
||||||
|
step_edit_region_view->frames_to_beats (step_edit_region->length()));
|
||||||
|
} else if (beats < 0.0) {
|
||||||
|
if (beats < step_edit_beat_pos) {
|
||||||
|
step_edit_beat_pos += beats; // its negative, remember
|
||||||
|
} else {
|
||||||
|
step_edit_beat_pos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StepEditor::step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity, Evoral::MusicalTime beat_duration)
|
||||||
|
{
|
||||||
|
/* do these things in case undo removed the step edit region
|
||||||
|
*/
|
||||||
|
if (!step_edit_region) {
|
||||||
|
resync_step_edit_position ();
|
||||||
|
prepare_step_edit_region ();
|
||||||
|
reset_step_edit_beat_pos ();
|
||||||
|
step_edit_region_view->show_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
step_edit_region_view->set_step_edit_cursor_width (step_editor->note_length());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (step_edit_region);
|
||||||
|
assert (step_edit_region_view);
|
||||||
|
|
||||||
|
if (beat_duration == 0.0) {
|
||||||
|
bool success;
|
||||||
|
beat_duration = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiStreamView* msv = _mtv.midi_view();
|
||||||
|
|
||||||
|
/* make sure its visible on the vertical axis */
|
||||||
|
|
||||||
|
if (pitch < msv->lowest_note() || pitch > msv->highest_note()) {
|
||||||
|
msv->update_note_range (pitch);
|
||||||
|
msv->set_note_range (MidiStreamView::ContentsRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure its visible on the horizontal axis */
|
||||||
|
|
||||||
|
nframes64_t fpos = step_edit_region->position() +
|
||||||
|
step_edit_region_view->beats_to_frames (step_edit_beat_pos + beat_duration);
|
||||||
|
|
||||||
|
if (fpos >= (_editor.leftmost_position() + _editor.current_page_frames())) {
|
||||||
|
_editor.reset_x_origin (fpos - (_editor.current_page_frames()/4));
|
||||||
|
}
|
||||||
|
|
||||||
|
step_edit_region_view->step_add_note (channel, pitch, velocity, step_edit_beat_pos, beat_duration);
|
||||||
|
|
||||||
|
if (_step_edit_triplet_countdown > 0) {
|
||||||
|
_step_edit_triplet_countdown--;
|
||||||
|
|
||||||
|
if (_step_edit_triplet_countdown == 0) {
|
||||||
|
_step_edit_triplet_countdown = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_step_edit_within_chord) {
|
||||||
|
step_edit_beat_pos += beat_duration;
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
} else {
|
||||||
|
step_edit_beat_pos += 1.0/Meter::ticks_per_beat; // tiny, but no longer overlapping
|
||||||
|
_step_edit_chord_duration = max (_step_edit_chord_duration, beat_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::set_step_edit_cursor_width (Evoral::MusicalTime beats)
|
||||||
|
{
|
||||||
|
if (step_edit_region_view) {
|
||||||
|
step_edit_region_view->set_step_edit_cursor_width (beats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StepEditor::step_edit_within_triplet() const
|
||||||
|
{
|
||||||
|
return _step_edit_triplet_countdown > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StepEditor::step_edit_within_chord() const
|
||||||
|
{
|
||||||
|
return _step_edit_within_chord;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_toggle_triplet ()
|
||||||
|
{
|
||||||
|
if (_step_edit_triplet_countdown == 0) {
|
||||||
|
_step_edit_within_chord = false;
|
||||||
|
_step_edit_triplet_countdown = 3;
|
||||||
|
} else {
|
||||||
|
_step_edit_triplet_countdown = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_toggle_chord ()
|
||||||
|
{
|
||||||
|
if (_step_edit_within_chord) {
|
||||||
|
_step_edit_within_chord = false;
|
||||||
|
step_edit_beat_pos += _step_edit_chord_duration;
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
} else {
|
||||||
|
_step_edit_triplet_countdown = 0;
|
||||||
|
_step_edit_within_chord = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_rest (Evoral::MusicalTime beats)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
if (beats == 0.0) {
|
||||||
|
beats = _editor.get_grid_type_as_beats (success, step_edit_insert_position);
|
||||||
|
} else {
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
step_edit_beat_pos += beats;
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_beat_sync ()
|
||||||
|
{
|
||||||
|
step_edit_beat_pos = ceil (step_edit_beat_pos);
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::step_edit_bar_sync ()
|
||||||
|
{
|
||||||
|
Session* _session = _mtv.session ();
|
||||||
|
|
||||||
|
if (!_session || !step_edit_region_view || !step_edit_region) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
framepos_t fpos = step_edit_region->position() +
|
||||||
|
step_edit_region_view->beats_to_frames (step_edit_beat_pos);
|
||||||
|
fpos = _session->tempo_map().round_to_bar (fpos, 1);
|
||||||
|
step_edit_beat_pos = ceil (step_edit_region_view->frames_to_beats (fpos - step_edit_region->position()));
|
||||||
|
step_edit_region_view->move_step_edit_cursor (step_edit_beat_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::playlist_changed ()
|
||||||
|
{
|
||||||
|
step_edit_region_connection.disconnect ();
|
||||||
|
_track->playlist()->RegionRemoved.connect (step_edit_region_connection, invalidator (*this),
|
||||||
|
ui_bind (&StepEditor::region_removed, this, _1),
|
||||||
|
gui_context());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StepEditor::region_removed (boost::weak_ptr<Region> wr)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<Region> r (wr.lock());
|
||||||
|
|
||||||
|
if (!r) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_edit_region == r) {
|
||||||
|
step_edit_region.reset();
|
||||||
|
step_edit_region_view = 0;
|
||||||
|
// force a recompute of the insert position
|
||||||
|
step_edit_beat_pos = -1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
StepEditor::name() const
|
||||||
|
{
|
||||||
|
return _track->name();
|
||||||
|
}
|
||||||
73
gtk2_ardour/step_editor.h
Normal file
73
gtk2_ardour/step_editor.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef __pbd__step_editor_h__
|
||||||
|
#define __pbd__step_editor_h__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
#include <sigc++/trackable.h>
|
||||||
|
|
||||||
|
#include "pbd/signals.h"
|
||||||
|
#include "evoral/types.hpp"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
class MidiTrack;
|
||||||
|
class MidiRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MidiRegionView;
|
||||||
|
class MidiTimeAxisView;
|
||||||
|
class PublicEditor;
|
||||||
|
class StepEntry;
|
||||||
|
|
||||||
|
class StepEditor : public PBD::ScopedConnectionList, public sigc::trackable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StepEditor (PublicEditor&, boost::shared_ptr<ARDOUR::MidiTrack>, MidiTimeAxisView&);
|
||||||
|
virtual ~StepEditor ();
|
||||||
|
|
||||||
|
void check_step_edit ();
|
||||||
|
void step_edit_rest (Evoral::MusicalTime beats);
|
||||||
|
void step_edit_beat_sync ();
|
||||||
|
void step_edit_bar_sync ();
|
||||||
|
int step_add_bank_change (uint8_t channel, uint8_t bank);
|
||||||
|
int step_add_program_change (uint8_t channel, uint8_t program);
|
||||||
|
int step_add_note (uint8_t channel, uint8_t pitch, uint8_t velocity,
|
||||||
|
Evoral::MusicalTime beat_duration);
|
||||||
|
void step_edit_sustain (Evoral::MusicalTime beats);
|
||||||
|
bool step_edit_within_triplet () const;
|
||||||
|
void step_edit_toggle_triplet ();
|
||||||
|
bool step_edit_within_chord () const;
|
||||||
|
void step_edit_toggle_chord ();
|
||||||
|
void reset_step_edit_beat_pos ();
|
||||||
|
void resync_step_edit_to_edit_point ();
|
||||||
|
void move_step_edit_beat_pos (Evoral::MusicalTime beats);
|
||||||
|
void set_step_edit_cursor_width (Evoral::MusicalTime beats);
|
||||||
|
|
||||||
|
std::string name() const;
|
||||||
|
|
||||||
|
void start_step_editing ();
|
||||||
|
void stop_step_editing ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ARDOUR::framepos_t step_edit_insert_position;
|
||||||
|
Evoral::MusicalTime step_edit_beat_pos;
|
||||||
|
boost::shared_ptr<ARDOUR::MidiRegion> step_edit_region;
|
||||||
|
MidiRegionView* step_edit_region_view;
|
||||||
|
uint8_t _step_edit_triplet_countdown;
|
||||||
|
bool _step_edit_within_chord;
|
||||||
|
Evoral::MusicalTime _step_edit_chord_duration;
|
||||||
|
PBD::ScopedConnection step_edit_region_connection;
|
||||||
|
PublicEditor& _editor;
|
||||||
|
boost::shared_ptr<ARDOUR::MidiTrack> _track;
|
||||||
|
StepEntry* step_editor;
|
||||||
|
MidiTimeAxisView& _mtv;
|
||||||
|
|
||||||
|
void region_removed (boost::weak_ptr<ARDOUR::Region>);
|
||||||
|
void playlist_changed ();
|
||||||
|
bool step_editor_hidden (GdkEventAny*);
|
||||||
|
void step_editor_hide ();
|
||||||
|
void resync_step_edit_position ();
|
||||||
|
void prepare_step_edit_region ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __pbd__step_editor_h__ */
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "ardour_ui.h"
|
#include "ardour_ui.h"
|
||||||
#include "midi_channel_selector.h"
|
#include "midi_channel_selector.h"
|
||||||
#include "midi_time_axis.h"
|
#include "midi_time_axis.h"
|
||||||
|
#include "step_editor.h"
|
||||||
#include "step_entry.h"
|
#include "step_entry.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
@ -55,8 +56,8 @@ _rest_event_handler (GtkWidget* widget, gpointer arg)
|
||||||
((StepEntry*)arg)->rest_event_handler ();
|
((StepEntry*)arg)->rest_event_handler ();
|
||||||
}
|
}
|
||||||
|
|
||||||
StepEntry::StepEntry (MidiTimeAxisView& mtv)
|
StepEntry::StepEntry (StepEditor& seditor)
|
||||||
: ArdourDialog (string_compose (_("Step Entry: %1"), mtv.name()))
|
: ArdourDialog (string_compose (_("Step Entry: %1"), seditor.name()))
|
||||||
, _current_note_length (1.0)
|
, _current_note_length (1.0)
|
||||||
, _current_note_velocity (64)
|
, _current_note_velocity (64)
|
||||||
, triplet_button ("3")
|
, triplet_button ("3")
|
||||||
|
|
@ -84,17 +85,18 @@ StepEntry::StepEntry (MidiTimeAxisView& mtv)
|
||||||
, program_button (_("+"))
|
, program_button (_("+"))
|
||||||
, _piano (0)
|
, _piano (0)
|
||||||
, piano (0)
|
, piano (0)
|
||||||
, _mtv (&mtv)
|
, se (&seditor)
|
||||||
{
|
{
|
||||||
register_actions ();
|
register_actions ();
|
||||||
load_bindings ();
|
load_bindings ();
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* set channel selector to first selected channel. if none
|
/* set channel selector to first selected channel. if none
|
||||||
are selected, it will remain at the value set in its
|
are selected, it will remain at the value set in its
|
||||||
constructor, above (1)
|
constructor, above (1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint16_t chn_mask = _mtv->channel_selector().get_selected_channels();
|
uint16_t chn_mask = se->channel_selector().get_selected_channels();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 16; ++i) {
|
for (uint32_t i = 0; i < 16; ++i) {
|
||||||
if (chn_mask & (1<<i)) {
|
if (chn_mask & (1<<i)) {
|
||||||
|
|
@ -103,6 +105,8 @@ StepEntry::StepEntry (MidiTimeAxisView& mtv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
RadioButtonGroup length_group = length_1_button.get_group();
|
RadioButtonGroup length_group = length_1_button.get_group();
|
||||||
length_2_button.set_group (length_group);
|
length_2_button.set_group (length_group);
|
||||||
length_4_button.set_group (length_group);
|
length_4_button.set_group (length_group);
|
||||||
|
|
@ -510,7 +514,7 @@ StepEntry::on_key_release_event (GdkEventKey* ev)
|
||||||
void
|
void
|
||||||
StepEntry::rest_event_handler ()
|
StepEntry::rest_event_handler ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_rest (0.0);
|
se->step_edit_rest (0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Evoral::MusicalTime
|
Evoral::MusicalTime
|
||||||
|
|
@ -565,13 +569,13 @@ StepEntry::on_show ()
|
||||||
void
|
void
|
||||||
StepEntry::beat_resync_click ()
|
StepEntry::beat_resync_click ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_beat_sync ();
|
se->step_edit_beat_sync ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::bar_resync_click ()
|
StepEntry::bar_resync_click ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_bar_sync ();
|
se->step_edit_bar_sync ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -703,13 +707,13 @@ StepEntry::load_bindings ()
|
||||||
void
|
void
|
||||||
StepEntry::toggle_triplet ()
|
StepEntry::toggle_triplet ()
|
||||||
{
|
{
|
||||||
_mtv->set_step_edit_cursor_width (note_length());
|
se->set_step_edit_cursor_width (note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::toggle_chord ()
|
StepEntry::toggle_chord ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_toggle_chord ();
|
se->step_edit_toggle_chord ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -756,37 +760,37 @@ StepEntry::dot_value_change ()
|
||||||
dot2_button.set_inconsistent (inconsistent);
|
dot2_button.set_inconsistent (inconsistent);
|
||||||
dot3_button.set_inconsistent (inconsistent);
|
dot3_button.set_inconsistent (inconsistent);
|
||||||
|
|
||||||
_mtv->set_step_edit_cursor_width (note_length());
|
se->set_step_edit_cursor_width (note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::program_click ()
|
StepEntry::program_click ()
|
||||||
{
|
{
|
||||||
_mtv->step_add_program_change (note_channel(), (int8_t) floor (program_adjustment.get_value()));
|
se->step_add_program_change (note_channel(), (int8_t) floor (program_adjustment.get_value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::bank_click ()
|
StepEntry::bank_click ()
|
||||||
{
|
{
|
||||||
_mtv->step_add_bank_change (note_channel(), (int8_t) floor (bank_adjustment.get_value()));
|
se->step_add_bank_change (note_channel(), (int8_t) floor (bank_adjustment.get_value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::insert_rest ()
|
StepEntry::insert_rest ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_rest (note_length());
|
se->step_edit_rest (note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::insert_grid_rest ()
|
StepEntry::insert_grid_rest ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_rest (0.0);
|
se->step_edit_rest (0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::insert_note (uint8_t note)
|
StepEntry::insert_note (uint8_t note)
|
||||||
{
|
{
|
||||||
_mtv->step_add_note (note_channel(), note, note_velocity(), note_length());
|
se->step_add_note (note_channel(), note, note_velocity(), note_length());
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
StepEntry::insert_c ()
|
StepEntry::insert_c ()
|
||||||
|
|
@ -972,7 +976,7 @@ StepEntry::length_value_change ()
|
||||||
length_32_button.set_inconsistent (inconsistent);
|
length_32_button.set_inconsistent (inconsistent);
|
||||||
length_64_button.set_inconsistent (inconsistent);
|
length_64_button.set_inconsistent (inconsistent);
|
||||||
|
|
||||||
_mtv->set_step_edit_cursor_width (note_length());
|
se->set_step_edit_cursor_width (note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1132,17 +1136,17 @@ StepEntry::octave_n (int n)
|
||||||
void
|
void
|
||||||
StepEntry::do_sustain ()
|
StepEntry::do_sustain ()
|
||||||
{
|
{
|
||||||
_mtv->step_edit_sustain (note_length());
|
se->step_edit_sustain (note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::back ()
|
StepEntry::back ()
|
||||||
{
|
{
|
||||||
_mtv->move_step_edit_beat_pos (-note_length());
|
se->move_step_edit_beat_pos (-note_length());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StepEntry::sync_to_edit_point ()
|
StepEntry::sync_to_edit_point ()
|
||||||
{
|
{
|
||||||
_mtv->resync_step_edit_to_edit_point ();
|
se->resync_step_edit_to_edit_point ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@
|
||||||
#include "ardour_dialog.h"
|
#include "ardour_dialog.h"
|
||||||
#include "gtk_pianokeyboard.h"
|
#include "gtk_pianokeyboard.h"
|
||||||
|
|
||||||
class MidiTimeAxisView;
|
class StepEditor;
|
||||||
|
|
||||||
class StepEntry : public ArdourDialog
|
class StepEntry : public ArdourDialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StepEntry (MidiTimeAxisView&);
|
StepEntry (StepEditor&);
|
||||||
~StepEntry ();
|
~StepEntry ();
|
||||||
|
|
||||||
void note_off_event_handler (int note);
|
void note_off_event_handler (int note);
|
||||||
|
|
@ -124,7 +124,7 @@ class StepEntry : public ArdourDialog
|
||||||
|
|
||||||
PianoKeyboard* _piano;
|
PianoKeyboard* _piano;
|
||||||
Gtk::Widget* piano;
|
Gtk::Widget* piano;
|
||||||
MidiTimeAxisView* _mtv;
|
StepEditor* se;
|
||||||
|
|
||||||
void bank_click ();
|
void bank_click ();
|
||||||
void program_click ();
|
void program_click ();
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ gtk2_ardour_sources = [
|
||||||
'simplerect.cc',
|
'simplerect.cc',
|
||||||
'splash.cc',
|
'splash.cc',
|
||||||
'startup.cc',
|
'startup.cc',
|
||||||
|
'step_editor.cc',
|
||||||
'step_entry.cc',
|
'step_entry.cc',
|
||||||
'streamview.cc',
|
'streamview.cc',
|
||||||
'strip_silence_dialog.cc',
|
'strip_silence_dialog.cc',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue