Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save zopieux/63eb756002d12284b7a75457c7b67443 to your computer and use it in GitHub Desktop.
Save zopieux/63eb756002d12284b7a75457c7b67443 to your computer and use it in GitHub Desktop.
MuseScore audio export hack for training aids
From bbd014bf407b2ec97fa18cca89d46d1867f62c83 Mon Sep 17 00:00:00 2001
From: Alexandre Macabies <[email protected]>
Date: Thu, 21 Sep 2023 22:53:31 +0200
Subject: [PATCH] Audio export conversion hack for training aids.
---
default.nix | 174 +++++++++++++
flake.lock | 61 +++++
flake.nix | 27 ++
src/app/app.cpp | 2 +
src/app/commandlineparser.cpp | 13 +
src/app/commandlineparser.h | 6 +
.../internal/convertercontroller.cpp | 243 ++++++++++++++++--
src/converter/internal/convertercontroller.h | 6 +
.../audioexport/iaudioexportconfiguration.h | 6 +
.../internal/audioexportconfiguration.cpp | 20 ++
.../internal/audioexportconfiguration.h | 8 +
11 files changed, 548 insertions(+), 18 deletions(-)
create mode 100644 default.nix
create mode 100644 flake.lock
create mode 100644 flake.nix
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000000..da80ce24ee
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,174 @@
+{ stdenv
+, lib
+, fetchFromGitHub
+, fetchpatch
+, cmake
+, ffmpeg
+, wrapQtAppsHook
+, pkg-config
+, ninja
+, alsa-lib
+, alsa-plugins
+, freetype
+, libjack2
+, lame
+, libogg
+, libpulseaudio
+, libsndfile
+, libvorbis
+, portaudio
+, portmidi
+, qtbase
+, qtdeclarative
+, qtgraphicaleffects
+, flac
+, qtquickcontrols
+, qtquickcontrols2
+, qtscript
+, qtsvg
+, qtxmlpatterns
+, qtnetworkauth
+, qtx11extras
+, darwin
+}:
+
+let
+ stdenv' = if stdenv.isDarwin then darwin.apple_sdk_11_0.stdenv else stdenv;
+ # portaudio propagates Darwin frameworks. Rebuild it using the 11.0 stdenv
+ # from Qt and the 11.0 SDK frameworks.
+ portaudio' =
+ if stdenv.isDarwin then
+ portaudio.override
+ {
+ stdenv = stdenv';
+ inherit (darwin.apple_sdk_11_0.frameworks)
+ AudioUnit
+ AudioToolbox
+ CoreAudio
+ CoreServices
+ Carbon
+ ;
+ } else portaudio;
+in
+stdenv'.mkDerivation rec {
+ pname = "musescore";
+ version = "4.1.1";
+
+ src = ./.;
+
+ patches = [
+ # Upstream from some reason wants to install qml files from qtbase in
+ # installPhase, this patch removes this behavior. See:
+ # https://github.com/musescore/MuseScore/issues/18665
+ # (fetchpatch {
+ # url = "https://github.com/doronbehar/MuseScore/commit/f48448a3ede46f5a7ef470940072fbfb6742487c.patch";
+ # hash = "sha256-UEc7auscnW0KMfWkLKQtm+UstuTNsuFeoNJYIidIlwM=";
+ # })
+ # Upstream removed the option to use system freetype library in v4.1.0,
+ # causing the app to crash on systems when the outdated bundled freetype
+ # tries to load the Noto Sans font. For more info on the crash itself,
+ # see #244409 and https://github.com/musescore/MuseScore/issues/18795.
+ # For now, re-add the option ourselves. The fix has been merged upstream,
+ # so we can remove this patch with the next version. In the future, we
+ # may replace the other bundled thirdparty libs with system libs, see
+ # https://github.com/musescore/MuseScore/issues/11572.
+ # (fetchpatch {
+ # url = "https://github.com/musescore/MuseScore/commit/9ab6b32b1c3b990cfa7bb172ee8112521dc2269c.patch";
+ # hash = "sha256-5GA29Z+o3I/uDTTDbkauZ8/xSdCE6yY93phMSY0ea7s=";
+ # })
+ ];
+
+ cmakeFlags = [
+ "-DMUSESCORE_BUILD_MODE=debug"
+ # Disable the build and usage of the `/bin/crashpad_handler` utility - it's
+ # not useful on NixOS, see:
+ # https://github.com/musescore/MuseScore/issues/15571
+ "-DMUE_BUILD_CRASHPAD_CLIENT=OFF"
+ # Use our freetype
+ "-DMUE_COMPILE_USE_SYSTEM_FREETYPE=ON"
+ # From some reason, in $src/build/cmake/SetupBuildEnvironment.cmake,
+ # upstream defaults to compiling to x86_64 only, unless this cmake flag is
+ # set
+ "-DMUE_COMPILE_BUILD_MACOS_APPLE_SILICON=ON"
+ # Don't bundle qt qml files, relevant really only for darwin, but we set
+ # this for all platforms anyway.
+ "-DMUE_COMPILE_INSTALL_QTQML_FILES=OFF"
+ "-DMUE_BUILD_VIDEOEXPORT_MODULE=ON"
+ # "-DCMAKE_INSTALL_PREFIX=/tmp/muselol"
+ ];
+
+ qtWrapperArgs = [
+ # MuseScore JACK backend loads libjack at runtime.
+ "--prefix ${lib.optionalString stdenv.isDarwin "DY"}LD_LIBRARY_PATH : ${lib.makeLibraryPath [ ffmpeg libjack2 ]}"
+ ] ++ lib.optionals (stdenv.isLinux) [
+ "--set ALSA_PLUGIN_DIR ${alsa-plugins}/lib/alsa-lib"
+ ] ++ lib.optionals (!stdenv.isDarwin) [
+ # There are some issues with using the wayland backend, see:
+ # https://musescore.org/en/node/321936
+ "--set-default QT_QPA_PLATFORM xcb"
+ ];
+
+ # HACK `propagatedSandboxProfile` does not appear to actually propagate the
+ # sandbox profile from `qtbase`, see:
+ # https://github.com/NixOS/nixpkgs/issues/237458
+ sandboxProfile = toString qtbase.__propagatedSandboxProfile or null;
+
+ nativeBuildInputs = [
+ wrapQtAppsHook
+ cmake
+ pkg-config
+ ninja
+ ];
+
+ buildInputs = [
+ libjack2
+ freetype
+ lame
+ libogg
+ libpulseaudio
+ libsndfile
+ libvorbis
+ ffmpeg
+ portaudio'
+ portmidi
+ flac
+ qtbase
+ qtdeclarative
+ qtgraphicaleffects
+ qtquickcontrols
+ qtquickcontrols2
+ qtscript
+ qtsvg
+ qtxmlpatterns
+ qtnetworkauth
+ qtx11extras
+ ] ++ lib.optionals stdenv.isLinux [
+ alsa-lib
+ ];
+
+ postInstall = ''
+ # Remove unneeded bundled libraries and headers
+ rm -r $out/{include,lib}
+ '' + lib.optionalString stdenv.isDarwin ''
+ mkdir -p "$out/Applications"
+ mv "$out/mscore.app" "$out/Applications/mscore.app"
+ mkdir -p $out/bin
+ ln -s $out/Applications/mscore.app/Contents/MacOS/mscore $out/bin/mscore.
+ '';
+
+ # Don't run bundled upstreams tests, as they require a running X window system.
+ doCheck = false;
+
+ # passthru.tests = nixosTests.musescore;
+
+ meta = with lib; {
+ description = "Music notation and composition software";
+ homepage = "https://musescore.org/";
+ license = licenses.gpl3Only;
+ maintainers = with maintainers; [ vandenoever doronbehar ];
+ # on aarch64-linux:
+ # error: cannot convert '<brace-enclosed initializer list>' to 'float32x4_t' in assignment
+ broken = (stdenv.isLinux && stdenv.isAarch64);
+ mainProgram = "mscore";
+ };
+}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000000..66fbd3ba68
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,61 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1694529238,
+ "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1694887919,
+ "narHash": "sha256-VSBAjjQGLKYG/8dpC/9V7/dLlimkUzdYcibDKjwnzDE=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "b2e813ada825ef491546ea81f42ef2d37ce71bf6",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000000..4142b7021f
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,27 @@
+{
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+
+ outputs = { self, nixpkgs, flake-utils }:
+ {
+ overlay = final: prev: {
+ musescore = prev.libsForQt5.callPackage.callPackage ./default.nix { };
+ };
+ } // flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs { inherit system; };
+ musescore = pkgs.libsForQt5.callPackage ./default.nix { };
+ in
+ {
+ packages = { inherit musescore; default = musescore; };
+ devShells.default = pkgs.mkShell
+ rec {
+ inputsFrom = [ musescore ];
+ buildInputs = [ pkgs.ffmpeg ];
+ nativeBuildInputs = with pkgs; [ cmake clang clang-tools ];
+ LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.ffmpeg ];
+ };
+ });
+}
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 22722ea9b4..ca323582a5 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -420,6 +420,8 @@ void App::applyCommandLineOptions(const CommandLineParser::Options& options, fra
#ifdef MUE_BUILD_IMPORTEXPORT_MODULE
audioExportConfiguration()->setExportMp3BitrateOverride(options.exportAudio.mp3Bitrate);
+ audioExportConfiguration()->setSplitVoices(options.exportSplit.splitVoices.value_or(false));
+ audioExportConfiguration()->setSoloStaffs(options.exportSplit.soloStaffs);
midiImportExportConfiguration()->setMidiImportOperationsFile(options.importMidi.operationsFile);
guitarProConfiguration()->setLinkedTabStaffCreated(options.guitarPro.linkedTabStaffCreated);
guitarProConfiguration()->setExperimental(options.guitarPro.experimental);
diff --git a/src/app/commandlineparser.cpp b/src/app/commandlineparser.cpp
index 7468abcf5a..293b8792fe 100644
--- a/src/app/commandlineparser.cpp
+++ b/src/app/commandlineparser.cpp
@@ -77,6 +77,9 @@ void CommandLineParser::init()
m_parser.addOption(QCommandLineOption("template-mode", "Save template mode, no page size")); // and no platform and creationDate tags
m_parser.addOption(QCommandLineOption({ "t", "test-mode" }, "Set test mode flag for all files")); // this includes --template-mode
+ m_parser.addOption(QCommandLineOption("split-voices", "Explode staff voices before exporting"));
+ m_parser.addOption(QCommandLineOption("solo-staff", "Make staff(s) louder than others"));
+
m_parser.addOption(QCommandLineOption("session-type", "Startup with given session type", "type")); // see StartupScenario::sessionTypeTromString
// Converter mode
@@ -231,6 +234,16 @@ void CommandLineParser::parse(int argc, char** argv)
}
}
+ if (m_parser.isSet("split-voices"))
+ {
+ m_options.exportSplit.splitVoices = true;
+ }
+
+ if (m_parser.isSet("solo-staff"))
+ {
+ m_options.exportSplit.soloStaffs = m_parser.values("solo-staff");
+ }
+
if (m_parser.isSet("template-mode")) {
m_options.notation.templateModeEnabled = true;
}
diff --git a/src/app/commandlineparser.h b/src/app/commandlineparser.h
index c0c03f4753..78134912dd 100644
--- a/src/app/commandlineparser.h
+++ b/src/app/commandlineparser.h
@@ -64,6 +64,12 @@ public:
std::optional<int> mp3Bitrate;
} exportAudio;
+ struct
+ {
+ std::optional<bool> splitVoices;
+ QStringList soloStaffs;
+ } exportSplit;
+
struct {
std::optional<std::string> resolution;
std::optional<int> fps;
diff --git a/src/converter/internal/convertercontroller.cpp b/src/converter/internal/convertercontroller.cpp
index 849d056c00..5713f1d82b 100644
--- a/src/converter/internal/convertercontroller.cpp
+++ b/src/converter/internal/convertercontroller.cpp
@@ -30,8 +30,13 @@
#include "io/dir.h"
#include "stringutils.h"
+// #include "async/async.h"
+// #include "async/asyncable.h"
#include "convertercodes.h"
#include "compat/backendapi.h"
+#include "dom/masterscore.h"
+#include "notation/imasternotation.h"
+// #include "audio/itracks.h"
#include "log.h"
@@ -68,30 +73,232 @@ mu::Ret ConverterController::fileConvert(const io::path_t& in, const io::path_t&
{
TRACEFUNC;
- LOGI() << "in: " << in << ", out: " << out;
- auto notationProject = notationCreator()->newProject();
- IF_ASSERT_FAILED(notationProject) {
- return make_ret(Err::UnknownError);
- }
-
std::string suffix = io::suffix(out);
+ auto dir = io::dirpath(out);
+ auto filenameNoExt = io::filename(out, false);
auto writer = writers()->writer(suffix);
- if (!writer) {
- return make_ret(Err::ConvertTypeUnknown);
- }
- Ret ret = notationProject->load(in, stylePath, forceMode);
- if (!ret) {
- LOGE() << "failed load notation, err: " << ret.toString() << ", path: " << in;
- return make_ret(Err::InFileFailedLoad);
+ LOGI() << "in: " << in << ", out: " << out;
+
+ String focusIns = {getenv("FOCUSINS")};
+ String quietIns = {getenv("QUIETINS")};
+
+ if (!QString(getenv("EXPLODE")).isEmpty())
+ {
+ auto notationProject = notationCreator()->newProject();
+ IF_ASSERT_FAILED(notationProject)
+ {
+ return make_ret(Err::UnknownError);
+ }
+
+ if (!writer)
+ {
+ return make_ret(Err::ConvertTypeUnknown);
+ }
+
+ Ret ret = notationProject->load(in, stylePath, forceMode);
+ if (!ret)
+ {
+ LOGE() << "failed load notation, err: " << ret.toString() << ", path: " << in;
+ return make_ret(Err::InFileFailedLoad);
+ }
+
+ globalContext()->setCurrentProject(notationProject);
+ mu::notation::IMasterNotationPtr master = notationProject->masterNotation();
+ mu::notation::INotationPtr notation = notationProject->masterNotation()->notation();
+ mu::engraving::MasterScore *score = notationProject->masterNotation()->masterScore();
+ mu::notation::INotationPartsPtr notationParts = notation->parts();
+
+ PartInstrumentList partList;
+ IDList originalIDs;
+ size_t idx = 0;
+ for (const auto *p : notationParts->partList())
+ {
+ originalIDs.emplace_back(p->id());
+ partList.append(PartInstrument{
+ .partId = p->id(),
+ .instrumentTemplate = instrumentsRepository()->instrumentTemplate("men"),
+ .isExistingPart = true,
+ .isSoloist = p->soloist(),
+ });
+ partList.append(PartInstrument{
+ .partId = notationParts->partList().size() + (idx++),
+ .instrumentTemplate = instrumentsRepository()->instrumentTemplate("men"),
+ .isExistingPart = false,
+ .isSoloist = p->soloist(),
+ });
+ }
+ master->parts()->setParts(partList, master->parts()->scoreOrder());
+
+ score->doLayout();
+
+#if 1
+ // Select all dynamics.
+ ElementPattern pattern;
+ pattern.type = int(ElementType::DYNAMIC);
+ pattern.subtype = 0;
+ pattern.staffStart = mu::nidx;
+ pattern.staffEnd = mu::nidx;
+ pattern.voice = mu::nidx;
+ pattern.system = 0;
+ pattern.subtypeValid = false;
+ pattern.durationTicks = Fraction(-1, 1);
+ score->scanElements(&pattern, score->collectMatch);
+ LOGI() << "SO MANY DYNAMICS " << pattern.el.size();
+ score->select(0, SelectType::SINGLE, 0);
+ score->select(pattern.el, SelectType::ADD, 0);
+ score->setUpdateAll();
+ score->update();
+ // And delete them.
+ score->startCmd();
+ score->cmdDeleteSelection();
+ score->endCmd();
+#endif
+
+ for (const auto &id : originalIDs)
+ {
+ // Select all.
+ mu::engraving::Selection sel(score);
+ const auto idx = score->staffIdx(score->partById(id));
+ sel.setRange(score->firstMeasureMM()->first(), score->lastMeasureMM()->last(), idx, idx + 1);
+ score->setSelection(sel);
+ score->setUpdateAll();
+ score->update();
+ // And explode them.
+ score->startCmd();
+ score->cmdExplode();
+ score->endCmd();
+ score->doLayout();
+ }
+
+ QStringList names;
+ for (const auto &id : originalIDs)
+ {
+ auto lg = notationParts->part(id)->longName();
+ auto pp = lg.toQString().split("\n");
+ names.append(pp);
+ }
+ LOGI() << "SPLIT NAMES ARE " << names;
+ if (size_t(names.size()) != notationParts->partList().size())
+ {
+ LOGI() << "Split name list " << names.size() << " does not match exploded part size " << notationParts->partList().size();
+ // globalContext()->setCurrentProject(nullptr);
+ // return make_ret(Ret::Code::UnknownError);
+ }
+
+#if 0
+ for (const auto *part : notationParts->partList())
+ {
+ for (const auto &ins : part->instrumentTrackIdList())
+ {
+ auto outP = notationProject->audioSettings()->trackOutputParams(ins);
+ outP.volume = 0.0;
+ outP.balance = 0.0;
+ outP.auxSends.clear();
+ notationProject->audioSettings()->setTrackOutputParams(ins, outP);
+ auto inP = notationProject->audioSettings()->trackInputParams(ins);
+ inP.resourceMeta.type = mu::audio::AudioResourceType::FluidSoundfont;
+ inP.resourceMeta.vendor = "Fluid";
+ inP.resourceMeta.id = focusIns.append(String("\0\0")).toStdString();
+ inP.resourceMeta.attributes.emplace(audio::synth::SOUNDFONT_NAME_ATTRIBUTE, focusIns);
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_NAME_ATTRIBUTE, focusIns);
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_BANK_ATTRIBUTE, "0");
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_PROGRAM_ATTRIBUTE, "0");
+ notationProject->audioSettings()->setTrackInputParams(ins, inP);
+ }
+ }
+#endif
+ notationProject->save(out.appendingSuffix("mscz"), SaveMode::Save);
}
+ else
+ {
+ auto notationProject = notationCreator()->newProject();
+ IF_ASSERT_FAILED(notationProject)
+ {
+ return make_ret(Err::UnknownError);
+ }
- globalContext()->setCurrentProject(notationProject);
+ Ret ret = notationProject->load(in, stylePath, forceMode);
+ if (!ret)
+ {
+ LOGE() << "failed load notation, err: " << ret.toString() << ", path: " << in;
+ return make_ret(Err::InFileFailedLoad);
+ }
- if (isConvertPageByPage(suffix)) {
- ret = convertPageByPage(writer, notationProject->masterNotation()->notation(), out);
- } else {
- ret = convertFullNotation(writer, notationProject->masterNotation()->notation(), out);
+ globalContext()->setCurrentProject(notationProject);
+ auto master = notationProject->masterNotation();
+ auto notation = notationProject->masterNotation()->notation();
+ auto score = notationProject->masterNotation()->masterScore();
+ auto notationParts = notation->parts();
+
+ QString focusRaw(getenv("FOCUS"));
+ QSet<size_t> focusIdx;
+ for (const auto &p : focusRaw.split(","))
+ {
+ focusIdx << p.toInt();
+ }
+
+ QString verbatimRaw(getenv("VERBATIM"));
+ QSet<size_t> verbatimIdx;
+ for (const auto &p : verbatimRaw.split(","))
+ {
+ verbatimIdx << p.toInt();
+ }
+
+ score->doLayout();
+ ElementPattern pattern;
+ pattern.type = int(ElementType::DYNAMIC);
+ pattern.subtype = 0;
+ pattern.staffStart = mu::nidx;
+ pattern.staffEnd = mu::nidx;
+ pattern.voice = mu::nidx;
+ pattern.system = 0;
+ pattern.subtypeValid = false;
+ pattern.durationTicks = Fraction(-1, 1);
+ score->scanElements(&pattern, score->collectMatch);
+ LOGI() << "SO MANY DYNAMICS " << pattern.el.size();
+ score->select(0, SelectType::SINGLE, 0);
+ score->select(pattern.el, SelectType::ADD, 0);
+ score->setUpdateAll();
+ score->update();
+ // And delete them.
+ score->startCmd();
+ score->cmdDeleteSelection();
+ score->endCmd();
+
+ size_t partIdx = 0;
+ for (const auto *part : notationParts->partList())
+ {
+ for (const auto &ins : part->instrumentTrackIdList())
+ {
+ if (verbatimIdx.contains(partIdx))
+ continue;
+ const bool isFocus = focusIdx.contains(partIdx);
+ auto outP = notationProject->audioSettings()->trackOutputParams(ins);
+ outP.volume = isFocus ? 0.0 : -6.0;
+ // outP.balance = isFocus ? +0.5 : -0.5;
+ outP.auxSends.clear();
+ notationProject->audioSettings()->setTrackOutputParams(ins, outP);
+ auto inP = notationProject->audioSettings()->trackInputParams(ins);
+ inP.resourceMeta.type = mu::audio::AudioResourceType::FluidSoundfont;
+ inP.resourceMeta.vendor = "Fluid";
+ inP.resourceMeta.id = (isFocus ? focusIns : quietIns).append(String("\0\0")).toStdString();
+ inP.resourceMeta.attributes.emplace(audio::synth::SOUNDFONT_NAME_ATTRIBUTE, isFocus ? focusIns : quietIns);
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_NAME_ATTRIBUTE, isFocus ? focusIns : quietIns);
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_BANK_ATTRIBUTE, "0");
+ inP.resourceMeta.attributes.emplace(audio::synth::PRESET_PROGRAM_ATTRIBUTE, "0");
+ notationProject->audioSettings()->setTrackInputParams(ins, inP);
+ }
+ partIdx++;
+ }
+ if (isConvertPageByPage(suffix))
+ {
+ ret = convertPageByPage(writer, notation, out);
+ }
+ else
+ {
+ ret = convertFullNotation(writer, notation, out);
+ }
}
globalContext()->setCurrentProject(nullptr);
diff --git a/src/converter/internal/convertercontroller.h b/src/converter/internal/convertercontroller.h
index 94d7e229f7..c9194f3551 100644
--- a/src/converter/internal/convertercontroller.h
+++ b/src/converter/internal/convertercontroller.h
@@ -31,6 +31,9 @@
#include "project/inotationwritersregister.h"
#include "project/iprojectrwregister.h"
#include "context/iglobalcontext.h"
+#include "notation/iinstrumentsrepository.h"
+#include "audio/isoundfontrepository.h"
+#include "audio/iplayback.h"
#include "types/retval.h"
@@ -41,6 +44,9 @@ class ConverterController : public IConverterController
INJECT(project::INotationWritersRegister, writers)
INJECT(project::IProjectRWRegister, projectRW)
INJECT(context::IGlobalContext, globalContext)
+ INJECT(notation::IInstrumentsRepository, instrumentsRepository)
+ INJECT(audio::ISoundFontRepository, soundFontRepository)
+ INJECT(audio::IPlayback, playback)
public:
ConverterController() = default;
diff --git a/src/importexport/audioexport/iaudioexportconfiguration.h b/src/importexport/audioexport/iaudioexportconfiguration.h
index 7c81ee1dc6..2ca23564fa 100644
--- a/src/importexport/audioexport/iaudioexportconfiguration.h
+++ b/src/importexport/audioexport/iaudioexportconfiguration.h
@@ -42,6 +42,12 @@ public:
virtual int exportSampleRate() const = 0;
virtual void setExportSampleRate(int rate) = 0;
virtual const std::vector<int>& availableSampleRates() const = 0;
+
+ virtual bool splitVoices() const = 0;
+ virtual void setSplitVoices(bool split) = 0;
+
+ virtual QStringList soloStaffs() const = 0;
+ virtual void setSoloStaffs(QStringList staffs) = 0;
};
}
diff --git a/src/importexport/audioexport/internal/audioexportconfiguration.cpp b/src/importexport/audioexport/internal/audioexportconfiguration.cpp
index fcdfb10616..ff0f40171b 100644
--- a/src/importexport/audioexport/internal/audioexportconfiguration.cpp
+++ b/src/importexport/audioexport/internal/audioexportconfiguration.cpp
@@ -72,3 +72,23 @@ const std::vector<int>& AudioExportConfiguration::availableSampleRates() const
static const std::vector<int> rates { 32000, 44100, 48000 };
return rates;
}
+
+bool AudioExportConfiguration::splitVoices() const
+{
+ return m_splitVoices;
+}
+
+void AudioExportConfiguration::setSplitVoices(bool split)
+{
+ m_splitVoices = split;
+}
+
+QStringList mu::iex::audioexport::AudioExportConfiguration::soloStaffs() const
+{
+ return m_soloStaffs;
+}
+
+void mu::iex::audioexport::AudioExportConfiguration::setSoloStaffs(QStringList staffs)
+{
+ m_soloStaffs = staffs;
+}
diff --git a/src/importexport/audioexport/internal/audioexportconfiguration.h b/src/importexport/audioexport/internal/audioexportconfiguration.h
index 85a00562df..e9b416911e 100644
--- a/src/importexport/audioexport/internal/audioexportconfiguration.h
+++ b/src/importexport/audioexport/internal/audioexportconfiguration.h
@@ -39,8 +39,16 @@ public:
void setExportSampleRate(int rate) override;
const std::vector<int>& availableSampleRates() const override;
+ virtual bool splitVoices() const override;
+ virtual void setSplitVoices(bool split) override;
+
+ virtual QStringList soloStaffs() const override;
+ virtual void setSoloStaffs(QStringList staffs) override;
+
private:
std::optional<int> m_exportMp3BitrateOverride = std::nullopt;
+ bool m_splitVoices = false;
+ QStringList m_soloStaffs;
};
}
--
2.41.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment