Compare commits
27 Commits
master
...
mode-clamp
Author | SHA1 | Date |
---|---|---|
Paul Davis | dc8382c0b5 | |
Paul Davis | e8baad9efa | |
Paul Davis | d0cdd0c9db | |
Paul Davis | bf28ecfc4c | |
Paul Davis | 407936277f | |
Paul Davis | bfe52ca668 | |
Paul Davis | a3a8f355ee | |
Paul Davis | 9f4bf02980 | |
Paul Davis | 987c4de725 | |
Paul Davis | ae8c755d51 | |
Paul Davis | 331377212e | |
Paul Davis | eb0c1984de | |
Paul Davis | 2bb880aac0 | |
Paul Davis | 1793c9a61a | |
Paul Davis | 4648785935 | |
Paul Davis | 6cdbd4174d | |
Paul Davis | 9f76d688fd | |
Paul Davis | 1555896d8e | |
Paul Davis | 55a0aadc74 | |
Paul Davis | 22efa2bf17 | |
Paul Davis | 15e4ba5123 | |
Paul Davis | 7f88c71bd3 | |
Paul Davis | fb7dd71c45 | |
Paul Davis | 4801f488c5 | |
Paul Davis | a7907d9e99 | |
Paul Davis | 46242a0079 | |
Paul Davis | b4d6b888bb |
|
@ -856,6 +856,13 @@ MidiRegionView::create_note_at (timepos_t const & t, double y, Temporal::Beats l
|
|||
Temporal::Beats region_start = t.beats();
|
||||
|
||||
const double note = view->y_to_note(y);
|
||||
|
||||
if (mtv->midi_track()->key_enforcment_policy() & NoInsert) {
|
||||
if (!mtv->midi_track()->key().in_key (note)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t chan = get_channel_for_add(region_start);
|
||||
const uint8_t velocity = get_velocity_for_add (region_start);
|
||||
|
||||
|
@ -1638,6 +1645,15 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions)
|
|||
const timepos_t note_start (note->time());
|
||||
timepos_t note_end (note->end_time());
|
||||
|
||||
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
|
||||
MusicalKey const & key (mtv->midi_track()->key());
|
||||
if (!(mtv->midi_track()->key_enforcment_policy() & NoDraw) || key.in_key (note->note())) {
|
||||
ev->show ();
|
||||
} else {
|
||||
ev->hide ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The note is drawn as a child item of this region view, so its
|
||||
* coordinate system is relative to the region view. This means that x0
|
||||
* and x1 are pixel offsets relative to beginning of the region (view)
|
||||
|
@ -2681,6 +2697,9 @@ MidiRegionView::note_dropped(NoteBase *, timecnt_t const & d_qn, int8_t dnote, b
|
|||
uint8_t highest_note_in_selection = 0;
|
||||
uint8_t highest_note_difference = 0;
|
||||
|
||||
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
|
||||
MusicalKey const & key (mtv->midi_track()->key());
|
||||
|
||||
if (!copy) {
|
||||
// find highest and lowest notes first
|
||||
|
||||
|
@ -2726,7 +2745,11 @@ MidiRegionView::note_dropped(NoteBase *, timecnt_t const & d_qn, int8_t dnote, b
|
|||
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
|
||||
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
|
||||
|
||||
note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
|
||||
if (!(mtv->midi_track()->key_enforcment_policy() & NoInsert) || key.in_key (new_pitch)) {
|
||||
note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
|
||||
} else {
|
||||
/* XXX remove it? or what? */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
|
@ -2769,6 +2792,10 @@ MidiRegionView::note_dropped(NoteBase *, timecnt_t const & d_qn, int8_t dnote, b
|
|||
lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
|
||||
highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
|
||||
|
||||
if (!(mtv->midi_track()->key_enforcment_policy() & NoInsert) || key.in_key (new_pitch)) {
|
||||
note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
|
||||
}
|
||||
|
||||
note_diff_add_note ((*i)->note(), true);
|
||||
|
||||
delete *i;
|
||||
|
@ -4219,7 +4246,7 @@ MidiRegionView::get_note_name (boost::shared_ptr<NoteType> n, uint8_t note_value
|
|||
name.empty() ? ParameterDescriptor::midi_note_name (note_value).c_str() : name.c_str(),
|
||||
(int) note_value,
|
||||
(int) n->channel() + 1,
|
||||
(int) n->velocity()); //we display velocity 0-based; velocity 0 is a 'note-off' so the user just sees values 1..127 which 'looks' 1-based
|
||||
(int) n->velocity()); //we display velocity 0-based; velocity 0 is a 'note-off' so the user just sees values 1..127 which 'looks' 1-based
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -349,19 +349,34 @@ MidiStreamView::draw_note_lines()
|
|||
* height of this note.
|
||||
*/
|
||||
|
||||
std::string color_mod_name;
|
||||
std::string color_name;
|
||||
|
||||
switch (i % 12) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 6:
|
||||
case 8:
|
||||
case 10:
|
||||
color = UIConfiguration::instance().color_mod ("piano roll black", "piano roll black");
|
||||
if (boost::dynamic_pointer_cast<MidiTrack>(_trackview.track())->key().in_key (i)) {
|
||||
color_name = X_("piano roll black");
|
||||
} else {
|
||||
color_name = X_("piano roll offkey");
|
||||
}
|
||||
color_mod_name = X_("piano roll black");
|
||||
break;
|
||||
default:
|
||||
color = UIConfiguration::instance().color_mod ("piano roll white", "piano roll white");
|
||||
if (boost::dynamic_pointer_cast<MidiTrack>(_trackview.track())->key().in_key (i)) {
|
||||
color_name = X_("piano roll white");
|
||||
} else {
|
||||
color_name = X_("piano roll offkey");
|
||||
}
|
||||
color_mod_name = X_("piano roll white");
|
||||
break;
|
||||
}
|
||||
|
||||
color = UIConfiguration::instance().color_mod (color_name, color_mod_name);
|
||||
|
||||
double h = y - prev_y;
|
||||
double mid = y + (h/2.0);
|
||||
|
||||
|
|
|
@ -640,6 +640,10 @@ MidiTimeAxisView::append_extra_display_menu_items ()
|
|||
cmi->set_active (midi_track ()->restore_pgm_on_load ());
|
||||
cmi->signal_activate().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_restore_pgm_on_load));
|
||||
|
||||
items.push_back (MenuElem (_("Scale"), *build_musical_mode_menu ()));
|
||||
items.push_back (MenuElem (_("Tonic (Root)"), *build_musical_root_menu ()));
|
||||
items.push_back (MenuElem (_("Key Enforcement"), *build_key_enforcement_menu()));
|
||||
|
||||
items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
|
||||
|
||||
items.push_back (SeparatorElem ());
|
||||
|
@ -1117,6 +1121,376 @@ MidiTimeAxisView::build_note_mode_menu()
|
|||
return mode_menu;
|
||||
}
|
||||
|
||||
Gtk::Menu*
|
||||
MidiTimeAxisView::build_musical_root_menu ()
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
Menu* root_menu = manage (new Menu);
|
||||
MenuList& items = root_menu->items();
|
||||
root_menu->set_name ("ArdourContextMenu");
|
||||
|
||||
RadioMenuItem::Group root_group;
|
||||
RadioMenuItem* last_item;
|
||||
|
||||
int r = midi_track()->key().root();
|
||||
|
||||
for (int n = 0; n < 12; ++n) {
|
||||
items.push_back (RadioMenuElem (root_group, ParameterDescriptor::midi_note_name (n, true, false), sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_root), n)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (r == n);
|
||||
}
|
||||
|
||||
return root_menu;
|
||||
}
|
||||
|
||||
Gtk::Menu*
|
||||
MidiTimeAxisView::build_key_enforcement_menu ()
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
Menu* menu = manage (new Menu);
|
||||
MenuList& items = menu->items();
|
||||
menu->set_name ("ArdourContextMenu");
|
||||
|
||||
RadioMenuItem::Group group;
|
||||
CheckMenuItem* last_check_item;
|
||||
RadioMenuItem* last_radio_item;
|
||||
|
||||
KeyEnforcementPolicy kep = midi_track()->key_enforcment_policy();
|
||||
|
||||
items.push_back (CheckMenuElem (_("Don't show non-scale ghost notes while drawing/editing")));
|
||||
last_check_item = dynamic_cast<CheckMenuItem*>(&items.back());
|
||||
last_check_item->set_active (kep & NoDraw);
|
||||
last_check_item->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_key_enforcement_policy), NoDraw, last_check_item));
|
||||
items.push_back (CheckMenuElem (_("Don't allow mouse edits to create non-scale notes")));
|
||||
last_check_item = dynamic_cast<CheckMenuItem*>(&items.back());
|
||||
last_check_item->set_active (kep & NoInsert);
|
||||
last_check_item->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_key_enforcement_policy), NoInsert, last_check_item));
|
||||
|
||||
items.push_back (RadioMenuElem (group, _("Force note edits of non-scale notes to next lower note")));
|
||||
last_radio_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_radio_item->set_active (kep & ForceLower);
|
||||
last_radio_item->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_key_enforcement_policy), ForceLower, last_radio_item));
|
||||
items.push_back (RadioMenuElem (group, _("Force note edits of non-scale notes to next higher note")));
|
||||
last_radio_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_radio_item->set_active (kep & ForceHigher);
|
||||
last_radio_item->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_key_enforcement_policy), ForceHigher, last_radio_item));
|
||||
items.push_back (RadioMenuElem (group, _("Force note edits of non-scale notes to nearest note")));
|
||||
last_radio_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_radio_item->set_active (kep & ForceNearest);
|
||||
last_radio_item->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_key_enforcement_policy), ForceNearest, last_radio_item));
|
||||
return menu;
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::toggle_key_enforcement_policy (KeyEnforcementPolicy kepb, CheckMenuItem* item)
|
||||
{
|
||||
KeyEnforcementPolicy kep = midi_track()->key_enforcment_policy();
|
||||
|
||||
/* Some of the menu items that trigger this are radio menu items, and
|
||||
this method will be called when they go inactive. We want to ignore
|
||||
these calls.
|
||||
*/
|
||||
|
||||
if (!item->get_active()) {
|
||||
return;
|
||||
}
|
||||
if (kep & kepb) {
|
||||
midi_track()->set_key_enforcement_policy (KeyEnforcementPolicy (kep & ~kepb));
|
||||
} else {
|
||||
midi_track()->set_key_enforcement_policy (KeyEnforcementPolicy (kep | kepb));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::set_musical_root (int r)
|
||||
{
|
||||
midi_track()->set_key (MusicalKey (midi_track()->key().type(), r));
|
||||
}
|
||||
|
||||
Gtk::Menu*
|
||||
MidiTimeAxisView::build_musical_mode_menu()
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
Menu* mode_menu = manage (new Menu);
|
||||
MenuList& items = mode_menu->items();
|
||||
mode_menu->set_name ("ArdourContextMenu");
|
||||
|
||||
RadioMenuItem::Group mode_group;
|
||||
RadioMenuItem* last_item;
|
||||
|
||||
MusicalMode::Type t = midi_track()->key().type();
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Chromatic"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Chromatic)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Chromatic);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Major (Ionian)"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::IonianMajor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::IonianMajor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Minor (Aeolian)"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::AeolianMinor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::AeolianMinor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Dorian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Dorian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Dorian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("HarmonicMinor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::HarmonicMinor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == 30);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("MelodicMinorAscending"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::MelodicMinorAscending)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::MelodicMinorAscending);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("MelodicMinorDescending"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::MelodicMinorDescending)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::MelodicMinorDescending);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Phrygian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Phrygian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Phrygian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Lydian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Lydian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Lydian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Mixolydian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Mixolydian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Mixolydian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Locrian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Locrian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Locrian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("PentatonicMajor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::PentatonicMajor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::PentatonicMajor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("PentatonicMinor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::PentatonicMinor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::PentatonicMinor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("BluesScale"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::BluesScale)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::BluesScale);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("NeapolitanMinor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::NeapolitanMinor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::NeapolitanMinor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("NeapolitanMajor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::NeapolitanMajor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::NeapolitanMajor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Oriental"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Oriental)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Oriental);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("DoubleHarmonic"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::DoubleHarmonic)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::DoubleHarmonic);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Enigmatic"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Enigmatic)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Enigmatic);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Hirajoshi"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Hirajoshi)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Hirajoshi);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("HungarianMinor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::HungarianMinor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::HungarianMinor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("HungarianMajor"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::HungarianMajor)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::HungarianMajor);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Kumoi"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Kumoi)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Kumoi);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Iwato"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Iwato)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Iwato);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Hindu"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Hindu)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Hindu);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Spanish8Tone"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Spanish8Tone)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Spanish8Tone);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Pelog"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Pelog)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Pelog);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("HungarianGypsy"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::HungarianGypsy)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::HungarianGypsy);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Overtone"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Overtone)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Overtone);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("LeadingWholeTone"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::LeadingWholeTone)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::LeadingWholeTone);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Arabian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Arabian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Arabian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Balinese"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Balinese)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Balinese);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Gypsy"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Gypsy)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Gypsy);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Mohammedan"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Mohammedan)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Mohammedan);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Javanese"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Javanese)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Javanese);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Persian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Persian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Persian);
|
||||
|
||||
items.push_back (
|
||||
RadioMenuElem (mode_group, _("Algerian"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_musical_mode),
|
||||
MusicalMode::Algerian)));
|
||||
last_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
last_item->set_active (t == MusicalMode::Algerian);
|
||||
|
||||
return mode_menu;
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::set_musical_mode (MusicalMode::Type mode_type)
|
||||
{
|
||||
midi_track()->set_key (MusicalKey (mode_type, midi_track()->key().root()));
|
||||
}
|
||||
|
||||
Gtk::Menu*
|
||||
MidiTimeAxisView::build_color_mode_menu()
|
||||
{
|
||||
|
@ -1781,3 +2155,13 @@ MidiTimeAxisView::get_regions_with_selected_data (RegionSelection& rs)
|
|||
{
|
||||
midi_view()->get_regions_with_selected_data (rs);
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::route_property_changed (const PBD::PropertyChange& pc)
|
||||
{
|
||||
RouteTimeAxisView::route_property_changed (pc);
|
||||
|
||||
if (pc.contains (Properties::musical_mode) || pc.contains (Properties::musical_root)) {
|
||||
_view->redisplay_track ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ protected:
|
|||
void start_step_editing ();
|
||||
void stop_step_editing ();
|
||||
void processors_changed (ARDOUR::RouteProcessorChange);
|
||||
void route_property_changed (const PBD::PropertyChange&);
|
||||
|
||||
private:
|
||||
sigc::signal<void, std::string, std::string> _midi_patch_settings_changed;
|
||||
|
@ -133,7 +134,13 @@ private:
|
|||
void build_automation_action_menu (bool);
|
||||
Gtk::Menu* build_note_mode_menu();
|
||||
Gtk::Menu* build_color_mode_menu();
|
||||
Gtk::Menu* build_musical_mode_menu ();
|
||||
Gtk::Menu* build_musical_root_menu ();
|
||||
Gtk::Menu* build_key_enforcement_menu ();
|
||||
|
||||
void toggle_key_enforcement_policy (ARDOUR::KeyEnforcementPolicy, Gtk::CheckMenuItem*);
|
||||
void set_musical_mode (MusicalMode::Type);
|
||||
void set_musical_root (int note);
|
||||
void set_note_mode (ARDOUR::NoteMode mode, bool apply_to_selection = false);
|
||||
void set_color_mode (ARDOUR::ColorMode, bool force = false, bool redisplay = true, bool apply_to_selection = false);
|
||||
void set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection = false);
|
||||
|
@ -199,4 +206,5 @@ private:
|
|||
StepEditor* _step_editor;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ardour_midi_time_axis_h__ */
|
||||
|
|
|
@ -294,6 +294,7 @@
|
|||
<ColorAlias name="piano roll black" alias="theme:contrasting selection"/>
|
||||
<ColorAlias name="piano roll black outline" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano roll white" alias="neutral:foreground2"/>
|
||||
<ColorAlias name="piano roll offkey" alias="alert:ruddy"/>
|
||||
<ColorAlias name="pinrouting custom: led active" alias="alert:ruddy"/>
|
||||
<ColorAlias name="pinrouting sidechain: led active" alias="alert:green"/>
|
||||
<ColorAlias name="play head" alias="theme:contrasting"/>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_key_h__
|
||||
#define __ardour_key_h__
|
||||
|
||||
#include "ardour/mode.h"
|
||||
|
||||
class MusicalKey : public MusicalMode
|
||||
{
|
||||
public:
|
||||
MusicalKey (Type t, int root) : MusicalMode (t), _root (root) {}
|
||||
~MusicalKey ();
|
||||
|
||||
int root () const { return _root; }
|
||||
void set_root (int);
|
||||
|
||||
bool in_key (int note) const;
|
||||
|
||||
private:
|
||||
int _root;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __ardour_key_h__ */
|
|
@ -24,11 +24,17 @@
|
|||
|
||||
#include "ardour/midi_channel_filter.h"
|
||||
#include "ardour/midi_ring_buffer.h"
|
||||
#include "ardour/key.h"
|
||||
#include "ardour/track.h"
|
||||
|
||||
namespace ARDOUR
|
||||
{
|
||||
|
||||
namespace Properties {
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<MusicalKey::Type> musical_mode;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<int> musical_root;
|
||||
}
|
||||
|
||||
class InterThreadInfo;
|
||||
class MidiPlaylist;
|
||||
class RouteGroup;
|
||||
|
@ -43,6 +49,8 @@ public:
|
|||
|
||||
int init ();
|
||||
|
||||
static void make_property_quarks ();
|
||||
|
||||
void realtime_locate (bool);
|
||||
void non_realtime_locate (samplepos_t);
|
||||
|
||||
|
@ -144,6 +152,12 @@ public:
|
|||
void realtime_handle_transport_stopped ();
|
||||
void region_edited (boost::shared_ptr<Region>);
|
||||
|
||||
MusicalKey const & key() const { return _key; }
|
||||
void set_key (MusicalKey const & key);
|
||||
|
||||
KeyEnforcementPolicy key_enforcment_policy () const;
|
||||
void set_key_enforcement_policy (KeyEnforcementPolicy);
|
||||
|
||||
protected:
|
||||
|
||||
XMLNode& state (bool save_template);
|
||||
|
@ -166,6 +180,9 @@ private:
|
|||
MidiChannelFilter _playback_filter;
|
||||
MidiChannelFilter _capture_filter;
|
||||
|
||||
MusicalKey _key;
|
||||
KeyEnforcementPolicy _key_enforcement_policy;
|
||||
|
||||
void set_state_part_two ();
|
||||
void set_state_part_three ();
|
||||
|
||||
|
|
|
@ -68,9 +68,11 @@ class MusicalMode
|
|||
~MusicalMode ();
|
||||
|
||||
std::vector<float> steps;
|
||||
Type type() const { return _type; }
|
||||
|
||||
private:
|
||||
static void fill (MusicalMode&, Type);
|
||||
Type _type;
|
||||
};
|
||||
|
||||
#endif /* __ardour_mode_h__ */
|
||||
|
|
|
@ -50,7 +50,7 @@ struct LIBARDOUR_API ParameterDescriptor : public Evoral::ParameterDescriptor
|
|||
HZ, ///< Frequency in Hertz
|
||||
};
|
||||
|
||||
static std::string midi_note_name (uint8_t, bool translate=true);
|
||||
static std::string midi_note_name (uint8_t, bool translate = true, bool with_octave = true);
|
||||
|
||||
/** Dual of midi_note_name, convert a note name into its midi note number. */
|
||||
typedef std::map<std::string, uint8_t> NameNumMap;
|
||||
|
|
|
@ -811,6 +811,15 @@ enum LocateTransportDisposition {
|
|||
RollIfAppropriate
|
||||
};
|
||||
|
||||
enum KeyEnforcementPolicy {
|
||||
NoDraw = 0x1, /* do not show visually as candidate for new notes */
|
||||
NoInsert = 0x2,
|
||||
NoPlay = 0x4,
|
||||
ForceLower = 0x8,
|
||||
ForceHigher = 0x10,
|
||||
ForceNearest = 0x20
|
||||
};
|
||||
|
||||
typedef std::vector<CaptureInfo*> CaptureInfos;
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -158,6 +158,7 @@ setup_enum_writer ()
|
|||
Trigger::State _TriggerState;
|
||||
Trigger::LaunchStyle _TriggerLaunchStyle;
|
||||
Trigger::FollowAction _TriggerFollowAction;
|
||||
KeyEnforcementPolicy _KeyEnforcementPolicy;
|
||||
|
||||
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
|
@ -868,6 +869,13 @@ setup_enum_writer ()
|
|||
REGISTER_CLASS_ENUM (Trigger, Repeat);
|
||||
REGISTER (_TriggerLaunchStyle);
|
||||
|
||||
REGISTER_ENUM (NoDraw);
|
||||
REGISTER_ENUM (NoInsert);
|
||||
REGISTER_ENUM (NoPlay);
|
||||
REGISTER_ENUM (ForceLower);
|
||||
REGISTER_ENUM (ForceHigher);
|
||||
REGISTER_ENUM (ForceNearest);
|
||||
REGISTER_BITS (_KeyEnforcementPolicy);
|
||||
}
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/midi_patch_manager.h"
|
||||
#include "ardour/midi_region.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/midi_ui.h"
|
||||
#include "ardour/midiport_manager.h"
|
||||
#include "ardour/mix.h"
|
||||
|
@ -563,6 +564,7 @@ ARDOUR::init (bool try_optimization, const char* localedir, bool with_gui)
|
|||
PresentationInfo::make_property_quarks ();
|
||||
TransportMaster::make_property_quarks ();
|
||||
Trigger::make_property_quarks ();
|
||||
MidiTrack::make_property_quarks ();
|
||||
|
||||
/* this is a useful ready to use PropertyChange that many
|
||||
things need to check. This avoids having to compose
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "ardour/key.h"
|
||||
|
||||
MusicalKey::~MusicalKey ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MusicalKey::set_root (int r)
|
||||
{
|
||||
/* force root into lowest octave. Yes, 12 tone for now */
|
||||
_root = (r % 12);
|
||||
}
|
||||
|
||||
bool
|
||||
MusicalKey::in_key (int note) const
|
||||
{
|
||||
/* currently 12 tone based */
|
||||
|
||||
note = note % 12;
|
||||
|
||||
/* we should speed this us. Probably a bitset */
|
||||
|
||||
if (note == _root) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (std::vector<float>::const_iterator i = steps.begin(); i != steps.end(); ++i) {
|
||||
int ii = (int) ((*i) * 2.0);
|
||||
|
||||
if (note == _root + ii) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -72,12 +72,27 @@ class InterThreadInfo;
|
|||
class MidiSource;
|
||||
class Region;
|
||||
class SMFSource;
|
||||
|
||||
|
||||
namespace Properties {
|
||||
PBD::PropertyDescriptor<MusicalMode::Type> musical_mode;
|
||||
PBD::PropertyDescriptor<int> musical_root;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
void
|
||||
MidiTrack::make_property_quarks ()
|
||||
{
|
||||
Properties::musical_mode.property_id = g_quark_from_static_string (X_("musical-mode"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for musical-mode = %1\n", Properties::musical_mode.property_id));
|
||||
Properties::musical_root.property_id = g_quark_from_static_string (X_("musical-root"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for musical-root = %1\n", Properties::musical_root.property_id));
|
||||
}
|
||||
|
||||
MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
|
||||
: Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI)
|
||||
, _immediate_events(6096) // FIXME: size?
|
||||
|
@ -87,6 +102,8 @@ MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode)
|
|||
, _step_editing (false)
|
||||
, _input_active (true)
|
||||
, _restore_pgm_on_load (true)
|
||||
, _key (MusicalKey (MusicalMode::IonianMajor, 0))
|
||||
, _key_enforcement_policy (KeyEnforcementPolicy (0))
|
||||
{
|
||||
_session.SessionLoaded.connect_same_thread (*this, boost::bind (&MidiTrack::restore_controls, this));
|
||||
|
||||
|
@ -120,6 +137,31 @@ MidiTrack::init ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
MidiTrack::set_key_enforcement_policy (KeyEnforcementPolicy kep)
|
||||
{
|
||||
_key_enforcement_policy = kep;
|
||||
}
|
||||
|
||||
KeyEnforcementPolicy
|
||||
MidiTrack::key_enforcment_policy () const
|
||||
{
|
||||
return _key_enforcement_policy;
|
||||
}
|
||||
|
||||
void
|
||||
MidiTrack::set_key (MusicalKey const & k)
|
||||
{
|
||||
_key = k;
|
||||
|
||||
PropertyChange pc;
|
||||
|
||||
pc.add (Properties::musical_mode);
|
||||
pc.add (Properties::musical_root);
|
||||
|
||||
PropertyChanged (pc); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
void
|
||||
MidiTrack::data_recorded (boost::weak_ptr<MidiSource> src)
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "ardour/mode.h"
|
||||
|
||||
MusicalMode::MusicalMode (MusicalMode::Type t)
|
||||
: _type (t)
|
||||
{
|
||||
fill (*this, t);
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ ParameterDescriptor::update_steps()
|
|||
}
|
||||
|
||||
std::string
|
||||
ParameterDescriptor::midi_note_name (const uint8_t b, bool translate)
|
||||
ParameterDescriptor::midi_note_name (const uint8_t b, bool translate, bool with_octave)
|
||||
{
|
||||
char buf[16];
|
||||
if (b > 127) {
|
||||
|
@ -279,9 +279,14 @@ ParameterDescriptor::midi_note_name (const uint8_t b, bool translate)
|
|||
S_("Note|B")
|
||||
};
|
||||
|
||||
/* MIDI note 0 is in octave -1 (in scientific pitch notation) */
|
||||
const int octave = b / 12 - 1;
|
||||
const size_t p = b % 12;
|
||||
|
||||
/* MIDI note 0 is in octave -1 (in scientific pitch notation) */
|
||||
if (!with_octave) {
|
||||
return translate ? notes[p] : en_notes[p];
|
||||
}
|
||||
|
||||
const int octave = b / 12 - 1;
|
||||
snprintf (buf, sizeof (buf), "%s%d", translate ? notes[p] : en_notes[p], octave);
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ libardour_sources = [
|
|||
'interpolation.cc',
|
||||
'io.cc',
|
||||
'io_processor.cc',
|
||||
'key.cc',
|
||||
'kmeterdsp.cc',
|
||||
'ladspa_plugin.cc',
|
||||
'latent.cc',
|
||||
|
@ -206,7 +207,7 @@ libardour_sources = [
|
|||
'route_group_member.cc',
|
||||
'rb_effect.cc',
|
||||
'rt_tasklist.cc',
|
||||
'scene_change.cc',
|
||||
'scene_change.cc',
|
||||
'search_paths.cc',
|
||||
'selection.cc',
|
||||
'send.cc',
|
||||
|
|
Loading…
Reference in New Issue