smoosic 1.0.37 → 1.0.39

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.
Files changed (38) hide show
  1. package/README.md +6 -3
  2. package/build/smoosic.js +89 -29
  3. package/changes.md +9 -1
  4. package/package.json +1 -1
  5. package/release/smoosic.js +89 -29
  6. package/release/styles/dialogs.css +4 -0
  7. package/src/application/exports.ts +4 -4
  8. package/src/render/audio/musicCursor.ts +1 -1
  9. package/src/render/sui/NoteEntryCaret.ts +4 -1
  10. package/src/render/sui/formatter.ts +3 -3
  11. package/src/render/sui/mapper.ts +1 -1
  12. package/src/render/sui/scoreView.ts +4 -4
  13. package/src/render/sui/scoreViewOperations.ts +10 -10
  14. package/src/render/sui/textEdit.ts +3 -1
  15. package/src/render/vex/vxMeasure.ts +12 -6
  16. package/src/smo/data/measure.ts +37 -37
  17. package/src/smo/data/measureModifiers.ts +106 -71
  18. package/src/smo/data/note.ts +4 -1
  19. package/src/smo/data/score.ts +50 -11
  20. package/src/smo/data/systemStaff.ts +2 -2
  21. package/src/smo/midi/midiToSmo.ts +28 -29
  22. package/src/smo/midi/smoToMidi.ts +3 -3
  23. package/src/smo/mxml/smoToXml.ts +11 -11
  24. package/src/smo/mxml/xmlState.ts +3 -3
  25. package/src/smo/mxml/xmlToSmo.ts +9 -9
  26. package/src/smo/xform/copypaste.ts +3 -3
  27. package/src/smo/xform/operations.ts +9 -6
  28. package/src/smo/xform/tickDuration.ts +10 -2
  29. package/src/styles/dialogs.css +4 -0
  30. package/src/ui/buttons/display.ts +2 -2
  31. package/src/ui/buttons/ribbon.ts +2 -2
  32. package/src/ui/components/dialogs/timeSignature.vue +223 -0
  33. package/src/ui/dialogs/fileDialogs.ts +1 -1
  34. package/src/ui/dialogs/keySignature.ts +1 -1
  35. package/src/ui/dialogs/tempo.ts +38 -38
  36. package/src/ui/dialogs/timeSignature.ts +45 -116
  37. package/src/ui/menus/timeSignature.ts +2 -2
  38. package/tools/smoosic-schema.json +4 -4
@@ -6,7 +6,7 @@ import { SmoMusic } from '../data/music';
6
6
  import { SmoMeasure, SmoVoice } from '../data/measure';
7
7
  import { SmoSystemStaff } from '../data/systemStaff';
8
8
  import { SmoScore } from '../data/score';
9
- import { SmoBarline, TimeSignature, SmoRehearsalMark, SmoMeasureModifierBase } from '../data/measureModifiers';
9
+ import { SmoBarline, SmoTimeSignature, SmoRehearsalMark, SmoMeasureModifierBase } from '../data/measureModifiers';
10
10
  import { SmoStaffHairpin, SmoSlur, SmoTie } from '../data/staffModifiers';
11
11
  import { SmoArticulation, SmoLyric, SmoOrnament } from '../data/noteModifiers';
12
12
  import { SmoSelector } from '../xform/selections';
@@ -14,7 +14,7 @@ import { SmoTuplet, SmoTupletTree } from '../data/tuplet';
14
14
 
15
15
  import { XmlHelpers } from './xmlHelpers';
16
16
  import { smoSerialize } from '../../common/serializationHelpers';
17
- import { SmoTempoText } from '../data/measureModifiers';
17
+ import { SmoTempo } from '../data/measureModifiers';
18
18
  import { XmlToSmo } from './xmlToSmo';
19
19
  import { SmoSystemGroup } from '../data/scoreModifiers';
20
20
  import { SuiSampleMedia } from '../../render/audio/samples';
@@ -51,8 +51,8 @@ export interface SmoState {
51
51
  note?: SmoNote,
52
52
  beamState: number,
53
53
  beamTicks: number,
54
- timeSignature?: TimeSignature,
55
- tempo?: SmoTempoText,
54
+ timeSignature?: SmoTimeSignature,
55
+ tempo?: SmoTempo,
56
56
  currentTupletLevel: number, // not sure about the name
57
57
  }
58
58
 
@@ -637,13 +637,13 @@ export class SmoToXml {
637
637
  if (smoState.tempo) {
638
638
  if (tempo.display && measure.measureNumber.measureIndex === 0 && smoState.measureTicks === 0) {
639
639
  displayTempo = true;
640
- } else if (tempo.display && !SmoTempoText.eq(smoState.tempo, tempo)) {
640
+ } else if (tempo.display && !SmoTempo.eq(smoState.tempo, tempo)) {
641
641
  displayTempo = true;
642
642
  }
643
643
  } else {
644
644
  displayTempo = true;
645
645
  }
646
- smoState.tempo = new SmoTempoText(tempo);
646
+ smoState.tempo = new SmoTempo(tempo);
647
647
  if (beforeNote === true && smoState.staffPartIx === 0 && smoState.measureTicks === 0 && smoState.partStaves[0].staffId === 0) {
648
648
  const mark: SmoMeasureModifierBase | undefined = measure.getRehearsalMark();
649
649
  if (mark) {
@@ -661,12 +661,12 @@ export class SmoToXml {
661
661
  const tempoElement = nn(directionElement, 'direction-type', null, '');
662
662
  XmlHelpers.createAttribute(directionElement, 'placement', 'above');
663
663
  let tempoText = tempo.tempoText;
664
- if (tempo.tempoMode === SmoTempoText.tempoModes.customMode) {
664
+ if (tempo.tempoMode === SmoTempo.tempoModes.customMode) {
665
665
  tempoText = tempo.customText;
666
666
  }
667
- if (tempo.tempoMode === SmoTempoText.tempoModes.textMode) {
667
+ if (tempo.tempoMode === SmoTempo.tempoModes.textMode) {
668
668
  nn(tempoElement, 'words', { words: tempoText }, 'words');
669
- } else if (tempo.tempoMode === SmoTempoText.tempoModes.customMode || tempo.tempoMode === SmoTempoText.tempoModes.durationMode) {
669
+ } else if (tempo.tempoMode === SmoTempo.tempoModes.customMode || tempo.tempoMode === SmoTempo.tempoModes.durationMode) {
670
670
  const metronomeElement = nn(tempoElement, 'metronome', null, '');
671
671
  let durationType = 'quarter';
672
672
  let dotType = false;
@@ -901,8 +901,8 @@ export class SmoToXml {
901
901
  const nn = XmlHelpers.createTextElementChild;
902
902
  const staff = smoState.partStaves[smoState.staffPartIx];
903
903
  const measure = staff.measures[smoState.measureIndex];
904
- const currentTs = (smoState.timeSignature as TimeSignature) ?? null;
905
- if (currentTs !== null && TimeSignature.equal(currentTs, measure.timeSignature)) {
904
+ const currentTs = (smoState.timeSignature as SmoTimeSignature) ?? null;
905
+ if (currentTs !== null && SmoTimeSignature.equal(currentTs, measure.timeSignature)) {
906
906
  return;
907
907
  }
908
908
  smoState.timeSignature = measure.timeSignature;
@@ -13,7 +13,7 @@ import {
13
13
  SmoTie,
14
14
  TieLine
15
15
  } from '../data/staffModifiers';
16
- import {SmoBarline, SmoMeasureModifierBase, SmoRehearsalMark, SmoTempoText} from '../data/measureModifiers';
16
+ import {SmoBarline, SmoMeasureModifierBase, SmoRehearsalMark, SmoTempo} from '../data/measureModifiers';
17
17
  import {SmoPartInfo} from '../data/partInfo';
18
18
  import {SmoMeasure} from '../data/measure';
19
19
  import {SmoNote} from '../data/note';
@@ -164,7 +164,7 @@ export interface XmlPartGroup {
164
164
  export class XmlState {
165
165
  static get defaults() {
166
166
  return {
167
- divisions: 4096, tempo: new SmoTempoText(SmoTempoText.defaults), timeSignature: '4/4', keySignature: 'c',
167
+ divisions: 4096, tempo: new SmoTempo(SmoTempo.defaults), timeSignature: '4/4', keySignature: 'c',
168
168
  clefInfo: [], staffGroups: [], smoStaves: []
169
169
  };
170
170
  }
@@ -195,7 +195,7 @@ export class XmlState {
195
195
  tupletStatesInProgress: Record<number, XmlTupletState> = {};
196
196
 
197
197
  tickCursor: number = 0;
198
- tempo: SmoTempoText = new SmoTempoText(SmoTempoText.defaults);
198
+ tempo: SmoTempo = new SmoTempo(SmoTempo.defaults);
199
199
  staffArray: XmlStaffInfo[] = [];
200
200
  staffIndex: number = 0;
201
201
  graceNotes: SmoGraceNote[] = [];
@@ -8,7 +8,7 @@ import { XmlHelpers } from './xmlHelpers';
8
8
  import { XmlVoiceInfo, XmlState, XmlWedgeInfo } from './xmlState';
9
9
  import { SmoLayoutManager, SmoPageLayout, SmoSystemGroup } from '../data/scoreModifiers';
10
10
  import { SmoTextGroup } from '../data/scoreText';
11
- import { SmoTempoText, SmoMeasureFormat, SmoMeasureModifierBase, SmoVolta, SmoBarline } from '../data/measureModifiers';
11
+ import { SmoTempo, SmoMeasureFormat, SmoMeasureModifierBase, SmoVolta, SmoBarline } from '../data/measureModifiers';
12
12
  import { SmoScore, isEngravingFont } from '../data/score';
13
13
  import { SmoMeasure, SmoMeasureParams } from '../data/measure';
14
14
  import { SmoMusic } from '../data/music';
@@ -397,11 +397,11 @@ export class XmlToSmo {
397
397
  static tempo(element: Element) {
398
398
  let tempoText = '';
399
399
  let customText = tempoText;
400
- const rv: { staffId: number, tempo: SmoTempoText }[] = [];
400
+ const rv: { staffId: number, tempo: SmoTempo }[] = [];
401
401
  const soundNodes = XmlHelpers.getChildrenFromPath(element,
402
402
  ['sound']);
403
403
  soundNodes.forEach((sound) => {
404
- let tempoMode = SmoTempoText.tempoModes.durationMode;
404
+ let tempoMode = SmoTempo.tempoModes.durationMode;
405
405
  tempoText = sound.getAttribute('tempo') as string;
406
406
  if (tempoText) {
407
407
  const bpm = parseInt(tempoText, 10);
@@ -410,20 +410,20 @@ export class XmlToSmo {
410
410
  tempoText = wordNode.length ? wordNode[0].textContent as string :
411
411
  tempoText.toString();
412
412
  if (isNaN(parseInt(tempoText, 10))) {
413
- if (SmoTempoText.tempoTexts[tempoText.toLowerCase()]) {
414
- tempoMode = SmoTempoText.tempoModes.textMode;
413
+ if (SmoTempo.tempoTexts[tempoText.toLowerCase()]) {
414
+ tempoMode = SmoTempo.tempoModes.textMode;
415
415
  } else {
416
- tempoMode = SmoTempoText.tempoModes.customMode;
416
+ tempoMode = SmoTempo.tempoModes.customMode;
417
417
  customText = tempoText;
418
418
  }
419
419
  }
420
- const params = SmoTempoText.defaults;
420
+ const params = SmoTempo.defaults;
421
421
  params.tempoMode = tempoMode;
422
422
  params.bpm = bpm;
423
423
  params.tempoText = tempoText;
424
424
  params.customText = customText;
425
425
  params.display = true;
426
- const tempo = new SmoTempoText(params);
426
+ const tempo = new SmoTempo(params);
427
427
  const staffId = XmlHelpers.getStaffId(element);
428
428
  rv.push({ staffId, tempo });
429
429
  }
@@ -567,7 +567,7 @@ export class XmlToSmo {
567
567
  // Only display tempo if changes.
568
568
  if (tempo.length) {
569
569
  // TODO: staff ID is with tempo, but tempo is per column in SMO
570
- if (!SmoTempoText.eq(xmlState.tempo, tempo[0].tempo)) {
570
+ if (!SmoTempo.eq(xmlState.tempo, tempo[0].tempo)) {
571
571
  xmlState.tempo = tempo[0].tempo;
572
572
  xmlState.tempo.display = true;
573
573
  }
@@ -13,7 +13,7 @@ import { TickMap } from './tickMap';
13
13
  import { SmoSystemStaff } from '../data/systemStaff';
14
14
  import { getId, Clef, Pitch } from '../data/common';
15
15
  import {SmoUnmakeTupletActor} from "./tickDuration";
16
- import { SmoTempoText, TimeSignature } from '../data/measureModifiers';
16
+ import { SmoTempo, SmoTimeSignature } from '../data/measureModifiers';
17
17
 
18
18
  /**
19
19
  * Used to calculate the offset and transposition of a note to be pasted
@@ -212,8 +212,8 @@ export class PasteBuffer {
212
212
  // Ordinarily, the key/tempo/time is mapped to the stave, but since we are pasting measure-by
213
213
  // measure here, we want to preserve it.
214
214
  clonedMeasure.keySignature = measureSelection.measure.keySignature;
215
- clonedMeasure.timeSignature = new TimeSignature(measureSelection.measure.timeSignature);
216
- clonedMeasure.tempo = new SmoTempoText(measureSelection.measure.tempo);
215
+ clonedMeasure.timeSignature = new SmoTimeSignature(measureSelection.measure.timeSignature);
216
+ clonedMeasure.tempo = new SmoTempo(measureSelection.measure.tempo);
217
217
  this.measures.push(clonedMeasure);
218
218
 
219
219
  const firstMeasure = this.measures[0];
@@ -10,8 +10,8 @@ import { SmoArticulation, SmoGraceNote, SmoLyric, SmoMicrotone, SmoOrnament,
10
10
  SmoDynamicText,
11
11
  SmoTabNote} from '../data/noteModifiers';
12
12
  import {
13
- SmoRehearsalMark, SmoMeasureText, SmoVolta, SmoMeasureFormat, SmoTempoText, SmoBarline,
14
- TimeSignature, SmoRepeatSymbol
13
+ SmoRehearsalMark, SmoMeasureText, SmoVolta, SmoMeasureFormat, SmoTempo, SmoBarline,
14
+ SmoTimeSignature, SmoRepeatSymbol
15
15
  } from '../data/measureModifiers';
16
16
  import { SmoStaffHairpin, SmoSlur, SmoTie, StaffModifierBase, SmoTieParams, SmoInstrument, SmoStaffHairpinParams,
17
17
  SmoSlurParams, SmoInstrumentMeasure, SmoStaffTextBracket, SmoStaffTextBracketParams,
@@ -139,7 +139,7 @@ export class SmoOperation {
139
139
  score.staves[tabStaves[0].startSelector.staff].removeTabStaves(tabStaves);
140
140
  }
141
141
  }
142
- static setTimeSignature(score: SmoScore, selections: SmoSelection[], timeSignature: TimeSignature) {
142
+ static setTimeSignature(score: SmoScore, selections: SmoSelection[], timeSignature: SmoTimeSignature) {
143
143
  const selectors: SmoSelector[] = [];
144
144
  let i = 0;
145
145
  // change the time signature for each stave in the score
@@ -151,7 +151,7 @@ export class SmoOperation {
151
151
  });
152
152
  selectors.forEach((selector: SmoSelector) => {
153
153
  const rowSelection: SmoSelection = (SmoSelection.measureSelection(score, selector.staff, selector.measure) as SmoSelection);
154
- rowSelection.measure.timeSignature = new TimeSignature(timeSignature);
154
+ rowSelection.measure.timeSignature = new SmoTimeSignature(timeSignature);
155
155
  rowSelection.measure.alignNotesWithTimeSignature();
156
156
  });
157
157
  }
@@ -744,7 +744,7 @@ export class SmoOperation {
744
744
  });
745
745
  }
746
746
 
747
- static addTempo(score: SmoScore, selection: SmoSelection, tempo: SmoTempoText) {
747
+ static addTempo(score: SmoScore, selection: SmoSelection, tempo: SmoTempo) {
748
748
  score.staves.forEach((staff) => {
749
749
  staff.addTempo(tempo, selection.selector.measure);
750
750
  });
@@ -1050,7 +1050,10 @@ export class SmoOperation {
1050
1050
  }
1051
1051
  });
1052
1052
  selections[0].staff.measureInstrumentMap = instMap;
1053
- selections[0].staff.updateInstrumentOffsets();
1053
+ // Don't update transpositions if everything is in concert key.
1054
+ if (!score.preferences.transposingScore){
1055
+ selections[0].staff.updateInstrumentOffsets();
1056
+ }
1054
1057
  score.setNoteInstrumentProperties();
1055
1058
  }
1056
1059
  static computeMultipartRest(score: SmoScore) {
@@ -277,8 +277,16 @@ export class SmoStretchNoteActor extends TickIteratorBase {
277
277
  stemTicksUsed: number,
278
278
  multiplier: number
279
279
  ) {
280
- const remainingTicks = stemTicksUsed - this.newStemTicks;
281
-
280
+ const originalTickCount = this.notes.reduce((a, b) => a + b.tickCount, 0);
281
+ const measureTicks = this.measure.timeSignature.ticksFromTimeSignature() -
282
+ (originalTickCount + (replacingNote.tickCount - originalNote.tickCount));
283
+ let remainingTicks = stemTicksUsed - this.newStemTicks;
284
+ // If this is the last note in the measure, and the measure doesn't have the full duration of notes,
285
+ // allow stretching. This isn't something that can usually happen,
286
+ // except in cases like import from xml, time signature changes, etc.
287
+ if (remainingTicks < 0 && measureTicks >= 0) {
288
+ remainingTicks = 0;
289
+ }
282
290
  if (remainingTicks >= 0) {
283
291
  this.notesToInsert.push(replacingNote);
284
292
 
@@ -1196,6 +1196,10 @@ button.translate-submit-button {
1196
1196
  #render-progress[value]::-webkit-progress-value {
1197
1197
  background: #F70;
1198
1198
  }
1199
+ body.progress-modal.printing #render-progress,
1200
+ body.progress-modal.printing .navbar-expand {
1201
+ display: none;
1202
+ }
1199
1203
  body.progress-modal #render-progress {
1200
1204
  display: block;
1201
1205
  }
@@ -1,7 +1,7 @@
1
1
  import { SuiButton, SuiButtonParams } from './button';
2
2
  import { createAndDisplayDialog } from '../dialogs/dialog';
3
3
  import { SuiKeySignatureDialog } from '../dialogs/keySignature';
4
- import { SuiTimeSignatureDialog } from '../dialogs/timeSignature';
4
+ import { SuiTimeSignatureDialogVue } from '../dialogs/timeSignature';
5
5
  import { SuiTempoDialog } from '../dialogs/tempo';
6
6
  import { SuiScoreViewDialogVue } from '../dialogs/scoreView';
7
7
  import { KeyEvent } from '../../smo/data/common';
@@ -96,7 +96,7 @@ export class DisplaySettings extends SuiButton {
96
96
  if (!this.completeNotifier) {
97
97
  return;
98
98
  }
99
- createAndDisplayDialog(SuiTimeSignatureDialog, {
99
+ SuiTimeSignatureDialogVue({
100
100
  completeNotifier: this.completeNotifier,
101
101
  view: this.view,
102
102
  eventSource: this.eventSource,
@@ -19,7 +19,7 @@ import { createApp, ref, reactive, watch } from 'vue';
19
19
  import { SuiKeySignatureDialog } from '../dialogs/keySignature';
20
20
  import { default as ribbonApp } from '../components/buttons/ribbon.vue';
21
21
  import { default as ribbonSidebarApp } from '../components/buttons/sidebar.vue';
22
- import { SuiTimeSignatureDialog } from '../dialogs/timeSignature';
22
+ import { SuiTimeSignatureDialogVue } from '../dialogs/timeSignature';
23
23
  import { SuiScoreViewDialogVue } from '../dialogs/scoreView';
24
24
 
25
25
  declare var $: any;
@@ -150,7 +150,7 @@ export class RibbonButtons {
150
150
  if (!this.controller) {
151
151
  return;
152
152
  }
153
- createAndDisplayDialog(SuiTimeSignatureDialog, {
153
+ SuiTimeSignatureDialogVue({
154
154
  completeNotifier: this.controller,
155
155
  view: this.view,
156
156
  eventSource: this.eventSource,
@@ -0,0 +1,223 @@
1
+ <script setup lang="ts">
2
+ import { ref, Ref, watch, reactive } from 'vue';
3
+ import numberInputApp from './numberInput.vue';
4
+ import {
5
+ TimeSignatureTime, SmoTimeSignature
6
+ } from '../../../smo/data/measureModifiers';
7
+ import dialogContainer from './dialogContainer.vue';
8
+ import { SelectOption } from '../../common';
9
+ import selectComp from './select.vue';
10
+
11
+ interface Props {
12
+ domId: string,
13
+ label: string,
14
+ timeSignature: SmoTimeSignature,
15
+ updateTimeSignatureCb: (mf: SmoTimeSignature) => Promise<void>,
16
+ updateApplyTo: (value: string) => Promise<void>,
17
+ commitCb: () => Promise<void>,
18
+ cancelCb: () => Promise<void>
19
+ }
20
+ const props = defineProps<Props>();
21
+ const durationSelection: SelectOption[] = [{
22
+ value: '2',
23
+ label: '2'
24
+ }, {
25
+ value: '4',
26
+ label: '4'
27
+ }, {
28
+ value: '8',
29
+ label: '8'
30
+ }];
31
+
32
+ const applyToOptions: SelectOption[] = [{
33
+ value: "Score",
34
+ label: 'Score'
35
+ }, {
36
+ value: "Selected",
37
+ label: 'Selected Measures'
38
+ }, {
39
+ value: "Remaining",
40
+ label: 'Remaining Measures'
41
+ }];
42
+ const applyTo: Ref<string> = ref('Selected');
43
+ const mainBeat = ref(4);
44
+ const mainDuration = ref(4);
45
+ const altDuration = ref(4);
46
+ const altDurationString = ref('4');
47
+ const mainDurationString = ref('4');
48
+ const altBeat = ref(0);
49
+ const isCompound = ref(false);
50
+ const durationFromString = (str: string): number => {
51
+ const val = parseInt(str);
52
+ if (str === '2' || str === '4' || str === '8') {
53
+ return val;
54
+ }
55
+ return 4;
56
+ }
57
+ watch(mainDuration, async (newVal) => {
58
+ if (mainDuration.value === storedTimeSignature.times[0].beatDuration) {
59
+ return;
60
+ }
61
+ storedTimeSignature.times[0].beatDuration = newVal;
62
+ await props.updateTimeSignatureCb(storedTimeSignature);
63
+ });
64
+ watch(altDuration, async (newVal) => {
65
+ if (storedTimeSignature.times.length === 1) {
66
+ storedTimeSignature.times.push({ actualBeats: altBeat.value, beatDuration: altDuration.value });
67
+ }
68
+ else if (newVal === storedTimeSignature.times[1].beatDuration) {
69
+ return;
70
+ }
71
+ storedTimeSignature.times[1].beatDuration = newVal;
72
+ await props.updateTimeSignatureCb(storedTimeSignature);
73
+ });
74
+ watch(altBeat, async (newVal) => {
75
+ if (storedTimeSignature.times.length === 1 && newVal > 0) {
76
+ storedTimeSignature.times.push({ actualBeats: newVal, beatDuration: storedTimeSignature.times[0].beatDuration });
77
+ }
78
+ else if (newVal < 1) {
79
+ if (storedTimeSignature.times.length > 1) {
80
+ storedTimeSignature.times.pop();
81
+ }
82
+ }
83
+ else if (storedTimeSignature.times.length > 1 && newVal === storedTimeSignature.times[1].actualBeats) {
84
+ return;
85
+ }
86
+ storedTimeSignature.times[1].actualBeats = newVal;
87
+ await props.updateTimeSignatureCb(storedTimeSignature);
88
+ });
89
+ watch(mainDurationString, (newVal) => {
90
+ mainDuration.value = durationFromString(newVal);
91
+ });
92
+ watch(altDurationString, (newVal) => {
93
+ altDuration.value = durationFromString(newVal);
94
+ });
95
+
96
+ const { domId, label, commitCb, cancelCb, } = { ...props };
97
+ const useSymbol: Ref<boolean> = ref(props.timeSignature.useSymbol);
98
+ const display: Ref<boolean> = ref(props.timeSignature.display);
99
+ const displayString: Ref<string> = ref(props.timeSignature.displayString);
100
+ const storedTimeSignature = new SmoTimeSignature(props.timeSignature);
101
+ if (storedTimeSignature.times.length > 1) {
102
+ isCompound.value = true;
103
+ altBeat.value = storedTimeSignature.times[1].actualBeats;
104
+ altDuration.value = storedTimeSignature.times[1].beatDuration;
105
+ }
106
+ mainBeat.value = storedTimeSignature.times[0].actualBeats;
107
+ mainDuration.value = storedTimeSignature.times[0].beatDuration;
108
+ const updateMainBeat = async (newVal: number) => {
109
+ mainBeat.value = newVal;
110
+ storedTimeSignature.times[0].actualBeats = newVal;
111
+ await props.updateTimeSignatureCb(storedTimeSignature);
112
+ }
113
+ const updateMainDurationString = async (newVal: string) => {
114
+ mainDurationString.value = newVal;
115
+ storedTimeSignature.times[0].beatDuration = durationFromString(newVal);
116
+ await props.updateTimeSignatureCb(storedTimeSignature);
117
+ }
118
+ const updateAltDurationString = async (newVal: string) => {
119
+ altDurationString.value = newVal;
120
+ storedTimeSignature.times[1].beatDuration = durationFromString(newVal);
121
+ await props.updateTimeSignatureCb(storedTimeSignature);
122
+ }
123
+ const updateAltBeat = async (newVal: number) => {
124
+ if (storedTimeSignature.times.length > 1 && storedTimeSignature.times[1].actualBeats === newVal) {
125
+ return;
126
+ }
127
+ if (newVal <= 1) {
128
+ return;
129
+ }
130
+ if (storedTimeSignature.times.length === 1) {
131
+ storedTimeSignature.times.push({ actualBeats: newVal, beatDuration: storedTimeSignature.times[0].beatDuration });
132
+ } else {
133
+ storedTimeSignature.times[1].actualBeats = newVal;
134
+ }
135
+ await props.updateTimeSignatureCb(storedTimeSignature);
136
+ }
137
+ watch(isCompound, async (newVal: boolean, oldVal: boolean) => {
138
+ if (newVal === oldVal) {
139
+ return;
140
+ }
141
+ if (newVal) {
142
+ altBeat.value = 4;
143
+ } else {
144
+ altBeat.value = 0;
145
+ }
146
+ await props.updateTimeSignatureCb(storedTimeSignature);
147
+ });
148
+ const getId = (str: string) => {
149
+ return `${props.domId}-${str}`;
150
+ }
151
+ </script>
152
+
153
+ <template>
154
+ <dialogContainer :domId="domId" :label="label" :cancelCb="cancelCb" :commitCb="commitCb"
155
+ :classes="'text-center mw-40 nw-40'">
156
+ <div class="row align-items-center">
157
+ <div class="checkbox-input-column-div">
158
+ <input class="form-check-input" type="checkbox" v-model="useSymbol" :id="getId('use-symbol')">
159
+ </input>
160
+ </div>
161
+ <div class="checkbox-input-label-div">
162
+ <span class="form-check-label" :for="getId('use-symbol')">Use Symbol</span>
163
+ </div>
164
+ <div class="checkbox-input-column-div">
165
+ <input class="form-check-input" type="checkbox" v-model="display" :id="getId('display-ts')">
166
+ </input>
167
+ </div>
168
+ <div class="checkbox-input-label-div">
169
+ <span class="form-check-label" :for="getId('display-cs')">Display Time Signature</span>
170
+ </div>
171
+ </div>
172
+ <div class="row align-items-center">
173
+ <div class="checkbox-input-column-div">
174
+ <input class="form-check-input" type="checkbox" v-model="isCompound" :id="getId('is-compound')">
175
+ </input>
176
+ </div>
177
+ <div class="checkbox-input-label-div">
178
+ <span class="form-check-label" :for="getId('system-break')">Compound Time</span>
179
+ </div>
180
+ </div>
181
+ <div class="row align-items-center">
182
+ <div class="col col-4">
183
+ <numberInputApp :domId="getId('num-main')" :initialValue="mainBeat" :changeCb="updateMainBeat" :precision="0"
184
+ :width="25" :minValue="1" :maxValue="16" />
185
+ </div>
186
+ <div class="number-input-label-div col col-4">
187
+ <span class="form-check-label">Beats/Measure</span>
188
+ </div>
189
+ <div class="col col-6">
190
+ <selectComp :domId="getId('main-duration')" :label="'Beat Duration'" :selections="durationSelection"
191
+ :initialValue="mainDurationString" :changeCb="updateMainDurationString" />
192
+ </div>
193
+ </div>
194
+ <div class="row align-items-center" :class="{ hide: !isCompound }">
195
+ <div class="col col-4">
196
+ <numberInputApp :domId="getId('num-alt')" :initialValue="altBeat" :changeCb="updateAltBeat" :precision="0"
197
+ :width="25" :minValue="0" :maxValue="16" />
198
+ </div>
199
+ <div class="number-input-label-div col col-4">
200
+ <span class="form-check-label">Compound Beats/Measure</span>
201
+ </div>
202
+ <div class="col col-6">
203
+ <selectComp :domId="getId('alt-duration')" :label="'Beat Duration'" :selections="durationSelection"
204
+ :initialValue="altDurationString" :changeCb="updateAltDurationString" />
205
+ </div>
206
+ </div>
207
+ <div class="row align-items-center">
208
+ <div class="col col-4">
209
+ <input type="text" class="form-control form-control-sm" v-model="displayString" :id="getId('display-string')" />
210
+ </div>
211
+ <div class="number-input-label-div col col-8">
212
+ <span class="form-check-lable">Alternate Display String (for pickups)</span>
213
+ </div>
214
+ </div>
215
+ <div class="row mb-2">
216
+ <div class="col col-3 text-end">Apply To</div>
217
+ <div class="col col-6">
218
+ <selectComp :domId="getId('page-size-select')" :label="''" :selections="applyToOptions" :initialValue="applyTo"
219
+ :changeCb="props.updateApplyTo" />
220
+ </div>
221
+ </div>
222
+ </dialogContainer>
223
+ </template>
@@ -65,7 +65,7 @@ export const SuiFileUploadDialog = async (parameters: SuiDialogParams) => {
65
65
  if (filename.endsWith('.mid') || filename.endsWith('.midi')) {
66
66
  await commitMidi();
67
67
  }
68
- else if (filename.endsWith('.xml') || filename.endsWith('.mxml')) {
68
+ else if (filename.endsWith('.xml') || filename.endsWith('.mxml') || filename.endsWith('.mxl')) {
69
69
  await commitXml();
70
70
  }
71
71
  else if (filename.endsWith('.json')) {
@@ -1,6 +1,6 @@
1
1
  // [Smoosic](https://github.com/AaronDavidNewman/Smoosic)
2
2
  // Copyright (c) Aaron David Newman 2021.
3
- import { SmoTempoText, SmoTempoNumberAttribute, SmoTempoStringAttribute, SmoTempoBooleanAttribute } from '../../smo/data/measureModifiers';
3
+ import { SmoTempo, SmoTempoNumberAttribute, SmoTempoStringAttribute, SmoTempoBooleanAttribute } from '../../smo/data/measureModifiers';
4
4
  import { SmoSelection, SmoSelector } from '../../smo/xform/selections';
5
5
  import { SuiScoreViewOperations } from '../../render/sui/scoreViewOperations';
6
6
  import { DialogDefinition, SuiDialogParams } from './dialog';