Compare commits

...

159 Commits

Author SHA1 Message Date
Elnur Ismailzada 44e7ed9209
Merge pull request #15803 from Eism/videoconverter_ls_ts_4.0_rc
Added commands for video convert mode. RC
2023-01-10 16:25:40 +02:00
Eism 6b9052b2b9 Added ls and ts commands for video converter 2023-01-10 15:07:40 +02:00
Eism 542a3034ae Fixed force mode for comminde line 2022-12-26 15:38:33 +02:00
Eism 548562132f Temporary disabled youtube usage 2022-12-13 23:58:31 +02:00
pereverzev_v e9869aa88d Added upper bound check for MuseSampler's version 2022-12-13 18:18:11 +02:00
pereverzev_v 9dcd13144a Switched API calls onto new dedicated domain 2022-12-13 13:40:45 +02:00
Michele Spagnolo 24b8e34858 keySigEvent must be added also if in C 2022-12-09 17:26:19 +02:00
DmitryArefiev 2ada4e779d Merge pull request #15068 from RomanPudashkin/blank_vst_window_fix
[MU4] Fix #14963: VST effect window on Master channel becomes blank after re-opening sore during one MU session
2022-12-09 14:12:39 +02:00
pereverzev+v 1d3a5a8771 Merge pull request #15071 from cbjeukendrup/handbook_url
Update handbook URL
2022-12-09 14:12:29 +02:00
pereverzev+v 4da8e5ed18 Merge pull request #15057 from vpereverzev/vst_plugin_params_crash_fix
[MU4] vst_plugin_state_loading
2022-12-09 12:41:21 +02:00
Aaron Sattely 25266e98a5 only use stem-anchored slurs on stemThrough staves 2022-12-09 12:41:04 +02:00
pereverzev+v 2e2085eb5d Merge pull request #15022 from RomanPudashkin/crash_when_closing_score
crash_when_closing_score
2022-12-08 19:58:26 +02:00
pereverzev+v bab78a6f81 Merge pull request #15024 from cbjeukendrup/partName_longName
Default part name should now be longName instead of trackName
2022-12-08 17:36:14 +02:00
pereverzev+v 12ec72a7fe Merge pull request #14940 from RomanPudashkin/use_only_ms_basic_metronome_sound
use_only_ms_basic_metronome_sound
2022-12-08 17:35:31 +02:00
Elnur Ismailzada dbbf2ad8e7 Merge pull request #15041 from Eism/score_copy_drag_crash_fix
fixed #13364: Attempt to duplicate element result in program freezing/crashing (Linux only)
2022-12-08 17:35:26 +02:00
Michele Spagnolo dc67d6429f When replacing an instrument, update transposition only once 2022-12-08 15:55:53 +02:00
RomanPudashkin c9b9717951 Merge pull request #15010 from vpereverzev/note_input_delay
[MU4] note_input_delay
2022-12-08 15:55:41 +02:00
RomanPudashkin 65f14814b9 Merge pull request #15025 from cbjeukendrup/pdf_export_multisize_parts
Pdf export: fix page size when writing parts with different page sizes to single file
2022-12-08 15:55:37 +02:00
Elnur Ismailzada 5654eb1da0
Merge pull request #15035 from Eism/score_ctrl_drag_disable_rc
score_ctrl_drag_disable_rc
2022-12-08 09:34:56 +02:00
Eism 701184d894 reverted #8174: lasso list selection
Element-by-element selection operations (Ctrl+click and Ctrl+drag) don't work very well. Let's reduce their number.
2022-12-08 08:50:03 +02:00
pereverzev_v f23002aedf Prevent crash on read of ChordLine during the copy-paste action 2022-12-07 23:30:22 +02:00
RomanPudashkin 92b3462113 Merge pull request #14982 from mike-spa/fixShiftRarrowSystemLineEdit
Fix shift + rightArrow system line edit
2022-12-07 17:18:11 +02:00
DmitryArefiev 8e17b96de8 Merge pull request #15009 from Eism/inspector_texts_fix
fixed #14968: Selecting two voltas will result in deletion of text and "repeat list" number, leading to score is not playable anymore
2022-12-07 17:00:44 +02:00
DmitryArefiev 95179da691 Merge pull request #14990 from RomanPudashkin/disappeared_vst_fx
[MU4] Fix #14752: Changing volume faders causes VST effects to be removed
2022-12-07 16:10:30 +02:00
pereverzev_v 1c5e4eb077 Applying spanner articulations specific to a staff only to chords from that staff 2022-12-07 14:41:46 +02:00
pereverzev_v 3820cd5411 Respect note length when calculating pitch bend intervals
Fixed #14958
2022-12-07 14:41:41 +02:00
RomanPudashkin cb5a7a8475 Merge pull request #14978 from RomanPudashkin/crash_when_add_fret_diagram
[MU4] Fix #14977: Crash when adding fret diagram to a note
2022-12-07 14:41:34 +02:00
Roman Pudashkin a43001b591 fix #14896: do not play the selected note twice if we were unable to add a new note 2022-12-06 19:51:46 +02:00
DmitryArefiev 02e6f1fdcf Merge pull request #14839 from cbjeukendrup/metronome_dont_mute_by_solo_or_range_selection
Don't mute metronome by solo or range selection
2022-12-06 19:51:39 +02:00
DmitryArefiev 2df795a9d7 Merge pull request #14948 from RomanPudashkin/disable_chord_symbols_playback
[MU4] Fix #13271:  'Play chord symbols' option doesn't save 'sound off' state for next opened scores and next MU sessions
2022-12-06 19:51:34 +02:00
RomanPudashkin ebf26c28e7 Merge pull request #14842 from Jojo-Schmitz/beams_crash
Fix GH14840: Crash when there are 6 or more beams (i.e. beamed 256th notes or shorter)
2022-12-06 17:57:48 +02:00
RomanPudashkin 7cd27b0805 Merge pull request #14987 from musescore/revert-14862-seek_optimization
Revert "seek_optimization"
2022-12-06 17:35:44 +02:00
Elnur Ismailzada cd7f437b6e
Merge pull request #14989 from Eism/backend_use_gtk_fix_rc
backend_use_gtk_fix_rc
2022-12-06 16:54:36 +02:00
Eism cc1853ea39 Create splash screen only for editor mode 2022-12-06 16:11:44 +02:00
Eism 32570c870e Don't install theme if screen usage is disabled
Screen usage disabled in converter mode
2022-12-06 16:11:36 +02:00
pereverzev+v 19abc468ad Merge pull request #14981 from vpereverzev/audio_export_issues
[MU4] audio_export_issues
2022-12-06 15:50:17 +02:00
Elnur Ismailzada 40c5b42bbd
Merge pull request #14938 from Eism/help_urls_fix_rc
help_urls_fix_rc
2022-12-05 15:24:25 +02:00
RomanPudashkin d791118d7b
Merge pull request #14939 from Eism/mmrest_crash_fix_rc
mmrest_crash_fix_rc
2022-12-05 14:21:49 +02:00
Eism 57e5f382e0 fixed #14918: Fixed a crash when accessing explicitParent in MMRest::layout 2022-12-05 10:10:47 +02:00
Eism 5a8d6ea733 fixed #14931: Fixed urls 2022-12-05 10:09:14 +02:00
pereverzev_v d050fb0a2d Fixed an issue with audio export on MS_Basic 2022-12-02 23:30:35 +02:00
pereverzev+v 85598a7881 Merge pull request #14884 from vpereverzev/musesounds_mappings
[MU4] preparation_for_musesounds_mappings
2022-12-02 19:23:36 +02:00
pereverzev+v 9de702260e Merge pull request #14672 from asattely/box-in-a-box
Fix #14643 - Crash when opening score with nested boxes
2022-12-02 19:23:30 +02:00
pereverzev+v 7f989ff0ce Merge pull request #14601 from cbjeukendrup/mscore_errors
Add missing error dialogs that should be the result of MScore errors
2022-12-02 18:38:21 +02:00
pereverzev+v 28ff70f8fb Merge pull request #14788 from cbjeukendrup/fp
Fixes for "fp"-like and "sf"-like dynamics
2022-12-02 18:38:12 +02:00
Casper Jeukendrup 2fa6ad8bcd Reduce margins 2022-12-02 18:38:01 +02:00
Casper Jeukendrup 95a9ac3ff1 Adjust spacing of items in Playback Toolbar 2022-12-02 18:37:56 +02:00
RomanPudashkin 890dfd80ec Merge pull request #14892 from RomanPudashkin/allow-space-to-remove-hyphen_fix
fix #13200 - allow using space to remove hyphen
2022-12-02 18:09:31 +02:00
RomanPudashkin 98a738855c Merge pull request #14889 from Eism/learn_hide_advanced_tab
fixed #14886: Hide 'Advanced' tab in 'Learn' section
2022-12-02 17:56:24 +02:00
Elnur Ismailzada 9f5e9f34d0 Merge pull request #14139 from cbjeukendrup/text_clipping
Fix various text clipping issues
2022-12-02 17:56:19 +02:00
RomanPudashkin 34b69c9a2f Merge pull request #14603 from cbjeukendrup/harmony_play_when_created
Play chord symbol after creating/editing and fix assertion failure
2022-12-02 12:57:15 +02:00
Michele Spagnolo 973a9a47ec Fix insert measure before MMRest 2022-12-02 12:56:52 +02:00
pereverzev_v b5a1133c6e Restored missing mapping id for electric guitar 2022-12-02 10:43:26 +02:00
RomanPudashkin a1bbe6487a Merge pull request #14561 from cbjeukendrup/default_page_size
Set default page size based on locale
2022-12-02 10:43:19 +02:00
pereverzev_v a988b5c549 Increased duration of staccato and staccatissimo notes for strings 2022-12-02 00:29:22 +02:00
pereverzev_v d7782c2413 Considering arpeggio's stretch during the rendering 2022-12-02 00:29:17 +02:00
RomanPudashkin d63f0cc1b3
Merge pull request #14870 from Eism/update_linux_fix_rc
update_linux_fix_rc
2022-12-01 18:29:29 +02:00
RomanPudashkin f9d4900da0
Merge pull request #14869 from RomanPudashkin/crash_after_export_rc
crash_after_export_rc
2022-12-01 18:29:13 +02:00
Michele Spagnolo 551fc83c6b Don't write undefined size and family property 2022-12-01 18:28:45 +02:00
Michele Spagnolo 0fbf0281ab Check if string contains custom formatting and set UNSTYLED 2022-12-01 18:28:45 +02:00
Michele Spagnolo e8cea477ab Fixing lost text formatting on copy/paste, save/reload
...and additional problems with styleChanged() command caused by incorrect UNSTYLED flag setting
2022-12-01 18:28:45 +02:00
Elnur Ismailzada 78350f8d80 Merge pull request #14850 from Eism/update_linux_fix
[MU4] Checking update on Linux
2022-12-01 16:58:29 +02:00
Roman Pudashkin 40dee9a240 fixed multiple crashes when creating a part and adding new instruments to it:
1. do not destroy bracket items inside ~Staff(): they will be deleted when DummyElement is deleted
2. use the correct score for the added part instead of using the main score
2022-12-01 16:55:09 +02:00
Roman Pudashkin b83262b669 removed some annoying logs 2022-12-01 16:54:52 +02:00
Roman Pudashkin c938c281c9 fix a crash when creating an excerpt and then deleting it via ctrl+z
1. we will now update m_potentialExcerpts every time there is any change in the excerpts list of the main score (to avoid storing irrelevant potential excerpts)

2. we will not recreate all items in m_potentialExcerpts every time. Only new ones will be created
2022-12-01 16:54:44 +02:00
Roman Pudashkin 02fa60e839 optimization: init excerpts only if the user confirms the export 2022-12-01 16:54:35 +02:00
Roman Pudashkin 262ccb2028 fixed a massive memory leak if the user exports parts that they have not yet opened. Such parts won't be added to the master score, but will be inited and filled with elements 2022-12-01 16:54:28 +02:00
Roman Pudashkin cea5f9b6c6 fix #13805: update m_parent when using setScore to ensure proper memory management 2022-12-01 16:54:19 +02:00
Casper Jeukendrup bcc69e95f8 Update name of cloud project when it has been renamed on MuseScore.com 2022-12-01 16:35:02 +02:00
Casper Jeukendrup d2635ec790 Fix name when saving project to cloud after re-opening
Should be filename, not work title
2022-12-01 16:34:54 +02:00
Roman Pudashkin df5498313a minor optimization 2022-12-01 15:43:54 +02:00
RomanPudashkin 2ec580f288 Merge pull request #14814 from Eism/shortcuts_find_macos_fix
fixed #14184 and #14585: Insert key instead of F on macOS
2022-12-01 14:36:50 +02:00
DmitryArefiev fe562d71b8 Merge pull request #14852 from RomanPudashkin/wrong_transposition_range
[MU4] Fix #14847: Replacing instrument affects instrument change with transposed instrument
2022-12-01 14:16:13 +02:00
pereverzev_v 805f1c1087 Added support of multi-voice playback for FluidSynth 2022-12-01 14:16:07 +02:00
Casper Jeukendrup acc57e2d5b LanguagesService: redirect short language codes to longer codes that we do have
For some languages, we only have long, specific codes in LanguagesHash / languages.json. If the user's system language is just "en", or "en_CY" for example, this will not be found. So, for short codes that are at risk, we map them to long codes that we do have.
2022-12-01 13:39:33 +02:00
jeetee cbba750a10 fix #13357 leading zeros on video duration 2022-12-01 13:39:33 +02:00
Marc Sabatella a1874b3a29 Fix scaling & offset of add/sus/no/omit 2022-12-01 13:39:33 +02:00
Marc Sabatella 3b71ff3b16 Fix chord symbol style file filter 2022-12-01 13:39:33 +02:00
Elnur Ismailzada 239f96a643
Merge pull request #14860 from Eism/win_workflow_fix
[MU4] RC. Fixed win workflow
2022-12-01 11:16:03 +02:00
Eism 3d9d3d4d41 Was missed after resolving conflicts on #14844 2022-12-01 10:31:21 +02:00
RomanPudashkin 4e334b10dd
Merge pull request #14855 from RomanPudashkin/update_4.0_rc
update_4.0_rc
2022-11-30 23:08:33 +02:00
RomanPudashkin 88a494cfb4
Merge pull request #14853 from cbjeukendrup/audio_export_no_solo_selection_4.0_rc
[MU4 RC] Don't solo selected tracks in audio export + fix exporting parts
2022-11-30 21:07:47 +02:00
Michele Spagnolo 7836c0f5d0 Fix beam glitch 2022-11-30 21:02:51 +02:00
Aaron Sattely eee1c1cd84 nullcheck in findLinkedVoiceElement 2022-11-30 20:57:51 +02:00
Roman Pudashkin 707e5852c7 fixed the chord symbol sound for string instruments 2022-11-30 20:57:31 +02:00
Roman Pudashkin 02945cbf12 fix #13327: use the standard articulation for chord symbols to ensure correct velocity calculation 2022-11-30 20:57:19 +02:00
Hemant Antony 1a023ff2d5 Fix #14807: Hide Count-in option 2022-11-30 20:56:53 +02:00
Casper Jeukendrup 1209e0b0ec
Let's try without the `setExportedNotation` method 2022-11-30 19:07:54 +01:00
Casper Jeukendrup 67cfccc028
Fix exporting audio for part scores 2022-11-30 19:07:54 +01:00
Casper Jeukendrup 458dca54fb
Don't solo selected staves during audio export 2022-11-30 19:07:53 +01:00
pereverzev_v 04c04001d7 Decreased the minimum interval between adjacent 2022-11-30 20:06:00 +02:00
RomanPudashkin 1431b58233 Merge pull request #14822 from Eism/volta_crash_fix
fixed #14685: Crash when opening one-measure score with 2nd ending assigned
2022-11-30 20:05:45 +02:00
RomanPudashkin f57122f224 Merge pull request #14804 from RomanPudashkin/change_instrument_fix
[MU4] Fix #14722: Incorrect transposition when changing from one transposing instrument to another
2022-11-30 20:05:03 +02:00
Elnur Ismailzada 9cfe34a1d5
Merge pull request #14844 from Eism/rc_nightly_rc
[MU4] Added triggering workflows for building 4.0_rc branch. RC
2022-11-30 14:26:43 +02:00
Eism 9f8c23b254 Checkout for 4.0_rc 2022-11-30 13:10:36 +02:00
pereverzev_v fe8a2de4c8 Brought back internal buffer capacity 2022-11-29 19:17:24 +02:00
RomanPudashkin c4977d4381
Merge pull request #14827 from cbjeukendrup/inspector_stemless_4.0_rc
[MU4 RC] Inspector: Fix the "Stemless" property
2022-11-29 16:39:12 +02:00
RomanPudashkin a4b5fed825 Merge pull request #14812 from cbjeukendrup/macOS_alt_characters
macOS: fix typing Option-key characters in Chord Symbols, Figured Bass, Fingering, Lyrics and Sticking
2022-11-29 15:54:06 +02:00
Casper Jeukendrup 6014da2192 Fix some other cases of overlapping notes
- for groups of tied notes where one or more notes were under a triplet
- for "cross-measure" notation
2022-11-29 15:26:54 +02:00
Casper Jeukendrup f745355e94
Inspector: Fix the "Stemless" property
It is a property of the chord rather than the stem, so we need a ChordSettingsModel.
2022-11-29 14:22:35 +01:00
pereverzev_v 7abe56a213 Allowing to enter into LowLatency mode only for buffer sizes lesser than supported upper bound 2022-11-29 14:06:17 +02:00
pereverzev_v 9e37717e15 Properly clear events after tempo changes 2022-11-28 23:46:42 +02:00
RomanPudashkin 6e5c4dc8e3 Merge pull request #14802 from sammik/instrument-change-fixes
fix Instrument change from palette
2022-11-28 22:34:31 +02:00
RomanPudashkin e74b6f308f Merge pull request #14799 from RomanPudashkin/update_sample_rate_in_liblame
[MU4] Fix #14662: Wrong pitch in exported audio file after changing Export sample rate settings (changing settings doesn't apply properly)
2022-11-28 22:28:16 +02:00
pereverzev_v dadc7d92cf Fixed #14093 2022-11-28 22:25:52 +02:00
RomanPudashkin 06b8692dec
Merge pull request #14761 from cbjeukendrup/🍒/4.0_rc/two_trivial_string_change_prs
[MU4 RC] Cherry-picking two trivial string change PRs
2022-11-28 10:38:16 +02:00
RomanPudashkin fdbd087461 Merge pull request #14781 from vpereverzev/tuplets_rendering
[MU4] tuplets_rendering
2022-11-27 19:44:14 +02:00
Peter Jonas 365446e370
Instruments: fix names of F and G soprano ocarinas
The trackName should not include the F or G tuning. This is added
separately in the traitName.

Now the F and G soprano ocarinas will be combined with the other
soprano ocarinas in the NSW and Instruments dialog.
2022-11-27 12:31:10 +01:00
Grzegorz Pruchniakowski 1ddc154484
Fix: Beam types -> Beam type
The first argument: should be "Beam type" because we select beam type, not types. The second argument: "types" occurs only once in strings to translate - only in this case.

Greetings,
Gootector
2022-11-27 12:31:09 +01:00
RomanPudashkin b43a6ec5a0
Merge pull request #14772 from RomanPudashkin/select_key_time_sig_fix_rc
select_key_time_sig_fix_rc
2022-11-26 18:01:09 +02:00
pereverzev_v e17bc32e88 Fixed #14634 2022-11-26 16:24:36 +02:00
Roman Pudashkin 5f171c5f6d fix #14769: added missing SelectType::ADD 2022-11-26 09:53:25 +02:00
Roman Pudashkin 54976734b4 introduced SoundSubCategory::Primary and SoundSubCategory::Secondary. For example, they can be used to differentiate the sound between Flute 1 and Flute 2 (or Violin 1 and Violin 2) 2022-11-25 19:05:43 +02:00
Roman Pudashkin ff1999223a don't treat OPE_OK as an error 2022-11-25 19:05:43 +02:00
Roman Pudashkin 149ea72df8 always restore the audio engine mode, even if something went wrong 2022-11-25 19:05:43 +02:00
Casper Jeukendrup 427f872221 Ensure the user is logged in when saving an existing cloud score 2022-11-25 19:05:43 +02:00
Roman Pudashkin f3168db80b more optimizations 2022-11-25 19:05:43 +02:00
Roman Pudashkin 84b26667a3 fix #14582: fixed massive memory leaks when selecting a range 2022-11-25 19:05:43 +02:00
Michele Spagnolo 6596497e7d Fix crash with invalid staff indices 2022-11-25 19:05:43 +02:00
Eism b942cc8ed0 Implemented progress dialog for uploading the score 2022-11-25 19:05:43 +02:00
Igor Korsukov a0de6dc41b fixed some crashes 2022-11-25 19:05:43 +02:00
Michele Spagnolo 5e8eb895c2 Make loop exit condition safer
(if the last segment was accidentally skipped, the equality was missed and we didn't exit the loop)
2022-11-25 19:05:43 +02:00
Michele Spagnolo c241032b8b Fix MM rest crash when doing ctrl+Z 2022-11-25 19:05:43 +02:00
RomanPudashkin 2409b8a330
Merge pull request #14747 from shoogle/instrument-bell-tree-4.0_rc
[MU4 RC] Add new instrument: Bell Tree
2022-11-25 17:17:08 +02:00
Peter Jonas 818bd2a763 Use Belltree MIDI drum sound for the Bell Tree and Mark Tree
The Mark Tree has no dedicated sound in General MIDI or Roland GS, so
we use the Belltree sound for it instead (drum note 84).
2022-11-25 14:28:22 +00:00
Peter Jonas 64e5086467 instruments.xml: Add Bell Tree and Mark Tree instruments
Run share/instruments/update_instruments_xml.py to fetch the latest
version of the online spreadsheet, which now contains the Bell Tree
and Mark Tree instruments.

https://en.wikipedia.org/wiki/Bell_tree
https://en.wikipedia.org/wiki/Mark_tree
2022-11-25 14:28:22 +00:00
pereverzev_v 3eb411716f Fixed a crash in exportdialogmodel 2022-11-25 14:53:37 +02:00
pereverzev_v 0ed7932801 Introduced TaskScheduler and parallelized audio sources rendering before mixing 2022-11-25 14:53:31 +02:00
RomanPudashkin a4675ee803
Merge pull request #14696 from RomanPudashkin/tremolo_mappings_rc
tremolo_mappings_rc
2022-11-23 20:39:31 +02:00
Roman Pudashkin 33498f043c fix #14527 2022-11-23 19:36:32 +02:00
Roman Pudashkin 69e21a5ee6 fix #14061: fixed the tremolo sound for string instruments 2022-11-23 19:36:19 +02:00
Roman Pudashkin f5a95dd0e1 introduced mpe::SoundSubCategory::Plucked 2022-11-23 19:36:10 +02:00
pereverzev_v 0fe713fe5a Added audio buffer profiler 2022-11-23 13:10:37 +02:00
pereverzev_v cd0626cce6 Fixed compilation errors for gcc and clang 2022-11-23 13:10:32 +02:00
pereverzev_v 14d66858ea Cleaned up redundant includes of IAudioBuffer 2022-11-23 13:10:28 +02:00
pereverzev_v 4ec9de79bc Proper number of channels for SineSource 2022-11-23 13:10:25 +02:00
pereverzev_v 82240d807b Added call of MuseSampler::allNotesAff to flush sounds 2022-11-23 13:10:22 +02:00
pereverzev_v cb75da2b3b Making audio devices sorting at model, not at audio driver itself 2022-11-23 13:10:19 +02:00
pereverzev_v 580307d973 Fixed issue with audio export launching when playback is running 2022-11-23 13:10:15 +02:00
pereverzev_v 5ec90f8827 Decoupled logic from AudioModule::init 2022-11-23 13:10:12 +02:00
pereverzev_v 74fb76bae0 Get rid of IAudioBuffer interface 2022-11-23 13:10:08 +02:00
pereverzev_v b65574ea33 Implemented lock-free audio-buffer 2022-11-23 13:10:05 +02:00
pereverzev_v aba024eda0 Implemented WASAPI audio driver 2022-11-23 13:10:01 +02:00
RomanPudashkin f0aa06f3ad
Merge pull request #14660 from RomanPudashkin/crash_after_copy_and_paste_notes_with_tremolo_rc
[MU4 RC] fix #14600: Crash when pasting a two-note tremolo that is too long to fit the bar
2022-11-22 15:21:23 +02:00
Roman Pudashkin 4474b20d99 fix #14600: tremolo must always have a second chord 2022-11-22 14:25:08 +02:00
RomanPudashkin d21ebb58fb
Merge pull request #14636 from RomanPudashkin/crash_when_inserting_new_measures_rc
[MU4 RC] Fix #14597: Crash when appending measures to new score
2022-11-22 09:59:01 +02:00
RomanPudashkin 2c14fae122
Merge pull request #14647 from cbjeukendrup/🍒/4.0_rc/crash_ctrl_drag_grip
[MU4 RC] Fix crash when Ctrl+dragging a grip if you also hit the element when hitting the grip
2022-11-22 08:32:55 +02:00
Casper Jeukendrup d4c4e6f6dc
Re-add MS3 hack for dragging barlines with Ctrl pressed 2022-11-22 00:58:37 +01:00
Casper Jeukendrup 02354e514a
Respect shift/ctrl modifiers when dragging grip (rather than whole element) 2022-11-22 00:58:37 +01:00
Casper Jeukendrup ff380a0958
Fix Ctrl+click to deselect one element from a range selection 2022-11-22 00:58:36 +01:00
Casper Jeukendrup 737f3d3b4b
Fix crash when Ctrl+dragging a grip if you also hit the element when hitting the grip
The element was unexpectedly deselected by Ctrl+MouseDown.
2022-11-22 00:58:36 +01:00
RomanPudashkin 1279972e0b
Merge pull request #14641 from asattely/explode-crash
fix underflow error in cmdExplode
2022-11-21 19:26:05 +02:00
RomanPudashkin 172169ea80
Merge pull request #14640 from RomanPudashkin/select_brackets_fix_rc
select_brackets_fix_rc
2022-11-21 19:08:35 +02:00
Roman Pudashkin 40c7901b41 fix #11883: use the dummy item for all brackets when destroying their original BracketItem to avoid invalid pointers 2022-11-21 18:09:46 +02:00
Roman Pudashkin 0ca2295793 fix #13870: reverted changes from PR #12697 2022-11-21 18:09:36 +02:00
Roman Pudashkin c76f4e72ab fix #14597: update the repeat lists after deleting all measures 2022-11-21 18:06:55 +02:00
RomanPudashkin 1e44ca6969
Merge pull request #14639 from RomanPudashkin/rc_ci_checks
rc_ci_checks
2022-11-21 18:04:50 +02:00
Roman Pudashkin d2afb72dab run the CI checks for PRs into 4.0_rc 2022-11-21 17:23:10 +02:00
Aaron Sattely f217faaf1d fix underflow error in cmdExplode 2022-11-20 19:50:50 -05:00
265 changed files with 4805 additions and 1631 deletions

View File

@ -4,6 +4,7 @@ on:
pull_request:
branches:
- master
- 4.0_rc
jobs:
codestyle:

View File

@ -4,9 +4,11 @@ on:
pull_request:
branches:
- master
- 4.0_rc
schedule:
- cron: '0 4 */1 */1 *' # At 04:00 on every day-of-month
schedule:
- cron: '0 3 */1 */1 *' # At 03:00 on every day-of-month for master
- cron: '0 5 */1 */1 *' # At 05:00 on every day-of-month for 4.0_rc
workflow_dispatch:
inputs:
build_mode:
@ -30,8 +32,14 @@ jobs:
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
- name: Clone repository
- name: Clone repository (default)
uses: actions/checkout@v2
if: ${{ github.event_name != 'schedule' || github.event.schedule == '0 3 */1 */1 *' }}
- name: Clone repository (4.0_rc)
uses: actions/checkout@v2
if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 5 */1 */1 *' }}
with:
ref: 4.0_rc
- name: Ccache cache files
uses: actions/cache@v2
with:
@ -101,8 +109,10 @@ jobs:
DO_PUBLISH='false'
fi
if [ "${{ github.event_name }}" == "pull_request" ]; then PR_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Lin${PR_INFO}")"
ADD_INFO="_${GITHUB_REF#refs/heads/}"
if [ "${{ github.event_name }}" == "schedule" && "${{ github.event.schedule }}" == "0 5 */1 */1 *" }} ]; then ADD_INFO="_4.0_rc"; fi
if [ "${{ github.event_name }}" == "pull_request" ]; then ADD_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Lin${ADD_INFO}")"
echo "github.repository: ${{ github.repository }}"
echo "BUILD_MODE=$BUILD_MODE" >> $GITHUB_ENV

View File

@ -4,9 +4,11 @@ on:
pull_request:
branches:
- master
- 4.0_rc
schedule:
- cron: '0 4 */1 */1 *' # At 04:00 on every day-of-month
schedule:
- cron: '0 3 */1 */1 *' # At 03:00 on every day-of-month for master
- cron: '0 5 */1 */1 *' # At 05:00 on every day-of-month for 4.0_rc
workflow_dispatch:
inputs:
build_mode:
@ -33,8 +35,14 @@ jobs:
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
- name: Clone repository
- name: Clone repository (default)
uses: actions/checkout@v2
if: ${{ github.event_name != 'schedule' || github.event.schedule == '0 3 */1 */1 *' }}
- name: Clone repository (4.0_rc)
uses: actions/checkout@v2
if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 5 */1 */1 *' }}
with:
ref: 4.0_rc
- name: Ccache cache files
uses: actions/cache@v2
with:
@ -118,8 +126,10 @@ jobs:
DO_PUBLISH='false'
fi
if [ "${{ github.event_name }}" == "pull_request" ]; then PR_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Mac${PR_INFO}")"
ADD_INFO="_${GITHUB_REF#refs/heads/}"
if [ "${{ github.event_name }}" == "schedule" && "${{ github.event.schedule }}" == "0 5 */1 */1 *" }} ]; then ADD_INFO="_4.0_rc"; fi
if [ "${{ github.event_name }}" == "pull_request" ]; then ADD_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Mac${ADD_INFO}")"
echo "github.repository: ${{ github.repository }}"
echo "BUILD_MODE=$BUILD_MODE" >> $GITHUB_ENV

View File

@ -4,6 +4,7 @@ on:
pull_request:
branches:
- master
- 4.0_rc
jobs:
run_tests:

View File

@ -4,6 +4,7 @@ on:
pull_request:
branches:
- master
- 4.0_rc
jobs:
setup:

View File

@ -4,8 +4,11 @@ on:
pull_request:
branches:
- master
schedule:
- cron: '0 4 */1 */1 *' # At 04:00 on every day-of-month
- 4.0_rc
schedule:
- cron: '0 3 */1 */1 *' # At 03:00 on every day-of-month for master
- cron: '0 5 */1 */1 *' # At 05:00 on every day-of-month for 4.0_rc
workflow_dispatch:
inputs:
build_mode:
@ -29,10 +32,17 @@ jobs:
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
- name: Clone repository
- name: Clone repository (default)
uses: actions/checkout@v2
if: ${{ github.event_name != 'schedule' || github.event.schedule == '0 3 */1 */1 *' }}
with:
fetch-depth: 3
- name: Clone repository (4.0_rc)
uses: actions/checkout@v2
if: ${{ github.event_name == 'schedule' && github.event.schedule == '0 5 */1 */1 *' }}
with:
fetch-depth: 3
ref: 4.0_rc
- name: Fetch submodules
run: |
git submodule update --init --recursive
@ -97,8 +107,10 @@ jobs:
DO_PUBLISH='false'
fi
if [ "${{ github.event_name }}" == "pull_request" ]; then PR_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Win${PR_INFO}")"
ADD_INFO="_${GITHUB_REF#refs/heads/}"
if [ "${{ github.event_name }}" == "schedule" && "${{ github.event.schedule }}" == "0 5 */1 */1 *" }} ]; then ADD_INFO="_4.0_rc"; fi
if [ "${{ github.event_name }}" == "pull_request" ]; then ADD_INFO="_${{ github.event.pull_request.number }}_${pull_request_title}"; fi
UPLOAD_ARTIFACT_NAME="$(tr '":<>|*?/\\' '_' <<<"MU4_${BUILD_NUMBER}_Win${ADD_INFO}")"
echo "github.repository: ${{ github.repository }}"
echo "BUILD_MODE=$BUILD_MODE" >> $GITHUB_ENV

View File

@ -4,6 +4,7 @@ on:
pull_request:
branches:
- master
- 4.0_rc
jobs:
run_tests:

View File

@ -1153,7 +1153,7 @@
</Instrument>
<Instrument id="g-soprano-ocarina">
<family>ocarinas</family>
<trackName>G Soprano Ocarina</trackName>
<trackName>Soprano Ocarina</trackName>
<longName>G Soprano Ocarina</longName>
<shortName>G S. Oc.</shortName>
<traitName type="tuning">G</traitName>
@ -1171,7 +1171,7 @@
</Instrument>
<Instrument id="f-soprano-ocarina">
<family>ocarinas</family>
<trackName>F Soprano Ocarina</trackName>
<trackName>Soprano Ocarina</trackName>
<longName>F Soprano Ocarina</longName>
<shortName>F S. Oc.</shortName>
<traitName type="tuning">F</traitName>
@ -7532,6 +7532,33 @@
<program value="0"/> <!--Standard Kit-->
</Channel>
</Instrument>
<Instrument id="bell-tree">
<family>unpitched-metal-percussion</family>
<trackName>Bell Tree</trackName>
<longName>Bell Tree</longName>
<shortName>Be. Tr.</shortName>
<description>Inverted metal bowls nested on a vertical rod in order of pitch. The pitches are indefinite.</description>
<musicXMLid>metal.bells.bell-tree</musicXMLid>
<clef>PERC</clef>
<stafftype staffTypePreset="perc1Line">percussion</stafftype>
<barlineSpan>1</barlineSpan>
<drumset>1</drumset>
<singleNoteDynamics>0</singleNoteDynamics>
<Drum pitch="84"> <!--Belltree-->
<head>normal</head>
<line>0</line>
<voice>0</voice>
<name>Glissando Down</name>
<stem>1</stem>
<shortcut>A</shortcut>
</Drum>
<Channel>
<!--MIDI: Bank 128, Prog 0; MS General: Standard-->
<controller ctrl="0" value="1"/> <!--Bank MSB-->
<program value="0"/> <!--Standard Kit-->
</Channel>
<genre>world</genre>
</Instrument>
<Instrument id="bells">
<family>unpitched-metal-percussion</family>
<trackName>Bells</trackName>
@ -7817,6 +7844,33 @@
<program value="0"/> <!--Standard Kit-->
</Channel>
</Instrument>
<Instrument id="mark-tree">
<family>unpitched-metal-percussion</family>
<trackName>Mark Tree</trackName>
<longName>Mark Tree</longName>
<shortName>Mk. Tr.</shortName>
<description>Chimes hung from a horizontal bar in order of pitch. The pitches are indefinite.</description>
<musicXMLid>metal.bells.mark-tree</musicXMLid>
<clef>PERC</clef>
<stafftype staffTypePreset="perc1Line">percussion</stafftype>
<barlineSpan>1</barlineSpan>
<drumset>1</drumset>
<singleNoteDynamics>0</singleNoteDynamics>
<Drum pitch="84"> <!--Belltree-->
<head>normal</head>
<line>0</line>
<voice>0</voice>
<name>Glissando Down</name>
<stem>1</stem>
<shortcut>A</shortcut>
</Drum>
<Channel>
<!--MIDI: Bank 128, Prog 0; MS General: Standard-->
<controller ctrl="0" value="1"/> <!--Bank MSB-->
<program value="0"/> <!--Standard Kit-->
</Channel>
<genre>world</genre>
</Instrument>
<Instrument id="metal-castanets">
<family>unpitched-metal-percussion</family>
<trackName>Metal Castanets</trackName>

View File

@ -596,26 +596,26 @@ QT_TRANSLATE_NOOP3("engraving/instruments", "Contrabass Recorder", "contrabass-r
//: shortName for Contrabass Recorder; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Cb. Rec.", "contrabass-recorder shortName"),
//: description for G Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: description for Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Soprano ocarina pitched in G.", "g-soprano-ocarina description"),
//: trackName for G Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "G Soprano Ocarina", "g-soprano-ocarina trackName"),
//: longName for G Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: trackName for Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Soprano Ocarina", "g-soprano-ocarina trackName"),
//: longName for Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "G Soprano Ocarina", "g-soprano-ocarina longName"),
//: shortName for G Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: shortName for Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "G S. Oc.", "g-soprano-ocarina shortName"),
//: traitName for G Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: traitName for Soprano Ocarina; tuning: G; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "G", "g-soprano-ocarina traitName"),
//: description for F Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: description for Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Soprano ocarina pitched in F.", "f-soprano-ocarina description"),
//: trackName for F Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "F Soprano Ocarina", "f-soprano-ocarina trackName"),
//: longName for F Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: trackName for Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Soprano Ocarina", "f-soprano-ocarina trackName"),
//: longName for Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "F Soprano Ocarina", "f-soprano-ocarina longName"),
//: shortName for F Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: shortName for Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "F S. Oc.", "f-soprano-ocarina shortName"),
//: traitName for F Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
//: traitName for Soprano Ocarina; tuning: F; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "F", "f-soprano-ocarina traitName"),
//: description for Ocarina; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
@ -3951,6 +3951,15 @@ QT_TRANSLATE_NOOP3("engraving/instruments", "Bell Plate", "bell-plate longName")
//: shortName for Bell Plate; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Be. Pla.", "bell-plate shortName"),
//: description for Bell Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Inverted metal bowls nested on a vertical rod in order of pitch. The pitches are indefinite.", "bell-tree description"),
//: trackName for Bell Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Bell Tree", "bell-tree trackName"),
//: longName for Bell Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Bell Tree", "bell-tree longName"),
//: shortName for Bell Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Be. Tr.", "bell-tree shortName"),
//: description for Bells; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Bells.", "bells description"),
//: trackName for Bells; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
@ -4041,6 +4050,15 @@ QT_TRANSLATE_NOOP3("engraving/instruments", "Iron Pipes", "iron-pipes longName")
//: shortName for Iron Pipes; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Ir. Pi.", "iron-pipes shortName"),
//: description for Mark Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Chimes hung from a horizontal bar in order of pitch. The pitches are indefinite.", "mark-tree description"),
//: trackName for Mark Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Mark Tree", "mark-tree trackName"),
//: longName for Mark Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Mark Tree", "mark-tree longName"),
//: shortName for Mark Tree; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Mk. Tr.", "mark-tree shortName"),
//: description for Metal Castanets; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names
QT_TRANSLATE_NOOP3("engraving/instruments", "Metal castanets.", "metal-castanets description"),
//: trackName for Metal Castanets; Please see https://github.com/musescore/MuseScore/wiki/Translating-instrument-names

View File

@ -383,6 +383,26 @@
<render>striangle</render>
</token>
<token class="modifier">
<name>add</name>
<render>add</render>
</token>
<token class="modifier">
<name>sus</name>
<render>sus</render>
</token>
<token class="modifier">
<name>no</name>
<render>no</render>
</token>
<token class="modifier">
<name>omit</name>
<render>omit</render>
</token>
<renderRoot>:n :a m:0.5:0</renderRoot>
<renderFunction>:a m:0.5:0 :n</renderFunction>
<renderBase>m:-0.2:1 / m:0.2:1 :n :a m:0:-2</renderBase>

View File

@ -69,7 +69,9 @@ int AppShell::run(int argc, char** argv)
qputenv("QML_DISABLE_DISK_CACHE", "true");
#ifdef Q_OS_LINUX
qputenv("QT_QPA_PLATFORMTHEME", "gtk3");
if (qEnvironmentVariable("QT_QPA_PLATFORM") != "offscreen") {
qputenv("QT_QPA_PLATFORMTHEME", "gtk3");
}
#endif
const char* appName;
@ -150,9 +152,10 @@ int AppShell::run(int argc, char** argv)
m->onPreInit(runMode);
}
SplashScreen splashScreen;
SplashScreen* splashScreen = nullptr;
if (runMode == framework::IApplication::RunMode::Editor) {
splashScreen.show();
splashScreen = new SplashScreen();
splashScreen->show();
}
// ====================================================
@ -257,7 +260,10 @@ int AppShell::run(int argc, char** argv)
engine->load(url);
splashScreen.close();
if (splashScreen) {
splashScreen->close();
delete splashScreen;
}
}
}

View File

@ -87,6 +87,8 @@ void CommandLineController::parse(const QStringList& args)
// m_parser.addOption(QCommandLineOption("piano-position", "Show Piano top or bottom. Default bottom", "bottom"));
m_parser.addOption(QCommandLineOption("resolution", "Resolution [2160p, 1440p, 1080p, 720p, 480p, 360p]", "1080p"));
m_parser.addOption(QCommandLineOption("fps", "Frame per second [60, 30, 24]", "24"));
m_parser.addOption(QCommandLineOption("ls", "Pause before playback in seconds (3.0)", "3.0"));
m_parser.addOption(QCommandLineOption("ts", "Pause before end of video in seconds (3.0)", "3.0"));
m_parser.addOption(QCommandLineOption("gp-linked", "create tabulature linked staves for guitar pro"));
m_parser.addOption(QCommandLineOption("gp-experimental", "experimental features for guitar pro import"));
@ -316,6 +318,14 @@ void CommandLineController::apply()
if (m_parser.isSet("fps")) {
videoExportConfiguration()->setFps(intValue("fps"));
}
if (m_parser.isSet("ls")) {
videoExportConfiguration()->setLeadingSec(doubleValue("ls"));
}
if (m_parser.isSet("ts")) {
videoExportConfiguration()->setTrailingSec(doubleValue("ts"));
}
}
#endif
@ -324,7 +334,7 @@ void CommandLineController::apply()
}
if (m_parser.isSet("f")) {
m_converterTask.params[CommandLineController::ParamKey::ForceMode] = m_parser.value("f");
m_converterTask.params[CommandLineController::ParamKey::ForceMode] = true;
}
if (m_parser.isSet("S")) {

View File

@ -167,7 +167,11 @@ void ApplicationActionController::quit(bool isAllInstances, const io::path_t& in
}
if (multiInstancesProvider()->instances().size() == 1 && !installerPath.empty()) {
#if defined(Q_OS_LINUX)
interactive()->revealInFileBrowser(installerPath);
#else
interactive()->openUrl(QUrl::fromLocalFile(installerPath.toQString()));
#endif
}
if (multiInstancesProvider()->instances().size() > 1) {

View File

@ -42,7 +42,7 @@ static const Settings::Key HAS_COMPLETED_FIRST_LAUNCH_SETUP(module_name, "applic
static const Settings::Key STARTUP_MODE_TYPE(module_name, "application/startup/modeStart");
static const Settings::Key STARTUP_SCORE_PATH(module_name, "application/startup/startScore");
static const std::string MUSESCORE_ONLINE_HANDBOOK_URL_PATH("/redirect/help");
static const std::string MUSESCORE_ONLINE_HANDBOOK_URL_PATH("/handbook/4");
static const std::string MUSESCORE_ASK_FOR_HELP_URL_PATH("/redirect/post/question");
static const std::string MUSESCORE_BUG_REPORT_URL_PATH("/redirect/post/bug-report?locale=");
static const std::string MUSESCORE_FORUM_URL_PATH("/forum");
@ -116,7 +116,7 @@ std::string AppShellConfiguration::handbookUrl() const
QString::fromStdString(utm)
};
return MUSESCORE_ONLINE_HANDBOOK_URL_PATH + "?" + params.join("&").toStdString();
return museScoreUrl() + MUSESCORE_ONLINE_HANDBOOK_URL_PATH + "?" + params.join("&").toStdString();
}
std::string AppShellConfiguration::askForHelpUrl() const
@ -127,7 +127,7 @@ std::string AppShellConfiguration::askForHelpUrl() const
"locale=" + QString::fromStdString(languageCode)
};
return MUSESCORE_ASK_FOR_HELP_URL_PATH + "?" + params.join("&").toStdString();
return museScoreUrl() + MUSESCORE_ASK_FOR_HELP_URL_PATH + "?" + params.join("&").toStdString();
}
std::string AppShellConfiguration::bugReportUrl() const
@ -142,7 +142,7 @@ std::string AppShellConfiguration::bugReportUrl() const
QString::fromStdString(_sha)
};
return MUSESCORE_BUG_REPORT_URL_PATH + "?" + params.join("&").toStdString();
return museScoreUrl() + MUSESCORE_BUG_REPORT_URL_PATH + "?" + params.join("&").toStdString();
}
std::string AppShellConfiguration::leaveFeedbackUrl() const
@ -163,12 +163,12 @@ std::string AppShellConfiguration::museScoreUrl() const
std::string AppShellConfiguration::museScoreForumUrl() const
{
return globalConfiguration()->museScoreUrl() + MUSESCORE_FORUM_URL_PATH;
return museScoreUrl() + MUSESCORE_FORUM_URL_PATH;
}
std::string AppShellConfiguration::museScoreContributionUrl() const
{
return globalConfiguration()->museScoreUrl() + MUSESCORE_CONTRIBUTE_URL_PATH;
return museScoreUrl() + MUSESCORE_CONTRIBUTE_URL_PATH;
}
std::string AppShellConfiguration::musicXMLLicenseUrl() const

View File

@ -50,7 +50,7 @@ StyledDialogView {
property string value: ""
width: 150
onCurrentTextEdited: input.value = newTextValue
onTextChanged: input.value = newTextValue
}
StyledTextLabel {

View File

@ -57,7 +57,7 @@ Rectangle {
FlatButton {
anchors.left: parent.left
width: 160
minWidth: 160
navigation.panel: root.navigation
navigation.order: 2
@ -76,7 +76,6 @@ Rectangle {
navigation.panel: root.navigation
navigation.order: 3
width: 132
text: qsTrc("global", "Cancel")
onClicked: {
@ -92,7 +91,6 @@ Rectangle {
navigation.panel: root.navigation
navigation.order: 1
width: 132
accentButton: true
text: qsTrc("global", "OK")

View File

@ -51,12 +51,14 @@ BaseSection {
width: parent.width
delegate: Row {
width: parent.width
spacing: root.columnSpacing
RoundedRadioButton {
anchors.verticalCenter: parent.verticalCenter
width: root.columnWidth
width: filePicker.visible ? Math.max(implicitWidth, root.columnWidth)
: parent.width
checked: modelData.checked
text: modelData.title
@ -72,6 +74,8 @@ BaseSection {
}
FilePicker {
id: filePicker
pathFieldWidth: root.columnWidth
spacing: root.columnSpacing
@ -102,6 +106,8 @@ BaseSection {
height: contentHeight
delegate: CheckBox {
width: parent.width
text: modelData.title
checked: modelData.visible

View File

@ -91,6 +91,8 @@ QList<unsigned int> CommonAudioApiConfigurationModel::bufferSizeList() const
result << bufferSize;
}
std::sort(result.begin(), result.end());
return result;
}

View File

@ -39,7 +39,7 @@ public:
virtual void signIn() = 0;
virtual void signOut() = 0;
virtual Ret requireAuthorization(const std::string& text = {}) = 0;
virtual Ret ensureAuthorization(const std::string& text = {}) = 0;
virtual ValCh<bool> userAuthorized() const = 0;
virtual ValCh<AccountInfo> accountInfo() const = 0;

View File

@ -158,5 +158,5 @@ mu::io::path_t CloudConfiguration::tokensFilePath() const
QString CloudConfiguration::apiRootUrl() const
{
return "https://api.musescore.com/editor/v1";
return "https://desktop.musescore.com/editor/v1";
}

View File

@ -416,8 +416,12 @@ void CloudService::signOut()
clearTokens();
}
mu::Ret CloudService::requireAuthorization(const std::string& text)
mu::Ret CloudService::ensureAuthorization(const std::string& text)
{
if (m_userAuthorized.val) {
return make_ok();
}
UriQuery query("musescore://cloud/requireauthorization");
query.addParam("text", Val(text));
return interactive()->open(query).ret;

View File

@ -60,7 +60,7 @@ public:
void signIn() override;
void signOut() override;
Ret requireAuthorization(const std::string& text = {}) override;
Ret ensureAuthorization(const std::string& text = {}) override;
ValCh<bool> userAuthorized() const override;
ValCh<AccountInfo> accountInfo() const override;

View File

@ -109,7 +109,7 @@ FocusScope {
FlatButton {
id: accountInfoButton
width: prv.buttonWidth
minWidth: prv.buttonWidth
text: qsTrc("cloud", "Account info")
accentButton: true
@ -131,7 +131,7 @@ FocusScope {
}
FlatButton {
width: prv.buttonWidth
minWidth: prv.buttonWidth
text: qsTrc("cloud", "Sign out")
navigation.name: "SignOut"

View File

@ -108,7 +108,7 @@ FocusScope {
FlatButton {
Layout.alignment: Qt.AlignLeft
width: privateProperties.buttonWidth
minWidth: privateProperties.buttonWidth
text: qsTrc("cloud", "Learn more")
navigation.name: "LearnMore"
@ -126,7 +126,7 @@ FocusScope {
spacing: 22
FlatButton {
width: privateProperties.buttonWidth
minWidth: privateProperties.buttonWidth
text: qsTrc("cloud", "Sign in")
navigation.name: "SignIn"
@ -140,7 +140,7 @@ FocusScope {
FlatButton {
id: createNewAccount
width: privateProperties.buttonWidth
minWidth: privateProperties.buttonWidth
text: qsTrc("cloud", "Create new account")
accentButton: true

View File

@ -56,7 +56,7 @@ void UiContextResolver::init()
notifyAboutContextChanged();
});
notation->interaction()->textEditingEnded().onNotify(this, [this]() {
notation->interaction()->textEditingEnded().onReceive(this, [this](engraving::TextBase*) {
notifyAboutContextChanged();
});

View File

@ -55,7 +55,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 16
clearTextButtonVisible: true
onCurrentTextEdited: function(newTextValue) {
onTextChanged: function(newTextValue) {
profModel.find(newTextValue)
}
}

View File

@ -29,6 +29,7 @@
#include "libmscore/segment.h"
#include "libmscore/chord.h"
#include "libmscore/note.h"
#include "libmscore/bracketItem.h"
#ifndef ENGRAVING_NO_ACCESSIBILITY
#include "accessibility/accessibleitem.h"
@ -44,6 +45,7 @@ DummyElement::DummyElement(EngravingObject* parent)
DummyElement::~DummyElement()
{
delete m_bracketItem;
delete m_note;
delete m_chord;
delete m_segment;
@ -83,6 +85,9 @@ void DummyElement::init()
m_note = Factory::createNote(m_chord);
m_note->setParent(m_chord);
m_bracketItem = Factory::createBracketItem(m_system);
m_bracketItem->setParent(m_system);
}
RootItem* DummyElement::rootItem()
@ -120,6 +125,11 @@ Note* DummyElement::note()
return m_note;
}
BracketItem* DummyElement::bracketItem()
{
return m_bracketItem;
}
EngravingItem* DummyElement::clone() const
{
return nullptr;

View File

@ -48,6 +48,7 @@ public:
Segment* segment();
Chord* chord();
Note* note();
BracketItem* bracketItem();
EngravingItem* clone() const override;
@ -66,6 +67,7 @@ private:
Segment* m_segment = nullptr;
Chord* m_chord = nullptr;
Note* m_note = nullptr;
BracketItem* m_bracketItem = nullptr;
};
}

View File

@ -48,6 +48,8 @@ public:
virtual io::path_t partStyleFilePath() const = 0;
virtual void setPartStyleFilePath(const io::path_t& path) = 0;
virtual SizeF defaultPageSize() const = 0;
virtual String iconsFontFamily() const = 0;
virtual draw::Color defaultColor() const = 0;

View File

@ -560,7 +560,7 @@ bool SymbolFont::isValid(SymId id) const
bool SymbolFont::useFallbackFont(SymId id) const
{
return MScore::useFallbackFont && !sym(id).isValid() && this != SymbolFonts::fallbackFont();
return MScore::useFallbackFont && !sym(id).isValid() && this != SymbolFonts::fallbackFont(false);
}
// =============================================

View File

@ -52,17 +52,7 @@ SymbolFont* SymbolFonts::fontByName(const String& name)
}
if (!font) {
LOGE() << "ScoreFont not found in list: " << name;
LOGE() << "ScoreFonts in list:";
for (const SymbolFont& f : s_symbolFonts) {
LOGE() << " " << f.name();
}
font = fallbackFont();
LOGE() << "Using fallback font " << font->name() << " instead.";
return font;
return fallbackFont();
}
if (!font->m_loaded) {
@ -92,11 +82,11 @@ void SymbolFonts::setFallbackFont(const String& name)
}
}
SymbolFont* SymbolFonts::fallbackFont()
SymbolFont* SymbolFonts::fallbackFont(bool load)
{
SymbolFont* font = &s_symbolFonts[s_fallback.index];
if (!font->m_loaded) {
if (load && !font->m_loaded) {
font->load();
}

View File

@ -39,7 +39,7 @@ public:
static SymbolFont* fontByName(const String& name);
static void setFallbackFont(const String& name);
static SymbolFont* fallbackFont();
static SymbolFont* fallbackFont(bool load = true);
static const char* fallbackTextFont();
private:

View File

@ -21,6 +21,13 @@
*/
#include "engravingconfiguration.h"
#include <cstdlib>
#ifndef NO_QT_SUPPORT
#include <QLocale>
#include <QPageSize>
#endif
#include "global/settings.h"
#include "draw/types/color.h"
#include "libmscore/mscore.h"
@ -98,6 +105,44 @@ void EngravingConfiguration::setPartStyleFilePath(const io::path_t& path)
settings()->setSharedValue(PART_STYLE_FILE_PATH, Val(path.toStdString()));
}
static bool defaultPageSizeIsLetter()
{
// try PAPERSIZE environment variable
const char* papersize = getenv("PAPERSIZE");
if (papersize) {
return strcmp(papersize, "letter") == 0;
}
#ifndef NO_QT_SUPPORT
// try locale
switch (QLocale::system().country()) {
case QLocale::UnitedStates:
case QLocale::Canada:
case QLocale::Mexico:
case QLocale::Chile:
case QLocale::Colombia:
case QLocale::CostaRica:
case QLocale::Panama:
case QLocale::Guatemala:
case QLocale::DominicanRepublic:
case QLocale::Philippines:
return true;
default:
return false;
}
#else
return false;
#endif
}
SizeF EngravingConfiguration::defaultPageSize() const
{
// Needs to be determined only once, therefore static
static SizeF size = SizeF::fromQSizeF(
QPageSize::size(defaultPageSizeIsLetter() ? QPageSize::Letter : QPageSize::A4, QPageSize::Inch));
return size;
}
mu::String EngravingConfiguration::iconsFontFamily() const
{
return String::fromStdString(uiConfiguration()->iconsFontFamily());

View File

@ -53,6 +53,8 @@ public:
io::path_t partStyleFilePath() const override;
void setPartStyleFilePath(const io::path_t& path) override;
SizeF defaultPageSize() const override;
String iconsFontFamily() const override;
draw::Color defaultColor() const override;

View File

@ -111,8 +111,8 @@ void LayoutBeams::restoreBeams(Measure* m)
for (EngravingItem* e : s->elist()) {
if (e && e->isChordRest()) {
ChordRest* cr = toChordRest(e);
if (isTopBeam(cr)) {
Beam* b = cr->beam();
Beam* b = cr->beam();
if (b && !b->elements().empty() && b->elements().front() == cr) {
b->layout();
b->addSkyline(m->system()->staff(b->staffIdx())->skyline());
}

View File

@ -192,7 +192,7 @@ void LayoutMeasure::createMMRest(const LayoutOptions& options, Score* score, Mea
for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
track_idx_t track = staffIdx * VOICES;
if (s->element(track) == 0) {
MMRest* mmr = new MMRest(s);
MMRest* mmr = Factory::createMMRest(s);
mmr->setDurationType(DurationType::V_MEASURE);
mmr->setTicks(mmrMeasure->ticks());
mmr->setTrack(track);

View File

@ -1397,6 +1397,9 @@ void LayoutSystem::processLines(System* system, std::vector<Spanner*> lines, boo
for (SpannerSegment* ss : segments) {
if (ss->addToSkyline()) {
staff_idx_t stfIdx = ss->systemFlag() ? ss->staffIdxOrNextVisible() : ss->staffIdx();
if (stfIdx == mu::nidx) {
continue;
}
system->staff(stfIdx)->skyline().add(ss->shape().translated(ss->pos()));
}
}

View File

@ -1189,7 +1189,7 @@ void Beam::offsetBeamWithAnchorShortening(std::vector<ChordRest*> chordRests, in
return;
}
// min stem lengths according to how many beams there are (starting with 1)
static const int minStemLengths[] = { 11, 13, 15, 18, 21 };
static const int minStemLengths[] = { 11, 13, 15, 18, 21, 24, 27, 30 };
const int middleLine = getMiddleStaffLine(startChord, endChord, staffLines);
int maxDictatorReduce = stemLengthDictator - minStemLengths[(isStartDictator ? startChord : endChord)->beams() - 1];
maxDictatorReduce = std::min(abs(dictator - middleLine), maxDictatorReduce);

View File

@ -312,21 +312,29 @@ bool Box::readProperties(XmlReader& e)
//! but when we add it to Box, the parent will be rewritten.
add(f);
} else if (tag == "HBox") {
HBox* hb = new HBox(this->system());
hb->read(e);
//! TODO Looks like a bug.
//! The HBox parent must be System
//! there is a method: `System* system() const { return (System*)parent(); }`,
//! but when we add it to Box, the parent will be rewritten.
add(hb);
// m_parent is used here (rather than system()) because explicit parent isn't set for this object
// until it is fully read. m_parent is nonetheless valid and using it here matches MU3 behavior.
// If we do not set the parent of this new box correctly, it will cause a crash on read()
// because it needs access to the system it is being added to. (c.r. issue #14643)
if (m_parent && m_parent->isSystem()) {
HBox* hb = new HBox(toSystem(m_parent));
hb->read(e);
//! TODO Looks like a bug.
//! The HBox parent must be System
//! there is a method: `System* system() const { return (System*)parent(); }`,
//! but when we add it to Box, the parent will be rewritten.
add(hb);
}
} else if (tag == "VBox") {
VBox* vb = new VBox(this->system());
vb->read(e);
//! TODO Looks like a bug.
//! The VBox parent must be System
//! there is a method: `System* system() const { return (System*)parent(); }`,
//! but when we add it to Box, the parent will be rewritten.
add(vb);
if (m_parent && m_parent->isSystem()) {
VBox* vb = new VBox(toSystem(m_parent));
vb->read(e);
//! TODO Looks like a bug.
//! The VBox parent must be System
//! there is a method: `System* system() const { return (System*)parent(); }`,
//! but when we add it to Box, the parent will be rewritten.
add(vb);
}
} else if (MeasureBase::readProperties(e)) {
} else {
return false;

View File

@ -553,7 +553,7 @@ void Bracket::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags p
void Bracket::setSelected(bool f)
{
// _bi->setSelected(f);
_bi->setSelected(f);
EngravingItem::setSelected(f);
}

View File

@ -523,16 +523,19 @@ EngravingItem* ChordRest::drop(EditData& data)
if (part()->instruments().find(tick().ticks()) != part()->instruments().end()) {
LOGD() << "InstrumentChange already exists at tick = " << tick().ticks();
delete e;
return 0;
return nullptr;
} else {
InstrumentChange* ic = toInstrumentChange(e);
ic->setParent(segment());
ic->setTrack(trackZeroVoice(track()));
Instrument* instr = ic->instrument();
Instrument* prevInstr = part()->instrument(tick());
if (instr && instr->isDifferentInstrument(*prevInstr)) {
ic->setupInstrument(instr);
const Instrument* instr = part()->instrument(tick());
IF_ASSERT_FAILED(instr) {
delete e;
return nullptr;
}
ic->setInstrument(*instr);
score()->undoAddElement(ic);
return e;
}

View File

@ -3210,7 +3210,7 @@ void Score::cmdExplode()
// keep note "i" from top, which is backwards from nnotes - 1
// reuse notes if there are more instruments than notes
size_t stavesPerNote = std::max((lastStaff - srcStaff) / nnotes, static_cast<size_t>(1));
size_t keepIndex = std::max(nnotes - 1 - (i / stavesPerNote), static_cast<size_t>(0));
size_t keepIndex = static_cast<size_t>(std::max(static_cast<int>(nnotes) - 1 - static_cast<int>(i / stavesPerNote), 0));
Note* keepNote = c->notes()[keepIndex];
for (Note* n : notes) {
if (n != keepNote) {

View File

@ -23,6 +23,7 @@
#include "durationelement.h"
#include "rw/xml.h"
#include "realfn.h"
#include "property.h"
#include "score.h"
@ -96,6 +97,14 @@ Fraction DurationElement::globalTicks() const
return f;
}
float DurationElement::timeStretchFactor() const
{
int nominalDuration = _duration.ticks();
int actualDuration = actualTicks().ticks();
return actualDuration / static_cast<float>(nominalDuration);
}
//---------------------------------------------------------
// actualTicks
//---------------------------------------------------------

View File

@ -60,6 +60,7 @@ public:
// Length expressed as a fraction of a whole note
virtual Fraction ticks() const { return _duration; }
Fraction globalTicks() const;
float timeStretchFactor() const;
void setTicks(const Fraction& f) { _duration = f; }
PropertyValue getProperty(Pid propertyId) const override;

View File

@ -23,6 +23,8 @@
#include <map>
#include <set>
#include "infrastructure/messagebox.h"
#include "accidental.h"
#include "articulation.h"
#include "barline.h"
@ -243,7 +245,9 @@ Tuplet* Score::addTuplet(ChordRest* destinationChordRest, Fraction ratio, Tuplet
Fraction fr = f * Fraction(1, _ratio.denominator());
if (!TDuration::isValid(fr)) {
// todo: there needs to be some kind of user feedback for failure to add tuplet
MessageBox::warning(mtrc("engraving", "Cannot create tuplet with ratio %1 for duration %2")
.arg(_ratio.toString(), f.toString()).toStdString(),
std::string(), { MessageBox::Ok });
return nullptr;
}
@ -4856,7 +4860,7 @@ static EngravingItem* findLinkedVoiceElement(EngravingItem* e, Staff* nstaff)
Measure* measure = segment->measure();
Measure* m = score->tick2measure(measure->tick());
Segment* s = m->findSegment(segment->segmentType(), segment->tick());
return s->element(dtrack);
return s ? s->element(dtrack) : nullptr;
}
//---------------------------------------------------------

View File

@ -2639,43 +2639,11 @@ bool EngravingItem::selected() const
void EngravingItem::setSelected(bool f)
{
setFlag(ElementFlag::SELECTED, f);
#ifndef ENGRAVING_NO_ACCESSIBILITY
if (f) {
initAccessibleIfNeed();
if (m_accessible) {
AccessibleRoot* currAccRoot = m_accessible->accessibleRoot();
AccessibleRoot* accRoot = score()->rootItem()->accessible()->accessibleRoot();
AccessibleRoot* dummyAccRoot = score()->dummy()->rootItem()->accessible()->accessibleRoot();
if (accRoot && currAccRoot == accRoot && accRoot->registered()) {
accRoot->setFocusedElement(m_accessible);
if (AccessibleItemPtr focusedElement = dummyAccRoot->focusedElement().lock()) {
accRoot->updateStaffInfo(m_accessible, focusedElement);
}
dummyAccRoot->setFocusedElement(nullptr);
}
if (dummyAccRoot && currAccRoot == dummyAccRoot && dummyAccRoot->registered()) {
dummyAccRoot->setFocusedElement(m_accessible);
if (AccessibleItemPtr focusedElement = accRoot->focusedElement().lock()) {
dummyAccRoot->updateStaffInfo(m_accessible, focusedElement);
}
accRoot->setFocusedElement(nullptr);
}
}
}
#endif
}
#ifndef ENGRAVING_NO_ACCESSIBILITY
void EngravingItem::initAccessibleIfNeed()
{
#ifndef ENGRAVING_NO_ACCESSIBILITY
if (!engravingConfiguration()->isAccessibleEnabled()) {
return;
}
@ -2685,12 +2653,10 @@ void EngravingItem::initAccessibleIfNeed()
}
doInitAccessible();
#endif
}
void EngravingItem::doInitAccessible()
{
#ifndef ENGRAVING_NO_ACCESSIBILITY
EngravingItemList parents;
auto parent = parentItem(false /*not explicit*/);
while (parent) {
@ -2703,9 +2669,10 @@ void EngravingItem::doInitAccessible()
}
setupAccessible();
#endif
}
#endif // ENGRAVING_NO_ACCESSIBILITY
KerningType EngravingItem::computeKerningType(const EngravingItem* nextItem) const
{
if (_userSetKerning != KerningType::NOT_SET) {

View File

@ -532,7 +532,9 @@ public:
#ifndef ENGRAVING_NO_ACCESSIBILITY
AccessibleItemPtr accessible() const;
void initAccessibleIfNeed();
#endif
virtual String accessibleInfo() const;
virtual String screenReaderInfo() const { return accessibleInfo(); }
// if the screen-reader needs a special string (see note for example)
@ -563,10 +565,8 @@ public:
std::vector<Spanner*>& endingSpanners() { return _endingSpanners; }
private:
void initAccessibleIfNeed();
void doInitAccessible();
#ifndef ENGRAVING_NO_ACCESSIBILITY
void doInitAccessible();
AccessibleItemPtr m_accessible;
#endif

View File

@ -186,6 +186,20 @@ void EngravingObject::moveToDummy()
void EngravingObject::setScore(Score* s)
{
doSetScore(s);
if (!m_parent) {
return;
}
if (m_parent->score() == s) {
return;
}
if (m_parent->isType(ElementType::DUMMY)) {
moveToDummy();
} else if (m_parent->isType(ElementType::SCORE)) {
setParent(s);
}
}
void EngravingObject::addChild(EngravingObject* o)

View File

@ -853,6 +853,7 @@ bool Harmony::isEditAllowed(EditData& ed) const
}
if (ed.key == Key_Return || ed.key == Key_Enter) {
// This "edit" is actually handled in NotationInteraction::editElement
return true;
}
@ -869,11 +870,6 @@ bool Harmony::edit(EditData& ed)
return false;
}
if (ed.key == Key_Return || ed.key == Key_Enter) {
endEdit(ed);
return true;
}
bool rv = TextBase::edit(ed);
// layout as text, without position reset

View File

@ -413,6 +413,10 @@ void Image::read(XmlReader& e)
bool Image::load(const io::path_t& ss)
{
if (ss.empty()) {
return false;
}
io::path_t path(ss);
// if file path is relative, prepend score path
FileInfo fi(path);

View File

@ -1779,6 +1779,16 @@ void Instrument::setTrait(const Trait& trait)
_trait = trait;
}
bool Instrument::isPrimary() const
{
return _isPrimary;
}
void Instrument::setIsPrimary(bool isPrimary)
{
_isPrimary = isPrimary;
}
void Instrument::updateInstrumentId()
{
if (_instrumentId.isEmpty()) {

View File

@ -335,6 +335,7 @@ class Instrument
bool _singleNoteDynamics = false;
Trait _trait;
bool _isPrimary = false;
public:
Instrument(String id = String());
@ -429,6 +430,9 @@ public:
Trait trait() const;
void setTrait(const Trait& trait);
bool isPrimary() const;
void setIsPrimary(bool isPrimary);
void updateInstrumentId();
bool singleNoteDynamics() const { return _singleNoteDynamics; }

View File

@ -981,6 +981,15 @@ PointF SLine::linePos(Grip grip, System** sys) const
x += cr->segment()->pos().x() + m->pos().x();
} else {
Segment* segment = (grip == Grip::START) ? startSegment() : endSegment();
if (grip == Grip::END && segment && segment->rtick().ticks() == 0) {
// The line should end on the left-most segment at this tick. If endSegment() is the first of
// the measure, we need to look back for other segments (eg endBarLine) in the prev measure
Segment* prevSegment = segment->prev1();
while (prevSegment && prevSegment->tick() == segment->tick()) {
segment = prevSegment;
prevSegment = segment->prev1();
}
}
if (segment) {
m = segment->measure();
if (m->mmRest()) {

View File

@ -193,6 +193,12 @@ void MasterScore::updateRepeatListTempo()
_repeatList2->updateTempo();
}
void MasterScore::updateRepeatList()
{
_repeatList->update(MScore::playRepeats);
_repeatList2->update(false);
}
//---------------------------------------------------------
// repeatList
//---------------------------------------------------------

View File

@ -161,6 +161,7 @@ public:
void setExpandRepeats(bool expandRepeats);
bool expandRepeats() const { return _expandRepeats; }
void updateRepeatListTempo();
void updateRepeatList();
const RepeatList& repeatList() const override;
const RepeatList& repeatList2() const override;

View File

@ -681,8 +681,12 @@ int MeasureBase::index() const
{
int idx = 0;
MeasureBase* m = score()->first();
Measure* mmRestFirst = nullptr;
if (isMeasure() && toMeasure(this)->isMMRest()) {
mmRestFirst = toMeasure(this)->mmRestFirst();
}
while (m) {
if (m == this) {
if (m == this || m == mmRestFirst) {
return idx;
}
m = m->next();

View File

@ -125,4 +125,38 @@ void MScore::registerUiTypes()
#endif
}
std::string MScore::errorToString(MsError err)
{
switch (err) {
case MsError::MS_NO_ERROR: return "MS_NO_ERROR";
case MsError::NO_NOTE_SELECTED: return "NO_NOTE_SELECTED";
case MsError::NO_CHORD_REST_SELECTED: return "NO_CHORD_REST_SELECTED";
case MsError::NO_LYRICS_SELECTED: return "NO_LYRICS_SELECTED";
case MsError::NO_NOTE_REST_SELECTED: return "NO_NOTE_REST_SELECTED";
case MsError::NO_FLIPPABLE_SELECTED: return "NO_FLIPPABLE_SELECTED";
case MsError::NO_STAFF_SELECTED: return "NO_STAFF_SELECTED";
case MsError::NO_NOTE_FIGUREDBASS_SELECTED: return "NO_NOTE_FIGUREDBASS_SELECTED";
case MsError::CANNOT_INSERT_TUPLET: return "CANNOT_INSERT_TUPLET";
case MsError::CANNOT_SPLIT_TUPLET: return "CANNOT_SPLIT_TUPLET";
case MsError::CANNOT_SPLIT_MEASURE_FIRST_BEAT: return "CANNOT_SPLIT_MEASURE_FIRST_BEAT";
case MsError::CANNOT_SPLIT_MEASURE_TUPLET: return "CANNOT_SPLIT_MEASURE_TUPLET";
case MsError::INSUFFICIENT_MEASURES: return "INSUFFICIENT_MEASURES";
case MsError::CANNOT_SPLIT_MEASURE_REPEAT: return "CANNOT_SPLIT_MEASURE_REPEAT";
case MsError::CANNOT_SPLIT_MEASURE_TOO_SHORT: return "CANNOT_SPLIT_MEASURE_TOO_SHORT";
case MsError::CANNOT_REMOVE_TIME_TUPLET: return "CANNOT_REMOVE_TIME_TUPLET";
case MsError::CANNOT_REMOVE_TIME_MEASURE_REPEAT: return "CANNOT_REMOVE_TIME_MEASURE_REPEAT";
case MsError::NO_DEST: return "NO_DEST";
case MsError::DEST_TUPLET: return "DEST_TUPLET";
case MsError::TUPLET_CROSSES_BAR: return "TUPLET_CROSSES_BAR";
case MsError::DEST_LOCAL_TIME_SIGNATURE: return "DEST_LOCAL_TIME_SIGNATURE";
case MsError::DEST_TREMOLO: return "DEST_TREMOLO";
case MsError::NO_MIME: return "NO_MIME";
case MsError::DEST_NO_CR: return "DEST_NO_CR";
case MsError::CANNOT_CHANGE_LOCAL_TIMESIG: return "CANNOT_CHANGE_LOCAL_TIMESIG";
case MsError::CORRUPTED_MEASURE: return "CORRUPTED_MEASURE";
}
return {};
}
}

View File

@ -280,6 +280,8 @@ public:
static double horizontalPageGapOdd;
static void setError(MsError e) { _error = e; }
static std::string errorToString(MsError err);
};
} // namespace mu::engraving

View File

@ -1708,7 +1708,7 @@ bool Note::readProperties(XmlReader& e)
}
} else if (tag == "offset") {
EngravingItem::readProperties(e);
} else if (tag == "ChordLine") {
} else if (tag == "ChordLine" && chord()) {
ChordLine* cl = Factory::createChordLine(chord());
cl->setNote(this);
cl->read(e);

View File

@ -332,13 +332,14 @@ Note* Score::addPitch(NoteVal& nval, bool addFlag, InputState* externalInputStat
// mouse click in state NoteType::ENTRY
//---------------------------------------------------------
void Score::putNote(const PointF& pos, bool replace, bool insert)
Ret Score::putNote(const PointF& pos, bool replace, bool insert)
{
Position p;
if (!getPosition(&p, pos, _is.voice())) {
LOGD("cannot put note here, get position failed");
return;
return make_ret(Ret::Code::UnknownError);
}
Score* score = p.segment->score();
// it is not safe to call Score::repitchNote() if p is on a TAB staff
bool isTablature = staff(p.staffIdx)->isTabStaff(p.segment->tick());
@ -351,17 +352,19 @@ void Score::putNote(const PointF& pos, bool replace, bool insert)
p.line -= stepOffset + 2 * stYOffset / lineDist;
if (score->inputState().usingNoteEntryMethod(NoteEntryMethod::REPITCH) && !isTablature) {
score->repitchNote(p, replace);
return score->repitchNote(p, replace);
} else {
if (insert || score->inputState().usingNoteEntryMethod(NoteEntryMethod::TIMEWISE)) {
score->insertChord(p);
return score->insertChord(p);
} else {
score->putNote(p, replace);
return score->putNote(p, replace);
}
}
return make_ok();
}
void Score::putNote(const Position& p, bool replace)
Ret Score::putNote(const Position& p, bool replace)
{
Staff* st = staff(p.staffIdx);
Segment* s = p.segment;
@ -373,15 +376,15 @@ void Score::putNote(const Position& p, bool replace)
const TracksMap& tracks = excerpt->tracksMapping();
if (!tracks.empty() && mu::key(tracks, _is.track(), mu::nidx) == mu::nidx) {
return;
return make_ret(Ret::Code::UnknownError);
}
}
DirectionV stemDirection = DirectionV::AUTO;
bool error;
bool error = false;
NoteVal nval = noteValForPosition(p, _is.accidentalType(), error);
if (error) {
return;
return make_ret(Ret::Code::UnknownError);
}
// warn and delete MeasureRepeat if necessary
@ -393,8 +396,9 @@ void Score::putNote(const Position& p, bool replace)
" If you enter notes here, it will be deleted."
" Do you want to continue?"));
if (b == MessageBox::Cancel) {
return;
return make_ret(Ret::Code::Cancel);
}
Score::deleteItem(m->measureRepeatElement(staffIdx));
}
@ -454,7 +458,7 @@ void Score::putNote(const Position& p, bool replace)
int tpc2 = note->tpc2default(nval.pitch);
undoChangeFretting(note, nval.pitch, nval.string, nval.fret, tpc1, tpc2);
setPlayNote(true);
return;
return make_ok();
}
}
} else { // not TAB
@ -465,7 +469,7 @@ void Score::putNote(const Position& p, bool replace)
if (chord->notes().size() > 1) {
undoRemoveElement(note);
}
return;
return make_ok();
}
}
addToChord = true; // if no special case, add note to chord
@ -476,31 +480,45 @@ void Score::putNote(const Position& p, bool replace)
NoteVal nval2 = noteValForPosition(p, AccidentalType::NONE, error);
forceAccidental = (nval.pitch == nval2.pitch);
}
Ret ret = make_ok();
if (addToChord && cr->isChord()) {
// if adding, add!
addNote(toChord(cr), nval, forceAccidental, _is.articulationIds());
Note* note = addNote(toChord(cr), nval, forceAccidental, _is.articulationIds());
if (!note) {
ret = make_ret(Ret::Code::UnknownError);
}
_is.setAccidentalType(AccidentalType::NONE);
return;
return ret;
} else {
// if not adding, replace current chord (or create a new one)
if (_is.rest()) {
nval.pitch = -1;
}
setNoteRest(_is.segment(), _is.track(), nval, _is.duration().fraction(), stemDirection, forceAccidental, _is.articulationIds());
Segment* seg = setNoteRest(_is.segment(), _is.track(), nval,
_is.duration().fraction(), stemDirection, forceAccidental, _is.articulationIds());
if (!seg) {
ret = make_ret(Ret::Code::UnknownError);
}
_is.setAccidentalType(AccidentalType::NONE);
}
if (cr && !st->isTabStaff(cr->tick())) {
_is.moveToNextInputPos();
}
return ret;
}
//---------------------------------------------------------
// repitchNote
//---------------------------------------------------------
void Score::repitchNote(const Position& p, bool replace)
Ret Score::repitchNote(const Position& p, bool replace)
{
Segment* s = p.segment;
Fraction tick = s->tick();
@ -516,7 +534,7 @@ void Score::repitchNote(const Position& p, bool replace)
AccidentalVal acci
= (at == AccidentalType::NONE ? s->measure()->findAccidental(s, p.staffIdx, p.line, error) : Accidental::subtype2value(at));
if (error) {
return;
return make_ret(Ret::Code::UnknownError);
}
int step = absStep(p.line, clef);
@ -532,7 +550,7 @@ void Score::repitchNote(const Position& p, bool replace)
}
if (!_is.segment()) {
return;
return make_ret(Ret::Code::UnknownError);
}
Chord* chord;
@ -540,7 +558,7 @@ void Score::repitchNote(const Position& p, bool replace)
if (!cr) {
cr = _is.segment()->nextChordRest(_is.track());
if (!cr) {
return;
return make_ret(Ret::Code::UnknownError);
}
}
if (cr->isRest()) { //skip rests
@ -551,7 +569,7 @@ void Score::repitchNote(const Position& p, bool replace)
if (next) {
_is.moveInputPos(next->segment());
}
return;
return make_ok();
} else {
chord = toChord(cr);
}
@ -641,13 +659,15 @@ void Score::repitchNote(const Position& p, bool replace)
if (next) {
_is.moveInputPos(next->segment());
}
return make_ok();
}
//---------------------------------------------------------
// insertChord
//---------------------------------------------------------
void Score::insertChord(const Position& pos)
Ret Score::insertChord(const Position& pos)
{
// insert
// TODO:
@ -656,18 +676,20 @@ void Score::insertChord(const Position& pos)
EngravingItem* el = selection().element();
if (!el || !(el->isNote() || el->isRest())) {
return;
return make_ret(Ret::Code::UnknownError);
}
Segment* seg = pos.segment;
if (seg->splitsTuplet()) {
MScore::setError(MsError::CANNOT_INSERT_TUPLET);
return;
return make_ret(Ret::Code::UnknownError);
}
if (_is.insertMode()) {
globalInsertChord(pos);
} else {
localInsertChord(pos);
}
return make_ok();
}
//---------------------------------------------------------

View File

@ -42,6 +42,7 @@ using namespace mu;
using namespace mu::engraving;
namespace mu::engraving {
const Fraction Part::MAIN_INSTRUMENT_TICK = Fraction(-1, 1);
//---------------------------------------------------------
// Part
//---------------------------------------------------------
@ -62,7 +63,7 @@ Part::Part(Score* s)
void Part::initFromInstrTemplate(const InstrumentTemplate* t)
{
_partName = t->trackName;
_partName = !t->longNames.empty() ? t->longNames.front().name() : t->trackName;
setInstrument(Instrument::fromTemplate(t));
}

View File

@ -87,6 +87,8 @@ class Part final : public EngravingObject
friend class compat::Read206;
public:
static const Fraction MAIN_INSTRUMENT_TICK;
Part(Score* score = nullptr);
void initFromInstrTemplate(const InstrumentTemplate*);

View File

@ -834,10 +834,10 @@ void RepeatList::unwind()
activeVolta = nullptr;
// Start next rs on the following measure
Measure const* const possibleNextMeasure = (*repeatListElementIt)->measure->nextMeasure();
rs = new RepeatSegment(playbackCount);
if (possibleNextMeasure == nullptr) {
rs = nullptr; // end of score, but will still encounter section break, notify it
// end of score, but will still encounter section break, notify it
} else {
rs = new RepeatSegment(playbackCount);
rs->addMeasure(possibleNextMeasure);
}
}

View File

@ -93,6 +93,11 @@
#include "undo.h"
#include "utils.h"
#ifndef ENGRAVING_NO_ACCESSIBILITY
#include "accessibility/accessibleitem.h"
#include "accessibility/accessibleroot.h"
#endif
#include "config.h"
#include "log.h"
@ -109,6 +114,30 @@ bool noMidi = false;
bool midiInputTrace = false;
bool midiOutputTrace = false;
static void markInstrumentsAsPrimary(std::vector<Part*>& parts)
{
TRACEFUNC;
std::unordered_map<String /*instrumentId*/, int /*count*/> instrumentCount;
for (Part* part : parts) {
Instrument* instrument = part->instrument();
if (!instrument) {
continue;
}
auto it = instrumentCount.find(instrument->id());
if (it == instrumentCount.cend()) {
it = instrumentCount.insert(instrumentCount.begin(), { instrument->id(), 0 });
}
it->second++;
bool isPrimary = (it->second % 2 != 0);
instrument->setIsPrimary(isPrimary);
}
}
//---------------------------------------------------------
// MeasureBaseList
//---------------------------------------------------------
@ -383,9 +412,6 @@ Score::~Score()
m = nm;
}
for (auto it = _spanner.cbegin(); it != _spanner.cend(); ++it) {
delete it->second;
}
_spanner.clear();
DeleteAll(_parts);
@ -457,6 +483,19 @@ bool Score::isPaletteScore() const
return this == gpaletteScore;
}
static void onBracketItemDestruction(const Score* score, const BracketItem* item)
{
BracketItem* dummy = score->dummy()->bracketItem();
for (const System* system : score->systems()) {
for (Bracket* bracket : system->brackets()) {
if (bracket && bracket->bracketItem() == item) {
bracket->setBracketItem(dummy);
}
}
}
}
//---------------------------------------------------------
// Score::onElementDestruction
// Ensure correct state of the score after destruction
@ -472,6 +511,10 @@ void Score::onElementDestruction(EngravingItem* e)
return;
}
if (e->isBracketItem()) {
onBracketItemDestruction(score, toBracketItem(e));
}
score->selection().remove(e);
score->cmdState().unsetElement(e);
score->elementDestroyed().send(e);
@ -2501,6 +2544,7 @@ void Score::insertPart(Part* part, staff_idx_t idx)
bool inserted = false;
staff_idx_t staff = 0;
part->setScore(this);
assignIdIfNeed(*part);
for (auto i = _parts.begin(); i != _parts.end(); ++i) {
@ -2516,6 +2560,7 @@ void Score::insertPart(Part* part, staff_idx_t idx)
}
masterScore()->rebuildMidiMapping();
setInstrumentsChanged(true);
markInstrumentsAsPrimary(_parts);
}
void Score::appendPart(Part* part)
@ -2524,8 +2569,10 @@ void Score::appendPart(Part* part)
return;
}
part->setScore(this);
assignIdIfNeed(*part);
_parts.push_back(part);
markInstrumentsAsPrimary(_parts);
}
//---------------------------------------------------------
@ -2546,6 +2593,7 @@ void Score::removePart(Part* part)
}
_parts.erase(_parts.begin() + index);
markInstrumentsAsPrimary(_parts);
if (_excerpt) {
for (Part* excerptPart : _excerpt->parts()) {
@ -2554,6 +2602,7 @@ void Score::removePart(Part* part)
}
mu::remove(_excerpt->parts(), excerptPart);
markInstrumentsAsPrimary(_excerpt->parts());
break;
}
}
@ -2992,6 +3041,7 @@ void Score::sortStaves(std::vector<staff_idx_t>& dst)
}
}
setLayoutAll();
markInstrumentsAsPrimary(_parts);
}
//---------------------------------------------------------
@ -3324,6 +3374,58 @@ void Score::padToggle(Pad p, const EditData& ed)
}
}
static void onFocusedItemChanged(EngravingItem* item)
{
#ifndef ENGRAVING_NO_ACCESSIBILITY
if (!item || !item->selected()) {
return;
}
if (item->isSpannerSegment()) {
item = toSpannerSegment(item)->spanner();
if (!item) {
return;
}
}
item->initAccessibleIfNeed();
AccessibleItemPtr accessible = item->accessible();
if (!accessible) {
return;
}
const Score* score = item->score();
if (!score) {
return;
}
AccessibleRoot* currAccRoot = accessible->accessibleRoot();
AccessibleRoot* accRoot = score->rootItem()->accessible()->accessibleRoot();
AccessibleRoot* dummyAccRoot = score->dummy()->rootItem()->accessible()->accessibleRoot();
if (accRoot && currAccRoot == accRoot && accRoot->registered()) {
accRoot->setFocusedElement(accessible);
if (AccessibleItemPtr focusedElement = dummyAccRoot->focusedElement().lock()) {
accRoot->updateStaffInfo(accessible, focusedElement);
}
dummyAccRoot->setFocusedElement(nullptr);
}
if (dummyAccRoot && currAccRoot == dummyAccRoot && dummyAccRoot->registered()) {
dummyAccRoot->setFocusedElement(accessible);
if (AccessibleItemPtr focusedElement = accRoot->focusedElement().lock()) {
dummyAccRoot->updateStaffInfo(accessible, focusedElement);
}
accRoot->setFocusedElement(nullptr);
}
#endif
}
//---------------------------------------------------------
// deselect
//---------------------------------------------------------
@ -3341,7 +3443,23 @@ void Score::deselect(EngravingItem* el)
// staffIdx is valid, if element is of type MEASURE
//---------------------------------------------------------
void Score::select(EngravingItem* e, SelectType type, staff_idx_t staffIdx)
void Score::select(EngravingItem* item, SelectType type, staff_idx_t staffIdx)
{
select(std::vector<EngravingItem*> { item }, type, staffIdx);
}
void Score::select(const std::vector<EngravingItem*>& items, SelectType type, staff_idx_t staffIdx)
{
for (EngravingItem* item : items) {
doSelect(item, type, staffIdx);
}
if (!_selection.elements().empty()) {
onFocusedItemChanged(_selection.elements().back());
}
}
void Score::doSelect(EngravingItem* e, SelectType type, staff_idx_t staffIdx)
{
// Move the playhead to the selected element's preferred play position.
if (e) {
@ -3386,7 +3504,7 @@ void Score::selectSingle(EngravingItem* e, staff_idx_t staffIdx)
setUpdateAll();
} else {
if (e->isMeasure()) {
select(e, SelectType::RANGE, staffIdx);
doSelect(e, SelectType::RANGE, staffIdx);
return;
}
addRefresh(e->abbox());
@ -3428,7 +3546,7 @@ void Score::selectAdd(EngravingItem* e)
SelState selState = _selection.state();
if (_selection.isRange()) {
select(e, SelectType::SINGLE, 0);
doSelect(e, SelectType::SINGLE, 0);
return;
}
@ -3542,7 +3660,7 @@ void Score::selectRange(EngravingItem* e, staff_idx_t staffIdx)
_selection.setRange(ocr->segment(), endSeg, oe->staffIdx(), oe->staffIdx() + 1);
_selection.extendRangeSelection(cr);
} else {
select(e, SelectType::SINGLE, 0);
doSelect(e, SelectType::SINGLE, 0);
return;
}
} else if (_selection.isRange()) {
@ -3600,7 +3718,7 @@ void Score::selectRange(EngravingItem* e, staff_idx_t staffIdx)
}
}
}
select(e, SelectType::SINGLE, staffIdx);
doSelect(e, SelectType::SINGLE, staffIdx);
return;
}
@ -3761,9 +3879,7 @@ void Score::selectSimilar(EngravingItem* e, bool sameStaff)
score->scanElements(&pattern, collectMatch);
score->select(0, SelectType::SINGLE, 0);
for (EngravingItem* ee : pattern.el) {
score->select(ee, SelectType::ADD, 0);
}
score->select(pattern.el, SelectType::ADD, 0);
}
//---------------------------------------------------------
@ -3796,9 +3912,7 @@ void Score::selectSimilarInRange(EngravingItem* e)
score->scanElementsInRange(&pattern, collectMatch);
score->select(0, SelectType::SINGLE, 0);
for (EngravingItem* ee : pattern.el) {
score->select(ee, SelectType::ADD, 0);
}
score->select(pattern.el, SelectType::ADD, 0);
}
//---------------------------------------------------------
@ -3925,14 +4039,18 @@ void Score::lassoSelect(const RectF& bbox)
break;
}
std::vector<EngravingItem*> el = page->items(frr);
for (EngravingItem* e : el) {
if (frr.contains(e->abbox())) {
if (e->type() != ElementType::MEASURE && e->selectable()) {
select(e, SelectType::ADD, 0);
std::vector<EngravingItem*> items = page->items(frr);
std::vector<EngravingItem*> itemsToSelect;
for (EngravingItem* item : items) {
if (frr.contains(item->abbox())) {
if (item->type() != ElementType::MEASURE && item->selectable()) {
itemsToSelect.push_back(item);
}
}
}
select(itemsToSelect, SelectType::ADD, 0);
}
}
@ -3940,7 +4058,7 @@ void Score::lassoSelect(const RectF& bbox)
// lassoSelectEnd
//---------------------------------------------------------
void Score::lassoSelectEnd(bool convertToRange)
void Score::lassoSelectEnd()
{
int noteRestCount = 0;
Segment* startSegment = 0;
@ -3956,11 +4074,6 @@ void Score::lassoSelectEnd(bool convertToRange)
}
_selection.setState(SelState::LIST);
if (!convertToRange) {
setUpdateAll();
return;
}
for (const EngravingItem* e : _selection.elements()) {
if (e->type() != ElementType::NOTE && e->type() != ElementType::REST) {
continue;
@ -5198,9 +5311,8 @@ void Score::changeSelectedNotesVoice(voice_idx_t voice)
if (!el.empty()) {
selection().clear();
}
for (EngravingItem* e : el) {
select(e, SelectType::ADD, mu::nidx);
}
select(el, SelectType::ADD, mu::nidx);
setLayoutAll();
}

View File

@ -32,6 +32,7 @@
#include "async/channel.h"
#include "io/iodevice.h"
#include "types/ret.h"
#include "modularity/ioc.h"
#include "draw/iimageprovider.h"
@ -459,13 +460,14 @@ private:
std::list<Fraction> splitGapToMeasureBoundaries(ChordRest*, Fraction);
void pasteChordRest(ChordRest* cr, const Fraction& tick, const Interval&);
void doSelect(EngravingItem* e, SelectType type, staff_idx_t staffIdx);
void selectSingle(EngravingItem* e, staff_idx_t staffIdx);
void selectAdd(EngravingItem* e);
void selectRange(EngravingItem* e, staff_idx_t staffIdx);
void cmdToggleVisible();
void putNote(const Position&, bool replace);
Ret putNote(const Position&, bool replace);
void resetTempo();
void resetTempoRange(const Fraction& tick1, const Fraction& tick2);
@ -732,14 +734,14 @@ public:
void cmdDeleteSelection();
void cmdFullMeasureRest();
void putNote(const mu::PointF&, bool replace, bool insert);
void insertChord(const Position&);
Ret putNote(const mu::PointF&, bool replace, bool insert);
Ret insertChord(const Position&);
void localInsertChord(const Position&);
void globalInsertChord(const Position&);
void cloneVoice(track_idx_t strack, track_idx_t dtrack, Segment* sf, const Fraction& lTick, bool link = true, bool spanner = true);
void repitchNote(const Position& pos, bool replace);
Ret repitchNote(const Position& pos, bool replace);
void regroupNotesAndRests(const Fraction& startTick, const Fraction& endTick, track_idx_t track);
bool checkTimeDelete(Segment*, Segment*);
void timeDelete(Measure*, Segment*, const Fraction&);
@ -808,7 +810,8 @@ public:
std::set<ChordRest*> getSelectedChordRests() const;
void getSelectedChordRest2(ChordRest** cr1, ChordRest** cr2) const;
void select(EngravingItem* obj, SelectType = SelectType::SINGLE, staff_idx_t staff = 0);
void select(EngravingItem* item, SelectType = SelectType::SINGLE, staff_idx_t staff = 0);
void select(const std::vector<EngravingItem*>& items, SelectType = SelectType::SINGLE, staff_idx_t staff = 0);
void selectSimilar(EngravingItem* e, bool sameStaff);
void selectSimilarInRange(EngravingItem* e);
static void collectMatch(void* data, EngravingItem* e);
@ -967,7 +970,7 @@ public:
void setBracketsAndBarlines();
void lassoSelect(const mu::RectF&);
void lassoSelectEnd(bool);
void lassoSelectEnd();
Page* searchPage(const mu::PointF&) const;
std::vector<System*> searchSystem(const mu::PointF& p, const System* preferredSystem = nullptr, double spacingFactor = 0.5,
@ -1160,7 +1163,9 @@ public:
void setNoteHeadWidth(double n) { _noteHeadWidth = n; }
std::list<staff_idx_t> uniqueStaves() const;
void transpositionChanged(Part* part, Interval oldTransposition, Fraction tickStart = { 0, 1 }, Fraction tickEnd = { -1, 1 });
void transpositionChanged(Part* part, const Fraction& instrumentTick, Interval oldTransposition);
void moveUp(ChordRest*);
void moveDown(ChordRest*);

View File

@ -552,8 +552,8 @@ void Selection::updateSelectedElements()
// the first segment for them.
return;
}
if (s2 && s2 == s2->measure()->first()) {
s2 = s2->prev1(); // we want the last segment of the previous measure
if (s2 && s2 == s2->measure()->first() && !(s2->measure()->prevMeasure() && s2->measure()->prevMeasure()->mmRest1())) {
s2 = s2->prev1(); // we want the last segment of the previous measure (unless it's part of a MMrest)
}
setRange(s1, s2, staffStart, staffEnd);
_plannedTick1 = Fraction(-1, 1);

View File

@ -44,7 +44,7 @@ class Chord;
//---------------------------------------------------------
struct ElementPattern {
std::list<EngravingItem*> el;
std::vector<EngravingItem*> el;
int type = 0;
int subtype = 0;
staff_idx_t staffStart = 0;

View File

@ -1053,24 +1053,25 @@ void Slur::slurPos(SlurPos* sp)
};
SlurAnchor sa1 = SlurAnchor::NONE;
SlurAnchor sa2 = SlurAnchor::NONE;
if (sc && sc->hook() && sc->up() == _up) {
sa1 = SlurAnchor::STEM;
}
if (scr->up() == ecr->up() && scr->up() == _up) {
if (stem1 && !stemSideStartForBeam()) {
if (staffHasStems) {
if (sc && sc->hook() && sc->up() == _up) {
sa1 = SlurAnchor::STEM;
}
if (stem2 && !stemSideEndForBeam()) {
sa2 = SlurAnchor::STEM;
}
} else if (ecr->segment()->system() != scr->segment()->system()) {
// in the case of continued slurs, we anchor to stem when necessary
if (scr->up() == _up && stem1 && !scr->beam()) {
sa1 = SlurAnchor::STEM;
}
if (ecr->up() == _up && stem2 && !ecr->beam()) {
sa2 = SlurAnchor::STEM;
if (scr->up() == ecr->up() && scr->up() == _up) {
if (stem1 && !stemSideStartForBeam()) {
sa1 = SlurAnchor::STEM;
}
if (stem2 && !stemSideEndForBeam()) {
sa2 = SlurAnchor::STEM;
}
} else if (ecr->segment()->system() != scr->segment()->system()) {
// in the case of continued slurs, we anchor to stem when necessary
if (scr->up() == _up && stem1 && !scr->beam()) {
sa1 = SlurAnchor::STEM;
}
if (ecr->up() == _up && stem2 && !ecr->beam()) {
sa2 = SlurAnchor::STEM;
}
}
}
@ -2094,7 +2095,8 @@ bool Slur::isOverBeams()
ChordRest* cr = toChordRest(seg->elist().at(track));
bool hasBeam = cr->beam() && cr->up() == up();
bool hasTrem = false;
if (Chord* c = toChord(cr)) {
if (cr->isChord()) {
Chord* c = toChord(cr);
hasTrem = c->tremolo() && c->tremolo()->twoNotes() && c->up() == up();
}
if (!(hasBeam || hasTrem)) {

View File

@ -399,21 +399,6 @@ Spanner::Spanner(const Spanner& s)
}
}
Spanner::~Spanner()
{
for (SpannerSegment* s : segments) {
if (s->parent() == this) {
delete s;
}
}
for (SpannerSegment* s : unusedSegments) {
if (s->parent() == this) {
delete s;
}
}
}
//---------------------------------------------------------
// mag
//---------------------------------------------------------
@ -1016,24 +1001,7 @@ Segment* Spanner::startSegment() const
Segment* Spanner::endSegment() const
{
Segment* endSeg = score()->tick2leftSegment(tick2());
if (!systemFlag()) {
return endSeg;
}
if (endSeg->rtick().ticks() == 0) {
// If this is the first segment of the measure, it may not be the left-most segment at this tick.
// There could be segments at the end of the previous measure. We nees those for correct layout of system lines.
Measure* prevMeas = endSeg->measure()->prevMeasure();
if (prevMeas) {
for (Segment& s : prevMeas->segments()) {
if (s.tick() == tick2()) {
endSeg = &s;
break;
}
}
}
}
return endSeg;
return score()->tick2leftSegment(tick2());
}
//---------------------------------------------------------
@ -1668,6 +1636,10 @@ void SpannerSegment::autoplaceSpannerSegment()
sl.add(sh.translated(pos()));
double yd = 0.0;
staff_idx_t stfIdx = systemFlag() ? staffIdxOrNextVisible() : staffIdx();
if (stfIdx == mu::nidx) {
_skipDraw = true;
return;
}
if (above) {
double d = system()->topDistance(stfIdx, sl);
if (d > -md) {

View File

@ -186,9 +186,6 @@ protected:
const std::vector<SpannerSegment*> spannerSegments() const { return segments; }
public:
~Spanner();
// Score Tree functions
virtual EngravingObject* scanParent() const override;
virtual EngravingObjectList scanChildren() const override;

View File

@ -80,15 +80,6 @@ Staff::Staff(const Staff& staff)
_part = staff._part;
}
//---------------------------------------------------------
// ~Staff
//---------------------------------------------------------
Staff::~Staff()
{
DeleteAll(brackets());
}
//---------------------------------------------------------
// clone
//---------------------------------------------------------

View File

@ -128,9 +128,7 @@ private:
void updateVisibilityVoices(Staff* masterStaff, const TracksMap& tracks);
public:
Staff* clone() const override;
~Staff();
void init(const InstrumentTemplate*, const StaffType* staffType, int);
void initFromStaffType(const StaffType* staffType);

View File

@ -914,7 +914,6 @@ void System::layout2(const LayoutContext& ctx)
}
if (visibleStaves.empty()) {
LOGD() << "====no visible staves, staves: " << _staves.size() << ", score staves: " << score()->nstaves();
return;
}
@ -1710,7 +1709,6 @@ staff_idx_t System::firstVisibleSysStaff() const
return i;
}
}
LOGD("no sys staff");
return mu::nidx;
}
@ -1726,7 +1724,6 @@ staff_idx_t System::lastVisibleSysStaff() const
return static_cast<staff_idx_t>(i);
}
}
LOGD("no sys staff");
return mu::nidx;
}

View File

@ -2293,10 +2293,12 @@ void TextBase::writeProperties(XmlWriter& xml, bool writeText, bool /*writeStyle
}
}
for (const auto& spp : *textStyle(textStyleType())) {
if (!isStyled(spp.pid) && spp.pid != Pid::FONT_FACE && spp.pid != Pid::FONT_SIZE && spp.pid != Pid::FONT_STYLE
&& spp.pid != Pid::TEXT_SCRIPT_ALIGN) {
writeProperty(xml, spp.pid);
if (isStyled(spp.pid)
|| (spp.pid == Pid::FONT_SIZE && getProperty(spp.pid).toDouble() == TextBase::UNDEFINED_FONT_SIZE)
|| (spp.pid == Pid::FONT_FACE && getProperty(spp.pid).value<String>() == TextBase::UNDEFINED_FONT_FAMILY)) {
continue;
}
writeProperty(xml, spp.pid);
}
if (writeText) {
xml.writeXml(u"text", xmlText());
@ -2332,7 +2334,9 @@ bool TextBase::readProperties(XmlReader& e)
}
}
if (tag == "text") {
setXmlText(e.readXml());
String str = e.readXml();
setXmlText(str);
checkCustomFormatting(str);
} else if (tag == "bold") {
bool val = e.readInt();
if (val) {
@ -2501,6 +2505,19 @@ void TextBase::setXmlText(const String& s)
layoutInvalid = true;
}
void TextBase::checkCustomFormatting(const String& s)
{
if (s.contains(u"<font face")) {
setPropertyFlags(Pid::FONT_FACE, PropertyFlags::UNSTYLED);
}
if (s.contains(u"<font size")) {
setPropertyFlags(Pid::FONT_SIZE, PropertyFlags::UNSTYLED);
}
if (s.contains(u"<b>") || s.contains(u"<i>") || s.contains(u"<u>") || s.contains(u"<s>")) {
setPropertyFlags(Pid::FONT_STYLE, PropertyFlags::UNSTYLED);
}
}
void TextBase::resetFormatting()
{
// reset any formatting properties that can be changed per-character (doesn't change existing text)

View File

@ -365,6 +365,7 @@ public:
void setPlainText(const String& t) { setXmlText(plainToXmlText(t)); }
virtual void setXmlText(const String&);
void setXmlText(const char* str) { setXmlText(String::fromUtf8(str)); }
void checkCustomFormatting(const String&);
String xmlText() const;
String plainText() const;
void resetFormatting();
@ -505,12 +506,16 @@ public:
inline bool isTextNavigationKey(int key, KeyboardModifiers modifiers)
{
if (modifiers & TextEditingControlModifier) {
static const std::set<int> standardTextOperationsKeys {
Key_Space, // Ctrl + Space inserts the space symbol
Key_A // select all
static const std::set<int> controlNavigationKeys {
Key_Left,
Key_Right,
Key_Up,
Key_Down,
Key_Home,
Key_End
};
return standardTextOperationsKeys.find(key) == standardTextOperationsKeys.end();
return controlNavigationKeys.find(key) != controlNavigationKeys.end();
}
static const std::set<int> navigationKeys {

View File

@ -860,4 +860,17 @@ void Score::transpositionChanged(Part* part, Interval oldV, Fraction tickStart,
}
}
}
void Score::transpositionChanged(Part* part, const Fraction& instrumentTick, Interval oldTransposition)
{
Fraction tickStart = instrumentTick;
Fraction tickEnd = { -1, 1 };
auto mainInstrumentEndIt = part->instruments().upper_bound(tickStart.ticks());
if (mainInstrumentEndIt != part->instruments().cend()) {
tickEnd = Fraction::fromTicks(mainInstrumentEndIt->first);
}
transpositionChanged(part, oldTransposition, tickStart, tickEnd);
}
}

View File

@ -53,7 +53,7 @@ class Tremolo final : public EngravingItem
DirectionV _direction;
mu::draw::PainterPath path;
int _lines; // derived from _subtype
int _lines = 0; // derived from _subtype
TremoloStyle _style { TremoloStyle::DEFAULT };
friend class Factory;

View File

@ -80,3 +80,13 @@ int SpannerFilter::spannerActualDurationTicks(const Spanner* spanner, const int
return nominalDurationTicks;
}
bool SpannerFilter::isMultiStaffSpanner(const Spanner* spanner)
{
static const ElementTypeSet MULTI_STAFF_SPANNERS = {
ElementType::PEDAL,
ElementType::PEDAL_SEGMENT
};
return MULTI_STAFF_SPANNERS.find(spanner->type()) != MULTI_STAFF_SPANNERS.cend();
}

View File

@ -36,6 +36,7 @@ public:
//!HACK Unfortunately, the behavior of different types of "spanners" is not consistent in terms of
//! calculation of their durations. This hack would not be actual once we'll get rid of "anchors" system
static int spannerActualDurationTicks(const Spanner* spanner, const int nominalDurationTicks);
static bool isMultiStaffSpanner(const Spanner* spanner);
protected:
friend class FilterBase<SpannerFilter>;

View File

@ -27,9 +27,9 @@
using namespace mu::engraving;
using namespace mu::mpe;
const PlaybackSetupData& KeyboardsSetupDataResolver::doResolve(const Instrument* instrument)
PlaybackSetupData KeyboardsSetupDataResolver::doResolve(const Instrument* instrument)
{
static std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
static const std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "celesta", { SoundId::Celesta, SoundCategory::Keyboards, {}, {} } },
{ "clavichord", { SoundId::Clavichord, SoundCategory::Keyboards, { SoundSubCategory::Baroque }, {} } },
{ "clavinet", { SoundId::Clavichord, SoundCategory::Keyboards, { SoundSubCategory::Electric }, {} } },

View File

@ -29,7 +29,7 @@ namespace mu::engraving {
class KeyboardsSetupDataResolver : public SetupDataResolverBase<KeyboardsSetupDataResolver>
{
public:
static const mpe::PlaybackSetupData& doResolve(const Instrument* instrument);
static mpe::PlaybackSetupData doResolve(const Instrument* instrument);
};
}

View File

@ -25,9 +25,9 @@
using namespace mu::engraving;
using namespace mu::mpe;
const PlaybackSetupData& PercussionsSetupDataResolver::doResolve(const Instrument* instrument)
PlaybackSetupData PercussionsSetupDataResolver::doResolve(const Instrument* instrument)
{
static std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
static const std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "timpani", { SoundId::Timpani, SoundCategory::Percussions, {}, {} } },
{ "roto-toms", { SoundId::RotoToms, SoundCategory::Percussions, {}, {} } },
{ "tubaphone", { SoundId::Tubaphone, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
@ -117,6 +117,7 @@ const PlaybackSetupData& PercussionsSetupDataResolver::doResolve(const Instrumen
{ "anvil", { SoundId::Anvil, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "bell-plate", { SoundId::Bell, SoundCategory::Percussions, { SoundSubCategory::Plate,
SoundSubCategory::Metal }, {} } },
{ "bell-tree", { SoundId::BellTree, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "bells", { SoundId::Bell, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "bowl-gongs", { SoundId::Gong, SoundCategory::Percussions, { SoundSubCategory::Metal,
SoundSubCategory::Bowl }, {} } },
@ -133,6 +134,7 @@ const PlaybackSetupData& PercussionsSetupDataResolver::doResolve(const Instrumen
{ "hi-hat", { SoundId::HiHat, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "iron-pipes", { SoundId::Pipe, SoundCategory::Percussions, { SoundSubCategory::Metal,
SoundSubCategory::Iron }, {} } },
{ "mark-tree", { SoundId::MarkTree, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "metal-castanets", { SoundId::Castanet, SoundCategory::Percussions, { SoundSubCategory::Metal }, {} } },
{ "metal-wind-chimes", { SoundId::Chimes, SoundCategory::Percussions, { SoundSubCategory::Metal,
SoundSubCategory::Wind }, {} } },

View File

@ -29,7 +29,7 @@ namespace mu::engraving {
class PercussionsSetupDataResolver : public SetupDataResolverBase<PercussionsSetupDataResolver>
{
public:
static const mpe::PlaybackSetupData& doResolve(const Instrument* instrument);
static mpe::PlaybackSetupData doResolve(const Instrument* instrument);
};
}

View File

@ -25,153 +25,227 @@
using namespace mu::engraving;
using namespace mu::mpe;
const PlaybackSetupData& StringsSetupDataResolver::doResolve(const Instrument* instrument)
PlaybackSetupData StringsSetupDataResolver::doResolve(const Instrument* instrument)
{
static std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "harp", { SoundId::Harp, SoundCategory::Strings, {}, {} } },
static const std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "harp", { SoundId::Harp, SoundCategory::Strings, { mpe::SoundSubCategory::Plucked }, {} } },
{ "cavaquinho", { SoundId::Cavaquinho, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "cavaquinho-tablature", { SoundId::Cavaquinho, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "soprano-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Soprano }, {} } },
SoundSubCategory::Soprano,
SoundSubCategory::Plucked }, {} } },
{ "alto-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Alto }, {} } },
SoundSubCategory::Alto,
SoundSubCategory::Plucked }, {} } },
{ "baritone-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Baritone }, {} } },
SoundSubCategory::Baritone,
SoundSubCategory::Plucked }, {} } },
{ "contra-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Contra }, {} } },
SoundSubCategory::Contra,
SoundSubCategory::Plucked }, {} } },
{ "electric-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "electric-guitar-treble-clef", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "electric-guitar-treble-clef", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "electric-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "electric-guitar-treble-clef", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "electric-guitar-tablature", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "guitar-steel", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "guitar-steel-treble-clef", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "guitar-steel-tablature", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "pedal-steel-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Pedal,
SoundSubCategory::Steel }, {} } },
SoundSubCategory::Steel,
SoundSubCategory::Plucked }, {} } },
{ "guitar-nylon", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon }, {} } },
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {} } },
{ "guitar-nylon-treble-clef", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon }, {} } },
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {} } },
{ "guitar-nylon-tablature", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon }, {} } },
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {} } },
{ "7-string-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon }, {} } },
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {} } },
{ "7-string-guitar-tablature", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon }, {} } },
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {} } },
{ "11-string-alto-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Alto }, {} } },
SoundSubCategory::Alto,
SoundSubCategory::Plucked }, {} } },
{ "12-string-guitar", { SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Steel,
SoundSubCategory::TwelveString }, {} } },
SoundSubCategory::TwelveString,
SoundSubCategory::Plucked }, {} } },
{ "5-string-electric-bass-high-c", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Tenor }, {} } },
SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "5-string-electric-bass-tab-high-c", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Tenor }, {} } },
{ "5-string-electric-bass-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "5-string-electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "6-string-electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "6-string-electric-bass-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "bass-guitar", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "bass-guitar-tablature", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "electric-bass-4-str-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
{ "electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric }, {} } },
SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "5-string-electric-bass-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "5-string-electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "6-string-electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "6-string-electric-bass-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "bass-guitar", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "bass-guitar-tablature", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "electric-bass-4-str-tab", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Plucked }, {} } },
{ "fretless-electric-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Fretless }, {} } },
{ "acoustic-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Acoustic }, {} } },
SoundSubCategory::Fretless,
SoundSubCategory::Plucked }, {} } },
{ "acoustic-bass", { SoundId::BassGuitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Plucked }, {} } },
{ "banjo", { SoundId::Banjo, SoundCategory::Strings, {}, {} } },
{ "tenor-banjo", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "banjo-tablature", { SoundId::Banjo, SoundCategory::Strings, {}, {} } },
{ "banjo", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "tenor-banjo", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "banjo-tablature", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "irish-tenor-banjo", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Irish,
SoundSubCategory::Tenor }, {} } },
SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "irish-tenor-banjo-tablature", { SoundId::Banjo, SoundCategory::Strings, { SoundSubCategory::Irish,
SoundSubCategory::Tenor }, {} } },
SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "ukulele", { SoundId::Ukulele, SoundCategory::Strings, {}, {} } },
{ "ukulele-4-str-tab", { SoundId::Ukulele, SoundCategory::Strings, {}, {} } },
{ "ukulele-low-g", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "tenor-ukulele", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "baritone-ukulele", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Baritone }, {} } },
{ "ukulele", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "ukulele-4-str-tab", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "ukulele-low-g", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "tenor-ukulele", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "baritone-ukulele", { SoundId::Ukulele, SoundCategory::Strings, { SoundSubCategory::Baritone,
SoundSubCategory::Plucked }, {} } },
{ "mandolin", { SoundId::Mandolin, SoundCategory::Strings, {}, {} } },
{ "mandolin-tablature", { SoundId::Mandolin, SoundCategory::Strings, {}, {} } },
{ "alto-mandola", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Alto }, {} } },
{ "mandola", { SoundId::Mandolin, SoundCategory::Strings, {}, {} } },
{ "tenor-mandola", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "octave-mandolin", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Octave }, {} } },
{ "mandocello", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Octave }, {} } },
{ "mandolin", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "mandolin-tablature", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "alto-mandola", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Alto,
SoundSubCategory::Plucked }, {} } },
{ "mandola", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "tenor-mandola", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "octave-mandolin", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Octave,
SoundSubCategory::Plucked }, {} } },
{ "mandocello", { SoundId::Mandolin, SoundCategory::Strings, { SoundSubCategory::Octave,
SoundSubCategory::Plucked }, {} } },
{ "mtn-dulcimer-std", { SoundId::MtnDulcimer, SoundCategory::Strings, {}, {} } },
{ "mtn-dulcimer-std-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, {}, {} } },
{ "mtn-dulcimer-baritone", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Baritone }, {} } },
{ "mtn-dulcimer-bartn-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Baritone }, {} } },
{ "mtn-dulcimer-bass", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Bass }, {} } },
{ "mtn-dulcimer-bass-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Bass }, {} } },
{ "mtn-dulcimer-std", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "mtn-dulcimer-std-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "mtn-dulcimer-baritone", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Baritone,
SoundSubCategory::Plucked, }, {} } },
{ "mtn-dulcimer-bartn-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Baritone,
SoundSubCategory::Plucked }, {} } },
{ "mtn-dulcimer-bass", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Bass,
SoundSubCategory::Plucked }, {} } },
{ "mtn-dulcimer-bass-chrom-tab", { SoundId::MtnDulcimer, SoundCategory::Strings, { SoundSubCategory::Bass,
SoundSubCategory::Plucked }, {} } },
{ "lute", { SoundId::Lute, SoundCategory::Strings, {}, {} } },
{ "lute-tablature", { SoundId::Lute, SoundCategory::Strings, {}, {} } },
{ "ren.-tenor-lute-5-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "ren.-tenor-lute-6-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "ren.-tenor-lute-7-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "ren.-tenor-lute-8-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "ren.-tenor-lute-9-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "ren.-tenor-lute-10-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor }, {} } },
{ "baroque-lute-13-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Baroque }, {} } },
{ "archlute-14-course", { SoundId::Lute, SoundCategory::Strings, {}, {} } },
{ "bouzouki-3-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Greek }, {} } },
{ "bouzouki-4-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Greek }, {} } },
{ "lute", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "lute-tablature", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "ren.-tenor-lute-5-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "ren.-tenor-lute-6-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "ren.-tenor-lute-7-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "ren.-tenor-lute-8-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "ren.-tenor-lute-9-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked, }, {} } },
{ "ren.-tenor-lute-10-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Tenor,
SoundSubCategory::Plucked }, {} } },
{ "baroque-lute-13-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Baroque,
SoundSubCategory::Plucked }, {} } },
{ "archlute-14-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "bouzouki-3-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Greek,
SoundSubCategory::Plucked }, {} } },
{ "bouzouki-4-course", { SoundId::Lute, SoundCategory::Strings, { SoundSubCategory::Greek,
SoundSubCategory::Plucked }, {} } },
{ "theorbo-14-course", { SoundId::Theorbo, SoundCategory::Strings, {}, {} } },
{ "theorbo-14-course", { SoundId::Theorbo, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "balalaika", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima }, {} } },
{ "balalaika-piccolo", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Piccolo }, {} } },
{ "balalaika-prima", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima }, {} } },
{ "balalaika", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-piccolo", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Piccolo,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-prima", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-alto", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima,
SoundSubCategory::Alto }, {} } },
SoundSubCategory::Alto,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-bass", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima,
SoundSubCategory::Bass }, {} } },
SoundSubCategory::Bass,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-contrabass", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Prima,
SoundSubCategory::Contra_Bass }, {} } },
{ "balalaika-secunda", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Secunda }, {} } },
SoundSubCategory::Contra_Bass,
SoundSubCategory::Plucked }, {} } },
{ "balalaika-secunda", { SoundId::Balalaika, SoundCategory::Strings, { SoundSubCategory::Secunda,
SoundSubCategory::Plucked }, {} } },
{ "koto", { SoundId::Koto, SoundCategory::Strings, { SoundSubCategory::Japanese }, {} } },
{ "shamisen", { SoundId::Shamisen, SoundCategory::Strings, { SoundSubCategory::Japanese }, {} } },
{ "sitar", { SoundId::Sitar, SoundCategory::Strings, { SoundSubCategory::Indian }, {} } },
{ "oud", { SoundId::Oud, SoundCategory::Strings, { SoundSubCategory::African }, {} } },
{ "prim", { SoundId::Prim, SoundCategory::Strings, {}, {} } },
{ "brac", { SoundId::Brac, SoundCategory::Strings, {}, {} } },
{ "bugarija", { SoundId::Bugarija, SoundCategory::Strings, {}, {} } },
{ "berda", { SoundId::Berda, SoundCategory::Strings, {}, {} } },
{ "celo", { SoundId::Celo, SoundCategory::Strings, {}, {} } },
{ "bandurria", { SoundId::Bandurria, SoundCategory::Strings, { SoundSubCategory::Spanish }, {} } },
{ "bandurria-tablature", { SoundId::Bandurria, SoundCategory::Strings, { SoundSubCategory::Spanish }, {} } },
{ "laud", { SoundId::Laud, SoundCategory::Strings, { SoundSubCategory::Spanish }, {} } },
{ "laud-tablature", { SoundId::Laud, SoundCategory::Strings, { SoundSubCategory::Spanish }, {} } },
{ "koto", { SoundId::Koto, SoundCategory::Strings, { SoundSubCategory::Japanese,
SoundSubCategory::Plucked }, {} } },
{ "shamisen", { SoundId::Shamisen, SoundCategory::Strings, { SoundSubCategory::Japanese,
SoundSubCategory::Plucked }, {} } },
{ "sitar", { SoundId::Sitar, SoundCategory::Strings, { SoundSubCategory::Indian,
SoundSubCategory::Plucked }, {} } },
{ "oud", { SoundId::Oud, SoundCategory::Strings, { SoundSubCategory::African,
SoundSubCategory::Plucked }, {} } },
{ "prim", { SoundId::Prim, SoundCategory::Strings, { SoundSubCategory::Plucked, }, {} } },
{ "brac", { SoundId::Brac, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "bugarija", { SoundId::Bugarija, SoundCategory::Strings, { mpe::SoundSubCategory::Plucked }, {} } },
{ "berda", { SoundId::Berda, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "celo", { SoundId::Celo, SoundCategory::Strings, { SoundSubCategory::Plucked }, {} } },
{ "bandurria", { SoundId::Bandurria, SoundCategory::Strings, { SoundSubCategory::Spanish,
SoundSubCategory::Plucked }, {} } },
{ "bandurria-tablature", { SoundId::Bandurria, SoundCategory::Strings, { SoundSubCategory::Spanish,
SoundSubCategory::Plucked }, {} } },
{ "laud", { SoundId::Laud, SoundCategory::Strings, { SoundSubCategory::Spanish,
SoundSubCategory::Plucked }, {} } },
{ "laud-tablature", { SoundId::Laud, SoundCategory::Strings, { SoundSubCategory::Spanish,
SoundSubCategory::Plucked }, {} } },
{ "strings", { SoundId::StringsGroup, SoundCategory::Strings, {}, {} } },
{ "double-bass", { SoundId::Contrabass, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "contrabass", { SoundId::Contrabass, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "contrabasses", { SoundId::ContrabassSection, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "contrabasses", { SoundId::Contrabass, SoundCategory::Strings, { SoundSubCategory::Orchestral,
SoundSubCategory::Section }, {} } },
{ "violin", { SoundId::Violin, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violins", { SoundId::ViolinSection, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violins", { SoundId::Violin, SoundCategory::Strings, { SoundSubCategory::Orchestral,
SoundSubCategory::Section }, {} } },
{ "viola", { SoundId::Viola, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violas", { SoundId::ViolaSection, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violas", { SoundId::Viola, SoundCategory::Strings, { SoundSubCategory::Orchestral,
SoundSubCategory::Section }, {} } },
{ "violoncello", { SoundId::Violoncello, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violoncellos", { SoundId::VioloncelloSection, SoundCategory::Strings, { SoundSubCategory::Orchestral }, {} } },
{ "violoncellos", { SoundId::Violoncello, SoundCategory::Strings, { SoundSubCategory::Orchestral,
SoundSubCategory::Section }, {} } },
{ "treble-viol", { SoundId::Viol, SoundCategory::Strings, {}, {} } },
{ "alto-viol", { SoundId::Viol, SoundCategory::Strings, { SoundSubCategory::Alto }, {} } },
@ -188,7 +262,8 @@ const PlaybackSetupData& StringsSetupDataResolver::doResolve(const Instrument* i
{ "nyckelharpa", { SoundId::Nyckelharpa, SoundCategory::Strings, { SoundSubCategory::Swedish }, {} } },
{ "bass-synthesizer", { SoundId::Synthesizer, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Bass }, {} } },
SoundSubCategory::Bass,
SoundSubCategory::Plucked }, {} } },
{ "bowed-synth", { SoundId::Synthesizer, SoundCategory::Strings, { SoundSubCategory::Electric,
SoundSubCategory::Bowed }, {} } },
};
@ -199,5 +274,16 @@ const PlaybackSetupData& StringsSetupDataResolver::doResolve(const Instrument* i
return empty;
}
static const std::unordered_set<SoundId> supportPrimaryAndSecondaryCategories {
SoundId::Violin
};
if (mu::contains(supportPrimaryAndSecondaryCategories, search->second.id)) {
SoundSubCategory category = instrument->isPrimary() ? SoundSubCategory::Primary : SoundSubCategory::Secondary;
PlaybackSetupData setupData = search->second;
setupData.subCategorySet.insert(category);
return setupData;
}
return search->second;
}

View File

@ -29,7 +29,7 @@ namespace mu::engraving {
class StringsSetupDataResolver : public SetupDataResolverBase<StringsSetupDataResolver>
{
public:
static const mpe::PlaybackSetupData& doResolve(const Instrument* instrument);
static mpe::PlaybackSetupData doResolve(const Instrument* instrument);
};
}

View File

@ -25,15 +25,15 @@
using namespace mu::engraving;
using namespace mu::mpe;
const PlaybackSetupData& VoicesSetupDataResolver::doResolve(const Instrument* instrument)
PlaybackSetupData VoicesSetupDataResolver::doResolve(const Instrument* instrument)
{
static std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
static const std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "boy-soprano", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Soprano,
SoundSubCategory::Boy }, {} } },
{ "soprano", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Soprano }, {} } },
{ "soprano-c-clef", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Soprano }, {} } },
{ "mezzo-soprano", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Mezzo_Soprano }, {} } },
{ "mezzo-soprano-c-clef", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Mezzo_Soprano }, {} } },
{ "mezzo-soprano", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Soprano }, {} } },
{ "mezzo-soprano-c-clef", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Soprano }, {} } },
{ "countertenor", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Counter_Tenor }, {} } },
{ "alto", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Alto }, {} } },
{ "alto-c-clef", { SoundId::Choir, SoundCategory::Voices, { SoundSubCategory::Alto }, {} } },

View File

@ -29,7 +29,7 @@ namespace mu::engraving {
class VoicesSetupDataResolver : public SetupDataResolverBase<VoicesSetupDataResolver>
{
public:
static const mpe::PlaybackSetupData& doResolve(const Instrument* instrument);
static mpe::PlaybackSetupData doResolve(const Instrument* instrument);
};
}

View File

@ -25,9 +25,9 @@
using namespace mu::engraving;
using namespace mu::mpe;
const PlaybackSetupData& WindsSetupDataResolver::doResolve(const Instrument* instrument)
PlaybackSetupData WindsSetupDataResolver::doResolve(const Instrument* instrument)
{
static std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
static const std::unordered_map<std::string, mpe::PlaybackSetupData> SETUP_DATA_MAP = {
{ "winds", { SoundId::WindsGroup, SoundCategory::Winds, {}, {} } },
{ "eb-piccolo", { SoundId::Piccolo, SoundCategory::Winds, {}, {} } },
{ "db-piccolo", { SoundId::Piccolo, SoundCategory::Winds, {}, {} } },
@ -92,6 +92,8 @@ const PlaybackSetupData& WindsSetupDataResolver::doResolve(const Instrument* ins
{ "tenor-gemshorn", { SoundId::Gemshorn, SoundCategory::Winds, { SoundSubCategory::Tenor }, {} } },
{ "bass-gemshorn", { SoundId::Gemshorn, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "theremin", { SoundId::Theremin, SoundCategory::Winds, { SoundSubCategory::Electric }, {} } },
{ "pan-flute", { SoundId::PanFlute, SoundCategory::Winds, {}, {} } },
{ "quena", { SoundId::Quena, SoundCategory::Winds, {}, {} } },
@ -161,19 +163,24 @@ const PlaybackSetupData& WindsSetupDataResolver::doResolve(const Instrument* ins
{ "piccolo-clarinet", { SoundId::Clarinet, SoundCategory::Winds, {}, {} } },
{ "soprano-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino }, {} } },
{ "eb-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino }, {} } },
{ "eb-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino,
SoundSubCategory::In_E_flat }, {} } },
{ "d-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino }, {} } },
{ "c-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino }, {} } },
{ "bb-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Sopranino }, {} } },
{ "bb-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano,
SoundSubCategory::In_B_flat }, {} } },
{ "clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano }, {} } },
{ "a-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano }, {} } },
{ "g-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano }, {} } },
{ "basset-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano }, {} } },
{ "basset-horn", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Soprano }, {} } },
{ "alto-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Alto }, {} } },
{ "bass-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "bb-bass-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "bb-bass-clarinet-bass-clef", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "bass-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass,
SoundSubCategory::In_B_flat }, {} } },
{ "bb-bass-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass,
SoundSubCategory::In_B_flat }, {} } },
{ "bb-bass-clarinet-bass-clef", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass,
SoundSubCategory::In_B_flat }, {} } },
{ "a-bass-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "a-bass-clarinet-bass-clef", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "contra-alto-clarinet", { SoundId::Clarinet, SoundCategory::Winds, { SoundSubCategory::Contra_Alto }, {} } },
@ -262,18 +269,23 @@ const PlaybackSetupData& WindsSetupDataResolver::doResolve(const Instrument* ins
{ "brass", { SoundId::BrassGroup, SoundCategory::Winds, {}, {} } },
{ "c-horn-alto", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Alto }, {} } },
{ "bb-horn-alto", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Alto }, {} } },
{ "a-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "ab-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "g-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "e-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "eb-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "d-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::French }, {} } },
{ "c-horn", { SoundId::Horn, SoundCategory::Winds, {}, {} } },
{ "c-horn-bass", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "bb-horn-basso", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Bass }, {} } },
{ "c-horn-alto", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Alto,
SoundSubCategory::In_C }, {} } },
{ "bb-horn-alto", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Alto,
SoundSubCategory::In_B_flat }, {} } },
{ "a-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_A }, {} } },
{ "ab-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_A_flat }, {} } },
{ "g-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_G }, {} } },
{ "e-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_E }, {} } },
{ "eb-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_E_flat }, {} } },
{ "d-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_D }, {} } },
{ "horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::French,
SoundSubCategory::In_F }, {} } },
{ "c-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::In_C }, {} } },
{ "c-horn-bass", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Bass,
SoundSubCategory::In_C }, {} } },
{ "bb-horn-basso", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Bass,
SoundSubCategory::In_B_flat }, {} } },
{ "vienna-horn", { SoundId::Horn, SoundCategory::Winds, { SoundSubCategory::Vienna }, {} } },
{ "bb-wagner-tuba", { SoundId::Tuba, SoundCategory::Winds, { SoundSubCategory::Wagner }, {} } },
@ -402,5 +414,16 @@ const PlaybackSetupData& WindsSetupDataResolver::doResolve(const Instrument* ins
return empty;
}
static const std::unordered_set<SoundId> supportPrimaryAndSecondaryCategories {
SoundId::Flute,
};
if (mu::contains(supportPrimaryAndSecondaryCategories, search->second.id)) {
SoundSubCategory category = instrument->isPrimary() ? SoundSubCategory::Primary : SoundSubCategory::Secondary;
PlaybackSetupData setupData = search->second;
setupData.subCategorySet.insert(category);
return setupData;
}
return search->second;
}

View File

@ -29,7 +29,7 @@ namespace mu::engraving {
class WindsSetupDataResolver : public SetupDataResolverBase<WindsSetupDataResolver>
{
public:
static const mpe::PlaybackSetupData& doResolve(const Instrument* instrument);
static mpe::PlaybackSetupData doResolve(const Instrument* instrument);
};
}

View File

@ -108,8 +108,14 @@ void ChordArticulationsParser::parseSpanners(const Chord* chord, const Rendering
continue;
}
if (spanner->part() != chord->part()) {
continue;
if (SpannerFilter::isMultiStaffSpanner(spanner)) {
if (spanner->part() != chord->part()) {
continue;
}
} else {
if (spanner->staffIdx() != chord->staffIdx()) {
continue;
}
}
if (!SpannerFilter::isItemPlayable(spanner, ctx)) {

View File

@ -68,7 +68,7 @@ void ArpeggioMetaParser::doParse(const EngravingItem* item, const RenderingConte
articulationMeta.type = type;
articulationMeta.pattern = ctx.profile->pattern(type);
articulationMeta.timestamp = ctx.nominalTimestamp;
articulationMeta.overallDuration = ctx.nominalDuration;
articulationMeta.overallDuration = ctx.nominalDuration * arpeggio->Stretch();
appendArticulationData(std::move(articulationMeta), result);
}

View File

@ -35,8 +35,15 @@ void TremoloMetaParser::doParse(const EngravingItem* item, const RenderingContex
const Tremolo* tremolo = toTremolo(item);
if (tremolo->twoNotes() && tremolo->chord2()->tick().ticks() == ctx.nominalPositionStartTick) {
return;
if (tremolo->twoNotes()) {
const Chord* chord2 = tremolo->chord2();
IF_ASSERT_FAILED(chord2) {
return;
}
if (chord2->tick().ticks() == ctx.nominalPositionStartTick) {
return;
}
}
mpe::ArticulationType type = mpe::ArticulationType::Undefined;
@ -72,7 +79,7 @@ void TremoloMetaParser::doParse(const EngravingItem* item, const RenderingContex
int overallDurationTicks = ctx.nominalDurationTicks;
if (tremolo->twoNotes() && tremolo->chord1() && tremolo->chord2()) {
overallDurationTicks = tremolo->chord1()->ticks().ticks() + tremolo->chord2()->ticks().ticks();
overallDurationTicks = tremolo->chord1()->actualTicks().ticks() + tremolo->chord2()->actualTicks().ticks();
}
mpe::ArticulationMeta articulationMeta;

View File

@ -126,13 +126,26 @@ void PlaybackContext::updateDynamicMap(const Dynamic* dynamic, const Segment* se
return;
}
applyDynamicToNextSegment(segment, prevDynamicLevel);
applyDynamicToNextSegment(segment, segmentPositionTick, prevDynamicLevel);
return;
}
const DynamicTransition& transition = dynamicTransitionFromType(type);
m_dynamicsMap[segmentPositionTick] = dynamicLevelFromType(transition.from);
applyDynamicToNextSegment(segment, dynamicLevelFromType(transition.to));
const int transitionDuration = dynamic->velocityChangeLength().ticks();
dynamic_level_t levelFrom = dynamicLevelFromType(transition.from);
dynamic_level_t levelTo = dynamicLevelFromType(transition.to);
dynamic_level_t range = levelTo - levelFrom;
std::map<int, int> dynamicsCurve = TConv::easingValueCurve(transitionDuration,
6 /*stepsCount*/,
static_cast<int>(range),
ChangeMethod::NORMAL);
for (const auto& pair : dynamicsCurve) {
m_dynamicsMap[segmentPositionTick + pair.first] = levelFrom + pair.second;
}
}
void PlaybackContext::updatePlayTechMap(const PlayTechAnnotation* annotation, const int segmentPositionTick)
@ -146,13 +159,16 @@ void PlaybackContext::updatePlayTechMap(const PlayTechAnnotation* annotation, co
m_playTechniquesMap[segmentPositionTick] = articulationFromPlayTechType(type);
}
void PlaybackContext::applyDynamicToNextSegment(const Segment* currentSegment, const mpe::dynamic_level_t dynamicLevel)
void PlaybackContext::applyDynamicToNextSegment(const Segment* currentSegment, const int segmentPositionTick,
const mpe::dynamic_level_t dynamicLevel)
{
if (!currentSegment->next()) {
return;
}
int nextSegmentPositionTick = currentSegment->next()->tick().ticks();
const int tickPositionOffset = segmentPositionTick - currentSegment->tick().ticks();
int nextSegmentPositionTick = currentSegment->next()->tick().ticks() + tickPositionOffset;
m_dynamicsMap[nextSegmentPositionTick] = dynamicLevel;
}
@ -181,12 +197,32 @@ void PlaybackContext::handleSpanners(const ID partId, const Score* score, const
int spannerDurationTicks = spannerTo - spannerFrom;
if (spannerDurationTicks == 0) {
if (spannerDurationTicks <= 0) {
continue;
}
const Hairpin* hairpin = toHairpin(spanner);
{
Dynamic* startDynamic
= toDynamic(hairpin->startSegment()->findAnnotation(ElementType::DYNAMIC, hairpin->track(), hairpin->track()));
if (startDynamic) {
if (startDynamic->dynamicType() != DynamicType::OTHER
&& !isOrdinaryDynamicType(startDynamic->dynamicType())
&& !isSingleNoteDynamicType(startDynamic->dynamicType())) {
// The hairpin starts with a transition dynamic; we should start the hairpin after the transition is complete
// This solution should be replaced once we have better infrastructure to see relations between Dynamics and Hairpins.
spannerFrom += startDynamic->velocityChangeLength().ticks();
spannerDurationTicks = spannerTo - spannerFrom;
if (spannerDurationTicks <= 0) {
continue;
}
}
}
}
DynamicType dynamicTypeFrom = hairpin->dynamicTypeFrom();
DynamicType dynamicTypeTo = hairpin->dynamicTypeTo();

View File

@ -52,7 +52,7 @@ private:
void updateDynamicMap(const Dynamic* dynamic, const Segment* segment, const int segmentPositionTick);
void updatePlayTechMap(const PlayTechAnnotation* annotation, const int segmentPositionTick);
void applyDynamicToNextSegment(const Segment* currentSegment, const mpe::dynamic_level_t dynamicLevel);
void applyDynamicToNextSegment(const Segment* currentSegment, const int segmentPositionTick, const mpe::dynamic_level_t dynamicLevel);
void handleSpanners(const ID partId, const Score* score, const int segmentStartTick, const int segmentEndTick,
const int tickPositionOffset);

View File

@ -41,6 +41,23 @@
using namespace mu::engraving;
using namespace mu::mpe;
static ArticulationMap makeArticulations(ArticulationType persistentArticulationApplied, ArticulationsProfilePtr profile,
timestamp_t timestamp, duration_t duration)
{
ArticulationMeta meta(persistentArticulationApplied,
profile->pattern(persistentArticulationApplied),
timestamp,
duration,
0,
0);
ArticulationMap articulations;
articulations.emplace(persistentArticulationApplied, mu::mpe::ArticulationAppliedData(std::move(meta), 0, mu::mpe::HUNDRED_PERCENT));
articulations.preCalculateAverageData();
return articulations;
}
void PlaybackEventsRenderer::render(const EngravingItem* item, const dynamic_level_t nominalDynamicLevel,
const ArticulationType persistentArticulationApplied,
const ArticulationsProfilePtr profile,
@ -90,7 +107,9 @@ void PlaybackEventsRenderer::render(const EngravingItem* item, const mpe::timest
}
void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol,
const int ticksPositionOffset, mpe::PlaybackEventsMap& result) const
const int ticksPositionOffset,
const mpe::ArticulationsProfilePtr profile,
mpe::PlaybackEventsMap& result) const
{
if (!chordSymbol->isRealizable()) {
return;
@ -110,7 +129,8 @@ void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol,
duration_t duration = durationFromTicks(bps.val, durationTicks);
voice_layer_idx_t voiceIdx = static_cast<voice_layer_idx_t>(chordSymbol->voice());
static ArticulationMap emptyArticulations;
ArticulationMap articulations = makeArticulations(mpe::ArticulationType::Standard, profile, eventTimestamp, duration);
for (auto it = notes.cbegin(); it != notes.cend(); ++it) {
int octave = playingOctave(it->first, it->second);
@ -121,13 +141,14 @@ void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol,
voiceIdx,
pitchLevel,
dynamicLevelFromType(mpe::DynamicType::Natural),
emptyArticulations,
articulations,
bps.val));
}
}
void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol, const mpe::timestamp_t actualTimestamp,
const mpe::duration_t actualDuration, mpe::PlaybackEventsMap& result) const
const mpe::duration_t actualDuration, const ArticulationsProfilePtr profile,
mpe::PlaybackEventsMap& result) const
{
if (!chordSymbol->isRealizable()) {
return;
@ -139,7 +160,8 @@ void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol, const
PlaybackEventList& events = result[actualTimestamp];
voice_layer_idx_t voiceIdx = static_cast<voice_layer_idx_t>(chordSymbol->voice());
static ArticulationMap emptyArticulations;
ArticulationMap articulations = makeArticulations(mpe::ArticulationType::Standard, profile, actualTimestamp, actualDuration);
for (auto it = notes.cbegin(); it != notes.cend(); ++it) {
int octave = playingOctave(it->first, it->second);
@ -150,7 +172,7 @@ void PlaybackEventsRenderer::renderChordSymbol(const Harmony* chordSymbol, const
voiceIdx,
pitchLevel,
dynamicLevelFromType(mpe::DynamicType::Natural),
emptyArticulations,
articulations,
2.0));
}
}
@ -212,7 +234,7 @@ void PlaybackEventsRenderer::renderNoteEvents(const Chord* chord, const int tick
}
int chordPosTick = chord->tick().ticks();
int chordDurationTicks = chord->durationTypeTicks().ticks();
int chordDurationTicks = chord->actualTicks().ticks();
const Score* score = chord->score();
@ -248,16 +270,7 @@ void PlaybackEventsRenderer::renderFixedNoteEvent(const Note* note, const mpe::t
const mpe::ArticulationType persistentArticulationApplied,
const mpe::ArticulationsProfilePtr profile, mpe::PlaybackEventList& result) const
{
ArticulationMeta meta(persistentArticulationApplied,
profile->pattern(persistentArticulationApplied),
actualTimestamp,
actualDuration,
0,
0);
ArticulationMap articulations;
articulations.emplace(persistentArticulationApplied, mpe::ArticulationAppliedData(std::move(meta), 0, mpe::HUNDRED_PERCENT));
articulations.preCalculateAverageData();
ArticulationMap articulations = makeArticulations(persistentArticulationApplied, profile, actualDuration, actualTimestamp);
result.emplace_back(buildFixedNoteEvent(note, actualTimestamp, actualDuration, actualDynamicLevel, articulations));
}

View File

@ -50,9 +50,10 @@ public:
const mpe::dynamic_level_t actualDynamicLevel, const mpe::ArticulationType persistentArticulationApplied,
const mpe::ArticulationsProfilePtr profile, mpe::PlaybackEventsMap& result) const;
void renderChordSymbol(const Harmony* chordSymbol, const int ticksPositionOffset, mpe::PlaybackEventsMap& result) const;
void renderChordSymbol(const Harmony* chordSymbol, const mpe::timestamp_t actualTimestamp, const mpe::duration_t actualDuration,
void renderChordSymbol(const Harmony* chordSymbol, const int ticksPositionOffset, const mpe::ArticulationsProfilePtr profile,
mpe::PlaybackEventsMap& result) const;
void renderChordSymbol(const Harmony* chordSymbol, const mpe::timestamp_t actualTimestamp, const mpe::duration_t actualDuration,
const mpe::ArticulationsProfilePtr profile, mpe::PlaybackEventsMap& result) const;
void renderMetronome(const Score* score, const int measureStartTick, const int measureEndTick, const int ticksPositionOffset,
mpe::PlaybackEventsMap& result) const;

View File

@ -208,17 +208,17 @@ void PlaybackModel::triggerEventsForItems(const std::vector<const EngravingItem*
duration_t actualDuration = MScore::defaultPlayDuration * 1000;
for (const EngravingItem* item : playableItems) {
if (item->isHarmony()) {
m_renderer.renderChordSymbol(toHarmony(item), actualTimestamp, actualDuration, result);
continue;
}
ArticulationsProfilePtr profile = profilesRepository()->defaultProfile(m_playbackDataMap[trackId].setupData.category);
ArticulationsProfilePtr profile = defaultActiculationProfile(trackId);
if (!profile) {
LOGE() << "unsupported instrument family: " << trackId.partId.toUint64();
return;
}
if (item->isHarmony()) {
m_renderer.renderChordSymbol(toHarmony(item), actualTimestamp, actualDuration, profile, result);
continue;
}
int utick = repeatList().tick2utick(item->tick().ticks());
const PlaybackContext& ctx = m_playbackCtxMap[trackId];
@ -340,8 +340,14 @@ void PlaybackModel::processSegment(const int tickPositionOffset, const Segment*
InstrumentTrackId trackId = chordSymbolsTrackId(item->part()->id());
ArticulationsProfilePtr profile = defaultActiculationProfile(trackId);
if (!profile) {
LOGE() << "unsupported instrument family: " << item->part()->id();
continue;
}
if (chordSymbol->play()) {
m_renderer.renderChordSymbol(chordSymbol, tickPositionOffset,
m_renderer.renderChordSymbol(chordSymbol, tickPositionOffset, profile,
m_playbackDataMap[trackId].originEvents);
}
@ -385,7 +391,7 @@ void PlaybackModel::processSegment(const int tickPositionOffset, const Segment*
const PlaybackContext& ctx = m_playbackCtxMap[trackId];
ArticulationsProfilePtr profile = profilesRepository()->defaultProfile(m_playbackDataMap[trackId].setupData.category);
ArticulationsProfilePtr profile = defaultActiculationProfile(trackId);
if (!profile) {
LOGE() << "unsupported instrument family: " << item->part()->id();
continue;
@ -570,10 +576,37 @@ void PlaybackModel::clearExpiredContexts(const track_idx_t trackFrom, const trac
}
}
void mu::engraving::PlaybackModel::removeEventsFromRange(const track_idx_t trackFrom, const track_idx_t trackTo,
const timestamp_t timestampFrom, const timestamp_t timestampTo)
{
for (const Part* part : m_score->parts()) {
if (part->startTrack() > trackTo || part->endTrack() <= trackFrom) {
continue;
}
for (const InstrumentTrackId& trackId : part->instrumentTrackIdSet()) {
removeTrackEvents(trackId, timestampFrom, timestampTo);
}
removeTrackEvents(chordSymbolsTrackId(part->id()), timestampFrom, timestampTo);
}
removeTrackEvents(METRONOME_TRACK_ID, timestampFrom, timestampTo);
}
void PlaybackModel::clearExpiredEvents(const int tickFrom, const int tickTo, const track_idx_t trackFrom, const track_idx_t trackTo)
{
TRACEFUNC;
if (!m_score || !m_score->lastMeasure()) {
return;
}
if (tickFrom == 0 && m_score->lastMeasure()->endTick().ticks() == tickTo) {
removeEventsFromRange(trackFrom, trackTo);
return;
}
for (const RepeatSegment* repeatSegment : m_score->repeatList()) {
int tickPositionOffset = repeatSegment->utick - repeatSegment->tick;
int repeatStartTick = repeatSegment->tick;
@ -586,19 +619,7 @@ void PlaybackModel::clearExpiredEvents(const int tickFrom, const int tickTo, con
timestamp_t timestampFrom = timestampFromTicks(m_score, tickFrom + tickPositionOffset);
timestamp_t timestampTo = timestampFromTicks(m_score, tickTo + tickPositionOffset);
for (const Part* part : m_score->parts()) {
if (part->startTrack() > trackTo || part->endTrack() <= trackFrom) {
continue;
}
for (const InstrumentTrackId& trackId : part->instrumentTrackIdSet()) {
removeEvents(trackId, timestampFrom, timestampTo);
}
removeEvents(chordSymbolsTrackId(part->id()), timestampFrom, timestampTo);
}
removeEvents(METRONOME_TRACK_ID, timestampFrom, timestampTo);
removeEventsFromRange(trackFrom, trackTo, timestampFrom, timestampTo);
}
}
@ -635,7 +656,8 @@ void PlaybackModel::notifyAboutChanges(const InstrumentTrackIdSet& oldTracks, co
}
}
void PlaybackModel::removeEvents(const InstrumentTrackId& trackId, const mpe::timestamp_t timestampFrom, const mpe::timestamp_t timestampTo)
void PlaybackModel::removeTrackEvents(const InstrumentTrackId& trackId, const mpe::timestamp_t timestampFrom,
const mpe::timestamp_t timestampTo)
{
auto search = m_playbackDataMap.find(trackId);
@ -645,6 +667,11 @@ void PlaybackModel::removeEvents(const InstrumentTrackId& trackId, const mpe::ti
PlaybackData& trackPlaybackData = search->second;
if (timestampFrom == -1 && timestampTo == -1) {
search->second.originEvents.clear();
return;
}
PlaybackEventsMap::const_iterator lowerBound;
if (timestampFrom == 0) {
@ -750,3 +777,13 @@ InstrumentTrackId PlaybackModel::idKey(const ID& partId, const std::string& inst
{
return { partId, instrumentId };
}
mpe::ArticulationsProfilePtr PlaybackModel::defaultActiculationProfile(const InstrumentTrackId& trackId) const
{
auto it = m_playbackDataMap.find(trackId);
if (it == m_playbackDataMap.cend()) {
return nullptr;
}
return profilesRepository()->defaultProfile(it->second.setupData.category);
}

View File

@ -121,7 +121,10 @@ private:
void collectChangesTracks(const InstrumentTrackId& trackId, ChangedTrackIdSet* result);
void notifyAboutChanges(const InstrumentTrackIdSet& oldTracks, const InstrumentTrackIdSet& changedTracks);
void removeEvents(const InstrumentTrackId& trackId, const mpe::timestamp_t timestampFrom, const mpe::timestamp_t timestampTo);
void removeEventsFromRange(const track_idx_t trackFrom, const track_idx_t trackTo, const mpe::timestamp_t timestampFrom = -1,
const mpe::timestamp_t timestampTo = -1);
void removeTrackEvents(const InstrumentTrackId& trackId, const mpe::timestamp_t timestampFrom = -1,
const mpe::timestamp_t timestampTo = -1);
TrackBoundaries trackBoundaries(const ScoreChangesRange& changesRange) const;
TickBoundaries tickBoundaries(const ScoreChangesRange& changesRange) const;
@ -130,6 +133,8 @@ private:
std::vector<const EngravingItem*> filterPlaybleItems(const std::vector<const EngravingItem*>& items) const;
mpe::ArticulationsProfilePtr defaultActiculationProfile(const InstrumentTrackId& trackId) const;
Score* m_score = nullptr;
bool m_expandRepeats = true;
bool m_playChordSymbols = true;

View File

@ -63,7 +63,9 @@ void PlaybackSetupDataResolver::resolveChordSymbolsSetupData(const Instrument* i
{
if (instrument->hasStrings()) {
static const mpe::PlaybackSetupData CHORD_SYMBOLS_SETUP_DATA = {
SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic, SoundSubCategory::Nylon }, {}
SoundId::Guitar, SoundCategory::Strings, { SoundSubCategory::Acoustic,
SoundSubCategory::Nylon,
SoundSubCategory::Plucked }, {}
};
result = CHORD_SYMBOLS_SETUP_DATA;

View File

@ -23,6 +23,7 @@
#include "arpeggiorenderer.h"
#include "libmscore/chord.h"
#include "libmscore/arpeggio.h"
using namespace mu::engraving;
using namespace mu::mpe;
@ -48,13 +49,18 @@ void ArpeggioRenderer::doRender(const EngravingItem* item, const mpe::Articulati
return;
}
const Arpeggio* arpeggio = chord->arpeggio();
IF_ASSERT_FAILED(arpeggio) {
return;
}
int stepsCount = static_cast<int>(chord->notes().size());
mpe::percentage_t percentageStep = mpe::HUNDRED_PERCENT / stepsCount;
auto buildEvent = [&](NominalNoteCtx& noteCtx, const int stepNumber) {
noteCtx.chordCtx.commonArticulations.updateOccupiedRange(preferredType, stepNumber * percentageStep,
(stepNumber + 1) * percentageStep);
noteCtx.timestamp += timestampOffsetStep(context) * stepNumber;
noteCtx.timestamp += timestampOffsetStep(context) * stepNumber * arpeggio->Stretch();
result.emplace_back(buildNoteEvent(std::move(noteCtx)));
};

Some files were not shown because too many files have changed in this diff Show More