948 lines
31 KiB
C++
948 lines
31 KiB
C++
/*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
* MuseScore-CLA-applies
|
|
*
|
|
* MuseScore
|
|
* Music Composition & Notation
|
|
*
|
|
* Copyright (C) 2021 MuseScore BVBA and others
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "notationbraille.h"
|
|
|
|
#include "translation.h"
|
|
|
|
#include "engraving/dom/factory.h"
|
|
#include "engraving/dom/measure.h"
|
|
#include "engraving/dom/segment.h"
|
|
#include "engraving/dom/slur.h"
|
|
#include "engraving/dom/spanner.h"
|
|
#include "engraving/dom/staff.h"
|
|
#include "engraving/dom/tie.h"
|
|
|
|
#include "braille.h"
|
|
#include "braillecode.h"
|
|
#include "brailleinput.h"
|
|
#include "brailleinputparser.h"
|
|
#include "louis.h"
|
|
|
|
using namespace mu::braille;
|
|
using namespace mu::io;
|
|
using namespace mu::notation;
|
|
|
|
namespace mu::engraving {
|
|
void NotationBraille::init()
|
|
{
|
|
setEnabled(brailleConfiguration()->braillePanelEnabled());
|
|
setCurrentItemPosition(-1, -1);
|
|
|
|
setMode(BrailleMode::Navigation);
|
|
|
|
path_t tablesdir = tablesDefaultDirPath();
|
|
setTablesDir(tablesdir.toStdString().c_str());
|
|
initTables(tablesdir.toStdString());
|
|
|
|
std::string welcome = braille_translate(table_for_literature.c_str(), "Welcome to MuseScore 4!");
|
|
setBrailleInfo(QString(welcome.c_str()));
|
|
|
|
brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() {
|
|
bool enabled = brailleConfiguration()->braillePanelEnabled();
|
|
setEnabled(enabled);
|
|
});
|
|
|
|
updateTableForLyricsFromPreferences();
|
|
brailleConfiguration()->brailleTableChanged().onNotify(this, [this]() {
|
|
updateTableForLyricsFromPreferences();
|
|
});
|
|
|
|
setIntervalDirection(brailleConfiguration()->intervalDirection());
|
|
brailleConfiguration()->intervalDirectionChanged().onNotify(this, [this]() {
|
|
BrailleIntervalDirection direction = brailleConfiguration()->intervalDirection();
|
|
setIntervalDirection(direction);
|
|
});
|
|
|
|
globalContext()->currentNotationChanged().onNotify(this, [this]() {
|
|
if (notation()) {
|
|
notation()->interaction()->selectionChanged().onNotify(this, [this]() {
|
|
doBraille();
|
|
});
|
|
|
|
notation()->notationChanged().onNotify(this, [this]() {
|
|
setCurrentItemPosition(0, 0);
|
|
doBraille(true);
|
|
});
|
|
|
|
notation()->interaction()->noteInput()->stateChanged().onNotify(this, [this]() {
|
|
if (interaction()->noteInput()->isNoteInputMode()) {
|
|
if (isNavigationMode()) {
|
|
setMode(BrailleMode::BrailleInput);
|
|
}
|
|
} else {
|
|
if (isBrailleInputMode()) {
|
|
setMode(BrailleMode::Navigation);
|
|
}
|
|
}
|
|
});
|
|
|
|
notation()->interaction()->noteInput()->noteAdded().onNotify(this, [this]() {
|
|
if (currentEngravingItem() && currentEngravingItem()->isNote()) {
|
|
LOGD() << "Note added: " << currentEngravingItem()->accessibleInfo();
|
|
Note* note = toNote(currentEngravingItem());
|
|
brailleInput()->setOctave(note->octave());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
void NotationBraille::updateTableForLyricsFromPreferences()
|
|
{
|
|
QString table = brailleConfiguration()->brailleTable();
|
|
int startPos = table.indexOf('[');
|
|
int endPos = table.indexOf(']');
|
|
if (startPos != -1 && endPos != -1) {
|
|
table = table.mid(startPos + 1, endPos - startPos - 1);
|
|
QString table_full_path = QString::fromStdString(tables_dir) + "/" + table;
|
|
if (check_tables(table_full_path.toStdString().c_str()) == 0) {
|
|
updateTableForLyrics(table.toStdString());
|
|
} else {
|
|
LOGD() << "Table check error!";
|
|
}
|
|
}
|
|
}
|
|
|
|
void NotationBraille::doBraille(bool force)
|
|
{
|
|
if (brailleConfiguration()->braillePanelEnabled()) {
|
|
EngravingItem* e = nullptr;
|
|
Measure* m = nullptr;
|
|
|
|
if (selection()->isSingle()) {
|
|
e = selection()->element();
|
|
LOGD() << " selected " << e->accessibleInfo();
|
|
m = e->findMeasure();
|
|
} else if (selection()->isRange()) {
|
|
for (auto el: selection()->elements()) {
|
|
if (el->isMeasure()) {
|
|
m = toMeasure(el);
|
|
break;
|
|
} else {
|
|
m = el->findMeasure();
|
|
if (m) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
e = m ? m : selection()->elements().front();
|
|
} else if (selection()->isList()) {
|
|
e = selection()->elements().front();
|
|
m = e->findMeasure();
|
|
}
|
|
if (e) {
|
|
setCurrentEngravingItem(e, false);
|
|
|
|
if (!m) {
|
|
brailleEngravingItemList()->clear();
|
|
Braille lb(score());
|
|
bool res = lb.convertItem(e, brailleEngravingItemList());
|
|
if (!res) {
|
|
QString txt = e->accessibleInfo();
|
|
std::string braille = braille_long_translate(table_for_literature.c_str(), txt.toStdString());
|
|
brailleEngravingItemList()->setBrailleStr(QString::fromStdString(braille));
|
|
setBrailleInfo(QString::fromStdString(braille));
|
|
} else {
|
|
setBrailleInfo(brailleEngravingItemList()->brailleStr());
|
|
}
|
|
current_measure = nullptr;
|
|
} else {
|
|
if (m != current_measure || force) {
|
|
brailleEngravingItemList()->clear();
|
|
Braille lb(score());
|
|
lb.convertMeasure(m, brailleEngravingItemList());
|
|
setBrailleInfo(brailleEngravingItemList()->brailleStr());
|
|
current_measure = m;
|
|
}
|
|
current_bei = brailleEngravingItemList()->getItem(e);
|
|
if (current_bei != nullptr) {
|
|
setCurrentItemPosition(current_bei->start(), current_bei->end());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mu::engraving::Score* NotationBraille::score()
|
|
{
|
|
return notation()->elements()->msScore()->score();
|
|
}
|
|
|
|
mu::engraving::Selection* NotationBraille::selection()
|
|
{
|
|
return &score()->selection();
|
|
}
|
|
|
|
mu::ValCh<std::string> NotationBraille::brailleInfo() const
|
|
{
|
|
return m_brailleInfo;
|
|
}
|
|
|
|
mu::ValCh<int> NotationBraille::cursorPosition() const
|
|
{
|
|
return m_cursorPosition;
|
|
}
|
|
|
|
mu::ValCh<int> NotationBraille::currentItemPositionStart() const
|
|
{
|
|
return m_currentItemPositionStart;
|
|
}
|
|
|
|
mu::ValCh<int> NotationBraille::currentItemPositionEnd() const
|
|
{
|
|
return m_currentItemPositionEnd;
|
|
}
|
|
|
|
mu::ValCh<std::string> NotationBraille::keys() const
|
|
{
|
|
return m_keys;
|
|
}
|
|
|
|
mu::ValCh<bool> NotationBraille::enabled() const
|
|
{
|
|
return m_enabled;
|
|
}
|
|
|
|
mu::ValCh<BrailleIntervalDirection> NotationBraille::intervalDirection() const
|
|
{
|
|
return m_intervalDirection;
|
|
}
|
|
|
|
mu::ValCh<int> NotationBraille::mode() const
|
|
{
|
|
return m_mode;
|
|
}
|
|
|
|
mu::ValCh<std::string> NotationBraille::cursorColor() const
|
|
{
|
|
return m_cursorColor;
|
|
}
|
|
|
|
void NotationBraille::setEnabled(bool enabled)
|
|
{
|
|
if (enabled == m_enabled.val) {
|
|
return;
|
|
}
|
|
m_enabled.set(enabled);
|
|
}
|
|
|
|
void NotationBraille::setIntervalDirection(const BrailleIntervalDirection direction)
|
|
{
|
|
if (direction == m_intervalDirection.val) {
|
|
return;
|
|
}
|
|
m_intervalDirection.set(direction);
|
|
}
|
|
|
|
BrailleEngravingItemList* NotationBraille::brailleEngravingItemList()
|
|
{
|
|
return &m_beil;
|
|
}
|
|
|
|
QString NotationBraille::getBrailleStr()
|
|
{
|
|
return m_beil.brailleStr();
|
|
}
|
|
|
|
BrailleInputState* NotationBraille::brailleInput()
|
|
{
|
|
return &m_braille_input;
|
|
}
|
|
|
|
void NotationBraille::setBrailleInfo(const QString& info)
|
|
{
|
|
std::string infoStd = info.toStdString();
|
|
|
|
if (m_brailleInfo.val == infoStd) {
|
|
return;
|
|
}
|
|
|
|
m_brailleInfo.set(infoStd);
|
|
}
|
|
|
|
void NotationBraille::setCursorPosition(const int pos)
|
|
{
|
|
if (!isNavigationMode()) {
|
|
return;
|
|
}
|
|
|
|
if (m_cursorPosition.val == pos || pos == 0) {
|
|
return;
|
|
}
|
|
|
|
m_cursorPosition.set(pos);
|
|
|
|
current_bei = brailleEngravingItemList()->getItem(pos);
|
|
if (current_bei != NULL && current_bei->el() != NULL
|
|
&& (current_bei->type() == BEIType::EngravingItem
|
|
|| current_bei->type() == BEIType::LyricItem)) {
|
|
setCurrentEngravingItem(current_bei->el(), true);
|
|
}
|
|
}
|
|
|
|
void NotationBraille::setCurrentItemPosition(const int start, const int end)
|
|
{
|
|
if (m_currentItemPositionStart.val == start
|
|
&& m_currentItemPositionEnd.val == end) {
|
|
return;
|
|
}
|
|
|
|
m_currentItemPositionStart.set(start);
|
|
m_currentItemPositionEnd.set(end);
|
|
}
|
|
|
|
INotationPtr NotationBraille::notation()
|
|
{
|
|
return globalContext()->currentNotation();
|
|
}
|
|
|
|
INotationInteractionPtr NotationBraille::interaction()
|
|
{
|
|
return notation() ? notation()->interaction() : nullptr;
|
|
}
|
|
|
|
DurationType getDuration(const QString key)
|
|
{
|
|
static const DurationType types[] = {
|
|
DurationType::V_64TH, DurationType::V_32ND, DurationType::V_16TH,
|
|
DurationType::V_EIGHTH, DurationType::V_QUARTER, DurationType::V_HALF,
|
|
DurationType::V_WHOLE, DurationType::V_BREVE, DurationType::V_LONG
|
|
};
|
|
bool is_ok = false;
|
|
int val = key.toInt(&is_ok);
|
|
|
|
if (!is_ok || val < 1 || val > 9) {
|
|
return DurationType::V_INVALID;
|
|
} else {
|
|
return types[val - 1];
|
|
}
|
|
}
|
|
|
|
void NotationBraille::setInputNoteDuration(Duration d)
|
|
{
|
|
InputState& inputState = score()->inputState();
|
|
inputState.setDuration(d);
|
|
score()->setInputState(inputState);
|
|
brailleInput()->setCurrentDuration(d.type());
|
|
}
|
|
|
|
void NotationBraille::setTupletDuration(int tuplet, Duration d)
|
|
{
|
|
LOGD() << tuplet << " " << (int)d.type();
|
|
brailleInput()->setCurrentDuration(d.type());
|
|
|
|
switch (tuplet) {
|
|
case 2:
|
|
d = d.shiftRetainDots(-1, false);
|
|
d = d.shiftRetainDots(-1, true);
|
|
break;
|
|
case 3:
|
|
d = d.shiftRetainDots(-1, false);
|
|
break;
|
|
case 5: case 6: case 7:
|
|
d = d.shiftRetainDots(-2, false);
|
|
break;
|
|
case 8:
|
|
d = d.shiftRetainDots(-2, false);
|
|
d = d.shiftRetainDots(-1, true);
|
|
break;
|
|
case 9:
|
|
d = d.shiftRetainDots(-3, false);
|
|
break;
|
|
}
|
|
InputState& inputState = score()->inputState();
|
|
inputState.setDuration(d);
|
|
score()->setInputState(inputState);
|
|
}
|
|
|
|
static TupletOptions makeTupletOption(int num)
|
|
{
|
|
TupletOptions option;
|
|
switch (num) {
|
|
case 2:
|
|
option.ratio = { 2, 3 };
|
|
break;
|
|
case 3:
|
|
option.ratio = { 3, 2 };
|
|
break;
|
|
case 5:
|
|
option.ratio = { 5, 4 };
|
|
break;
|
|
case 6:
|
|
option.ratio = { 6, 4 };
|
|
break;
|
|
case 7:
|
|
option.ratio = { 7, 4 };
|
|
break;
|
|
case 8:
|
|
option.ratio = { 8, 6 };
|
|
break;
|
|
case 9:
|
|
option.ratio = { 9, 8 };
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return option;
|
|
}
|
|
|
|
bool matchPattern(const std::string sequence, const std::string pattern)
|
|
{
|
|
QStringList seqs = QString::fromStdString(sequence).split("+");
|
|
QStringList pats = QString::fromStdString(pattern).split("+");
|
|
|
|
if (seqs.length() != pats.length()) {
|
|
return false;
|
|
}
|
|
seqs.sort();
|
|
pats.sort();
|
|
|
|
for (int i = 0; i < seqs.length(); i++) {
|
|
if (seqs.at(i) != pats.at(i)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void NotationBraille::setKeys(const QString& sequence)
|
|
{
|
|
LOGD() << sequence;
|
|
std::string seq = sequence.toStdString();
|
|
m_keys.set(seq);
|
|
|
|
if (seq == "Left") {
|
|
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::Chord);
|
|
} else if (seq == "Right") {
|
|
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::Chord);
|
|
} else if (matchPattern(seq, "Ctrl+Left")) {
|
|
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::Measure);
|
|
} else if (matchPattern(seq, "Ctrl+Right")) {
|
|
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::Measure);
|
|
} else if (matchPattern(seq, "Alt+Left")) {
|
|
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::EngravingItem);
|
|
} else if (matchPattern(seq, "Alt+Right")) {
|
|
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::EngravingItem);
|
|
} else if (matchPattern(seq, "Ctrl+End")) {
|
|
interaction()->selectLastElement();
|
|
} else if (matchPattern(seq, "Ctrl+Home")) {
|
|
interaction()->selectFirstElement();
|
|
} else if (seq == "Delete") {
|
|
if (currentEngravingItem()) {
|
|
interaction()->deleteSelection();
|
|
if (!brailleInput()->intervals().empty()) {
|
|
brailleInput()->removeLastInterval();
|
|
}
|
|
}
|
|
} else if (seq == "N") {
|
|
toggleMode();
|
|
brailleInput()->initialize();
|
|
} else if (seq == "Plus") {
|
|
if (isBrailleInputMode()) {
|
|
interaction()->noteInput()->doubleNoteInputDuration();
|
|
}
|
|
} else if (seq == "Minus") {
|
|
if (isBrailleInputMode()) {
|
|
interaction()->noteInput()->halveNoteInputDuration();
|
|
}
|
|
} else if (matchPattern(seq, "Space+F") && isBrailleInputMode()) {
|
|
brailleInput()->setNoteGroup(NoteGroup::Group1);
|
|
brailleInput()->resetBuffer();
|
|
} else if (matchPattern(seq, "Space+D") && isBrailleInputMode()) {
|
|
brailleInput()->setNoteGroup(NoteGroup::Group2);
|
|
brailleInput()->resetBuffer();
|
|
} else if (matchPattern(seq, "Space+S") && isBrailleInputMode()) {
|
|
brailleInput()->setNoteGroup(NoteGroup::Group3);
|
|
brailleInput()->resetBuffer();
|
|
} else if (matchPattern(seq, "Space+S+D+J+K") && isBrailleInputMode()) {
|
|
LOGD() << "tuplet input";
|
|
brailleInput()->setTupletIndicator(true);
|
|
brailleInput()->resetBuffer();
|
|
} else if (seq == "Space") {
|
|
brailleInput()->reset();
|
|
} else if (isBrailleInputMode() && !sequence.isEmpty()) {
|
|
QString pattern = parseBrailleKeyInput(sequence);
|
|
if (!pattern.isEmpty()) {
|
|
brailleInput()->insertToBuffer(pattern);
|
|
} else {
|
|
brailleInput()->insertToBuffer(sequence);
|
|
}
|
|
LOGD() << brailleInput()->buffer();
|
|
std::string braille = translate2Braille(brailleInput()->buffer().toStdString());
|
|
BieRecognize(braille, brailleInput()->tupletIndicator());
|
|
|
|
NoteName prevNoteName = NoteName::C;
|
|
int prevNoteOctave = -1; // unknown octave
|
|
|
|
if (Segment* seg = interaction()->noteInput()->state().segment) {
|
|
const track_idx_t track = interaction()->noteInput()->state().currentTrack;
|
|
Chord* prevChord = nullptr;
|
|
|
|
for (Segment* s = seg->prev1(SegmentType::ChordRest); s; s = s->prev1(SegmentType::ChordRest)) {
|
|
EngravingItem* e = s->element(track);
|
|
if (e && e->isChord()) {
|
|
prevChord = toChord(e);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (prevChord) {
|
|
Note* rootNote = (currentIntervalDirection() == IntervalDirection::Up) ? prevChord->downNote() : prevChord->upNote();
|
|
String pitchName;
|
|
String accidental; // needed for tpc2name
|
|
tpc2name(rootNote->tpc(), NoteSpellingType::STANDARD, NoteCaseType::UPPER, pitchName, accidental);
|
|
size_t inote = String("CDEFGAB").indexOf(pitchName.at(0));
|
|
IF_ASSERT_FAILED(inote >= 0 && inote <= 6) {
|
|
} else {
|
|
prevNoteName = static_cast<NoteName>(inote);
|
|
prevNoteOctave = rootNote->octave();
|
|
}
|
|
}
|
|
}
|
|
|
|
brailleInput()->setNoteName(prevNoteName, true);
|
|
brailleInput()->setOctave(prevNoteOctave, true);
|
|
|
|
BieSequencePatternType type = brailleInput()->parseBraille(currentIntervalDirection());
|
|
switch (type) {
|
|
case BieSequencePatternType::Note: {
|
|
LOGD() << "note";
|
|
if (brailleInput()->accidental() != mu::notation::AccidentalType::NONE) {
|
|
interaction()->noteInput()->setAccidental(brailleInput()->accidental());
|
|
}
|
|
|
|
setVoice(brailleInput()->accord());
|
|
|
|
if (brailleInput()->tupletNumber() != -1
|
|
&& brailleInput()->tupletDuration().type() != DurationType::V_INVALID) {
|
|
Duration duration = brailleInput()->tupletDuration();
|
|
int tuplet = brailleInput()->tupletNumber();
|
|
setTupletDuration(tuplet, duration);
|
|
TupletOptions option = makeTupletOption(brailleInput()->tupletNumber());
|
|
interaction()->noteInput()->addTuplet(option);
|
|
brailleInput()->clearTuplet();
|
|
}
|
|
|
|
DurationType d = brailleInput()->getCloseDuration();
|
|
Duration duration = Duration(d);
|
|
setInputNoteDuration(duration);
|
|
|
|
interaction()->noteInput()->addNote(brailleInput()->noteName(), NoteAddingMode::NextChord);
|
|
|
|
if (brailleInput()->addedOctave() != -1) {
|
|
if (brailleInput()->addedOctave() < brailleInput()->octave()) {
|
|
for (int i = brailleInput()->addedOctave(); i < brailleInput()->octave(); i++) {
|
|
interaction()->movePitch(MoveDirection::Down, PitchMode::OCTAVE);
|
|
}
|
|
} else if (brailleInput()->addedOctave() > brailleInput()->octave()) {
|
|
for (int i = brailleInput()->octave(); i < brailleInput()->addedOctave(); i++) {
|
|
interaction()->movePitch(MoveDirection::Up, PitchMode::OCTAVE);
|
|
}
|
|
}
|
|
brailleInput()->setOctave(brailleInput()->addedOctave(), true);
|
|
}
|
|
|
|
if (brailleInput()->longSlurStart()) {
|
|
if (brailleInput()->longSlurStartNote() == NULL) {
|
|
if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
|
|
Note* note = toNote(currentEngravingItem());
|
|
brailleInput()->setLongSlurStartNote(note);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (brailleInput()->tieStartNote() != NULL) {
|
|
addTie();
|
|
brailleInput()->clearTie();
|
|
}
|
|
|
|
if (brailleInput()->slurStartNote() != NULL) {
|
|
addSlur();
|
|
brailleInput()->clearSlur();
|
|
}
|
|
|
|
playbackController()->playElements({ currentEngravingItem() });
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::Rest: {
|
|
LOGD() << "rest";
|
|
DurationType d = brailleInput()->getCloseDuration();
|
|
Duration duration = Duration(d);
|
|
if (brailleInput()->dots() > 0) {
|
|
duration.setDots(brailleInput()->dots());
|
|
}
|
|
setInputNoteDuration(Duration(duration));
|
|
interaction()->putRest(duration);
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::Interval: {
|
|
LOGD() << "interval";
|
|
if (brailleInput()->accidental() != mu::notation::AccidentalType::NONE) {
|
|
interaction()->noteInput()->setAccidental(brailleInput()->accidental());
|
|
}
|
|
interaction()->noteInput()->addNote(brailleInput()->noteName(), NoteAddingMode::CurrentChord);
|
|
|
|
if (brailleInput()->addedOctave() != -1) {
|
|
if (brailleInput()->addedOctave() < brailleInput()->octave()) {
|
|
for (int i = brailleInput()->addedOctave(); i < brailleInput()->octave(); i++) {
|
|
interaction()->movePitch(MoveDirection::Down, PitchMode::OCTAVE);
|
|
}
|
|
} else if (brailleInput()->addedOctave() > brailleInput()->octave()) {
|
|
for (int i = brailleInput()->octave(); i < brailleInput()->addedOctave(); i++) {
|
|
interaction()->movePitch(MoveDirection::Up, PitchMode::OCTAVE);
|
|
}
|
|
}
|
|
brailleInput()->setOctave(brailleInput()->addedOctave());
|
|
}
|
|
playbackController()->playElements({ currentEngravingItem() });
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::Tuplet: case BieSequencePatternType::Tuplet3: {
|
|
LOGD() << "tuplet";
|
|
std::string stateTuplet;
|
|
stateTuplet = "Tuplet " + std::to_string(brailleInput()->tupletNumber());
|
|
auto notationAccessibility = notation()->accessibility();
|
|
if (!notationAccessibility) {
|
|
return;
|
|
}
|
|
notationAccessibility->setTriggeredCommand(stateTuplet);
|
|
break;
|
|
}
|
|
case BieSequencePatternType::Tie: {
|
|
LOGD() << "tie";
|
|
if (brailleInput()->tie()) {
|
|
if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
|
|
Note* note = toNote(currentEngravingItem());
|
|
brailleInput()->setTieStartNote(note);
|
|
}
|
|
}
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::NoteSlur: {
|
|
LOGD() << "note slur";
|
|
if (brailleInput()->noteSlur()) {
|
|
if (brailleInput()->slurStartNote() == NULL) {
|
|
if (currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
|
|
Note* note = toNote(currentEngravingItem());
|
|
brailleInput()->setSlurStartNote(note);
|
|
}
|
|
}
|
|
}
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::LongSlurStop: {
|
|
LOGD() << "long slur stop";
|
|
if (brailleInput()->longSlurStop()) {
|
|
if (brailleInput()->longSlurStartNote() != NULL) {
|
|
addLongSlur();
|
|
brailleInput()->clearLongSlur();
|
|
}
|
|
}
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
case BieSequencePatternType::Dot: {
|
|
LOGD() << "dot " << brailleInput()->dots();
|
|
if (brailleInput()->dots() > 0) {
|
|
interaction()->increaseDecreaseDuration(-brailleInput()->dots(), true);
|
|
}
|
|
brailleInput()->reset();
|
|
break;
|
|
}
|
|
default: {
|
|
// TODO
|
|
}
|
|
}
|
|
} else if (isBrailleInputMode() && !sequence.isEmpty()) {
|
|
QString pattern = parseBrailleKeyInput(sequence);
|
|
if (!pattern.isEmpty()) {
|
|
brailleInput()->insertToBuffer(pattern);
|
|
} else {
|
|
brailleInput()->insertToBuffer(sequence);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool NotationBraille::addTie()
|
|
{
|
|
if (!brailleInput()->tieStartNote()) {
|
|
return false;
|
|
}
|
|
|
|
if (!currentEngravingItem() || !currentEngravingItem()->isNote()) {
|
|
return false;
|
|
}
|
|
|
|
score()->startCmd();
|
|
Note* note = toNote(currentEngravingItem());
|
|
|
|
Tie* tie = Factory::createTie(score()->dummy());
|
|
tie->setStartNote(brailleInput()->tieStartNote());
|
|
tie->setEndNote(note);
|
|
tie->setTrack(brailleInput()->tieStartNote()->track());
|
|
tie->setTick(brailleInput()->tieStartNote()->chord()->segment()->tick());
|
|
tie->setTicks(note->chord()->segment()->tick() - brailleInput()->tieStartNote()->chord()->segment()->tick());
|
|
score()->undoAddElement(tie);
|
|
score()->endCmd();
|
|
return true;
|
|
}
|
|
|
|
bool NotationBraille::addSlur()
|
|
{
|
|
if (brailleInput()->slurStartNote() != NULL
|
|
&& currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
|
|
Note* note1 = brailleInput()->slurStartNote();
|
|
Note* note2 = toNote(currentEngravingItem());
|
|
|
|
if (note1->parent()->isChordRest() && note2->parent()->isChordRest()) {
|
|
LOGD() << "add slur";
|
|
ChordRest* firstChordRest = toChordRest(note1->parent());
|
|
ChordRest* secondChordRest = toChordRest(note2->parent());
|
|
|
|
score()->startCmd();
|
|
|
|
Slur* slur = Factory::createSlur(firstChordRest->measure()->system());
|
|
slur->setScore(firstChordRest->score());
|
|
slur->setTick(firstChordRest->tick());
|
|
slur->setTick2(secondChordRest->tick());
|
|
slur->setTrack(firstChordRest->track());
|
|
if (secondChordRest->staff()->part() == firstChordRest->staff()->part()
|
|
&& !secondChordRest->staff()->isLinked(firstChordRest->staff())) {
|
|
slur->setTrack2(secondChordRest->track());
|
|
} else {
|
|
slur->setTrack2(firstChordRest->track());
|
|
}
|
|
slur->setStartElement(firstChordRest);
|
|
slur->setEndElement(secondChordRest);
|
|
|
|
firstChordRest->score()->undoAddElement(slur);
|
|
SlurSegment* ss = new SlurSegment(firstChordRest->score()->dummy()->system());
|
|
ss->setSpannerSegmentType(SpannerSegmentType::SINGLE);
|
|
if (firstChordRest == secondChordRest) {
|
|
ss->setSlurOffset(Grip::END, PointF(3.0 * firstChordRest->spatium(), 0.0));
|
|
}
|
|
slur->add(ss);
|
|
|
|
score()->endCmd();
|
|
doBraille(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool NotationBraille::addLongSlur()
|
|
{
|
|
if (brailleInput()->longSlurStartNote() != NULL
|
|
&& currentEngravingItem() != NULL && currentEngravingItem()->isNote()) {
|
|
Note* note1 = brailleInput()->longSlurStartNote();
|
|
Note* note2 = toNote(currentEngravingItem());
|
|
|
|
if (note1->parent()->isChordRest() && note2->parent()->isChordRest()) {
|
|
ChordRest* firstChordRest = toChordRest(note1->parent());
|
|
ChordRest* secondChordRest = toChordRest(note2->parent());
|
|
|
|
score()->startCmd();
|
|
|
|
Slur* slur = Factory::createSlur(firstChordRest->measure()->system());
|
|
slur->setScore(firstChordRest->score());
|
|
slur->setTick(firstChordRest->tick());
|
|
slur->setTick2(secondChordRest->tick());
|
|
slur->setTrack(firstChordRest->track());
|
|
if (secondChordRest->staff()->part() == firstChordRest->staff()->part()
|
|
&& !secondChordRest->staff()->isLinked(firstChordRest->staff())) {
|
|
slur->setTrack2(secondChordRest->track());
|
|
} else {
|
|
slur->setTrack2(firstChordRest->track());
|
|
}
|
|
slur->setStartElement(firstChordRest);
|
|
slur->setEndElement(secondChordRest);
|
|
|
|
firstChordRest->score()->undoAddElement(slur);
|
|
SlurSegment* ss = new SlurSegment(firstChordRest->score()->dummy()->system());
|
|
ss->setSpannerSegmentType(SpannerSegmentType::SINGLE);
|
|
if (firstChordRest == secondChordRest) {
|
|
ss->setSlurOffset(Grip::END, PointF(3.0 * firstChordRest->spatium(), 0.0));
|
|
}
|
|
slur->add(ss);
|
|
|
|
score()->endCmd();
|
|
doBraille(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool NotationBraille::setVoice(bool new_voice)
|
|
{
|
|
if (currentEngravingItem() == NULL || currentMeasure() == NULL) {
|
|
return false;
|
|
}
|
|
|
|
staff_idx_t staff = currentEngravingItem()->staffIdx();
|
|
|
|
if (new_voice) {
|
|
int voices = 0;
|
|
for (size_t i = 1; i < VOICES; ++i) {
|
|
if (current_measure->hasVoice(staff * VOICES + i)) {
|
|
voices++;
|
|
}
|
|
}
|
|
if (voices >= 3) {
|
|
return false;
|
|
}
|
|
|
|
score()->inputState().moveInputPos(currentMeasure()->segments().firstCRSegment());
|
|
interaction()->noteInput()->setCurrentVoice(voices + 1);
|
|
return true;
|
|
} else {
|
|
Segment* segment = score()->inputState().segment();
|
|
Measure* measure = segment->measure();
|
|
if (!measure->hasVoice(staff + 1) && segment->tick() == measure->tick()) {
|
|
interaction()->noteInput()->setCurrentVoice(0);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void NotationBraille::setMode(const BrailleMode mode)
|
|
{
|
|
switch (mode) {
|
|
case BrailleMode::Undefined:
|
|
case BrailleMode::Navigation:
|
|
setCursorColor("black");
|
|
break;
|
|
case BrailleMode::BrailleInput:
|
|
setCursorColor("green");
|
|
break;
|
|
}
|
|
|
|
m_mode.set((int)mode);
|
|
}
|
|
|
|
void NotationBraille::toggleMode()
|
|
{
|
|
std::string stateTitle;
|
|
|
|
switch ((BrailleMode)mode().val) {
|
|
case BrailleMode::Undefined:
|
|
case BrailleMode::Navigation:
|
|
setMode(BrailleMode::BrailleInput);
|
|
interaction()->noteInput()->startNoteInput();
|
|
stateTitle = trc("notation", "Note input mode");
|
|
break;
|
|
case BrailleMode::BrailleInput:
|
|
setMode(BrailleMode::Navigation);
|
|
interaction()->noteInput()->endNoteInput();
|
|
stateTitle = trc("notation", "Normal mode");
|
|
break;
|
|
}
|
|
|
|
auto notationAccessibility = notation()->accessibility();
|
|
if (!notationAccessibility) {
|
|
return;
|
|
}
|
|
notationAccessibility->setTriggeredCommand(stateTitle);
|
|
}
|
|
|
|
bool NotationBraille::isNavigationMode()
|
|
{
|
|
return mode().val == (int)BrailleMode::Navigation;
|
|
}
|
|
|
|
bool NotationBraille::isBrailleInputMode()
|
|
{
|
|
return mode().val == (int)BrailleMode::BrailleInput;
|
|
}
|
|
|
|
void NotationBraille::setCursorColor(const QString color)
|
|
{
|
|
m_cursorColor.set(color.toStdString());
|
|
}
|
|
|
|
path_t NotationBraille::tablesDefaultDirPath() const
|
|
{
|
|
return globalConfiguration()->appDataPath() + "tables";
|
|
}
|
|
|
|
void NotationBraille::setCurrentEngravingItem(EngravingItem* e, bool select)
|
|
{
|
|
if (!e) {
|
|
return;
|
|
}
|
|
|
|
bool play = current_engraving_item != e;
|
|
current_engraving_item = e;
|
|
if (isNavigationMode()) {
|
|
if (select) {
|
|
if (play) {
|
|
playbackController()->playElements({ e });
|
|
}
|
|
interaction()->select({ e });
|
|
}
|
|
}
|
|
}
|
|
|
|
IntervalDirection NotationBraille::currentIntervalDirection()
|
|
{
|
|
switch (m_intervalDirection.val) {
|
|
case BrailleIntervalDirection::Up:
|
|
return IntervalDirection::Up;
|
|
case BrailleIntervalDirection::Down:
|
|
return IntervalDirection::Down;
|
|
case BrailleIntervalDirection::Auto:
|
|
break;
|
|
}
|
|
if (EngravingItem* element = currentEngravingItem()) {
|
|
if (Staff* staff = element->staff()) {
|
|
ClefType clef = staff->clef(element->tick());
|
|
if (clef >= ClefType::G && clef <= ClefType::C3) {
|
|
return IntervalDirection::Down;
|
|
}
|
|
return IntervalDirection::Up;
|
|
}
|
|
}
|
|
return IntervalDirection::Down;
|
|
}
|
|
|
|
EngravingItem* NotationBraille::currentEngravingItem()
|
|
{
|
|
return current_engraving_item;
|
|
}
|
|
|
|
Measure* NotationBraille::currentMeasure()
|
|
{
|
|
return current_measure;
|
|
}
|
|
}
|