smoosic 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/smoosic.js +17 -17
- package/package.json +4 -4
- package/release/smoosic.js +17 -17
- package/src/render/sui/formatter.ts +2 -1
- package/src/render/sui/scoreRender.ts +16 -0
- package/src/render/sui/scoreView.ts +11 -13
- package/src/render/sui/scoreViewOperations.ts +2 -0
- package/src/render/sui/tracker.ts +34 -29
- package/src/render/vex/vxMeasure.ts +7 -2
- package/src/render/vex/vxNote.ts +16 -1
- package/src/render/vex/vxSystem.ts +2 -1
- package/src/smo/data/music.ts +1 -1
- package/src/smo/data/score.ts +8 -3
- package/src/smo/data/scoreModifiers.ts +11 -4
- package/src/smo/data/systemStaff.ts +39 -6
- package/src/smo/xform/copypaste.ts +135 -48
- package/src/smo/xform/tickDuration.ts +4 -0
- package/src/smo/xform/tickMap.ts +1 -28
- package/src/smo/xform/undo.ts +1 -1
- package/src/ui/dialogs/preferences.ts +11 -0
|
@@ -42,7 +42,8 @@ export interface ModifierPlacement {
|
|
|
42
42
|
* @category SmoTransform
|
|
43
43
|
*/
|
|
44
44
|
export class PasteBuffer {
|
|
45
|
-
notes: PasteNote[]
|
|
45
|
+
notes: Record<number, PasteNote[]>;
|
|
46
|
+
staffIndex: number;
|
|
46
47
|
noteIndex: number;
|
|
47
48
|
measures: SmoMeasure[];
|
|
48
49
|
measureIndex: number;
|
|
@@ -54,8 +55,9 @@ export class PasteBuffer {
|
|
|
54
55
|
destination: SmoSelector = SmoSelector.default;
|
|
55
56
|
staffSelectors: SmoSelector[] = [];
|
|
56
57
|
constructor() {
|
|
57
|
-
this.notes =
|
|
58
|
+
this.notes = {};
|
|
58
59
|
this.noteIndex = 0;
|
|
60
|
+
this.staffIndex = 0;
|
|
59
61
|
this.measures = [];
|
|
60
62
|
this.measureIndex = -1;
|
|
61
63
|
this.remainder = 0;
|
|
@@ -66,11 +68,18 @@ export class PasteBuffer {
|
|
|
66
68
|
this.score = score;
|
|
67
69
|
}
|
|
68
70
|
getCopyBufferTickCount() {
|
|
69
|
-
let
|
|
70
|
-
this.notes
|
|
71
|
-
|
|
71
|
+
let maxRv = 0;
|
|
72
|
+
const staves = Object.keys(this.notes);
|
|
73
|
+
staves.forEach((staffStr: string) => {
|
|
74
|
+
const staff: number = parseInt(staffStr);
|
|
75
|
+
const notes = this.notes[staff];
|
|
76
|
+
let rv = 0;
|
|
77
|
+
notes.forEach((note) => {
|
|
78
|
+
rv += note.note.tickCount;
|
|
79
|
+
});
|
|
80
|
+
maxRv = Math.max(rv, maxRv);
|
|
72
81
|
});
|
|
73
|
-
return
|
|
82
|
+
return maxRv;
|
|
74
83
|
}
|
|
75
84
|
setSelections(score: SmoScore, selections: SmoSelection[]) {
|
|
76
85
|
this.notes = [];
|
|
@@ -108,6 +117,7 @@ export class PasteBuffer {
|
|
|
108
117
|
let minSelector = selections[0].selector;
|
|
109
118
|
selections.forEach((selection) => {
|
|
110
119
|
selector = JSON.parse(JSON.stringify(selection.selector));
|
|
120
|
+
const staff = selector.staff;
|
|
111
121
|
if (SmoSelector.gt(selector, maxSelector)) {
|
|
112
122
|
maxSelector = selector;
|
|
113
123
|
}
|
|
@@ -151,17 +161,24 @@ export class PasteBuffer {
|
|
|
151
161
|
pasteNote.tupletStart = SmoTupletTree.clone(tupletTree);
|
|
152
162
|
}
|
|
153
163
|
}
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
if (!this.notes[staff]) {
|
|
165
|
+
this.notes[staff] = [];
|
|
166
|
+
}
|
|
167
|
+
this.notes[staff].push(pasteNote);
|
|
156
168
|
}
|
|
157
169
|
});
|
|
158
|
-
this.notes
|
|
159
|
-
|
|
160
|
-
|
|
170
|
+
const staves = Object.keys(this.notes);
|
|
171
|
+
staves.forEach((staffStr) => {
|
|
172
|
+
const staff = parseInt(staffStr);
|
|
173
|
+
const notes = this.notes[staff];
|
|
174
|
+
notes.sort((a, b) =>
|
|
175
|
+
SmoSelector.gt(a.selector, b.selector) ? 1 : -1
|
|
176
|
+
);
|
|
177
|
+
});
|
|
161
178
|
}
|
|
162
179
|
|
|
163
180
|
clearSelections() {
|
|
164
|
-
this.notes =
|
|
181
|
+
this.notes = {};
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
_findModifier(selector: SmoSelector) {
|
|
@@ -181,7 +198,7 @@ export class PasteBuffer {
|
|
|
181
198
|
|
|
182
199
|
// Before pasting, populate an array of existing measures from the paste destination
|
|
183
200
|
// so we know how to place the notes.
|
|
184
|
-
_populateMeasureArray(selector: SmoSelector) {
|
|
201
|
+
_populateMeasureArray(selector: SmoSelector, notes: PasteNote[]) {
|
|
185
202
|
let measureSelection = SmoSelection.measureSelection(this.score!, selector.staff, selector.measure);
|
|
186
203
|
if (!measureSelection) {
|
|
187
204
|
return;
|
|
@@ -204,16 +221,21 @@ export class PasteBuffer {
|
|
|
204
221
|
|
|
205
222
|
let currentDuration = tickmapForFirstMeasure.durationMap[selector.tick];
|
|
206
223
|
const measureTotalDuration = tickmapForFirstMeasure.totalDuration;
|
|
207
|
-
|
|
208
|
-
|
|
224
|
+
|
|
225
|
+
for (let i: number = 0; i < notes.length; i++) {
|
|
226
|
+
const selection: PasteNote = notes[i];
|
|
209
227
|
if (selection.tupletStart) {
|
|
210
228
|
// const tupletTree: SmoTupletTree | null = SmoTupletTree.getTupletTreeForNoteIndex(this.tupletNoteMap, selection.selector.voice, selection.selector.tick);
|
|
211
|
-
if (currentDuration + selection.tupletStart.totalTicks > measureTotalDuration &&
|
|
229
|
+
if (currentDuration + selection.tupletStart.totalTicks > measureTotalDuration &&
|
|
230
|
+
currentDuration + selection.note.tickCount < measureTotalDuration &&
|
|
231
|
+
measureSelection !== null) {
|
|
212
232
|
//if tuplet does not fit in a measure as a whole we cannot paste it, it is ether the whole thing or nothing
|
|
213
233
|
//reset everything that has been changed so far and return
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
234
|
+
if (measureSelection === null) {
|
|
235
|
+
this.measures = [];
|
|
236
|
+
this.staffSelectors = [];
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
217
239
|
}
|
|
218
240
|
}
|
|
219
241
|
if (currentDuration + selection.note.tickCount > measureTotalDuration && measureSelection !== null) {
|
|
@@ -222,7 +244,8 @@ export class PasteBuffer {
|
|
|
222
244
|
const remainder = (currentDuration + selection.note.tickCount) - measureTotalDuration;
|
|
223
245
|
currentDuration = remainder;
|
|
224
246
|
|
|
225
|
-
measureSelection = SmoSelection.measureSelection(this.score as SmoScore,
|
|
247
|
+
measureSelection = SmoSelection.measureSelection(this.score as SmoScore,
|
|
248
|
+
measureSelection.selector.staff,measureSelection.selector.measure + 1);
|
|
226
249
|
|
|
227
250
|
// If the paste buffer overlaps the end of the score, we can't paste (TODO: add a measure in this case)
|
|
228
251
|
if (measureSelection != null) {
|
|
@@ -235,7 +258,6 @@ export class PasteBuffer {
|
|
|
235
258
|
currentDuration += selection.note.tickCount;
|
|
236
259
|
}
|
|
237
260
|
}
|
|
238
|
-
|
|
239
261
|
const lastMeasure = this.measures[this.measures.length - 1];
|
|
240
262
|
|
|
241
263
|
//adjust the beginning of the paste
|
|
@@ -248,10 +270,13 @@ export class PasteBuffer {
|
|
|
248
270
|
}
|
|
249
271
|
|
|
250
272
|
if (this.measures.length > 1) {
|
|
251
|
-
this._removeOverlappingTuplets(firstMeasure,
|
|
252
|
-
|
|
273
|
+
this._removeOverlappingTuplets(firstMeasure,
|
|
274
|
+
selector.tick, firstMeasure.voices[selector.voice].notes.length - 1, selector.voice);
|
|
275
|
+
this._removeOverlappingTuplets(lastMeasure,
|
|
276
|
+
0, lastMeasure.getClosestIndexFromTickCount(selector.voice, currentDuration), selector.voice);
|
|
253
277
|
} else {
|
|
254
|
-
this._removeOverlappingTuplets(firstMeasure,
|
|
278
|
+
this._removeOverlappingTuplets(firstMeasure,
|
|
279
|
+
selector.tick, lastMeasure.getClosestIndexFromTickCount(selector.voice, currentDuration), selector.voice);
|
|
255
280
|
}
|
|
256
281
|
|
|
257
282
|
//if there are more than 2 measures remove tuplets from all but first and last measure.
|
|
@@ -284,7 +309,7 @@ export class PasteBuffer {
|
|
|
284
309
|
// ### _populateVoice
|
|
285
310
|
// ### Description:
|
|
286
311
|
// Create a new voice for a new measure in the paste destination
|
|
287
|
-
_populateVoice(): SmoVoice[] {
|
|
312
|
+
_populateVoice(notes: PasteNote[]): SmoVoice[] {
|
|
288
313
|
// this._populateMeasureArray();
|
|
289
314
|
const measures = this.measures;
|
|
290
315
|
let measure = measures[0];
|
|
@@ -301,8 +326,8 @@ export class PasteBuffer {
|
|
|
301
326
|
measure.voices.push(nvoice);
|
|
302
327
|
}
|
|
303
328
|
tickmap = measure.tickmapForVoice(this.destination.voice);
|
|
304
|
-
this._populateNew(voice, measure, tickmap, startSelector);
|
|
305
|
-
if (this.noteIndex <
|
|
329
|
+
this._populateNew(voice, measure, tickmap, startSelector, notes);
|
|
330
|
+
if (this.noteIndex < notes.length && this.measureIndex < measures.length) {
|
|
306
331
|
voice = {
|
|
307
332
|
notes: []
|
|
308
333
|
};
|
|
@@ -399,16 +424,16 @@ export class PasteBuffer {
|
|
|
399
424
|
* @param startSelector
|
|
400
425
|
* @returns
|
|
401
426
|
*/
|
|
402
|
-
_populateNew(voice: SmoVoice, measure: SmoMeasure, tickmap: TickMap, startSelector: SmoSelector) {
|
|
427
|
+
_populateNew(voice: SmoVoice, measure: SmoMeasure, tickmap: TickMap, startSelector: SmoSelector, notes: PasteNote[]) {
|
|
403
428
|
let currentDuration = tickmap.durationMap[startSelector.tick];
|
|
404
429
|
let i = 0;
|
|
405
430
|
let j = 0;
|
|
406
431
|
const totalDuration = tickmap.totalDuration;
|
|
407
|
-
while (currentDuration < totalDuration && this.noteIndex <
|
|
432
|
+
while (currentDuration < totalDuration && this.noteIndex < notes.length) {
|
|
408
433
|
if (!this.score) {
|
|
409
434
|
return;
|
|
410
435
|
}
|
|
411
|
-
const selection: PasteNote =
|
|
436
|
+
const selection: PasteNote = notes[this.noteIndex];
|
|
412
437
|
const note: SmoNote = selection.note;
|
|
413
438
|
if (note.noteType === 'n') {
|
|
414
439
|
const pitchAr: number[] = [];
|
|
@@ -499,7 +524,8 @@ export class PasteBuffer {
|
|
|
499
524
|
diffToAdjustRemainingTuplets += lmap.length;
|
|
500
525
|
existingIndex++;
|
|
501
526
|
}
|
|
502
|
-
SmoTupletTree.adjustTupletIndexes(
|
|
527
|
+
SmoTupletTree.adjustTupletIndexes(
|
|
528
|
+
measure.tupletTrees, voiceIndex, startIndexToAdjustRemainingTuplets, diffToAdjustRemainingTuplets);
|
|
503
529
|
|
|
504
530
|
for (let i = existingIndex + 1; i < measure.voices[voiceIndex].notes.length; i++) {
|
|
505
531
|
voice.notes.push(SmoNote.clone(measure.voices[voiceIndex].notes[i]));
|
|
@@ -523,19 +549,19 @@ export class PasteBuffer {
|
|
|
523
549
|
}
|
|
524
550
|
serializedMeasure.voices = voices;
|
|
525
551
|
}
|
|
526
|
-
|
|
527
|
-
if (
|
|
528
|
-
return;
|
|
552
|
+
pasteChordNotes(selector: SmoSelector, notes: PasteNote[]): PasteNote[] {
|
|
553
|
+
if (notes.length < 1) {
|
|
554
|
+
return [];
|
|
529
555
|
}
|
|
530
556
|
if (!this.score) {
|
|
531
|
-
return;
|
|
557
|
+
return [];
|
|
532
558
|
}
|
|
533
559
|
let srcTick = 0;
|
|
534
560
|
let destTick = 0;
|
|
535
561
|
let srcIndex = 0;
|
|
536
562
|
let selection = SmoSelection.noteSelection(this.score!, selector.staff, selector.measure, selector.voice, selector.tick);
|
|
537
|
-
while (selection && selection.note && srcIndex <
|
|
538
|
-
const srcNote =
|
|
563
|
+
while (selection && selection.note && srcIndex < notes.length) {
|
|
564
|
+
const srcNote = notes[srcIndex].note;
|
|
539
565
|
const chords = srcNote.getChords();
|
|
540
566
|
if (selection && selection.note) {
|
|
541
567
|
const destNote = selection.note;
|
|
@@ -546,7 +572,7 @@ export class PasteBuffer {
|
|
|
546
572
|
chords.forEach((chord) => {
|
|
547
573
|
if (selection) {
|
|
548
574
|
const nchord = SmoLyric.transposeChordToKey(
|
|
549
|
-
chord, selection.measure.transposeIndex,
|
|
575
|
+
chord, selection.measure.transposeIndex,notes[srcIndex].originalKey, selection.measure.keySignature);
|
|
550
576
|
destNote.addLyric(nchord);
|
|
551
577
|
}
|
|
552
578
|
});
|
|
@@ -563,19 +589,80 @@ export class PasteBuffer {
|
|
|
563
589
|
srcIndex += 1;
|
|
564
590
|
}
|
|
565
591
|
}
|
|
592
|
+
return notes;
|
|
566
593
|
}
|
|
567
|
-
|
|
568
|
-
let
|
|
569
|
-
|
|
594
|
+
pasteIntoScore(score: SmoScore, selector: SmoSelector, func:(selector: SmoSelector, notes: PasteNote[]) => PasteNote[]) {
|
|
595
|
+
let lowest: SmoSelector = SmoSelector.default;
|
|
596
|
+
const enforceRect = true;
|
|
597
|
+
let pasted = 0;
|
|
598
|
+
let startMeasure = 0;
|
|
599
|
+
let startTick = 0;
|
|
600
|
+
let startStaff = 0;
|
|
601
|
+
for (let j = 0; j < score?.staves.length; ++j ) {
|
|
602
|
+
if (!this.notes[j]) {
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
const notes = this.notes[j];
|
|
606
|
+
if (pasted === 0) {
|
|
607
|
+
lowest.measure = selector.measure;
|
|
608
|
+
lowest.tick = selector.tick;
|
|
609
|
+
lowest.staff = selector.staff;
|
|
610
|
+
startMeasure = notes[0].selector.measure;
|
|
611
|
+
startTick = notes[0].selector.tick;
|
|
612
|
+
startStaff = notes[0].selector.staff;
|
|
613
|
+
} else {
|
|
614
|
+
if (enforceRect) {
|
|
615
|
+
if (notes[0].selector.measure !== startMeasure || notes[0].selector.tick !== startTick) {
|
|
616
|
+
// can only paste rectangles. Maybe warn?
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (notes[0].selector.staff !== startStaff + 1) {
|
|
620
|
+
// can only paste rectangles, not clear where next selection goes
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (score.staves.length <= lowest.staff + 1) {
|
|
625
|
+
// nowhere to paste this.
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
lowest.staff += 1;
|
|
629
|
+
startStaff += 1;
|
|
630
|
+
}
|
|
631
|
+
pasted += 1;
|
|
632
|
+
// Replace with fresh copy of the pasted notes
|
|
633
|
+
this.notes[j] = func(lowest, notes);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
pasteChords(selector: SmoSelector) {
|
|
637
|
+
if (!this.score) {
|
|
570
638
|
return;
|
|
571
639
|
}
|
|
640
|
+
const func = (selector: SmoSelector, notes: PasteNote[]) => {
|
|
641
|
+
return this.pasteChordNotes(selector, notes);
|
|
642
|
+
}
|
|
643
|
+
this.pasteIntoScore(this.score, selector, func);
|
|
644
|
+
}
|
|
645
|
+
pasteSelections(selector: SmoSelector) {
|
|
572
646
|
if (!this.score) {
|
|
573
647
|
return;
|
|
574
648
|
}
|
|
575
|
-
const
|
|
576
|
-
|
|
649
|
+
const func = (selector: SmoSelector, notes: PasteNote[]) => {
|
|
650
|
+
return this.pasteNoteSelections(selector, notes);
|
|
651
|
+
}
|
|
652
|
+
this.pasteIntoScore(this.score, selector, func);
|
|
653
|
+
}
|
|
654
|
+
pasteNoteSelections(selector: SmoSelector, notes: PasteNote[]): PasteNote[] {
|
|
655
|
+
let i = 0;
|
|
656
|
+
if (notes.length < 1) {
|
|
657
|
+
return notes;
|
|
658
|
+
}
|
|
659
|
+
if (!this.score) {
|
|
660
|
+
return notes;
|
|
661
|
+
}
|
|
662
|
+
const maxCutVoice = notes.map((n) => n.selector.voice).reduce((a, b) => a > b ? a : b);
|
|
663
|
+
const minCutVoice = notes.map((n) => n.selector.voice).reduce((a, b) => a > b ? a : b);
|
|
577
664
|
const backupNotes: PasteNote[] = [];
|
|
578
|
-
|
|
665
|
+
notes.forEach((bb) => {
|
|
579
666
|
const note = (SmoNote.deserialize(bb.note.serialize()));
|
|
580
667
|
const selector = JSON.parse(JSON.stringify(bb.selector));
|
|
581
668
|
let tupletStart = bb.tupletStart;
|
|
@@ -591,12 +678,12 @@ export class PasteBuffer {
|
|
|
591
678
|
this.noteIndex = 0;
|
|
592
679
|
this.measureIndex = -1;
|
|
593
680
|
this.remainder = 0;
|
|
594
|
-
this._populateMeasureArray(selector);
|
|
681
|
+
this._populateMeasureArray(selector, notes);
|
|
595
682
|
if (this.measures.length === 0) {
|
|
596
|
-
return;
|
|
683
|
+
return notes;
|
|
597
684
|
}
|
|
598
685
|
|
|
599
|
-
const voices = this._populateVoice();
|
|
686
|
+
const voices = this._populateVoice(notes);
|
|
600
687
|
const measureSel = JSON.parse(JSON.stringify(this.destination));
|
|
601
688
|
const selectors: SmoSelector[] = [];
|
|
602
689
|
for (i = 0; i < this.measures.length && i < voices.length; ++i) {
|
|
@@ -659,6 +746,6 @@ export class PasteBuffer {
|
|
|
659
746
|
selection.staff.addStaffModifier(mod.modifier);
|
|
660
747
|
}
|
|
661
748
|
});
|
|
662
|
-
|
|
749
|
+
return(backupNotes);
|
|
663
750
|
}
|
|
664
751
|
}
|
|
@@ -307,6 +307,10 @@ export class SmoStretchNoteActor extends TickIteratorBase {
|
|
|
307
307
|
|
|
308
308
|
static apply(params: SmoStretchNoteParams) {
|
|
309
309
|
const actor = new SmoStretchNoteActor(params);
|
|
310
|
+
// The duration would extend over the barline.
|
|
311
|
+
if (actor.notesToInsert.length < 1) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
310
314
|
SmoTickIterator.iterateOverTicks(actor.measure, actor, actor.voice);
|
|
311
315
|
}
|
|
312
316
|
iterateOverTick(note: SmoNote, tickmap: TickMap, index: number) {
|
package/src/smo/xform/tickMap.ts
CHANGED
|
@@ -20,6 +20,7 @@ export class TickMap {
|
|
|
20
20
|
keySignature: string;
|
|
21
21
|
voice: number;
|
|
22
22
|
notes: SmoNote[] = [];
|
|
23
|
+
priorAccidentals: TickAccidental[] = [];
|
|
23
24
|
index: number = 0;
|
|
24
25
|
startIndex: number = 0;
|
|
25
26
|
endIndex: number = 0;
|
|
@@ -107,34 +108,6 @@ export class TickMap {
|
|
|
107
108
|
this.durationAccidentalMap[this.durationMap[this.index]] = newObj;
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
// ### getActiveAccidental
|
|
111
|
-
// return the active accidental for the given note
|
|
112
|
-
getActiveAccidental(pitch: Pitch, iteratorIndex: number, keySignature: string) {
|
|
113
|
-
let defaultAccidental: string = SmoMusic.getKeySignatureKey(pitch.letter, keySignature);
|
|
114
|
-
let i = 0;
|
|
115
|
-
let j = 0;
|
|
116
|
-
defaultAccidental = defaultAccidental.length > 1 ? defaultAccidental[1] : 'n';
|
|
117
|
-
if (iteratorIndex === 0) {
|
|
118
|
-
return defaultAccidental;
|
|
119
|
-
}
|
|
120
|
-
// Back up the accidental map until we have a match, or until we run out
|
|
121
|
-
for (i = iteratorIndex; i > 0; --i) {
|
|
122
|
-
const map: Record<string, TickAccidental> = this.accidentalMap[i - 1];
|
|
123
|
-
const mapKeys = Object.keys(map);
|
|
124
|
-
for (j = 0; j < mapKeys.length; ++j) {
|
|
125
|
-
const mapKey: string = mapKeys[j];
|
|
126
|
-
// The letter name + accidental in the map
|
|
127
|
-
const mapPitch: Pitch = map[mapKey].pitch;
|
|
128
|
-
const mapAcc = mapPitch.accidental ? mapPitch.accidental : 'n';
|
|
129
|
-
|
|
130
|
-
// if the letters match and the accidental...
|
|
131
|
-
if (mapPitch.letter.toLowerCase() === pitch.letter) {
|
|
132
|
-
return mapAcc;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return defaultAccidental;
|
|
137
|
-
}
|
|
138
111
|
get duration() {
|
|
139
112
|
return this.totalDuration;
|
|
140
113
|
}
|
package/src/smo/xform/undo.ts
CHANGED
|
@@ -426,7 +426,7 @@ export class UndoBuffer {
|
|
|
426
426
|
} else {
|
|
427
427
|
if (typeof(staffMap[buf.selector.staff]) === 'number') {
|
|
428
428
|
buf.selector.staff = staffMap[buf.selector.staff];
|
|
429
|
-
const staff = SmoSystemStaff.deserialize(buf.json);
|
|
429
|
+
const staff = SmoSystemStaff.deserialize(buf.json, !score.preferences.transposingScore);
|
|
430
430
|
score.replaceStaff(buf.selector.staff, staff);
|
|
431
431
|
}
|
|
432
432
|
}
|
|
@@ -79,6 +79,13 @@ export class SuiScorePreferencesAdapter extends SuiComponentAdapter {
|
|
|
79
79
|
this.preferences.transposingScore = value;
|
|
80
80
|
this.view.updateScorePreferences(this.preferences);
|
|
81
81
|
}
|
|
82
|
+
get showPartNames() {
|
|
83
|
+
return this.preferences.showPartNames;
|
|
84
|
+
}
|
|
85
|
+
set showPartNames(value: boolean) {
|
|
86
|
+
this.preferences.showPartNames = value;
|
|
87
|
+
this.view.updateScorePreferences(this.preferences);
|
|
88
|
+
}
|
|
82
89
|
async cancel() {
|
|
83
90
|
const p1 = JSON.stringify(this.preferences);
|
|
84
91
|
const p2 = JSON.stringify(this.backup);
|
|
@@ -125,6 +132,10 @@ export class SuiScorePreferencesDialog extends SuiDialogAdapterBase<SuiScorePref
|
|
|
125
132
|
smoName: 'hideEmptyLines',
|
|
126
133
|
control: 'SuiToggleComponent',
|
|
127
134
|
label: 'Hide Empty Lines'
|
|
135
|
+
}, {
|
|
136
|
+
smoName: 'showPartNames',
|
|
137
|
+
control: 'SuiToggleComponent',
|
|
138
|
+
label: 'Show Part Names in Score'
|
|
128
139
|
}, {
|
|
129
140
|
smoName: 'defaultDupleDuration',
|
|
130
141
|
control: 'SuiDropdownComponent',
|