Skip to content

Commit

Permalink
Merge pull request #24784 from rpatters1/rpatters1/keyboard-switch-co…
Browse files Browse the repository at this point in the history
…ncert-transposed

Switch PianoKeyboard between Notated Pitch (effective pitch) and Playback Pitch (completed).
  • Loading branch information
cbjeukendrup authored Oct 4, 2024
2 parents 9dae103 + 6a0159d commit 4662ac8
Show file tree
Hide file tree
Showing 18 changed files with 140 additions and 18 deletions.
4 changes: 2 additions & 2 deletions src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3384,7 +3384,7 @@ void Score::cmdMoveLyrics(Lyrics* lyrics, DirectionV dir)
// realtimeAdvance
//---------------------------------------------------------

void Score::realtimeAdvance()
void Score::realtimeAdvance(bool allowTransposition)
{
InputState& is = inputState();
if (!is.noteEntryMode()) {
Expand All @@ -3410,7 +3410,7 @@ void Score::realtimeAdvance()
Chord* prevChord = prevCR->isChord() ? toChord(prevCR) : 0;
bool partOfChord = false;
for (const MidiInputEvent& ev : midiPitches) {
addTiedMidiPitch(ev.pitch, partOfChord, prevChord);
addTiedMidiPitch(ev.pitch, partOfChord, prevChord, allowTransposition);
partOfChord = true;
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/engraving/dom/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1560,9 +1560,9 @@ void Score::cmdRemoveTimeSig(TimeSig* ts)
// addTiedMidiPitch
//---------------------------------------------------------

Note* Score::addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord)
Note* Score::addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord, bool allowTransposition)
{
Note* n = addMidiPitch(pitch, addFlag);
Note* n = addMidiPitch(pitch, addFlag, allowTransposition);
if (prevChord) {
Note* nn = prevChord->findNote(n->pitch());
if (nn) {
Expand All @@ -1580,14 +1580,14 @@ Note* Score::addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord)
return n;
}

NoteVal Score::noteVal(int pitch) const
NoteVal Score::noteVal(int pitch, bool allowTransposition) const
{
NoteVal nval(pitch);
Staff* st = staff(inputState().track() / VOICES);

// if transposing, interpret MIDI pitch as representing desired written pitch
// set pitch based on corresponding sounding pitch
if (!style().styleB(Sid::concertPitch)) {
if (!style().styleB(Sid::concertPitch) && allowTransposition) {
nval.pitch += st->part()->instrument(inputState().tick())->transpose().chromatic;
}
// let addPitch calculate tpc values from pitch
Expand All @@ -1601,9 +1601,9 @@ NoteVal Score::noteVal(int pitch) const
// addMidiPitch
//---------------------------------------------------------

Note* Score::addMidiPitch(int pitch, bool addFlag)
Note* Score::addMidiPitch(int pitch, bool addFlag, bool allowTransposition)
{
NoteVal nval = noteVal(pitch);
NoteVal nval = noteVal(pitch, allowTransposition);
return addPitch(nval, addFlag);
}

Expand Down
8 changes: 4 additions & 4 deletions src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ class Score : public EngravingObject, public muse::Injectable
void cmdMoveRest(Rest*, DirectionV);
void cmdMoveLyrics(Lyrics*, DirectionV);

void realtimeAdvance();
void realtimeAdvance(bool allowTransposition);

void addRemoveBreaks(int interval, bool lock);

Expand Down Expand Up @@ -497,9 +497,9 @@ class Score : public EngravingObject, public muse::Injectable
bool containsElement(const EngravingItem*) const;

Note* addPitch(NoteVal&, bool addFlag, InputState* externalInputState = nullptr);
Note* addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord);
NoteVal noteVal(int pitch) const;
Note* addMidiPitch(int pitch, bool addFlag);
Note* addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord, bool allowTransposition);
NoteVal noteVal(int pitch, bool allowTransposition) const;
Note* addMidiPitch(int pitch, bool addFlag, bool allowTransposition);
Note* addNote(Chord*, const NoteVal& noteVal, bool forceAccidental = false, const std::set<SymId>& articulationIds = {},
InputState* externalInputState = nullptr);
Note* addNoteToTiedChord(Chord*, const NoteVal& noteVal, bool forceAccidental = false, const std::set<SymId>& articulationIds = {});
Expand Down
3 changes: 3 additions & 0 deletions src/notation/inotationconfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE
virtual muse::ValCh<int> pianoKeyboardNumberOfKeys() const = 0;
virtual void setPianoKeyboardNumberOfKeys(int number) = 0;

virtual muse::ValCh<bool> midiUseWrittenPitch() const = 0;
virtual void setMidiUseWrittenPitch(bool useWrittenPitch) = 0;

// TODO: Delete when the new percussion panel is finished
virtual bool useNewPercussionPanel() const = 0;
virtual void setUseNewPercussionPanel(bool use) = 0;
Expand Down
17 changes: 17 additions & 0 deletions src/notation/internal/notationconfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static const Settings::Key MOUSE_ZOOM_PRECISION(module_name, "ui/canvas/zoomPrec
static const Settings::Key USER_STYLES_PATH(module_name, "application/paths/myStyles");

static const Settings::Key IS_MIDI_INPUT_ENABLED(module_name, "io/midi/enableInput");
static const Settings::Key USE_MIDI_INPUT_WRITTEN_PITCH(module_name, "io/midi/useWrittenPitch");
static const Settings::Key IS_AUTOMATICALLY_PAN_ENABLED(module_name, "application/playback/panPlayback");
static const Settings::Key PLAYBACK_SMOOTH_PANNING(module_name, "application/playback/smoothPan");
static const Settings::Key IS_PLAY_REPEATS_ENABLED(module_name, "application/playback/playRepeats");
Expand Down Expand Up @@ -220,6 +221,12 @@ void NotationConfiguration::init()
m_pianoKeyboardNumberOfKeys.set(val.toInt());
});

settings()->setDefaultValue(USE_MIDI_INPUT_WRITTEN_PITCH, Val(true));
m_midiInputUseWrittenPitch.val = settings()->value(USE_MIDI_INPUT_WRITTEN_PITCH).toBool();
settings()->valueChanged(USE_MIDI_INPUT_WRITTEN_PITCH).onReceive(this, [this](const Val& val) {
m_midiInputUseWrittenPitch.set(val.toBool());
});

settings()->setDefaultValue(USE_NEW_PERCUSSION_PANEL_KEY, Val(false));
settings()->setDefaultValue(AUTO_SHOW_PERCUSSION_PANEL_KEY, Val(true));

Expand Down Expand Up @@ -919,6 +926,16 @@ void NotationConfiguration::setPianoKeyboardNumberOfKeys(int number)
settings()->setSharedValue(PIANO_KEYBOARD_NUMBER_OF_KEYS, Val(number));
}

ValCh<bool> NotationConfiguration::midiUseWrittenPitch() const
{
return m_midiInputUseWrittenPitch;
}

void NotationConfiguration::setMidiUseWrittenPitch(bool useWrittenPitch)
{
settings()->setSharedValue(USE_MIDI_INPUT_WRITTEN_PITCH, Val(useWrittenPitch));
}

muse::io::path_t NotationConfiguration::firstScoreOrderListPath() const
{
return settings()->value(FIRST_SCORE_ORDER_LIST_KEY).toString();
Expand Down
4 changes: 4 additions & 0 deletions src/notation/internal/notationconfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ class NotationConfiguration : public INotationConfiguration, public muse::async:
muse::ValCh<int> pianoKeyboardNumberOfKeys() const override;
void setPianoKeyboardNumberOfKeys(int number) override;

muse::ValCh<bool> midiUseWrittenPitch() const override;
void setMidiUseWrittenPitch(bool useWrittenPitch) override;

bool useNewPercussionPanel() const override;
void setUseNewPercussionPanel(bool use) override;

Expand Down Expand Up @@ -231,6 +234,7 @@ class NotationConfiguration : public INotationConfiguration, public muse::async:
muse::async::Notification m_isPlayRepeatsChanged;
muse::async::Notification m_isPlayChordSymbolsChanged;
muse::ValCh<int> m_pianoKeyboardNumberOfKeys;
muse::ValCh<bool> m_midiInputUseWrittenPitch;
muse::async::Channel<QColor> m_anchorColorChanged;

int m_styleDialogLastPageIndex = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/notation/internal/notationmidiinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ Note* NotationMidiInput::addNoteToScore(const muse::midi::Event& e)
}
}

mu::engraving::Note* note = sc->addMidiPitch(inputEv.pitch, inputEv.chord);
mu::engraving::Note* note = sc->addMidiPitch(inputEv.pitch, inputEv.chord, configuration()->midiUseWrittenPitch().val);

sc->activeMidiPitches().push_back(inputEv);

Expand Down Expand Up @@ -250,7 +250,7 @@ Note* NotationMidiInput::makeNote(const muse::midi::Event& e)
note->setParent(chord);
note->setStaffIdx(engraving::track2staff(inputState.cr()->track()));

engraving::NoteVal nval = score->noteVal(e.note());
engraving::NoteVal nval = score->noteVal(e.note(), configuration()->midiUseWrittenPitch().val);
note->setNval(nval);

return note;
Expand Down Expand Up @@ -306,7 +306,7 @@ void NotationMidiInput::doRealtimeAdvance()

QTimer::singleShot(100, Qt::PreciseTimer, [this]() {
m_undoStack->prepareChanges();
m_getScore->score()->realtimeAdvance();
m_getScore->score()->realtimeAdvance(configuration()->midiUseWrittenPitch().val);
m_undoStack->commitChanges();
});

Expand Down
3 changes: 3 additions & 0 deletions src/notation/tests/mocks/notationconfigurationmock.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ class NotationConfigurationMock : public INotationConfiguration
MOCK_METHOD(muse::ValCh<int>, pianoKeyboardNumberOfKeys, (), (const, override));
MOCK_METHOD(void, setPianoKeyboardNumberOfKeys, (int), (override));

MOCK_METHOD(muse::ValCh<bool>, midiUseWrittenPitch, (), (const, override));
MOCK_METHOD(void, setMidiUseWrittenPitch, (bool), (override));

MOCK_METHOD(bool, useNewPercussionPanel, (), (const, override));
MOCK_METHOD(void, setUseNewPercussionPanel, (bool), (override));

Expand Down
6 changes: 4 additions & 2 deletions src/notation/view/pianokeyboard/pianokeyboardcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,12 @@ void PianoKeyboardController::updateNotesKeys(const std::vector<const Note*>& re
m_keyStatesChanged.notify();
};

const bool useWrittenPitch = notationConfiguration()->midiUseWrittenPitch().val;

for (const mu::engraving::Note* note : receivedNotes) {
newKeys.insert(static_cast<piano_key_t>(note->epitch()));
newKeys.insert(static_cast<piano_key_t>(useWrittenPitch ? note->epitch() : note->ppitch()));
for (const mu::engraving::Note* otherNote : note->chord()->notes()) {
newOtherNotesInChord.insert(static_cast<piano_key_t>(otherNote->epitch()));
newOtherNotesInChord.insert(static_cast<piano_key_t>(useWrittenPitch ? otherNote->epitch() : otherNote->ppitch()));
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/notation/view/pianokeyboard/pianokeyboardcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@

#include "modularity/ioc.h"
#include "context/iglobalcontext.h"
#include "inotationconfiguration.h"

#include "pianokeyboardtypes.h"

namespace mu::notation {
class PianoKeyboardController : public muse::Injectable, public muse::async::Asyncable
{
muse::Inject<INotationConfiguration> notationConfiguration = { this };
muse::Inject<context::IGlobalContext> context = { this };

public:
Expand Down
13 changes: 13 additions & 0 deletions src/playback/internal/playbackcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ static const ActionCode LOOP_IN_CODE("loop-in");
static const ActionCode LOOP_OUT_CODE("loop-out");
static const ActionCode METRONOME_CODE("metronome");
static const ActionCode MIDI_ON_CODE("midi-on");
static const ActionCode INPUT_WRITTEN_PITCH("midi-input-written-pitch");
static const ActionCode INPUT_SOUNDING_PITCH("midi-input-sounding-pitch");
static const ActionCode COUNT_IN_CODE("countin");
static const ActionCode PAN_CODE("pan");
static const ActionCode REPEAT_CODE("repeat");
Expand Down Expand Up @@ -107,6 +109,8 @@ void PlaybackController::init()
dispatcher()->reg(this, PAN_CODE, this, &PlaybackController::toggleAutomaticallyPan);
dispatcher()->reg(this, METRONOME_CODE, this, &PlaybackController::toggleMetronome);
dispatcher()->reg(this, MIDI_ON_CODE, this, &PlaybackController::toggleMidiInput);
dispatcher()->reg(this, INPUT_WRITTEN_PITCH, [this]() { PlaybackController::setMidiUseWrittenPitch(true); });
dispatcher()->reg(this, INPUT_SOUNDING_PITCH, [this]() { PlaybackController::setMidiUseWrittenPitch(false); });
dispatcher()->reg(this, COUNT_IN_CODE, this, &PlaybackController::toggleCountIn);
dispatcher()->reg(this, PLAYBACK_SETUP, this, &PlaybackController::openPlaybackSetupDialog);

Expand Down Expand Up @@ -728,6 +732,13 @@ void PlaybackController::toggleMidiInput()
notifyActionCheckedChanged(MIDI_ON_CODE);
}

void PlaybackController::setMidiUseWrittenPitch(bool useWrittenPitch)
{
notationConfiguration()->setMidiUseWrittenPitch(useWrittenPitch);
notifyActionCheckedChanged(INPUT_WRITTEN_PITCH);
notifyActionCheckedChanged(INPUT_SOUNDING_PITCH);
}

void PlaybackController::toggleCountIn()
{
bool countInEnabled = notationConfiguration()->isCountInEnabled();
Expand Down Expand Up @@ -1401,6 +1412,8 @@ bool PlaybackController::actionChecked(const ActionCode& actionCode) const
QMap<std::string, bool> isChecked {
{ LOOP_CODE, isLoopEnabled() },
{ MIDI_ON_CODE, notationConfiguration()->isMidiInputEnabled() },
{ INPUT_WRITTEN_PITCH, notationConfiguration()->midiUseWrittenPitch().val },
{ INPUT_SOUNDING_PITCH, !notationConfiguration()->midiUseWrittenPitch().val },
{ REPEAT_CODE, notationConfiguration()->isPlayRepeatsEnabled() },
{ PLAY_CHORD_SYMBOLS_CODE, notationConfiguration()->isPlayChordSymbolsEnabled() },
{ PAN_CODE, notationConfiguration()->isAutomaticallyPanEnabled() },
Expand Down
1 change: 1 addition & 0 deletions src/playback/internal/playbackcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ class PlaybackController : public IPlaybackController, public muse::actions::Act
void toggleAutomaticallyPan();
void toggleMetronome();
void toggleMidiInput();
void setMidiUseWrittenPitch(bool useWrittenPitch);
void toggleCountIn();
void toggleLoopPlayback();

Expand Down
36 changes: 35 additions & 1 deletion src/playback/internal/playbackuiactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const UiActionList PlaybackUiActions::m_mainActions = {
)
};

const UiActionList PlaybackUiActions::m_settingsActions = {
const UiActionList PlaybackUiActions::m_midiInputActions = {
UiAction("midi-on",
mu::context::UiCtxAny,
mu::context::CTX_ANY,
Expand All @@ -87,6 +87,28 @@ const UiActionList PlaybackUiActions::m_settingsActions = {
IconCode::Code::MIDI_INPUT,
Checkable::Yes
),
};

const UiActionList PlaybackUiActions::m_midiInputPitchActions = {
UiAction("midi-input-written-pitch",
mu::context::UiCtxAny,
mu::context::CTX_ANY,
TranslatableString("action", "Written pitch"),
TranslatableString("action", "Input written pitch"),
IconCode::Code::NONE,
Checkable::Yes
),
UiAction("midi-input-sounding-pitch",
mu::context::UiCtxAny,
mu::context::CTX_ANY,
TranslatableString("action", "Sounding pitch"),
TranslatableString("action", "Input sounding pitch"),
IconCode::Code::NONE,
Checkable::Yes
),
};

const UiActionList PlaybackUiActions::m_settingsActions = {
UiAction("repeat",
mu::context::UiCtxAny,
mu::context::CTX_NOTATION_FOCUSED,
Expand Down Expand Up @@ -165,6 +187,8 @@ const UiActionList& PlaybackUiActions::actionsList() const
static UiActionList alist;
if (alist.empty()) {
alist.insert(alist.end(), m_mainActions.cbegin(), m_mainActions.cend());
alist.insert(alist.end(), m_midiInputActions.cbegin(), m_midiInputActions.cend());
alist.insert(alist.end(), m_midiInputPitchActions.cbegin(), m_midiInputPitchActions.cend());
alist.insert(alist.end(), m_settingsActions.cbegin(), m_settingsActions.cend());
alist.insert(alist.end(), m_loopBoundaryActions.cbegin(), m_loopBoundaryActions.cend());
}
Expand Down Expand Up @@ -199,6 +223,16 @@ muse::async::Channel<ActionCodeList> PlaybackUiActions::actionCheckedChanged() c
return m_actionCheckedChanged;
}

const UiActionList& PlaybackUiActions::midiInputActions()
{
return m_midiInputActions;
}

const UiActionList& PlaybackUiActions::midiInputPitchActions()
{
return m_midiInputPitchActions;
}

const UiActionList& PlaybackUiActions::settingsActions()
{
return m_settingsActions;
Expand Down
4 changes: 4 additions & 0 deletions src/playback/internal/playbackuiactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ class PlaybackUiActions : public muse::ui::IUiActionsModule, public muse::async:
bool actionChecked(const muse::ui::UiAction& act) const override;
muse::async::Channel<muse::actions::ActionCodeList> actionCheckedChanged() const override;

static const muse::ui::UiActionList& midiInputActions();
static const muse::ui::UiActionList& midiInputPitchActions();
static const muse::ui::UiActionList& settingsActions();
static const muse::ui::UiActionList& loopBoundaryActions();

static const muse::ui::ToolConfig& defaultPlaybackToolConfig();

private:
static const muse::ui::UiActionList m_mainActions;
static const muse::ui::UiActionList m_midiInputActions;
static const muse::ui::UiActionList m_midiInputPitchActions;
static const muse::ui::UiActionList m_settingsActions;
static const muse::ui::UiActionList m_loopBoundaryActions;

Expand Down
23 changes: 23 additions & 0 deletions src/playback/view/playbacktoolbarmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ void PlaybackToolBarModel::updateActions()
MenuItemList result;
MenuItemList settingsItems;

for (const UiAction& action : PlaybackUiActions::midiInputActions()) {
settingsItems << makeMenuItem(action.code);
}

settingsItems << makeInputPitchMenu();
settingsItems << makeSeparator();

for (const UiAction& action : PlaybackUiActions::settingsActions()) {
settingsItems << makeMenuItem(action.code);
}
Expand Down Expand Up @@ -131,6 +138,22 @@ void PlaybackToolBarModel::updateActions()
setItems(result);
}

MenuItem* PlaybackToolBarModel::makeInputPitchMenu()
{
MenuItemList items;

for (const UiAction& action : PlaybackUiActions::midiInputPitchActions()) {
items << makeMenuItem(action.code);
}

MenuItem* menu = makeMenu(muse::TranslatableString("notation", "Input pitch"), items);
UiAction action = menu->action();
action.iconCode = IconCode::Code::MUSIC_NOTES;
menu->setAction(action);

return menu;
}

void PlaybackToolBarModel::onActionsStateChanges(const ActionCodeList& codes)
{
AbstractMenuModel::onActionsStateChanges(codes);
Expand Down
Loading

0 comments on commit 4662ac8

Please sign in to comment.