Skip to content

Add manual reassignment for MuseSounds Matches#33645

Closed
TrevorDogVH wants to merge 2 commits into
musescore:mainfrom
TrevorDogVH:muse-sounds-reassignment-detection-review
Closed

Add manual reassignment for MuseSounds Matches#33645
TrevorDogVH wants to merge 2 commits into
musescore:mainfrom
TrevorDogVH:muse-sounds-reassignment-detection-review

Conversation

@TrevorDogVH
Copy link
Copy Markdown

@TrevorDogVH TrevorDogVH commented May 30, 2026

Adds a manual Muse Sounds reassignment workflow for matching score instruments to available Muse Sounds resources.

Manual verification:

  • Score opens successfully.
  • Muse Sounds reassignment finds and applies expected matches.
  • Mixer opens and closes without crashing.
  • Playback works after entering a one-bar phrase, using the correct sounds.

Automated verification:

  • playback_test passed locally.
  • muse_ui_tests could not run in the Codex environment because no macOS screen was available.

Depends on companion muse_framework PR:
https://github.com/musescore/muse_framework/pulls?q=is%3Apr+author%3ATrevorDogVHPASTE_LINK_TO_THE_FIRST_PR_HEREResolves: #NNNNN

  • I signed the CLA
  • The title of the PR describes the problem it addresses
  • Each commit's message describes its purpose and effects, and references the issue it resolves
  • If changes are extensive, there is a sequence of easily reviewable commits
  • The code in the PR follows the coding rules
  • There are no unnecessary changes
  • The code compiles and runs on my machine, preferably after each commit individually
  • I created a unit test or vtest to verify the changes I made (if applicable)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements a Muse Sounds instrument reassignment feature that lets users match their notation instruments to available Muse Sounds candidates. The PlaybackController gains soundfont fallback logic and reassignment query/action APIs. A new MuseSoundsReassignModel loads available audio resources, scores candidates by matching against staff names and metadata, and applies selections. A new MuseSoundsReassignDialog presents an interactive list with dropdowns for candidate selection. The feature integrates into the existing sound profiles workflow via a button in SoundProfilesDialog. Supporting changes include UI scrollbar fixes in MixerPanel and ScoresGridView, a muse submodule update, and macOS codesigning for bundled Qt plugins.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning Pull request description is incomplete and contains multiple critical issues that prevent proper understanding and tracking of the changes. Complete all required template sections: (1) Replace placeholder 'Resolves: #NNNNN' with actual issue number, (2) Add proper summary of changes and motivation, (3) Check all applicable checklist items to indicate compliance, (4) Fix malformed framework PR link, (5) Ensure all checklist items are explicitly addressed before merge.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add manual reassignment for MuseSounds Matches' is specific, concise, and directly reflects the PR's primary objective of implementing a manual reassignment workflow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
src/playback/qml/MuseScore/Playback/MixerPanel.qml (1)

154-160: 💤 Low value

Consider documenting the tolerance threshold.

The 1-pixel tolerance check is a good optimization to prevent unnecessary position updates. However, a brief inline comment would help future maintainers understand why this threshold was chosen.

📝 Suggested documentation improvement
         let endY = Math.max(0, flickable.contentHeight - flickable.height)
+        // Skip positioning if already at end (within 1px tolerance)
         if (Math.abs(flickable.contentY - endY) < 1) {
             return
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/MixerPanel.qml` around lines 154 - 160,
Add a short inline comment explaining the 1-pixel tolerance used in the check
between flickable.contentY and endY (e.g., why Math.abs(... ) < 1 prevents tiny
flicking/rounding updates), and consider replacing the magic number with a named
constant (e.g., const TOLERANCE = 1) used in the comparison to make the intent
clearer in the block that sets flickable.contentY = endY.
src/playback/internal/playbackcontroller.cpp (1)

119-124: ⚖️ Poor tradeoff

Clarify why activeProfileName == museSoundsProfileName forces basic profile input.

In PlaybackController::doAddTrack, shouldAvoidMuseSamplerInput() is used only to choose inParams (track input source): when the active profile equals museSoundsProfileName, useBasicProfile becomes true and inParams is replaced with resources from basicSoundProfileName(). Track output params are still derived from the existing originParams, so the active Muse Sounds profile still applies to playback/output, while MIDI/input uses the basic profile.

The current predicate name doesn’t document this coupling; adding a short comment (or renaming) to explain why Muse Sounds active should imply “avoid MuseSampler input” would resolve the confusion.

src/playback/qml/MuseScore/Playback/musesoundsreassignmodel.cpp (1)

246-252: 💤 Low value

OK applies a candidate to every matched track by default.

selectedCandidateIndex defaults to 0, so any track that has at least one candidate but no current MuseSampler match will be silently reassigned to its top-ranked candidate when the user presses OK, with no per-row opt-out. If the intent is "only change what the user picked," consider adding a "keep current"/no-change option per row.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/musesoundsreassignmodel.cpp` around lines
246 - 252, The loop silently leaves choice.selectedCandidateIndex at its default
0 causing automatic reassignment; change the logic so selectedCandidateIndex is
initialized to a sentinel (e.g., -1) and only set to a concrete index when a
real match is detected (the code that compares
currentParams.resourceMeta.type/id to choice.candidates[i].resource.id inside
the for loop), and add a per-row "keep current"/no-change candidate in
choice.candidates or the UI so that when selectedCandidateIndex == -1 the OK
action skips that track instead of assigning the top-ranked candidate.
src/playback/qml/MuseScore/Playback/SoundProfilesDialog.qml (1)

250-250: 💤 Low value

Non-reactive enabled binding.

canReassignInstrumentsToMuseSounds() is a Q_INVOKABLE with no associated notify signal, so this binding evaluates once and won't refresh if availability changes while the dialog is open (e.g., after resources finish loading). If availability can change during the dialog's lifetime, expose it as a notifiable Q_PROPERTY instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/SoundProfilesDialog.qml` at line 250, The
binding uses the Q_INVOKABLE method canReassignInstrumentsToMuseSounds(), which
is non-notifiable so enabled is evaluated only once; change the model to expose
a notifiable Q_PROPERTY (e.g., bool canReassignInstrumentsToMuseSounds READ
canReassignInstrumentsToMuseSounds NOTIFY
canReassignInstrumentsToMuseSoundsChanged) with an accompanying signal
canReassignInstrumentsToMuseSoundsChanged and emit that signal when the
underlying availability changes, then update the QML usage to bind to
profilesListModel.canReassignInstrumentsToMuseSounds (the property) instead of
calling the method so the button enabled state reacts to runtime changes.
src/playback/qml/MuseScore/Playback/MuseSoundsReassignDialog.qml (1)

120-125: 💤 Low value

Transient empty-state flash while resources load.

load() resolves asynchronously, so on open hasChoices is initially false and this "No matching Muse Sounds were found…" message (and a disabled OK) is shown until buildChoices completes. Consider gating the empty-state on a loaded flag to avoid the brief misleading message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/MuseSoundsReassignDialog.qml` around
lines 120 - 125, Add a "loaded" flag and gate the empty-state and OK disabling
on it: initialize reassignModel.loaded = false before calling
reassignModel.load()/buildChoices, set reassignModel.loaded = true in the
.then/after the async load/buildChoices completes (or in its finished callback),
change the StyledTextLabel visible binding to visible: reassignModel.loaded &&
!reassignModel.hasChoices, and update any OK button disabled binding (where it
checks !reassignModel.hasChoices) to also include !reassignModel.loaded so the
empty message and disabled state only appear after loading completes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/macos_integration/CMakeLists.txt`:
- Around line 119-120: The CMake step ad-hoc-signs the nested library
(execute_process calling codesign on
"${the_appex_path}/Contents/MacOS/platforms/libqcocoa.dylib") but the packaging
script (buildscripts/packaging/macOS/package.sh) only re-signs the .appex
without --deep, so the ad-hoc signature can persist; fix by updating packaging
to either explicitly re-sign the nested libqcocoa.dylib with the real Developer
ID identity (the same style as the .appex sign, using the Developer ID
Application: MuseScore identity and entitlements.plist) or when signing the
.appex in package.sh add the --deep flag so the recursive signing overwrites the
ad-hoc signature; ensure the codesign invocation in package.sh mirrors the
runtime/options/entitlements usage used elsewhere so spctl/notarization sees the
proper Developer ID signature.

In `@src/playback/qml/MuseScore/Playback/soundprofilesmodel.cpp`:
- Around line 69-79: The method
SoundProfilesModel::reassignInstrumentsToMuseSounds appears unused; either wire
it into the dialog flow called by openMuseSoundsReassignDialog() (so the
dialog’s confirm/auto-apply action invokes
controller()->reassignInstrumentsToAvailableMuseSounds() via
SoundProfilesModel::reassignInstrumentsToMuseSounds() and then updates
m_activeProfile/m_currentlySelectedProfile and emits
activeProfileChanged()/currentlySelectedProfileChanged()), or remove the unused
method and any leftover references if the logic is intended to live elsewhere;
ensure canReassignInstrumentsToMuseSounds() remains the button enabled check
while the actual reassign work is triggered from the dialog confirm handler
(openMuseSoundsReassignDialog()) if you choose to keep the behavior.

In `@src/project/qml/MuseScore/Project/internal/ScoresPage/ScoresGridView.qml`:
- Line 123: Add an inline comment in ScoresGridView.qml next to the
ScrollBar.vertical: null line explaining why the vertical scrollbar was removed
(e.g., to avoid duplicate scroll chrome when the parent provides scrolling or to
enable touch/paging behavior) and what interaction replaces it; reference the
related StyledScrollBar usage in ScoresListView.qml so reviewers see the
intentional inconsistency; then verify and document (in the same comment) that
keyboard and focus-based scrolling still work (e.g., via arrow/page keys or
focus handling on the grid items) and note any required focus/keyboard handlers
that must remain or be added to allow discoverability and navigation of
off-viewport content.

---

Nitpick comments:
In `@src/playback/qml/MuseScore/Playback/MixerPanel.qml`:
- Around line 154-160: Add a short inline comment explaining the 1-pixel
tolerance used in the check between flickable.contentY and endY (e.g., why
Math.abs(... ) < 1 prevents tiny flicking/rounding updates), and consider
replacing the magic number with a named constant (e.g., const TOLERANCE = 1)
used in the comparison to make the intent clearer in the block that sets
flickable.contentY = endY.

In `@src/playback/qml/MuseScore/Playback/MuseSoundsReassignDialog.qml`:
- Around line 120-125: Add a "loaded" flag and gate the empty-state and OK
disabling on it: initialize reassignModel.loaded = false before calling
reassignModel.load()/buildChoices, set reassignModel.loaded = true in the
.then/after the async load/buildChoices completes (or in its finished callback),
change the StyledTextLabel visible binding to visible: reassignModel.loaded &&
!reassignModel.hasChoices, and update any OK button disabled binding (where it
checks !reassignModel.hasChoices) to also include !reassignModel.loaded so the
empty message and disabled state only appear after loading completes.

In `@src/playback/qml/MuseScore/Playback/musesoundsreassignmodel.cpp`:
- Around line 246-252: The loop silently leaves choice.selectedCandidateIndex at
its default 0 causing automatic reassignment; change the logic so
selectedCandidateIndex is initialized to a sentinel (e.g., -1) and only set to a
concrete index when a real match is detected (the code that compares
currentParams.resourceMeta.type/id to choice.candidates[i].resource.id inside
the for loop), and add a per-row "keep current"/no-change candidate in
choice.candidates or the UI so that when selectedCandidateIndex == -1 the OK
action skips that track instead of assigning the top-ranked candidate.

In `@src/playback/qml/MuseScore/Playback/SoundProfilesDialog.qml`:
- Line 250: The binding uses the Q_INVOKABLE method
canReassignInstrumentsToMuseSounds(), which is non-notifiable so enabled is
evaluated only once; change the model to expose a notifiable Q_PROPERTY (e.g.,
bool canReassignInstrumentsToMuseSounds READ canReassignInstrumentsToMuseSounds
NOTIFY canReassignInstrumentsToMuseSoundsChanged) with an accompanying signal
canReassignInstrumentsToMuseSoundsChanged and emit that signal when the
underlying availability changes, then update the QML usage to bind to
profilesListModel.canReassignInstrumentsToMuseSounds (the property) instead of
calling the method so the button enabled state reacts to runtime changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 004645f2-a979-4bed-83f7-6e942027a225

📥 Commits

Reviewing files that changed from the base of the PR and between 14757b2 and 2e86a01.

📒 Files selected for processing (18)
  • muse
  • src/macos_integration/CMakeLists.txt
  • src/playback/internal/playbackcontroller.cpp
  • src/playback/internal/playbackcontroller.h
  • src/playback/iplaybackcontroller.h
  • src/playback/playbackmodule.cpp
  • src/playback/qml/MuseScore/Playback/CMakeLists.txt
  • src/playback/qml/MuseScore/Playback/MixerPanel.qml
  • src/playback/qml/MuseScore/Playback/MuseSoundsReassignDialog.qml
  • src/playback/qml/MuseScore/Playback/SoundProfilesDialog.qml
  • src/playback/qml/MuseScore/Playback/musesoundsreassignmodel.cpp
  • src/playback/qml/MuseScore/Playback/musesoundsreassignmodel.h
  • src/playback/qml/MuseScore/Playback/soundprofilesmodel.cpp
  • src/playback/qml/MuseScore/Playback/soundprofilesmodel.h
  • src/playback/tests/mocks/playbackcontrollermock.h
  • src/project/qml/MuseScore/Project/internal/ScoresPage/ScoresGridView.qml
  • src/stubs/playback/playbackcontrollerstub.cpp
  • src/stubs/playback/playbackcontrollerstub.h

Comment on lines +119 to 120
execute_process(COMMAND codesign --force --sign - --timestamp=none \"${the_appex_path}/Contents/MacOS/platforms/libqcocoa.dylib\")
execute_process(COMMAND codesign --force --sign - --timestamp=none --options runtime --entitlements \"${CMAKE_CURRENT_SOURCE_DIR}/entitlements.plist\" \"${the_appex_path}\")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look at how the .appex / nested plugins are signed during packaging.
fd -t f 'package.sh' buildscripts | xargs -r rg -nC3 'codesign|--deep|libqcocoa|appex|--entitlements'
# Any other place that signs platform plugins?
rg -nC3 'libqcocoa|platforms' --glob '!**/*.dylib'

Repository: musescore/MuseScore

Length of output: 35656


Clarify packaging re-signing: ad-hoc libqcocoa.dylib may not be overwritten

CMake does ad-hoc signing of the bundled nested dylib before signing the .appex:

execute_process(COMMAND codesign --force --sign - --timestamp=none \"${the_appex_path}/Contents/MacOS/platforms/libqcocoa.dylib\")
execute_process(COMMAND codesign --force --sign - --timestamp=none --options runtime --entitlements \"${CMAKE_CURRENT_SOURCE_DIR}/entitlements.plist\" \"${the_appex_path}\")

In buildscripts/packaging/macOS/package.sh, the packaging step re-signs only the .appex with codesign ... -s "Developer ID Application: MuseScore" without --deep (and there’s no explicit re-sign of libqcocoa.dylib there); --deep is only used when re-signing the main app, followed by codesign --verify --deep --strict. That means the ad-hoc signature on libqcocoa.dylib could persist into the shipped bundle.

Ensure packaging either (a) re-signs the nested libqcocoa.dylib explicitly with the real Developer ID identity, or (b) re-signs the .appex recursively (via --deep) so the ad-hoc signature is overwritten; otherwise spctl/notarization may fail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/macos_integration/CMakeLists.txt` around lines 119 - 120, The CMake step
ad-hoc-signs the nested library (execute_process calling codesign on
"${the_appex_path}/Contents/MacOS/platforms/libqcocoa.dylib") but the packaging
script (buildscripts/packaging/macOS/package.sh) only re-signs the .appex
without --deep, so the ad-hoc signature can persist; fix by updating packaging
to either explicitly re-sign the nested libqcocoa.dylib with the real Developer
ID identity (the same style as the .appex sign, using the Developer ID
Application: MuseScore identity and entitlements.plist) or when signing the
.appex in package.sh add the --deep flag so the recursive signing overwrites the
ad-hoc signature; ensure the codesign invocation in package.sh mirrors the
runtime/options/entitlements usage used elsewhere so spctl/notarization sees the
proper Developer ID signature.

Comment on lines +69 to +79
void SoundProfilesModel::reassignInstrumentsToMuseSounds()
{
controller()->reassignInstrumentsToAvailableMuseSounds();

if (INotationProjectPtr project = context()->currentProject()) {
m_activeProfile = project->audioSettings()->activeSoundProfile().toQString();
m_currentlySelectedProfile = m_activeProfile;
emit activeProfileChanged();
emit currentlySelectedProfileChanged();
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find any caller of the auto-apply method (QML or C++)
rg -nP -C3 'reassignInstrumentsToMuseSounds\s*\(' -g '!**/soundprofilesmodel.*'

Repository: musescore/MuseScore

Length of output: 45


Potential dead code: SoundProfilesModel::reassignInstrumentsToMuseSounds()
SoundProfilesDialog.qml only calls openMuseSoundsReassignDialog() (the button action) and uses canReassignInstrumentsToMuseSounds() only for the button enabled state; the repo contains no other call sites for reassignInstrumentsToMuseSounds() beyond its definition (src/playback/qml/MuseScore/Playback/soundprofilesmodel.cpp:69-79). Wire it into the dialog/auto-apply flow or remove it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/playback/qml/MuseScore/Playback/soundprofilesmodel.cpp` around lines 69 -
79, The method SoundProfilesModel::reassignInstrumentsToMuseSounds appears
unused; either wire it into the dialog flow called by
openMuseSoundsReassignDialog() (so the dialog’s confirm/auto-apply action
invokes controller()->reassignInstrumentsToAvailableMuseSounds() via
SoundProfilesModel::reassignInstrumentsToMuseSounds() and then updates
m_activeProfile/m_currentlySelectedProfile and emits
activeProfileChanged()/currentlySelectedProfileChanged()), or remove the unused
method and any leftover references if the logic is intended to live elsewhere;
ensure canReassignInstrumentsToMuseSounds() remains the button enabled check
while the actual reassign work is triggered from the dialog confirm handler
(openMuseSoundsReassignDialog()) if you choose to keep the behavior.

visible: view.contentHeight > view.height
z: 2
}
ScrollBar.vertical: null
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare scrollbar patterns between list and grid views
echo "=== ScoresListView scrollbar ==="
rg -n 'ScrollBar\.vertical' src/project/qml/MuseScore/Project/internal/ScoresPage/ScoresListView.qml -A 5

echo -e "\n=== ScoresGridView scrollbar ==="
rg -n 'ScrollBar\.vertical' src/project/qml/MuseScore/Project/internal/ScoresPage/ScoresGridView.qml -A 5

Repository: musescore/MuseScore

Length of output: 557


Document rationale + confirm UX/accessibility after removing grid vertical scrollbar

  • ScoresGridView.qml sets ScrollBar.vertical: null (line 123), while ScoresListView.qml retains a StyledScrollBar (around lines 192-197), creating UI inconsistency without any in-code explanation.
  • Add an inline comment explaining why the grid should remove the scrollbar (and what problem/behavior it addresses or replaces).
  • Verify/discuss that users can still discover and navigate additional content beyond the viewport (including keyboard/focus scrolling) despite the missing scrollbar.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/project/qml/MuseScore/Project/internal/ScoresPage/ScoresGridView.qml` at
line 123, Add an inline comment in ScoresGridView.qml next to the
ScrollBar.vertical: null line explaining why the vertical scrollbar was removed
(e.g., to avoid duplicate scroll chrome when the parent provides scrolling or to
enable touch/paging behavior) and what interaction replaces it; reference the
related StyledScrollBar usage in ScoresListView.qml so reviewers see the
intentional inconsistency; then verify and document (in the same comment) that
keyboard and focus-based scrolling still work (e.g., via arrow/page keys or
focus handling on the grid items) and note any required focus/keyboard handlers
that must remain or be added to allow discoverability and navigation of
off-viewport content.

@TrevorDogVH
Copy link
Copy Markdown
Author

Resolves: N/A

Summary:
Adds a manual Muse Sounds reassignment workflow so users can match score instruments to available Muse Sounds candidates from the Sound Profiles dialog.

Changes:

  • Adds PlaybackController APIs to check for and apply available Muse Sounds reassignments.
  • Adds a MuseSoundsReassignDialog and MuseSoundsReassignModel for reviewing candidate matches.
  • Scores candidates using staff names, MuseSampler metadata, playback setup data, and MusicXML sound IDs.
  • Adds safer fallback behavior so scores can open with MS Basic when MuseSampler input parameters are not safe to use at load time.
  • Stabilizes related QML scroll areas that were crashing during score load and mixer updates.
  • Includes macOS bundle signing support for bundled Qt plugins used by Quick Look.

Manual verification:

  • Opened the app and score successfully.
  • Ran Muse Sounds reassignment and confirmed expected matches.
  • Opened and closed the mixer without crashing.
  • Entered a one-bar phrase and confirmed playback used the correct sounds.

Automated verification:

  • playback_test passed locally.
  • muse_ui_tests could not run in the Codex environment because no macOS screen was available.

Companion framework PR:
PASTE_THE_MUSE_FRAMEWORK_PR_LINK_HERE

@TrevorDogVH
Copy link
Copy Markdown
Author

Companion framework PR: https://github.com/musescore/muse_framework/pull/NUMBER

@mathesoncalum
Copy link
Copy Markdown
Contributor

Please read, understand, and complete the contributor checklist before opening a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants