Implement live braille view

This commit is contained in:
TuanLa1972 2023-06-13 03:15:45 +01:00 committed by Peter Jonas
parent aa6031e275
commit 886995e13c
24 changed files with 2543 additions and 72 deletions

View file

@ -1,23 +1,41 @@
set(MODULE braille)
set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/braillemodule.cpp
${CMAKE_CURRENT_LIST_DIR}/braillemodule.h
${CMAKE_CURRENT_LIST_DIR}/internal/braillewriter.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/braillewriter.h
${CMAKE_CURRENT_LIST_DIR}/internal/braille.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/braille.h
)
set(MODULE_LINK
engraving
)
include(${PROJECT_SOURCE_DIR}/build/module.cmake)
add_subdirectory(tables)
add_subdirectory(thirdparty/liblouis)
if (MUE_BUILD_UNIT_TESTS)
add_subdirectory(tests)
endif()
set(MODULE_QRC ${CMAKE_CURRENT_LIST_DIR}/braille.qrc)
set(MODULE_QML_IMPORT ${CMAKE_CURRENT_LIST_DIR}/qml)
set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/braillemodule.cpp
${CMAKE_CURRENT_LIST_DIR}/braillemodule.h
${CMAKE_CURRENT_LIST_DIR}/ibrailleconfiguration.h
${CMAKE_CURRENT_LIST_DIR}/ibrailleconverter.h
${CMAKE_CURRENT_LIST_DIR}/inotationbraille.h
${CMAKE_CURRENT_LIST_DIR}/internal/brailleconfiguration.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/brailleconfiguration.h
${CMAKE_CURRENT_LIST_DIR}/internal/brailleconverter.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/brailleconverter.h
${CMAKE_CURRENT_LIST_DIR}/internal/braillewriter.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/braillewriter.h
${CMAKE_CURRENT_LIST_DIR}/internal/braille.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/braille.h
${CMAKE_CURRENT_LIST_DIR}/internal/louis.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/louis.h
${CMAKE_CURRENT_LIST_DIR}/internal/notationbraille.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/notationbraille.h
${CMAKE_CURRENT_LIST_DIR}/view/braillemodel.cpp
${CMAKE_CURRENT_LIST_DIR}/view/braillemodel.h
)
set(MODULE_LINK
engraving
liblouis
)
include(${PROJECT_SOURCE_DIR}/build/module.cmake)

6
src/braille/braille.qrc Normal file
View file

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>qml/MuseScore/Braille/qmldir</file>
<file>qml/MuseScore/Braille/BrailleView.qml</file>
</qresource>
</RCC>

View file

@ -21,12 +21,23 @@
*/
#include "braillemodule.h"
#include <QQmlEngine>
#include "modularity/ioc.h"
#include "ui/iuiengine.h"
#include "project/inotationwritersregister.h"
#include "internal/brailleconfiguration.h"
#include "internal/brailleconverter.h"
#include "internal/notationbraille.h"
#include "internal/braillewriter.h"
#include "inotationbraille.h"
#include "view/braillemodel.h"
using namespace mu::engraving;
using namespace mu::notation;
using namespace mu::project;
namespace mu::braille {
@ -42,4 +53,34 @@ void BrailleModule::resolveImports()
writers->reg({ "brf" }, std::make_shared<BrailleWriter>());
}
}
void BrailleModule::registerExports()
{
m_brailleConfiguration = std::make_shared<BrailleConfiguration>();
m_brailleConverter = std::make_shared<BrailleConverter>();
m_notationBraille = std::make_shared<NotationBraille>();
modularity::ioc()->registerExport<IBrailleConfiguration>(moduleName(), m_brailleConfiguration);
modularity::ioc()->registerExport<IBrailleConverter>(moduleName(), m_brailleConverter);
modularity::ioc()->registerExport<INotationBraille>(moduleName(), m_notationBraille);
}
void BrailleModule::registerUiTypes()
{
using namespace notation;
qmlRegisterType<BrailleModel>("MuseScore.Braille", 1, 0, "BrailleModel");
modularity::ioc()->resolve<ui::IUiEngine>(moduleName())->addSourceImportPath(braille_QML_IMPORT);
}
void BrailleModule::onInit(const framework::IApplication::RunMode& mode)
{
if (framework::IApplication::RunMode::GuiApp != mode) {
return;
}
m_brailleConfiguration->init();
m_notationBraille->init();
}
}

View file

@ -24,12 +24,26 @@
#include "modularity/imodulesetup.h"
namespace mu::engraving {
class NotationBraille;
class BrailleConverter;
class BrailleConfiguration;
}
namespace mu::braille {
class BrailleModule : public modularity::IModuleSetup
{
public:
std::string moduleName() const override;
void resolveImports() override;
void registerExports() override;
void registerUiTypes() override;
void onInit(const framework::IApplication::RunMode& mode) override;
private:
std::shared_ptr<engraving::BrailleConfiguration> m_brailleConfiguration;
std::shared_ptr<engraving::BrailleConverter> m_brailleConverter;
std::shared_ptr<engraving::NotationBraille> m_notationBraille;
};
}

View file

@ -0,0 +1,48 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_IBRAILLECONFIGURATION_H
#define MU_BRAILLE_IBRAILLECONFIGURATION_H
#include "modularity/imoduleinterface.h"
#include "async/notification.h"
namespace mu::braille {
class IBrailleConfiguration : MODULE_EXPORT_INTERFACE
{
INTERFACE_ID(IBrailleConfiguration)
public:
virtual ~IBrailleConfiguration() = default;
virtual async::Notification braillePanelEnabledChanged() const = 0;
virtual bool braillePanelEnabled() const = 0;
virtual void setBraillePanelEnabled(const bool enabled) = 0;
virtual async::Notification brailleTableChanged() const = 0;
virtual QString brailleTable() const = 0;
virtual void setBrailleTable(const QString table) = 0;
virtual QStringList brailleTableList() = 0;
};
}
#endif // MU_BRAILLE_IBRAILLECONFIGURATION_H

View file

@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2023 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/>.
*/
#ifndef MU_BRAILLE_IBRAILLECONVERTER_H
#define MU_BRAILLE_IBRAILLECONVERTER_H
#include <QIODevice>
#include "modularity/imoduleinterface.h"
namespace mu::engraving {
class Score;
}
namespace mu::braille {
class IBrailleConverter : MODULE_EXPORT_INTERFACE
{
INTERFACE_ID(IBrailleConverter)
public:
virtual ~IBrailleConverter() = default;
virtual bool write(engraving::Score* score, QIODevice& device) = 0;
};
}
#endif // MU_BRAILLE_IBRAILLECONVERTER_H

View file

@ -0,0 +1,53 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_INOTATIONBRAILLE_H
#define MU_BRAILLE_INOTATIONBRAILLE_H
#include "types/retval.h"
#include "modularity/imoduleinterface.h"
namespace mu::braille {
class INotationBraille : MODULE_EXPORT_INTERFACE
{
INTERFACE_ID(INotationBraille)
public:
virtual ~INotationBraille() = default;
virtual ValCh<std::string> brailleInfo() const = 0;
virtual ValCh<int> cursorPosition() const = 0;
virtual ValCh<int> currentItemPositionStart() const = 0;
virtual ValCh<int> currentItemPositionEnd() const = 0;
virtual ValCh<std::string> shortcut() const = 0;
virtual ValCh<bool> enabled() const = 0;
virtual void setEnabled(bool enabled) = 0;
virtual void setCursorPosition(const int pos) = 0;
virtual void setCurrentItemPosition(const int, const int) = 0;
virtual void setShortcut(const QString&) = 0;
};
}
#endif // MU_NOTATION_INOTATIONBRAILLE_H

View file

@ -39,6 +39,7 @@
#include "libmscore/hairpin.h"
#include "libmscore/jump.h"
#include "libmscore/keysig.h"
#include "libmscore/lyrics.h"
#include "libmscore/marker.h"
#include "libmscore/measure.h"
#include "libmscore/mmrest.h"
@ -66,7 +67,12 @@
#include "containers.h"
#include "louis.h"
#include "braille.h"
namespace mu::engraving {
// Max lyrics num
#define MAX_LYRICS_NUM 16
// Table 1. Page 2. Music Braille Code 2015.
#define BRAILLE_EQUALS_METRONOME QString("7")
#define BRAILLE_MUSICAL_HYPEN QString("\"")
@ -310,6 +316,292 @@ namespace mu::engraving {
#define BRAILLE_UP_BOW QString("<'")
#define BRAILLE_LEFT_HAND_PIZZICATO QString("_>")
std::string Braille_UpperNumbers[] = { "245", "1", "12", "14", "145",
"15", "124", "1245", "125", "24" };
std::string Braille_LowerNumbers[] = { "356", "2", "23", "25", "256",
"26", "235", "2356", "236", "35" };
std::string Braille_LyricLineIndicator = "56-23";
std::string Braille_NumIndicator = "3456";
std::string getBraillePattern(std::string dots)
{
const char* dotc = dots.c_str();
int d = atoi(dotc);
switch (d) {
case 0: return " ";
case 1: return "";
case 2: return "";
case 12: return "";
case 3: return "";
case 13: return "";
case 23: return "";
case 123: return "";
case 4: return "";
case 14: return "";
case 24: return "";
case 124: return "";
case 34: return "";
case 134: return "";
case 234: return "";
case 1234: return "";
case 5: return "";
case 15: return "";
case 25: return "";
case 125: return "";
case 35: return "";
case 135: return "";
case 235: return "";
case 1235: return "";
case 45: return "";
case 145: return "";
case 245: return "";
case 1245: return "";
case 345: return "";
case 1345: return "";
case 2345: return "";
case 12345: return "";
case 6: return "";
case 16: return "";
case 26: return "";
case 126: return "";
case 36: return "";
case 136: return "";
case 236: return "";
case 1236: return "";
case 46: return "";
case 146: return "";
case 246: return "";
case 1246: return "";
case 346: return "";
case 1346: return "";
case 2346: return "";
case 12346: return "";
case 56: return "";
case 156: return "";
case 256: return "";
case 1256: return "";
case 356: return "";
case 1356: return "";
case 2356: return "";
case 12356: return "";
case 456: return "";
case 1456: return "";
case 2456: return "";
case 12456: return "";
case 3456: return "";
case 13456: return "";
case 23456: return "";
case 123456: return "";
}
return " ";
}
std::string translate2Braille(std::string codes)
{
std::stringstream test(codes);
std::string segment;
std::vector<std::string> seglist;
std::string txt = "";
while (std::getline(test, segment, '-')) {
txt.append(getBraillePattern(segment));
}
return txt;
}
std::string intToBrailleUpperNumbers(std::string txt, bool indicator)
{
std::string braille = "";
if (indicator) {
braille.append(translate2Braille(Braille_NumIndicator));
}
for (size_t i=0; i < txt.length(); i++) {
char c = txt.at(i);
if (c - '0' <= 9) {
braille.append(translate2Braille(Braille_UpperNumbers[c - '0']));
}
}
return braille;
}
std::string intToBrailleLowerNumbers(std::string txt, bool indicator)
{
std::string braille = "";
if (indicator) {
braille.append(Braille_NumIndicator);
}
for (size_t i=0; i < txt.length(); i++) {
char c = txt.at(i);
if (c - '0' <= 9) {
braille.append(Braille_LowerNumbers[c - '0']);
}
}
return braille;
}
BrailleEngravingItems::BrailleEngravingItems()
{
m_braille_str = QString();
}
BrailleEngravingItems::~BrailleEngravingItems()
{
clear();
}
void BrailleEngravingItems::clear()
{
m_braille_str = QString();
m_items.clear();
}
void BrailleEngravingItems::join(BrailleEngravingItems* another, bool newline, bool del)
{
int len = m_braille_str.length();
if (newline && !m_braille_str.isEmpty()) {
m_braille_str.append("\n");
len++;
}
m_braille_str.append(another->brailleStr());
for (auto item: *another->items()) {
item.second.first += len;
item.second.second += len;
m_items.push_back(item);
}
if (del) {
delete another;
}
}
void BrailleEngravingItems::join(const std::vector<BrailleEngravingItems*>& lst, bool newline, bool del)
{
for (auto item: lst) {
join(item, newline, del);
}
}
QString BrailleEngravingItems::brailleStr()
{
return m_braille_str;
}
std::vector<std::pair<EngravingItem*, std::pair<int, int> > >* BrailleEngravingItems::items()
{
return &m_items;
}
void BrailleEngravingItems::setBrailleStr(const QString& str)
{
m_braille_str = str;
m_items.clear();
}
void BrailleEngravingItems::addPrefixStr(const QString& str)
{
int len = str.length();
m_braille_str = str + m_braille_str;
for (size_t i=0; i < m_items.size(); i++) {
m_items[i].second.first += len;
m_items[i].second.second += len;
}
}
void BrailleEngravingItems::addEngravingItem(EngravingItem* el, const QString& braille)
{
//braille = braille.replace(QRegularExpression ("/\\/"), "\\\\");
//Manual doubling slashes '\' because Regex doesn't work. Don't know why.
QString txt = QString();
for (int i=0; i < braille.length(); i++) {
if (braille.at(i) == '\\') {
txt.append(braille.at(i));
}
txt.append(braille.at(i));
}
QString unitxt = QString::fromStdString(braille_long_translate(table_ascii_to_unicode.c_str(), txt.toStdString()));
int start = m_braille_str.length();
int end = start + unitxt.length();
m_items.push_back({ el, { start, end } });
m_braille_str.append(unitxt);
}
void BrailleEngravingItems::addLyricsItem(Lyrics* l)
{
std::string txt = l->plainText().toStdString();
QString unitxt = QString::fromStdString(braille_long_translate(table_for_literature.c_str(), txt));
switch (l->syllabic()) {
case LyricsSyllabic::SINGLE:
case LyricsSyllabic::BEGIN:
if (!m_braille_str.isEmpty()) {
m_braille_str.append(" ");
}
// fallthrough
case LyricsSyllabic::END:
case LyricsSyllabic::MIDDLE:
int start = m_braille_str.length();
int end = start + unitxt.length();
m_items.push_back({ l, { start, end } });
m_braille_str.append(unitxt);
break;
}
}
mu::engraving::EngravingItem* BrailleEngravingItems::getEngravingItem(int pos)
{
for (size_t i=0; i < m_items.size(); i++) {
if (m_items[i].second.first <= pos && m_items[i].second.second >= pos) {
return m_items[i].first;
}
}
return nullptr;
}
std::pair<int, int> BrailleEngravingItems::getBraillePos(EngravingItem* e)
{
//LOGD() << "getBraillePos " << e << " " << e->accessibleInfo();
for (size_t i=0; i < m_items.size(); i++) {
if (!m_items[i].first) {
continue;
}
//LOGD() << " -" << _items[i].first << " " << _items[i].first->accessibleInfo() << " {" << _items[i].second.first << "," << _items[i].second.second << "}";
if (m_items[i].first == e) {
return m_items[i].second;
}
if (m_items[i].first->elementBase() == e->elementBase()) {
return m_items[i].second;
}
}
//LOGD() << "getBraillePos " << e->accessibleInfo() << " NOT FOUND";
return { -1, -1 };
}
void BrailleEngravingItems::log()
{
LOGD() << brailleStr();
for (size_t i=0; i < m_items.size(); i++) {
if (!m_items[i].first) {
LOGD() << " - null {" << m_items[i].second.first << "," << m_items[i].second.second << "}";
} else {
LOGD() << " -" << m_items[i].first->accessibleInfo() << " {" << m_items[i].second.first << "," << m_items[i].second.second <<
"}";
}
}
}
TextToUEBBraille::TextToUEBBraille()
{
textToBrailleASCII["a"] = 'a';
@ -437,7 +729,7 @@ QString TextToUEBBraille::braille(QChar c)
return QString(c);
}
QString TextToUEBBraille::braille(QString text)
QString TextToUEBBraille::braille(const QString& text)
{
QString buffer, t, p;
QTextStream rez(&buffer), tmp(&t);
@ -487,11 +779,11 @@ QString TextToUEBBraille::braille(QString text)
Braille::Braille(Score* s)
{
score = s;
for (size_t i = 0; i < score->staves().size(); ++i) {
previousNote.push_back(nullptr);
currentCleffType.push_back(ClefType::INVALID);
currentKey.push_back(Key::INVALID);
m_score = s;
for (size_t i = 0; i < m_score->staves().size(); ++i) {
m_context.previousNote.push_back(nullptr);
m_context.currentClefType.push_back(ClefType::INVALID);
m_context.currentKey.push_back(Key::INVALID);
}
}
@ -499,14 +791,15 @@ bool Braille::write(QIODevice& device)
{
credits(device);
instruments(device);
size_t nrStaves = score->staves().size();
size_t nrStaves = m_score->staves().size();
std::vector<QString> measureBraille(nrStaves);
std::vector<QString> line(nrStaves + 1);
std::vector<QString> lyrics(nrStaves + 1);
int currentLineLength = 0;
int currentMeasureMaxLength = 0;
bool measureAboveMax = false;
for (MeasureBase* mb = score->measures()->first(); mb != nullptr; mb = mb->next()) {
for (MeasureBase* mb = m_score->measures()->first(); mb != nullptr; mb = mb->next()) {
if (!mb->isMeasure()) {
continue;
}
@ -525,7 +818,7 @@ bool Braille::write(QIODevice& device)
currentLineLength += measureNumberLen;
}
if (m->hasMMRest() && score->styleB(Sid::createMultiMeasureRests)) {
if (m->hasMMRest() && m_score->styleB(Sid::createMultiMeasureRests)) {
mb = m = m->mmRest();
}
@ -573,7 +866,10 @@ bool Braille::write(QIODevice& device)
QTextStream out(&device);
for (size_t i = 0; i < nrStaves; ++i) {
out << line[i].toUtf8() << Qt::endl;
line[i] = QString();
if (!lyrics[i].isEmpty()) {
out << lyrics[i].toUtf8() << Qt::endl;
}
line[i] = lyrics[i] = QString();
}
currentLineLength = 0;
// 3.2.1. Page 53. Music Braille Code 2015.
@ -598,14 +894,74 @@ bool Braille::write(QIODevice& device)
return true;
}
bool Braille::convertMeasure(Measure* measure, BrailleEngravingItems* beiz)
{
size_t nrStaves = m_score->staves().size();
std::vector<BrailleEngravingItems> measureBraille(nrStaves);
std::vector<BrailleEngravingItems> lyrics(nrStaves + 1);
/*
for (MeasureBase* mb = m_score->measures()->first(); mb != nullptr; mb = mb->next()) {
if (!mb->isMeasure() || mb != measure ) {
continue;
}
Measure* m = toMeasure(mb);
if (m->hasMMRest() && m_score->styleB(Sid::createMultiMeasureRests)) {
mb = m = m->mmRest();
}
for (size_t i = 0; i < nrStaves; ++i) {
BrailleEngravingItems measureBraille;
BrailleEngravingItems measureLyrics;
brailleMeasureItems(&measureBraille, m, static_cast<int>(i));
measureBraille.log();
beiz->join(&measureBraille, true, false);
brailleMeasureLyrics(&measureLyrics, m, static_cast<int>(i));
if(!measureLyrics.isEmpty()) {
beiz->join(&measureLyrics, true, false);
}
}
}
*/
if (measure->hasMMRest() && m_score->styleB(Sid::createMultiMeasureRests)) {
measure = measure->mmRest();
}
for (size_t i = 0; i < nrStaves; ++i) {
BrailleEngravingItems measureBraille;
BrailleEngravingItems measureLyrics;
brailleMeasureItems(&measureBraille, measure, static_cast<int>(i));
measureBraille.log();
beiz->join(&measureBraille, true, false);
brailleMeasureLyrics(&measureLyrics, measure, static_cast<int>(i));
if (!measureLyrics.isEmpty()) {
beiz->join(&measureLyrics, true, false);
}
}
return true;
}
bool Braille::convertItem(EngravingItem* el, BrailleEngravingItems* bei)
{
return brailleSingleItem(bei, el);
}
void Braille::resetOctave(size_t stave)
{
previousNote[stave] = nullptr;
m_context.previousNote[stave] = nullptr;
}
void Braille::resetOctaves()
{
for (size_t i = 0; i < score->staves().size(); ++i) {
for (size_t i = 0; i < m_score->staves().size(); ++i) {
resetOctave(i);
}
}
@ -614,7 +970,7 @@ void Braille::credits(QIODevice& device)
{
QTextStream out(&device);
// find the vboxes in every page and write their elements as credit-words
for (const auto page : score->pages()) {
for (const auto page : m_score->pages()) {
for (const auto system : page->systems()) {
for (const auto mb : system->measures()) {
if (mb->isVBox()) {
@ -632,14 +988,14 @@ void Braille::credits(QIODevice& device)
QStringList creators;
// the creator types commonly found in MusicXML
creators << "arranger" << "composer" << "lyricist" << "poet" << "translator";
for (QString type : creators) {
QString creator = score->metaTag(type);
for (const QString& type : creators) {
QString creator = m_score->metaTag(type);
if (!creator.isEmpty()) {
out << TextToUEBBraille().braille(QString("%1 %2").arg(type).arg(creator)).toUtf8() << Qt::endl;
}
}
if (!score->metaTag(u"copyright").isEmpty()) {
out << TextToUEBBraille().braille(QString("© %2").arg(score->metaTag(u"copyright"))).toUtf8() << Qt::endl;
if (!m_score->metaTag(u"copyright").isEmpty()) {
out << TextToUEBBraille().braille(QString("© %2").arg(m_score->metaTag(u"copyright"))).toUtf8() << Qt::endl;
}
out << Qt::endl;
out.flush();
@ -649,8 +1005,8 @@ void Braille::instruments(QIODevice& device)
{
//Print staff number to instrument mapping.
QTextStream out(&device);
for (size_t i = 0; i < score->staves().size(); ++i) {
out << TextToUEBBraille().braille(QString("%1 %2").arg(i + 1).arg(score->staves()[i]->part()->instrumentName())) << Qt::endl;
for (size_t i = 0; i < m_score->staves().size(); ++i) {
out << TextToUEBBraille().braille(QString("%1 %2").arg(i + 1).arg(m_score->staves()[i]->part()->instrumentName())) << Qt::endl;
}
out << Qt::endl;
out.flush();
@ -694,7 +1050,7 @@ int Braille::computeInterval(Note* note1, Note* note2, bool ignoreOctave)
std::vector<Slur*> Braille::slurs(ChordRest* chordRest)
{
std::vector<Slur*> result;
SpannerMap& smap = score->spannerMap();
SpannerMap& smap = m_score->spannerMap();
auto spanners = smap.findOverlapping(chordRest->tick().ticks(), chordRest->tick().ticks());
for (auto interval : spanners) {
Spanner* spanner = interval.value;
@ -711,7 +1067,7 @@ std::vector<Slur*> Braille::slurs(ChordRest* chordRest)
std::vector<Hairpin*> Braille::hairpins(ChordRest* chordRest)
{
std::vector<Hairpin*> result;
SpannerMap& smap = score->spannerMap();
SpannerMap& smap = m_score->spannerMap();
auto spanners = smap.findOverlapping(chordRest->tick().ticks(), chordRest->tick().ticks());
for (auto interval : spanners) {
Spanner* spanner = interval.value;
@ -900,6 +1256,225 @@ BarLine* Braille::lastBarline(Measure* measure, track_idx_t track)
return nullptr;
}
bool Braille::brailleSingleItem(BrailleEngravingItems* beiz, EngravingItem* el)
{
resetOctaves();
if (el->isMarker()) {
beiz->addEngravingItem(el, brailleMarker(toMarker(el)));
return true;
} else if (el->isJump()) {
beiz->addEngravingItem(el, brailleJump(toJump(el)));
return true;
} else if (el->isDynamic()) {
beiz->addEngravingItem(el, brailleDynamic(toDynamic(el)));
return true;
} else if (el->isClef()) {
beiz->addEngravingItem(el, brailleClef(toClef(el)));
return true;
} else if (el->isKeySig()) {
beiz->addEngravingItem(el, brailleKeySig(toKeySig(el)));
return true;
} else if (el->isTimeSig()) {
beiz->addEngravingItem(el, brailleTimeSig(toTimeSig(el)));
return true;
} else if (el->isMMRest()) {
beiz->addEngravingItem(el, brailleMMRest(toMMRest(el)));
return true;
} else if (el->isRest()) {
beiz->addEngravingItem(el, brailleRest(toRest(el)));
return true;
} else if (el->isChord()) {
beiz->addEngravingItem(el, brailleChord(toChord(el)));
return true;
} else if (el->isBreath()) {
beiz->addEngravingItem(el, brailleBreath(toBreath(el)));
return true;
} else if (el->isBarLine()) {
beiz->addEngravingItem(el, brailleBarline(toBarLine(el)));
return true;
} else if (el->isMeasureRepeat()) {
beiz->addEngravingItem(el, brailleMeasureRepeat(toMeasureRepeat(el)));
return true;
} else if (el->isBreath()) {
beiz->addEngravingItem(el, brailleBreath(toBreath(el)));
return true;
} else if (el->isLyrics()) {
beiz->addEngravingItem(el, brailleLyrics(toLyrics(el)));
return true;
} else if (el->isNote()) {
Note* note = toNote(el);
beiz->addEngravingItem(el, brailleChordRootNote(note->chord(), note));
return true;
}
return false;
}
void Braille::brailleMeasureItems(BrailleEngravingItems* beiz, Measure* measure, int staffCount)
{
//QTextStream out(&rez);
//LOGD("Braille::brailleMeasure %d", staffCount);
//Render all repeats and jumps that are on the left
for (EngravingItem* el : measure->el()) {
if (el->isMarker()) {
Marker* marker = toMarker(el);
if (marker->textStyleType() == TextStyleType::REPEAT_LEFT) {
beiz->addEngravingItem(el, brailleMarker(toMarker(el)));
}
}
if (el->isJump()) {
Jump* jump = toJump(el);
if (jump->textStyleType() == TextStyleType::REPEAT_LEFT) {
beiz->addEngravingItem(el, brailleJump(toJump(el)));
}
}
}
auto spanners = m_score->spannerMap().findOverlapping(measure->tick().ticks(), measure->endTick().ticks());
for (auto interval : spanners) {
Spanner* s = interval.value;
if (s && s->isVolta()) {
beiz->addEngravingItem(s, brailleVolta(measure, toVolta(s), staffCount));
}
}
//Render everything that is in Voice 1
for (auto seg = measure->first(); seg; seg = seg->next()) {
for (EngravingItem* annotation : seg->annotations()) {
if (annotation->isTempoText()) {
beiz->addEngravingItem(annotation, brailleTempoText(toTempoText(annotation), staffCount));
}
if (annotation->track() == staffCount * VOICES) {
if (annotation->isDynamic()) {
beiz->addEngravingItem(annotation, brailleDynamic(toDynamic(annotation)));
}
}
}
EngravingItem* el = seg->element(staffCount * VOICES);
if (!el) {
continue;
}
if (el->isClef()) {
beiz->addEngravingItem(el, brailleClef(toClef(el)));
} else if (el->isKeySig()) {
beiz->addEngravingItem(el, brailleKeySig(toKeySig(el)));
} else if (el->isTimeSig()) {
beiz->addEngravingItem(el, brailleTimeSig(toTimeSig(el)));
} else if (el->isMMRest()) {
beiz->addEngravingItem(el, brailleMMRest(toMMRest(el)));
} else if (el->isRest()) {
beiz->addEngravingItem(el, brailleRest(toRest(el)));
} else if (el->isChord()) {
beiz->addEngravingItem(el, brailleChord(toChord(el)));
} else if (el->isBreath()) {
beiz->addEngravingItem(el, brailleBreath(toBreath(el)));
} else if (el->isBarLine() && toBarLine(el) != lastBarline(measure, el->track())) {
beiz->addEngravingItem(el, brailleBarline(toBarLine(el)));
} else if (el->isMeasureRepeat()) {
beiz->addEngravingItem(el, brailleMeasureRepeat(toMeasureRepeat(el)));
}
}
// Render the rest of the voices
for (size_t i = 1; i < VOICES; ++i) {
if (measure->hasVoice(staffCount * VOICES + i)) {
// 11.1.1. Page 87. Music Braille Code 2015.
// All voices must be complete when writing the other voices in Braille.
// We exchange the voices to voice 0 and back for MuseScore to add the missing beats as rests
// Then we undo the change, so we don't have an altered score.
// TODO: Braille dot 5 should be put before the rests that appear in Braille, but are not originally in the score
/*
m_score->deselectAll();
m_score->select(measure, SelectType::RANGE, staffCount);
m_score->update();
m_score->startCmd();
m_score->cmdExchangeVoice(0, static_cast<int>(i));
m_score->endCmd();
m_score->startCmd();
m_score->cmdExchangeVoice(0, static_cast<int>(i));
m_score->endCmd();
*/
resetOctave(staffCount);
beiz->addEngravingItem(nullptr, BRAILLE_FULL_MEASURE_IN_ACORD);
for (auto seg = measure->first(); seg; seg = seg->next()) {
EngravingItem* el = seg->element(staffCount * VOICES + i);
if (!el) {
continue;
}
if (el->isRest()) {
beiz->addEngravingItem(el, brailleRest(toRest(el)));
}
if (el->isChord()) {
beiz->addEngravingItem(el, brailleChord(toChord(el)));
}
if (el->isBreath()) {
beiz->addEngravingItem(el, brailleBreath(toBreath(el)));
}
}
resetOctave(staffCount);
// Undo filling the missing beats with rests, so we don't have an altered score.
// m_score->undoRedo(true, nullptr);
// m_score->undoRedo(true, nullptr);
// m_score->deselectAll();
}
}
//Render the barline
BarLine* bl = lastBarline(measure, staffCount * VOICES);
beiz->addEngravingItem(bl, brailleBarline(bl));
//Render repeats and jumps that are on the right
for (EngravingItem* el : measure->el()) {
if (el->isMarker()) {
Marker* marker = toMarker(el);
if (marker->textStyleType() == TextStyleType::REPEAT_RIGHT) {
beiz->addEngravingItem(el, brailleMarker(toMarker(el)));
}
}
if (el->isJump()) {
Jump* jump = toJump(el);
if (jump->textStyleType() == TextStyleType::REPEAT_RIGHT) {
beiz->addEngravingItem(el, brailleJump(toJump(el)));
}
}
}
}
void Braille::brailleMeasureLyrics(BrailleEngravingItems* beiz, Measure* measure, int staffCount)
{
BrailleEngravingItems lyrics[MAX_LYRICS_NUM];
for (auto seg = measure->first(); seg; seg = seg->next()) {
if (!seg->isChordRestType()) {
continue;
}
for (voice_idx_t voice = 0; voice < VOICES; ++voice) {
if (measure->hasVoice(staffCount * VOICES + voice)) {
ChordRest* cr = seg->cr(staffCount * VOICES + voice);
if (cr && !cr->lyrics().empty()) {
for (Lyrics* l : cr->lyrics()) {
int no = l->no();
lyrics[no].addLyricsItem(l);
}
}
}
}
}
for (int i=0; i < MAX_LYRICS_NUM; i++) {
if (lyrics[i].isEmpty()) {
lyrics[i].clear();
} else {
lyrics[i].addPrefixStr(QString::fromStdString(translate2Braille(Braille_LyricLineIndicator)));
beiz->join(&lyrics[i], true, false);
}
}
}
QString Braille::brailleAccidentalType(AccidentalType accidental)
{
switch (accidental) {
@ -1216,7 +1791,7 @@ QString Braille::brailleChord(Chord* chord)
// In Treble, Soprano, Alto clefs: Write the upper most note, then rest of notes as intervals downward
// In Tenor, Baritone, Bass clefs: Write the lower most note, then rest of notes as intervals upward
std::vector<Note*> notes;
if (ascendingChords(currentCleffType[chord->staffIdx()])) {
if (ascendingChords(m_context.currentClefType[chord->staffIdx()])) {
for (auto it = chord->notes().begin(); it != chord->notes().end(); ++it) {
notes.push_back(*it);
}
@ -1374,7 +1949,7 @@ QString Braille::brailleChordRootNote(Chord* chord, Note* rootNote)
int octave = rootNote->octave();
// 3.2.1. Page 53. Music Braille Code 2015.
// Octave signs at the beginning of the line or when the melodic line is interrupted by specific elements
if (!this->previousNote[chord->staffIdx()]) {
if (!this->m_context.previousNote[chord->staffIdx()]) {
octaveBraille = brailleOctave(octave);
}
// 3.2.2. Octave signs in a melodic progression. Page 53. Music Braille Code 2015.
@ -1382,12 +1957,12 @@ QString Braille::brailleChordRootNote(Chord* chord, Note* rootNote)
// b. the octave is always marked in a skip greater than a fifth
// c. the octave is only marked in a skip of a fourth or fifth when the second note is in a different octave from the first.
else {
int interval = computeInterval(previousNote[chord->staffIdx()], rootNote, false);
if (interval > 5 || (interval > 3 && (previousNote[chord->staffIdx()]->octave() != rootNote->octave()))) {
int interval = computeInterval(m_context.previousNote[chord->staffIdx()], rootNote, false);
if (interval > 5 || (interval > 3 && (m_context.previousNote[chord->staffIdx()]->octave() != rootNote->octave()))) {
octaveBraille = brailleOctave(octave);
}
}
previousNote[chord->staffIdx()] = rootNote;
m_context.previousNote[chord->staffIdx()] = rootNote;
QString accidentalBraille = QString();
if (rootNote->accidental()) {
@ -1414,11 +1989,11 @@ QString Braille::brailleChordRootNote(Chord* chord, Note* rootNote)
QString Braille::brailleClef(Clef* clef)
{
//In Braille, the clef is printed only at it's first appearance.
if (currentCleffType[clef->staffIdx()] == clef->clefType()) {
if (m_context.currentClefType[clef->staffIdx()] == clef->clefType()) {
return QString();
}
currentCleffType[clef->staffIdx()] = clef->clefType();
m_context.currentClefType[clef->staffIdx()] = clef->clefType();
resetOctave(clef->staffIdx());
switch (clef->clefType()) {
@ -1630,11 +2205,11 @@ QString Braille::brailleKeySig(KeySig* keySig)
//In Braille, the key signature is printed only at it's first appearance.
//Paragraf 6.5. Page 61. Music Braille Code 2015.
if (!keySig || keySig->segment()->isKeySigAnnounceType()
|| (currentKey[keySig->staffIdx()] == keySig->key() && !keySig->isCustom())) {
|| (m_context.currentKey[keySig->staffIdx()] == keySig->key() && !keySig->isCustom())) {
return QString();
}
currentKey[keySig->staffIdx()] = keySig->key();
m_context.currentKey[keySig->staffIdx()] = keySig->key();
resetOctave(keySig->staffIdx());
QString brailleKeySig = QString();
@ -1693,6 +2268,12 @@ QString Braille::brailleKeySig(KeySig* keySig)
return brailleKeySig;
}
QString Braille::brailleLyrics(Lyrics* lyrics)
{
std::string txt = lyrics->plainText().toStdString();
return QString::fromStdString(braille_long_translate(table_for_literature.c_str(), txt));
}
QString Braille::brailleMarker(Marker* marker)
{
switch (marker->markerType()) {
@ -1721,6 +2302,7 @@ QString Braille::brailleMeasure(Measure* measure, int staffCount)
QString rez;
QTextStream out(&rez);
//LOGD("Braille::brailleMeasure %d", staffCount);
//Render all repeats and jumps that are on the left
for (EngravingItem* el : measure->el()) {
if (el->isMarker()) {
@ -1737,7 +2319,7 @@ QString Braille::brailleMeasure(Measure* measure, int staffCount)
}
}
auto spanners = score->spannerMap().findOverlapping(measure->tick().ticks(), measure->endTick().ticks());
auto spanners = m_score->spannerMap().findOverlapping(measure->tick().ticks(), measure->endTick().ticks());
for (auto interval : spanners) {
Spanner* s = interval.value;
if (s && s->isVolta()) {
@ -1792,15 +2374,17 @@ QString Braille::brailleMeasure(Measure* measure, int staffCount)
// We exchange the voices to voice 0 and back for MuseScore to add the missing beats as rests
// Then we undo the change, so we don't have an altered score.
// TODO: Braille dot 5 should be put before the rests that appear in Braille, but are not originally in the score
score->deselectAll();
score->select(measure, SelectType::RANGE, staffCount);
score->update();
score->startCmd();
score->cmdExchangeVoice(0, static_cast<int>(i));
score->endCmd();
score->startCmd();
score->cmdExchangeVoice(0, static_cast<int>(i));
score->endCmd();
/* FIXME: may break live braille but be required for export
m_score->deselectAll();
m_score->select(measure, SelectType::RANGE, staffCount);
m_score->update();
m_score->startCmd();
m_score->cmdExchangeVoice(0, static_cast<int>(i));
m_score->endCmd();
m_score->startCmd();
m_score->cmdExchangeVoice(0, static_cast<int>(i));
m_score->endCmd();
*/
resetOctave(staffCount);
out << BRAILLE_FULL_MEASURE_IN_ACORD;
@ -1823,14 +2407,15 @@ QString Braille::brailleMeasure(Measure* measure, int staffCount)
resetOctave(staffCount);
// Undo filling the missing beats with rests, so we don't have an altered score.
score->undoRedo(true, nullptr);
score->undoRedo(true, nullptr);
score->deselectAll();
m_score->undoRedo(true, nullptr);
m_score->undoRedo(true, nullptr);
m_score->deselectAll();
}
}
//Render the barline
out << brailleBarline(lastBarline(measure, staffCount * VOICES));
BarLine* bl = lastBarline(measure, staffCount * VOICES);
out << brailleBarline(bl);
//Render repeats and jumps that are on the right
for (EngravingItem* el : measure->el()) {

View file

@ -37,11 +37,13 @@ class ChordRest;
class Clef;
class DurationElement;
class Dynamic;
class EngravingItem;
class Fermata;
class Fingering;
class Hairpin;
class Jump;
class KeySig;
class Lyrics;
class Marker;
class Measure;
class MeasureRepeat;
@ -55,6 +57,36 @@ class TimeSig;
class Tuplet;
class Volta;
class BrailleEngravingItems
{
public:
BrailleEngravingItems();
~BrailleEngravingItems();
void clear();
void join(BrailleEngravingItems*, bool newline = true, bool del = true);
void join(const std::vector<BrailleEngravingItems*>&, bool newline = true, bool del = true);
QString brailleStr();
std::vector<std::pair<EngravingItem*, std::pair<int, int> > >* items();
void setBrailleStr(const QString& str);
void addPrefixStr(const QString& str);
void addEngravingItem(EngravingItem*, const QString& braille);
void addLyricsItem(Lyrics*);
bool isEmpty() { return m_braille_str.isEmpty(); }
EngravingItem* getEngravingItem(int pos);
std::pair<int, int> getBraillePos(EngravingItem* e);
void log();
private:
QString m_braille_str;
std::vector<std::pair<EngravingItem*, std::pair<int, int> > > m_items;
};
//This class currently supports just a limited conversion from text to braille
//TODO: enhance it to have full support from text to UEB, including contractions
//http://www.brailleauthority.org/learn/braillebasic.pdf
@ -64,7 +96,7 @@ class TextToUEBBraille
public:
TextToUEBBraille();
QString braille(QChar c);
QString braille(QString text);
QString braille(const QString& text);
private:
const QString ASCII_PREFIX_CAPITAL_LETTER = QString(",");
@ -75,6 +107,12 @@ private:
QMap<QString, QString> textToBrailleASCII;
};
struct BrailleContext {
std::vector<Note*> previousNote;
std::vector<ClefType> currentClefType;
std::vector<Key> currentKey;
};
// Braille export is implemented according to Music Braille Code 2015
// published by the Braille Authority of North America
// http://www.brailleauthority.org/music/Music_Braille_Code_2015.pdf
@ -84,17 +122,14 @@ class Braille
public:
Braille(Score* s);
bool write(QIODevice& device);
bool convertMeasure(Measure* m, BrailleEngravingItems* beis);
bool convertItem(EngravingItem* el, BrailleEngravingItems* beis);
private:
static constexpr int MAX_CHARS_PER_LINE = 40;
Score* score;
/* ------------ Context ------------ */
std::vector<Note*> previousNote;
std::vector<ClefType> currentCleffType;
std::vector<Key> currentKey;
/* --------------------------------- */
Score* m_score = nullptr;
BrailleContext m_context;
void resetOctave(size_t stave);
void resetOctaves();
@ -117,6 +152,11 @@ private:
BarLine* lastBarline(Measure* measure, track_idx_t track);
/* --------------------------------------------------------------- */
void brailleMeasure(BrailleEngravingItems* res, Measure* measure, int staffCount);
bool brailleSingleItem(BrailleEngravingItems* beiz, EngravingItem* el);
void brailleMeasureItems(BrailleEngravingItems* res, Measure* measure, int staffCount);
void brailleMeasureLyrics(BrailleEngravingItems* res, Measure* measure, int staffCount);
QString brailleAccidentalType(AccidentalType accidental);
QString brailleArpeggio(Arpeggio* arpeggio);
QString brailleArticulation(Articulation* articulation);
@ -133,6 +173,7 @@ private:
QString brailleGraceNoteMarking(Chord* chord);
QString brailleJump(Jump* jump);
QString brailleKeySig(KeySig* keySig);
QString brailleLyrics(Lyrics* lyrics);
QString brailleMarker(Marker* marker);
QString brailleMeasure(Measure* measure, int staffCount);
QString brailleMeasureRepeat(MeasureRepeat* measureRepeat);

View file

@ -0,0 +1,284 @@
/*
* 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 "brailleconfiguration.h"
#include "settings.h"
using namespace mu;
using namespace mu::framework;
using namespace mu::async;
namespace mu::engraving {
static const std::string module_name("braille");
static const Settings::Key BRAILLE_STATUS(module_name, "score/braille/status");
static const Settings::Key BRAILLE_TABLE(module_name, "score/braille/table");
void BrailleConfiguration::init()
{
settings()->setDefaultValue(BRAILLE_STATUS, Val(false));
settings()->valueChanged(BRAILLE_STATUS).onReceive(this, [this](const Val&) {
m_braillePanelEnabledChanged.notify();
});
settings()->setDefaultValue(BRAILLE_TABLE, Val("default"));
settings()->valueChanged(BRAILLE_TABLE).onReceive(this, [this](const Val&) {
m_brailleTableChanged.notify();
});
}
async::Notification BrailleConfiguration::braillePanelEnabledChanged() const
{
return m_braillePanelEnabledChanged;
}
bool BrailleConfiguration::braillePanelEnabled() const
{
return settings()->value(BRAILLE_STATUS).toBool();
}
void BrailleConfiguration::setBraillePanelEnabled(const bool enabled)
{
settings()->setSharedValue(BRAILLE_STATUS, Val(enabled));
}
async::Notification BrailleConfiguration::brailleTableChanged() const
{
return m_brailleTableChanged;
}
QString BrailleConfiguration::brailleTable() const
{
return settings()->value(BRAILLE_TABLE).toQString();
}
void BrailleConfiguration::setBrailleTable(const QString tabl)
{
settings()->setSharedValue(BRAILLE_TABLE, Val(tabl));
}
QStringList BrailleConfiguration::brailleTableList()
{
return {
"Afrikaans uncontracted braille [afr-za-g1.ctb]",
"Afrikaans contracted braille [afr-za-g2.ctb]",
"Arabic uncontracted braille [ar.tbl]",
"Arabic contracted braille [ar-ar-g2.ctb]",
"Arabic computer braille [ar-ar-comp8.utb]",
"Assamese braille [as.tbl]",
"Awadhi braille [awa.tbl]",
"Bashkir braille [ba.utb]",
"Belarusian braille [bel.utb]",
"Belarusian computer braille [bel-comp.utb]",
"Bulgarian computer braille [bg.tbl]",
"Bulgarian braille [bg.utb]",
"Bihari braille [bh.tbl]",
"Bengali braille [bn.tbl]",
"Tibetan computer braille [bo.tbl]",
"Braj braille [bra.tbl]",
"Catalan braille [ca.tbl]",
"Cherokee braille [chr-us-g1.ctb]",
"Coptic computer braille [cop-eg-comp8.utb]",
"Kurdish braille [ckb.tbl]",
"Czech braille [cs.tbl]",
"Czech computer braille [cs-comp8.utb]",
"Welsh uncontracted braille [cy-cy-g1.utb]",
"Welsh contracted braille [cy.tbl]",
"Danish computer braille (1993 standard) [da-dk-g08_1993.ctb]",
"Danish 6-dot uncontracted braille (1993 standard) [da-dk-g16-lit_1993.ctb]",
"Danish 6-dot uncontracted braille (1993 standard) [da-dk-g16_1993.ctb]",
"Danish 8-dot uncontracted braille (1993 standard) [da-dk-g18_1993.ctb]",
"Danish 6-dot contracted braille (1993 standard) [da-dk-g26-lit_1993.ctb]",
"Danish 6-dot contracted braille (1993 standard) [da-dk-g26_1993.ctb]",
"Danish 6-dot partially contracted braille (1993 standard) [da-dk-g26l-lit_1993.ctb]",
"Danish 6-dot partially contracted braille (1993 standard) [da-dk-g26l_1993.ctb]",
"Danish 8-dot contracted braille (1993 standard) [da-dk-g28_1993.ctb]",
"Danish 8-dot partially contracted braille (1993 standard) [da-dk-g28l_1993.ctb]",
"Danish computer braille (2022 standard) [da-dk-g08.ctb]",
"Danish 6-dot uncontracted braille (2022 standard) [da-dk-g16.ctb]",
"Danish 8-dot uncontracted braille (2022 standard) [da-dk-g18.ctb]",
"Danish 6-dot contracted braille (2022 standard) [da-dk-g26.ctb]",
"Danish 8-dot contracted braille (2022 standard) [da-dk-g28.ctb]",
"German 8-dot computer braille [de-de-comp8.ctb]",
"German 6-dot computer braille [de-comp6.utb]",
"German uncontracted braille [de-g0.utb]",
"German uncontracted braille with indication of capitals [de-g0-detailed.utb]",
"German partially contracted braille [de-g1.ctb]",
"German partially contracted braille with indication of capitals [de-g1-detailed.ctb]",
"German contracted braille [de-g2.ctb]",
"German contracted braille with indication of capitals [de-g2-detailed.ctb]",
"Dravidian computer braille [dra.tbl]",
"Greek braille [el.ctb]",
"Greek internationalized braille as used by English speakers [grc-international-en.utb]",
"Persian computer braille [fa-ir-comp8.ctb]",
"Persian braille [fa-ir-g1.utb]",
"Unified English uncontracted braille [en-ueb-g1.ctb]",
"Unified English contracted braille [en-ueb-g2.ctb]",
"English computer braille as used in Canada [en_CA.tbl]",
"English uncontracted braille as used in the U.K. [en-gb-g1.utb]",
"English contracted braille as used in the U.K. [en_GB.tbl]",
"English computer braille as used in the U.K. [en-gb-comp8.ctb]",
"North American Braille Computer Code [en-nabcc.utb]",
"English uncontracted braille as used in the U.S. [en-us-g1.ctb]",
"English 6-dot computer braille as used in the U.S. [en-us-comp6.ctb]",
"English 8-dot computer braille as used in the U.S. [en_US-comp8-ext.tbl]",
"English contracted braille as used in the U.S. [en_US.tbl]",
"Esperanto braille [eo.tbl]",
"Esperanto x-system braille [eo-g1-x-system.ctb]",
"Spanish uncontracted braille [es.tbl]",
"Spanish contracted braille [es-g2.ctb]",
"Spanish computer braille [Es-Es-G0.utb]",
"Estonian computer braille [et.tbl]",
"Finnish braille [fi.utb]",
"Finnish computer braille [fi-fi-8dot.ctb]",
"French uncontracted braille [fr-bfu-comp6.utb]",
"French computer braille [fr-bfu-comp8.utb]",
"French contracted braille [fr-bfu-g2.ctb]",
"Irish uncontracted braille [ga-g1.utb]",
"Irish contracted braille [ga-g2.ctb]",
"Scottish Gaelic computer braille [gd.tbl]",
"Ethiopic braille [gez.tbl]",
"Gondi braille [gon.tbl]",
"Gujarati braille [gu.tbl]",
"Hawaiian braille [haw-us-g1.ctb]",
"Hebrew computer braille [he-IL-comp8.utb]",
"Israeli braille [he-IL.utb]",
"Hindi braille [hi.tbl]",
"Croatian braille [hr-g1.tbl]",
"Croatian computer braille [hr-comp8.tbl]",
"Hungarian computer braille [hu-hu-comp8.ctb]",
"Hungarian partially contracted braille [hu.tbl]",
"Hungarian contracted braille [hu-hu-g2.ctb]",
"Armenian computer braille [hy.tbl]",
"Icelandic braille [is.tbl]",
"Italian braille [it.tbl]",
"Italian computer braille [it-it-comp8.utb]",
"Inuktitut braille [iu-ca-g1.ctb]",
"Kantenji [ja-kantenji.utb]",
"Georgian braille [ka.utb]",
"Khasi braille [kha.tbl]",
"Kazakh braille [kk.utb]",
"Khmer braille [km-g1.utb]",
"Northern Kurdish braille [kmr.tbl]",
"Kannada braille [kn.tbl]",
"Korean contracted braille (2006 standard) [ko-2006-g2.ctb]",
"Korean uncontracted braille (2006 standard) [ko-2006-g1.ctb]",
"Korean contracted braille [ko-g2.ctb]",
"Korean uncontracted braille [ko-g1.ctb]",
"Konkani braille [kok.tbl]",
"Kurukh braille [kru.tbl]",
"Luganda braille [lg-ug-g1.utb]",
"Lithuanian 8-dot braille [lt.tbl]",
"Lithuanian 6-dot braille [lt-6dot.tbl]",
"Latvian braille [lv.tbl]",
"Maori braille [mao-nz-g1.ctb]",
"Malayalam braille [ml.tbl]",
"Mongolian uncontracted braille [mn-MN-g1.utb]",
"Mongolian contracted braille [mn-MN-g2.ctb]",
"Manipuri braille [mni.tbl]",
"Marathi braille [mr.tbl]",
"Malay braille [ms-my-g2.ctb]",
"Maltese computer braille [mt.tbl]",
"Munda braille [mun.tbl]",
"Marwari braille [mwr.tbl]",
"Burmese uncontracted braille [my-g1.utb]",
"Burmese contracted braille [my-g2.ctb]",
"Norwegian computer braille [no-no-comp8.ctb]",
"Norwegian 6-dot uncontracted braille [no-no-g0.utb]",
"Norwegian 8-dot uncontracted braille [no-no-8dot.utb]",
"Norwegian 8-dot uncontracted braille with 6-dot fallback [no-no-8dot-fallback-6dot-g0.utb]",
"Norwegian grade 1 contracted braille [no-no-g1.ctb]",
"Norwegian grade 2 contracted braille [no-no-g2.ctb]",
"Norwegian grade 3 contracted braille [no-no-g3.ctb]",
"Nepali braille [ne.tbl]",
"Dutch braille [nl.tbl]",
"Dutch computer braille [nl-comp8.utb]",
"Sepedi uncontracted braille [nso-za-g1.utb]",
"Sepedi contracted braille [nso-za-g2.ctb]",
"Chichewa braille [ny-mw.utb]",
"Oriya braille [or.tbl]",
"Punjabi braille [pa.tbl]",
"Pali braille [pi.tbl]",
"Polish computer braille [pl-pl-comp8.ctb]",
"Polish braille [pl.tbl]",
"Portuguese contracted braille [pt.tbl]",
"Portuguese uncontracted braille [pt-pt-g1.utb]",
"Portuguese computer braille [pt-pt-comp8.ctb]",
"Romanian computer braille [ro.tbl]",
"Russian computer braille [ru.ctb]",
"Russian braille [ru-litbrl.ctb]",
"Russian braille with indication of capitals [ru-litbrl-detailed.utb]",
"Russian braille for program sources [ru-compbrl.ctb]",
"Russian contracted braille [ru-ru-g1.ctb]",
"Kinyarwanda braille [rw-rw-g1.utb]",
"Sanskrit braille [sa.tbl]",
"Yakut braille [sah.utb]",
"Sindhi braille [sd.tbl]",
"Slovak braille [sk-g1.ctb]",
"Slovenian braille [sl.tbl]",
"Slovenian computer braille [sl-si-comp8.ctb]",
"Sesotho uncontracted braille [sot-za-g1.ctb]",
"Sesotho contracted braille [sot-za-g2.ctb]",
"Serbian braille [sr.tbl]",
"Swedish computer braille (1996 standard) [sv-1996.ctb]",
"Swedish computer braille (1989 standard) [sv-1989.ctb]",
"Swedish uncontracted braille [sv-g0.utb]",
"Swedish partially contracted braille [sv-g1.ctb]",
"Swedish contracted braille [sv-g2.ctb]",
"Swahili grade 1.2 contracted braille [sw-ke-g1-2.ctb]",
"Swahili grade 1.3 contracted braille [sw-ke-g1-3.ctb]",
"Swahili grade 1.4 contracted braille [sw-ke-g1-4.ctb]",
"Swahili grade 1.5 contracted braille [sw-ke-g1-5.ctb]",
"Swahili uncontracted braille [sw-ke-g1.utb]",
"Swahili grade 2 contracted braille [sw-ke-g2.ctb]",
"Tamil braille [ta-ta-g1.ctb]",
"Tamil computer braille [ta.tbl]",
"Telugu braille [te.tbl]",
"Turkish computer braille [tr.tbl]",
"Turkish braille [tr-g2.tbl]",
"Setswana uncontracted braille [tsn-za-g1.ctb]",
"Setswana contracted braille [tsn-za-g2.ctb]",
"Tatar braille [tt.utb]",
"Ukrainian braille [uk.utb]",
"Ukrainian computer braille [uk-comp.utb]",
"Uzbek braille [uz-g1.utb]",
"Urdu uncontracted braille [ur-pk-g1.utb]",
"Urdu contracted braille [ur-pk-g2.ctb]",
"Tshivenda uncontracted braille [ve-za-g1.utb]",
"Tshivenda contracted braille [ve-za-g2.ctb]",
"Vietnamese computer braille [vi.ctb]",
"Vietnamese uncontracted braille [vi-vn-g0.utb]",
"Vietnamese partially contracted braille [vi-vn-g1.ctb]",
"Vietnamese contracted braille [vi-vn-g2.ctb]",
"Southern Vietnamese braille [vi-saigon-g1.ctb]",
"isiXhosa uncontracted braille [xh-za-g1.utb]",
"isiXhosa contracted braille [xh-za-g2.ctb]",
"Chinese current braille without tones, for simplified Chinese characters [zh_CHN.tbl]",
"Cantonese braille [zh_HK.tbl]",
"Taiwanese bopomofo braille [zh-tw.ctb]",
"Chinese common braille, for simplified Chinese characters [zhcn-cbs.ctb]",
"Chinese current braille with tones [zhcn-g1.ctb]",
"Chinese double-phonic braille [zhcn-g2.ctb]",
"isiZulu uncontracted braille [zu-za-g1.utb]",
"isiZulu contracted braille [zu-za-g2.ctb]",
};
}
}

View file

@ -0,0 +1,51 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_NOTATIONCONFIGURATION_H
#define MU_BRAILLE_NOTATIONCONFIGURATION_H
#include "async/asyncable.h"
#include "ibrailleconfiguration.h"
namespace mu::engraving {
class BrailleConfiguration : public mu::braille::IBrailleConfiguration, public async::Asyncable
{
public:
void init();
async::Notification braillePanelEnabledChanged() const override;
bool braillePanelEnabled() const override;
void setBraillePanelEnabled(const bool enabled) override;
async::Notification brailleTableChanged() const override;
QString brailleTable() const override;
void setBrailleTable(const QString table) override;
QStringList brailleTableList() override;
private:
async::Notification m_braillePanelEnabledChanged;
async::Notification m_brailleTableChanged;
};
}
#endif // MU_BRAILLE_NOTATIONCONFIGURATION_H

View file

@ -0,0 +1,32 @@
/*
* 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 "brailleconverter.h"
#include "braille.h"
namespace mu::engraving {
bool BrailleConverter::write(Score* score, QIODevice& device)
{
return Braille(score).write(device);
}
}

View file

@ -0,0 +1,35 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_BRAILLECONVERTER_H
#define MU_BRAILLE_BRAILLECONVERTER_H
#include "../ibrailleconverter.h"
namespace mu::engraving {
class BrailleConverter : public mu::braille::IBrailleConverter
{
public:
bool write(Score* score, QIODevice& device) override;
};
}
#endif // MU_BRAILLE_BRAILLECONVERTER_H

View file

@ -0,0 +1,340 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2023 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 <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <vector>
#include "braille/thirdparty/liblouis/liblouis/internal.h"
#include "braille/thirdparty/liblouis/liblouis/liblouis.h"
#define WIDECHARS_ARE_UCS4
#define FUNC u32_to_u8
#define SRC_UNIT uint32_t
#define DST_UNIT uint8_t
/* Type representing a Unicode character. */
typedef uint32_t ucs4_t;
int
u8_uctomb(uint8_t* s, ucs4_t uc, int n)
{
if (uc < 0x80) {
if (n > 0) {
s[0] = uc;
return 1;
}
/* else return -2, below. */
} else {
int count;
if (uc < 0x800) {
count = 2;
} else if (uc < 0x10000) {
if (uc < 0xd800 || uc >= 0xe000) {
count = 3;
} else {
return -1;
}
} else if (uc < 0x110000) {
count = 4;
} else {
return -1;
}
if (n >= count) {
switch (count) { /* note: code falls through cases! */
case 4: s[3] = 0x80 | (uc & 0x3f);
uc = uc >> 6;
uc |= 0x10000;
case 3: s[2] = 0x80 | (uc & 0x3f);
uc = uc >> 6;
uc |= 0x800;
case 2: s[1] = 0x80 | (uc & 0x3f);
uc = uc >> 6;
uc |= 0xc0;
/*case 1:*/ s[0] = uc;
}
return count;
}
}
return -2;
}
DST_UNIT*
FUNC(const SRC_UNIT* s, size_t n, DST_UNIT* resultbuf, size_t* lengthp)
{
const SRC_UNIT* s_end = s + n;
/* Output string accumulator. */
DST_UNIT* result;
size_t allocated;
size_t length;
if (resultbuf != NULL) {
result = resultbuf;
allocated = *lengthp;
} else {
result = NULL;
allocated = 0;
}
length = 0;
/* Invariants:
result is either == resultbuf or == NULL or malloc-allocated.
If length > 0, then result != NULL. */
while (s < s_end)
{
ucs4_t uc;
int count;
/* Fetch a Unicode character from the input string. */
uc = *s++;
/* No need to call the safe variant u32_mbtouc, because
u8_uctomb will verify uc anyway. */
/* Store it in the output string. */
count = u8_uctomb(result + length, uc, allocated - length);
if (count == -1) {
if (!(result == resultbuf || result == NULL)) {
free(result);
}
errno = EILSEQ;
return NULL;
}
if (count == -2) {
DST_UNIT* memory;
allocated = (allocated > 0 ? 2 * allocated : 12);
if (length + 6 > allocated) {
allocated = length + 6;
}
if (result == resultbuf || result == NULL) {
memory = (DST_UNIT*)malloc(allocated * sizeof(DST_UNIT));
} else {
memory
=(DST_UNIT*)realloc(result, allocated * sizeof(DST_UNIT));
}
if (memory == NULL) {
if (!(result == resultbuf || result == NULL)) {
free(result);
}
errno = ENOMEM;
return NULL;
}
if (result == resultbuf && length > 0) {
memcpy((char*)memory, (char*)result,
length * sizeof(DST_UNIT));
}
result = memory;
count = u8_uctomb(result + length, uc, allocated - length);
if (count < 0) {
abort();
}
}
length += count;
}
if (length == 0) {
if (result == NULL) {
/* Return a non-NULL value. NULL means error. */
result = (DST_UNIT*)malloc(1);
if (result == NULL) {
errno = ENOMEM;
return NULL;
}
}
} else if (result != resultbuf && length < allocated) {
/* Shrink the allocated memory if possible. */
DST_UNIT* memory;
memory = (DST_UNIT*)realloc(result, length * sizeof(DST_UNIT));
if (memory != NULL) {
result = memory;
}
}
*lengthp = length;
return result;
}
std::string table_unicode_to_ascii = "unicode-to-ascii.dis";
std::string table_ascii_to_unicode = "ascii-to-unicode.dis";
std::string table_for_literature = "unicode.dis,en-us-g2.ctb";
std::string table_for_general = "unicode.dis,en-us-symbols.mus";
std::string tables_dir = "";
void initTables(std::string dir)
{
if (dir.empty()) {
table_unicode_to_ascii = "unicode-to-ascii.dis";
table_ascii_to_unicode = "ascii-to-unicode.dis";
table_for_literature = "unicode.dis,en-us-g2.ctb";
table_for_general = "unicode.dis,en-us-symbols.mus";
} else {
table_unicode_to_ascii = dir + "/unicode-to-ascii.dis";
table_ascii_to_unicode = dir + "/ascii-to-unicode.dis";
table_for_literature = dir + "/unicode.dis," + dir + "/en-us-g2.ctb";
table_for_general = dir + "/unicode.dis," + dir + "/en-us-symbols.mus";
}
tables_dir = dir;
}
void updateTableForLyrics(std::string table)
{
if (tables_dir.empty()) {
table_for_literature = "unicode.dis," + table;
} else {
table_for_literature = tables_dir + "/unicode.dis," + tables_dir + "/" + table;
}
}
std::string braille_translate(const char* table_name, std::string txt)
{
//cout << "braille_translate " << table_name << " " << txt << "\n";
uint8_t* outputbuf;
size_t outlen;
widechar inbuf[MAXSTRING];
widechar transbuf[MAXSTRING];
int inlen;
int translen;
inlen = _lou_extParseChars(txt.c_str(), inbuf);
translen = MAXSTRING;
lou_translateString(
table_name, inbuf, &inlen, transbuf, &translen, NULL, NULL, 0);
#ifdef WIDECHARS_ARE_UCS4
//outputbuf = (uint8_t *) malloc (translen * sizeof(widechar) * sizeof (uint8_t));
outputbuf = u32_to_u8(transbuf, translen, NULL, &outlen);
#else
outputbuf = u16_to_u8(transbuf, translen, NULL, &outlen);
#endif
std::string ret = std::string(outputbuf, outputbuf + outlen);
free(outputbuf);
//cout << " " << ret << "\n";
return ret;
}
int check_tables(const char* tables)
{
if (lou_checkTable(tables) == 0) {
return -1;
} else {
return 0;
}
}
char* setTablesDir(const char* tablesdir)
{
return lou_setDataPath(tablesdir);
}
char* getTablesDir()
{
return lou_getDataPath();
}
std::vector<std::string> split_string(std::string txt, int width)
{
std::vector<std::string> lines;
QString str = QString::fromStdString(txt);
int len = str.length();
if (len <= width) {
lines.push_back(txt);
return lines;
}
while (len > width) {
int idx = width - 1;
for (; idx >= 0; idx--) {
QString ch = str.left(idx).right(1);
if (ch == "") {
break;
}
}
if (idx == 0 || idx == -1) {
idx = width;
}
QString line = str.left(idx);
str = str.right(len - idx);
len = str.length();
lines.push_back(line.toStdString());
}
if (len > 0) {
lines.push_back(str.toStdString());
}
return lines;
}
std::string braille_long_translate(const char* table_name, std::string txt)
{
std::vector<std::string> lines = split_string(txt, 256);
if (lines.size() == 0) {
return "";
}
std::string buffer = braille_translate(table_name, lines.front());
for (size_t i = 1; i < lines.size(); i++) {
std::string txt = lines[i] + " ";
buffer.append(braille_translate(table_name, txt));
}
return buffer;
}
std::string braille_multi_line_translate(const char* table_name, std::string txt)
{
std::stringstream ss(txt);
std::string line;
std::string buffer = "";
while (std::getline(ss, line)) {
if (line == "[EOP]" || line == "[NP]") {
buffer.append(line).append("\n");
} else {
std::string converted = braille_translate(table_name, line);
buffer.append(converted).append("\n");
}
}
return buffer;
}
int get_braille_text_length(const char* table_name, std::string txt)
{
std::string buffer = braille_translate(table_name, txt);
return QString::fromStdString(txt).length();
}

View file

@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2023 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/>.
*/
#ifndef MU_BRAILLE_LOUIS_H
#define MU_BRAILLE_LOUIS_H
#include <string>
extern std::string table_ascii_to_unicode;
extern std::string table_unicode_to_ascii;
extern std::string table_for_literature;
extern std::string table_for_general;
extern std::string tables_dir;
std::string get_louis_version();
std::string braille_translate(const char* table_name, std::string txt);
int check_tables(const char* tables);
char* setTablesDir(const char* tablesdir);
char* getTablesDir();
void initTables(std::string dir);
void updateTableForLyrics(std::string table);
std::string braille_long_translate(const char* table_name, std::string txt);
std::string braille_multi_line_translate(const char* table_name, std::string txt);
int get_braille_text_length(const char* table_name, std::string txt);
#endif // MU_BRAILLE_LOUIS_H

View file

@ -0,0 +1,289 @@
/*
* 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 "io/iodevice.h"
#include "io/buffer.h"
#include "notationbraille.h"
#include "translation.h"
#include "libmscore/masterscore.h"
#include "libmscore/spanner.h"
#include "libmscore/segment.h"
#include "libmscore/slur.h"
#include "libmscore/staff.h"
#include "libmscore/part.h"
#include "libmscore/sig.h"
#include "libmscore/measure.h"
#include "braille/internal/braille.h"
#include "braille/internal/louis.h"
#include "log.h"
using namespace mu::notation;
using namespace mu::async;
using namespace mu::engraving;
using namespace mu::io;
void NotationBraille::init()
{
setEnabled(brailleConfiguration()->braillePanelEnabled());
setCurrentItemPosition(-1, -1);
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.0!");
setBrailleInfo(QString(welcome.c_str()));
brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() {
bool enabled = brailleConfiguration()->braillePanelEnabled();
setEnabled(enabled);
});
updateTableForLyricsFromPreferences();
brailleConfiguration()->brailleTableChanged().onNotify(this, [this]() {
updateTableForLyricsFromPreferences();
});
globalContext()->currentNotationChanged().onNotify(this, [this]() {
if (notation()) {
doBraille(true);
notation()->interaction()->selectionChanged().onNotify(this, [this]() {
doBraille();
});
}
});
}
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();
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) {
if (!m) {
brailleEngravingItems()->clear();
Braille lb(score());
bool res = lb.convertItem(e, brailleEngravingItems());
if (!res) {
QString txt = e->accessibleInfo();
std::string braille = braille_long_translate(table_for_literature.c_str(), txt.toStdString());
brailleEngravingItems()->setBrailleStr(QString::fromStdString(braille));
setBrailleInfo(QString::fromStdString(braille));
} else {
setBrailleInfo(brailleEngravingItems()->brailleStr());
}
current_measure = nullptr;
} else {
if (m != current_measure || force) {
brailleEngravingItems()->clear();
Braille lb(score());
lb.convertMeasure(m, brailleEngravingItems());
setBrailleInfo(brailleEngravingItems()->brailleStr());
current_measure = m;
}
std::pair<int, int> pos = brailleEngravingItems()->getBraillePos(e);
if (pos.first != -1) {
setCurrentItemPosition(pos.first, pos.second);
}
}
}
}
}
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::shortcut() const
{
return m_shortcut;
}
mu::ValCh<bool> NotationBraille::enabled() const
{
return m_enabled;
}
void NotationBraille::setEnabled(bool enabled)
{
if (enabled == m_enabled.val) {
return;
}
m_enabled.set(enabled);
}
mu::engraving::BrailleEngravingItems* NotationBraille::brailleEngravingItems()
{
return &m_bei;
}
QString NotationBraille::getBrailleStr()
{
return m_bei.brailleStr();
}
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 (m_cursorPosition.val == pos) {
return;
}
m_cursorPosition.set(pos);
notation::EngravingItem* el = brailleEngravingItems()->getEngravingItem(pos);
if (el != nullptr) {
interaction()->select({ el });
}
}
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;
}
void NotationBraille::setShortcut(const QString& sequence)
{
LOGD() << sequence;
std::string seq = sequence.toStdString();
m_shortcut.set(seq);
if (seq == "Left") {
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::Chord);
} else if (seq == "Right") {
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::Chord);
} else if (seq == "Ctrl+Left") {
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::Measure);
} else if (seq == "Ctrl+Right") {
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::Measure);
} else if (seq == "Alt+Left") {
interaction()->moveSelection(MoveDirection::Left, MoveSelectionType::EngravingItem);
} else if (seq == "Alt+Right") {
interaction()->moveSelection(MoveDirection::Right, MoveSelectionType::EngravingItem);
} else if (seq == "Ctrl+End") {
interaction()->selectLastElement();
} else if (seq == "Ctrl+Home") {
interaction()->selectFirstElement();
}// else if(shortcutsController()->isRegistered(seq)) {
// shortcutsController()->activate(seq);
//}
}
path_t NotationBraille::tablesDefaultDirPath() const
{
return globalConfiguration()->appDataPath() + "tables";
}

View file

@ -0,0 +1,101 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_NOTATIONBRAILLE_H
#define MU_BRAILLE_NOTATIONBRAILLE_H
#include "modularity/ioc.h"
#include "global/iglobalconfiguration.h"
#include "io/ifilesystem.h"
#include "ui/iuiconfiguration.h"
#include "engraving/iengravingconfiguration.h"
#include "inotationbraille.h"
#include "notation/notationtypes.h"
#include "async/asyncable.h"
#include "async/notification.h"
#include "braille/internal/braille.h"
#include "context/iglobalcontext.h"
#include "notation/inotationconfiguration.h"
#include "ibrailleconfiguration.h"
namespace mu::engraving {
class Score;
class Selection;
class NotationBraille : public mu::braille::INotationBraille, public async::Asyncable
{
INJECT(framework::IGlobalConfiguration, globalConfiguration)
INJECT(context::IGlobalContext, globalContext)
INJECT(notation::INotationConfiguration, notationConfiguration)
INJECT(braille::IBrailleConfiguration, brailleConfiguration)
public:
void init();
void doBraille(bool force = false);
ValCh<std::string> brailleInfo() const override;
ValCh<int> cursorPosition() const override;
ValCh<int> currentItemPositionStart() const override;
ValCh<int> currentItemPositionEnd() const override;
ValCh<std::string> shortcut() const override;
ValCh<bool> enabled() const override;
void setEnabled(bool enabled) override;
void setCursorPosition(const int pos) override;
void setCurrentItemPosition(const int, const int) override;
void setShortcut(const QString&) override;
notation::INotationPtr notation();
notation::INotationInteractionPtr interaction();
BrailleEngravingItems* brailleEngravingItems();
QString getBrailleStr();
private:
Score* score();
Selection* selection();
Measure* current_measure = nullptr;
void setBrailleInfo(const QString& info);
void setCurrentShortcut(const QString& sequence);
void updateTableForLyricsFromPreferences();
io::path_t tablesDefaultDirPath() const;
ValCh<std::string> m_brailleInfo;
ValCh<int> m_cursorPosition;
ValCh<int> m_currentItemPositionStart;
ValCh<int> m_currentItemPositionEnd;
ValCh<std::string> m_shortcut;
ValCh<bool> m_enabled;
BrailleEngravingItems m_bei;
async::Notification m_selectionChanged;
};
}
#endif // MU_BRAILLE_NOTATIONBRAILLE_H

View file

@ -0,0 +1,150 @@
/*
* 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/>.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.Braille 1.0
StyledFlickable {
id: root
property NavigationPanel navigationPanel: NavigationPanel {
name: "BrailleView"
enabled: brailleTextArea.enabled && brailleTextArea.visible
direction: NavigationPanel.Both
}
BrailleModel {
id: brailleModel
onCurrentItemChanged: {
if(brailleModel.currentItemPositionStart.valueOf() != -1 &&
brailleModel.currentItemPositionEnd.valueOf() != -1) {
//brailleInfo.select(brailleModel.currentItemPositionStart.valueOf(), brailleModel.currentItemPositionEnd.valueOf());
if(brailleTextArea.focus) {
brailleTextArea.cursorPosition = brailleModel.currentItemPositionEnd.valueOf();
}
}
}
onBraillePanelEnabledChanged: {
root.visible = brailleModel.enabled
}
Component.onCompleted: {
root.visible = brailleModel.enabled
}
}
TextArea.flickable: TextArea {
id: brailleTextArea
text: brailleModel.brailleInfo
wrapMode: Text.AlignLeft
NavigationControl {
id: fakeNavCtrl
name: "Braille"
enabled: brailleTextArea.enabled && brailleTextArea.visible
panel: root.navigationPanel
order: 1
accessible.role: MUAccessible.EditableText
accessible.name: "Braille"
accessible.visualItem: brailleTextArea
accessible.text: brailleTextArea.text
accessible.selectedText: brailleTextArea.selectedText
accessible.selectionStart: brailleTextArea.selectionStart
accessible.selectionEnd: brailleTextArea.selectionEnd
accessible.cursorPosition: brailleTextArea.cursorPosition
onActiveChanged: {
if (fakeNavCtrl.active) {
brailleTextArea.forceActiveFocus();
if(brailleModel.currentItemPositionStart.valueOf() != -1 &&
brailleModel.currentItemPositionEnd.valueOf() != -1) {
brailleTextArea.cursorPosition = brailleModel.currentItemPositionEnd.valueOf();
}
} else {
brailleTextArea.focus = false
}
}
}
NavigationFocusBorder {
navigationCtrl: fakeNavCtrl
drawOutsideParent: false
}
onCursorPositionChanged: {
brailleModel.cursorPosition = brailleTextArea.cursorPosition;
}
Keys.onPressed: {
if(event.key !== Qt.Key_Shift && event.key !== Qt.Key_Alt &&
event.key !== Qt.Key_Control) {
var shortcut = "";
if(event.modifiers === Qt.ShiftModifier) {
shortcut = shortcut === "" ? "Shift" : shortcut += "+Shift";
}
if(event.modifiers === Qt.AltModifier) {
shortcut = shortcut === "" ? "Alt" : shortcut += "+Alt";
}
if(event.modifiers === Qt.ControlModifier) {
shortcut = shortcut === "" ? "Ctrl" : shortcut += "+Ctrl";
}
if(shortcut !== "") shortcut += "+";
if(event.key === Qt.Key_Right) {
shortcut += "Right"
} else if(event.key === Qt.Key_Left) {
shortcut += "Left"
} else if(event.key === Qt.Key_Up) {
shortcut += "Up"
} else if(event.key === Qt.Key_Down) {
shortcut += "Down"
} else if(event.key === Qt.Key_PageUp) {
shortcut += "PgUp"
} else if(event.key === Qt.Key_PageDown) {
shortcut += "PgDown"
} else if(event.key === Qt.Key_Home) {
shortcut += "Home"
} else if(event.key === Qt.Key_End) {
shortcut += "End"
}
if(shortcut !== "Left" && shortcut !== "Right" &&
shortcut !== "Up" && shortcut !== "Down") {
brailleModel.shorcut = shortcut;
event.accepted = true;
}
}
}
}
ScrollBar.vertical: StyledScrollBar {}
}

View file

@ -0,0 +1,2 @@
module MuseScore.Braille
BrailleView 1.0 BrailleView.qml

View file

@ -0,0 +1,182 @@
/*
* 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 "braillemodel.h"
#include "types/translatablestring.h"
#include "log.h"
namespace mu::notation {
BrailleModel::BrailleModel(QObject* parent)
: QObject(parent)
{
load();
}
QString BrailleModel::brailleInfo() const
{
return notationBraille() ? QString::fromStdString(notationBraille()->brailleInfo().val) : QString();
}
QString BrailleModel::shortcut() const
{
return notationBraille() ? QString::fromStdString(notationBraille()->shortcut().val) : QString();
}
int BrailleModel::cursorPosition() const
{
return notationBraille() ? notationBraille()->cursorPosition().val : 0;
}
int BrailleModel::currentItemPositionStart() const
{
return notationBraille() ? notationBraille()->currentItemPositionStart().val : 0;
}
int BrailleModel::currentItemPositionEnd() const
{
return notationBraille() ? notationBraille()->currentItemPositionEnd().val : 0;
}
void BrailleModel::setCursorPosition(int pos) const
{
if (!notationBraille()) {
return;
}
if (notationBraille()->cursorPosition().val == pos) {
return;
}
notationBraille()->setCursorPosition(pos);
}
void BrailleModel::setShortcut(const QString& sequence) const
{
if (!notationBraille()) {
return;
}
notationBraille()->setShortcut(sequence);
}
bool BrailleModel::enabled() const
{
//if(!notationBraille()) return false;
//return notationBraille()->enabled().val;
return brailleConfiguration()->braillePanelEnabled();
}
void BrailleModel::setEnabled(bool e) const
{
if (!notationBraille()) {
return;
}
if (notationBraille()->enabled().val == e) {
return;
}
notationBraille()->setEnabled(e);
emit braillePanelEnabledChanged();
}
void BrailleModel::load()
{
TRACEFUNC;
onCurrentNotationChanged();
context()->currentNotationChanged().onNotify(this, [this]() {
onCurrentNotationChanged();
});
}
void BrailleModel::onCurrentNotationChanged()
{
if (!notation()) {
return;
}
listenChangesInnotationBraille();
listenCurrentItemChanges();
listenShortcuts();
listenBraillePanelEnabledChanges();
listenCursorPositionChanges();
}
void BrailleModel::listenChangesInnotationBraille()
{
if (!notationBraille()) {
return;
}
notationBraille()->brailleInfo().ch.onReceive(this, [this](const std::string&) {
emit brailleInfoChanged();
});
}
void BrailleModel::listenShortcuts()
{
if (!notationBraille()) {
return;
}
notationBraille()->shortcut().ch.onReceive(this, [this](const std::string&) {
emit shortcutFired();
});
}
void BrailleModel::listenCursorPositionChanges()
{
if (!notationBraille()) {
return;
}
notationBraille()->cursorPosition().ch.onReceive(this, [this](const int) {
emit cursorPositionChanged();
});
}
void BrailleModel::listenCurrentItemChanges()
{
if (!notationBraille()) {
return;
}
notationBraille()->currentItemPositionStart().ch.onReceive(this, [this](int) {
emit currentItemChanged();
});
notationBraille()->currentItemPositionEnd().ch.onReceive(this, [this](int) {
emit currentItemChanged();
});
}
void BrailleModel::listenBraillePanelEnabledChanges()
{
if (!notationBraille()) {
return;
}
notationBraille()->enabled().ch.onReceive(this, [this](const int) {
emit braillePanelEnabledChanged();
});
}
INotationPtr BrailleModel::notation() const
{
return context()->currentNotation();
}
}

View file

@ -0,0 +1,94 @@
/*
* 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/>.
*/
#ifndef MU_BRAILLE_BRAILLEMODEL_H
#define MU_BRAILLE_BRAILLEMODEL_H
#include <QObject>
#include "async/asyncable.h"
#include "actions/actionable.h"
#include "modularity/ioc.h"
#include "inotationbraille.h"
#include "ibrailleconfiguration.h"
#include "notation/inotationconfiguration.h"
#include "context/iglobalcontext.h"
namespace mu::notation {
class BrailleModel : public QObject, public async::Asyncable, public actions::Actionable
{
Q_OBJECT
INJECT(context::IGlobalContext, context)
INJECT(notation::INotationConfiguration, notationConfiguration)
INJECT(braille::IBrailleConfiguration, brailleConfiguration)
INJECT(braille::INotationBraille, notationBraille)
Q_PROPERTY(QString brailleInfo READ brailleInfo NOTIFY brailleInfoChanged)
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
Q_PROPERTY(int currentItemPositionStart READ currentItemPositionStart NOTIFY currentItemChanged)
Q_PROPERTY(int currentItemPositionEnd READ currentItemPositionEnd NOTIFY currentItemChanged)
Q_PROPERTY(QString shorcut READ shortcut WRITE setShortcut NOTIFY shortcutFired)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY braillePanelEnabledChanged)
public:
explicit BrailleModel(QObject* parent = nullptr);
Q_INVOKABLE void load();
QString brailleInfo() const;
int cursorPosition() const;
void setCursorPosition(int pos) const;
int currentItemPositionStart() const;
int currentItemPositionEnd() const;
QString shortcut() const;
void setShortcut(const QString& sequence) const;
bool enabled() const;
void setEnabled(bool e) const;
signals:
void brailleInfoChanged() const;
void cursorPositionChanged() const;
void currentItemChanged() const;
void shortcutFired() const;
void braillePanelEnabledChanged() const;
private:
INotationPtr notation() const;
void onCurrentNotationChanged();
void listenChangesInBraille();
void listenChangesInnotationBraille();
void listenCursorPositionChanges();
void listenCurrentItemChanges();
void listenShortcuts();
void listenBraillePanelEnabledChanges();
};
}
#endif // MU_BRAILLE_BRAILLEMODEL_H

View file

@ -153,7 +153,7 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/view/selectionfiltermodel.h
${CMAKE_CURRENT_LIST_DIR}/view/editgridsizedialogmodel.cpp
${CMAKE_CURRENT_LIST_DIR}/view/editgridsizedialogmodel.h
${CMAKE_CURRENT_LIST_DIR}/view/pianokeyboard/pianokeyboardtypes.h
${CMAKE_CURRENT_LIST_DIR}/view/pianokeyboard/pianokeyboardcontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/view/pianokeyboard/pianokeyboardcontroller.h

View file

@ -26,6 +26,7 @@ import QtQuick.Controls 2.15
import MuseScore.Ui 1.0
import MuseScore.UiComponents 1.0
import MuseScore.NotationScene 1.0
import MuseScore.Braille 1.0
import "internal"
@ -73,7 +74,7 @@ FocusScope {
Layout.fillWidth: true
navigationPanel.section: navSec
navigationPanel.order: popUpLoader.navigationOrderEnd + 1
navigationPanel.order: 1
}
SeparatorLine { visible: tabPanel.visible }
@ -99,7 +100,7 @@ FocusScope {
section: navSec
enabled: notationView.enabled && notationView.visible
direction: NavigationPanel.Both
order: 1
order: tabPanel.navigationPanel.order + 1
}
NavigationControl {
@ -194,6 +195,17 @@ FocusScope {
}
}
BrailleView {
id: brailleView
SplitView.fillWidth: true
SplitView.preferredHeight: 50
SplitView.minimumHeight: 30
navigationPanel.section: navSec
navigationPanel.order: popUpLoader.navigationOrderEnd + 1
}
Component {
id: navigatorComp
@ -248,7 +260,7 @@ FocusScope {
Layout.fillWidth: true
navigationPanel.section: navSec
navigationPanel.order: tabPanel.navigationPanel.order + 1
navigationPanel.order: brailleView.navigationPanel.order + 1
onClosed: {
fakeNavCtrl.requestActive()

View file

@ -42,7 +42,9 @@ Item {
property NavigationSection navigationSection: null
property int navigationOrderStart: 0
property int navigationOrderEnd: Boolean(loader.item) ? loader.item.navigationOrderEnd : 0
property int navigationOrderEnd: Boolean(loader.item)
? loader.item.navigationOrderEnd
: navigationOrderStart
QtObject {
id: prv