smoosic 1.0.19 → 1.0.21
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 +9 -9
- package/package.json +1 -1
- package/release/smoosic.js +9 -9
- package/src/render/sui/scoreViewOperations.ts +8 -0
- package/src/render/sui/svgPageMap.ts +0 -1
- package/src/render/sui/tracker.ts +3 -0
- package/src/render/vex/vxMeasure.ts +2 -1
- package/src/smo/data/measure.ts +36 -3
- package/src/smo/data/music.ts +10 -1
- package/src/smo/mxml/xmlState.ts +4 -1
- package/src/smo/xform/operations.ts +6 -0
- package/src/ui/menus/voices.ts +86 -10
- package/build/html/loading-unittest.html +0 -40
- package/build/html/translator.html +0 -35
|
@@ -454,6 +454,14 @@ export class SuiScoreViewOperations extends SuiScoreView {
|
|
|
454
454
|
SmoOperation.setActiveVoice(this.score, index);
|
|
455
455
|
this._renderChangedMeasures(measuresToAdd);
|
|
456
456
|
await this.renderer.updatePromise();
|
|
457
|
+
this.tracker.selectActiveVoice();
|
|
458
|
+
}
|
|
459
|
+
async swapVoices(voice1: number, voice2: number): Promise<void> {
|
|
460
|
+
const selections = this.tracker.getSelectedMeasures();
|
|
461
|
+
const altSelections = this._getEquivalentSelections(selections);
|
|
462
|
+
SmoOperation.swapVoice(selections, voice1, voice2);
|
|
463
|
+
SmoOperation.swapVoice(altSelections, voice1, voice2);
|
|
464
|
+
this._renderChangedMeasures(selections);
|
|
457
465
|
}
|
|
458
466
|
/**
|
|
459
467
|
* Assign an instrument to a set of measures
|
|
@@ -496,7 +496,6 @@ export class SvgPageMap {
|
|
|
496
496
|
const x = (box.x - this.containerOffset.x) / cof;
|
|
497
497
|
const y = (box.y - this.containerOffset.y) / cof;
|
|
498
498
|
const logicalBox = SvgHelpers.boxPoints(x, y, Math.max(box.width / cof, 1), Math.max(box.height / cof, 1));
|
|
499
|
-
logicalBox.y -= Math.round(logicalBox.y / this.layout.pageHeight) / this.layout.svgScale;
|
|
500
499
|
if (layoutDebug.mask | layoutDebug.values['mouseDebug']) {
|
|
501
500
|
layoutDebug.updateMouseDebug(box, logicalBox, this.containerOffset);
|
|
502
501
|
}
|
|
@@ -666,6 +666,9 @@ export class SuiTracker extends SuiMapper implements TrackerKeyHandler {
|
|
|
666
666
|
selection.box = JSON.parse(JSON.stringify(this.suggestion.box));
|
|
667
667
|
selection.scrollBox = JSON.parse(JSON.stringify(this.suggestion.scrollBox));
|
|
668
668
|
this.selections = [selection];
|
|
669
|
+
// There is a single selection, make sure the active voice is set to it.
|
|
670
|
+
selection.measure.setActiveVoice(selection.selector.voice);
|
|
671
|
+
this.selectActiveVoice();
|
|
669
672
|
}
|
|
670
673
|
}
|
|
671
674
|
if (preselected && this.modifierSelections.length) {
|
|
@@ -219,7 +219,8 @@ export class VxMeasure implements VxMeasureIf {
|
|
|
219
219
|
if (smoNote.fillStyle && !this.printing) {
|
|
220
220
|
vexNote.setStyle({ fillStyle: smoNote.fillStyle });
|
|
221
221
|
} else if (voiceIx > 0 && !this.printing) {
|
|
222
|
-
|
|
222
|
+
const voiceFill = ['#115511','#555511','#883344']
|
|
223
|
+
vexNote.setStyle({ fillStyle: voiceFill[voiceIx - 1] });
|
|
223
224
|
} else if (smoNote.isHidden() && this.printing) {
|
|
224
225
|
vexNote.setStyle({ fillStyle: "#ffffff00" });
|
|
225
226
|
}
|
package/src/smo/data/measure.ts
CHANGED
|
@@ -989,8 +989,16 @@ export class SmoMeasure implements SmoMeasureParams, TickMappable {
|
|
|
989
989
|
*/
|
|
990
990
|
alignNotesWithTimeSignature() {
|
|
991
991
|
const tsTicks = SmoMusic.timeSignatureToTicks(this.timeSignature.timeSignature);
|
|
992
|
-
|
|
993
|
-
|
|
992
|
+
let aligned = true;
|
|
993
|
+
for (let i = 0; i < this.voices.length; ++i) {
|
|
994
|
+
const voice = this.voices[i];
|
|
995
|
+
if (this.getTicksFromVoice(i) !== tsTicks) {
|
|
996
|
+
aligned = false;
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
if (aligned) {
|
|
1001
|
+
return true;
|
|
994
1002
|
}
|
|
995
1003
|
const replaceNoteWithDuration = (target: number, ar: SmoNote[], note: SmoNote) => {
|
|
996
1004
|
const fitNote = new SmoNote(SmoNote.defaults);
|
|
@@ -1193,7 +1201,32 @@ export class SmoMeasure implements SmoMeasureParams, TickMappable {
|
|
|
1193
1201
|
this.activeVoice = vix;
|
|
1194
1202
|
}
|
|
1195
1203
|
}
|
|
1196
|
-
|
|
1204
|
+
getSwapVoicePairs() {
|
|
1205
|
+
const rv = [];
|
|
1206
|
+
for (let i = 0; i < this.voices.length; ++i) {
|
|
1207
|
+
for (let j = i + 1; j < this.voices.length; ++j) {
|
|
1208
|
+
rv.push([i, j]);
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return rv;
|
|
1212
|
+
}
|
|
1213
|
+
swapVoices(voice1: number, voice2: number) {
|
|
1214
|
+
if (this.voices.length > voice1 && this.voices.length > voice2) {
|
|
1215
|
+
const v1 = this.voices[voice1];
|
|
1216
|
+
const v2 = this.voices[voice2];
|
|
1217
|
+
const nvoices: SmoVoice[] = [];
|
|
1218
|
+
for (let i = 0; i < this.voices.length; ++i) {
|
|
1219
|
+
if (i === voice1) {
|
|
1220
|
+
nvoices.push(v2);
|
|
1221
|
+
} else if (i === voice2) {
|
|
1222
|
+
nvoices.push(v1);
|
|
1223
|
+
} else {
|
|
1224
|
+
nvoices.push(this.voices[i]);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
this.voices = nvoices;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1197
1230
|
tickmapForVoice(voiceIx: number) {
|
|
1198
1231
|
return new TickMap(this, voiceIx);
|
|
1199
1232
|
}
|
package/src/smo/data/music.ts
CHANGED
|
@@ -1534,7 +1534,7 @@ export class SmoMusic {
|
|
|
1534
1534
|
return SmoMusic._validDurations;
|
|
1535
1535
|
}
|
|
1536
1536
|
/**
|
|
1537
|
-
* Get the closest duration
|
|
1537
|
+
* Get the closest valid duration for this number of ticks, but not going over
|
|
1538
1538
|
* @param ticks
|
|
1539
1539
|
* @returns
|
|
1540
1540
|
*/
|
|
@@ -1549,6 +1549,15 @@ export class SmoMusic {
|
|
|
1549
1549
|
}
|
|
1550
1550
|
return null;
|
|
1551
1551
|
}
|
|
1552
|
+
static closestSimpleDurationFromTicks(ticks: number): number {
|
|
1553
|
+
let closest = SmoMusic.durationsDescending[0];
|
|
1554
|
+
for (let i = 0; i < SmoMusic.durationsDescending.length; ++i) {
|
|
1555
|
+
if (Math.abs(SmoMusic.durationsDescending[i] - ticks) < closest) {
|
|
1556
|
+
closest = i;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
return closest;
|
|
1560
|
+
}
|
|
1552
1561
|
static _ticksToDuration: Record<string, string> = {};
|
|
1553
1562
|
|
|
1554
1563
|
// ### ticksToDuration
|
package/src/smo/mxml/xmlState.ts
CHANGED
|
@@ -732,8 +732,11 @@ export class XmlState {
|
|
|
732
732
|
smoTupletParams.startIndex = xmlTupletState.start!.tick;
|
|
733
733
|
smoTupletParams.endIndex = xmlTupletState.end!.tick;
|
|
734
734
|
for (let i = smoTupletParams.startIndex; i <= smoTupletParams.endIndex; i++) {
|
|
735
|
-
smoTupletParams.totalTicks += notes[i].tickCount;
|
|
735
|
+
smoTupletParams.totalTicks += Math.floor(notes[i].tickCount);
|
|
736
736
|
}
|
|
737
|
+
// Normalize to an allowed note length, because MusicXML durations do not add up
|
|
738
|
+
smoTupletParams.totalTicks = SmoMusic.closestSimpleDurationFromTicks(smoTupletParams.totalTicks);
|
|
739
|
+
|
|
737
740
|
smoTupletParams.voice = xmlTupletState.start!.voice;
|
|
738
741
|
const smoTuplet = new SmoTuplet(smoTupletParams);
|
|
739
742
|
for (let i = 0; i < xmlTupletStateTreeNode.children.length; i++) {
|
|
@@ -124,6 +124,12 @@ export class SmoOperation {
|
|
|
124
124
|
static populateVoice(selection: SmoSelection, voiceIx: number) {
|
|
125
125
|
selection.measure.populateVoice(voiceIx);
|
|
126
126
|
}
|
|
127
|
+
static swapVoice(selections: SmoSelection[], voice1: number, voice2: number) {
|
|
128
|
+
const measures = SmoSelection.getMeasureList(selections);
|
|
129
|
+
measures.forEach((ss) => {
|
|
130
|
+
ss.measure.swapVoices(voice1, voice2);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
127
133
|
|
|
128
134
|
static setTabStave(score: SmoScore, tabStave: SmoTabStave) {
|
|
129
135
|
score.staves[tabStave.startSelector.staff].updateTabStave(tabStave);
|
package/src/ui/menus/voices.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SuiMenuBase, SuiMenuParams, MenuDefinition, SuiMenuHandler, SuiMenuShowOption,
|
|
2
|
-
SuiConfiguredMenuOption, SuiConfiguredMenu,
|
|
2
|
+
SuiConfiguredMenuOption, SuiConfiguredMenu, MenuChoiceDefinition } from './menu';
|
|
3
3
|
import { createAndDisplayDialog } from '../dialogs/dialog';
|
|
4
4
|
|
|
5
5
|
declare var $: any;
|
|
@@ -10,15 +10,82 @@ declare var $: any;
|
|
|
10
10
|
export class SuiVoiceMenu extends SuiConfiguredMenu {
|
|
11
11
|
constructor(params: SuiMenuParams) {
|
|
12
12
|
super(params, 'Voices', SuiVoiceMenuOptions);
|
|
13
|
-
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class voiceSwapperMenuOption implements SuiConfiguredMenuOption {
|
|
16
|
+
voice1: number;
|
|
17
|
+
voice2: number;
|
|
18
|
+
cmd: string;
|
|
19
|
+
label: string;
|
|
20
|
+
get menuChoice(): MenuChoiceDefinition {
|
|
21
|
+
return {
|
|
22
|
+
icon: '',
|
|
23
|
+
text: this.label,
|
|
24
|
+
value: this.cmd
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
constructor(voice1: number, voice2: number) {
|
|
28
|
+
this.voice1 = voice1;
|
|
29
|
+
this.voice2 = voice2;
|
|
30
|
+
this.label = `Swap ${voice1 + 1} and ${voice2 + 1}`;
|
|
31
|
+
this.cmd = `${voice1}To${voice2}`;
|
|
32
|
+
}
|
|
33
|
+
async handler(menu: SuiMenuBase) {
|
|
34
|
+
menu.view.swapVoices(this.voice1, this.voice2);
|
|
35
|
+
}
|
|
36
|
+
display(menu: SuiMenuBase) {
|
|
37
|
+
const measures = menu.view.tracker.getSelectedMeasures();
|
|
38
|
+
if (measures.length > 0) {
|
|
39
|
+
const sel = measures[0];
|
|
40
|
+
const swaps = sel.measure.getSwapVoicePairs();
|
|
41
|
+
for (let i = 0; i < swaps.length; ++i) {
|
|
42
|
+
const pair = swaps[i];
|
|
43
|
+
if (this.voice1 == pair[0] && this.voice2 == pair[1]) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class selectVoiceMenuOption implements SuiConfiguredMenuOption {
|
|
52
|
+
voice: number;
|
|
53
|
+
constructor(voice: number) {
|
|
54
|
+
this.voice = voice;
|
|
55
|
+
}
|
|
56
|
+
async handler (menu: SuiMenuBase) {
|
|
57
|
+
await menu.view.populateVoice(this.voice);
|
|
58
|
+
}
|
|
59
|
+
display (menu: SuiMenuBase) {
|
|
60
|
+
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
61
|
+
const mm = menu.view.tracker.selections[i].measure;
|
|
62
|
+
if (mm.voices.length === 1) {
|
|
63
|
+
return this.voice === 1;
|
|
64
|
+
}
|
|
65
|
+
// If there are n voices, and I am n+1, show option
|
|
66
|
+
if (mm.voices.length === this.voice) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (mm.voices.length > this.voice && mm.getActiveVoice() !== this.voice) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
get menuChoice() {
|
|
76
|
+
return {
|
|
77
|
+
icon: '',
|
|
78
|
+
text: `Voice ${this.voice + 1}`,
|
|
79
|
+
value: `voice${this.voice.toString()}`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
14
82
|
}
|
|
15
|
-
|
|
16
83
|
/**
|
|
17
84
|
* @category SuiMenu
|
|
18
85
|
*/
|
|
19
86
|
const selectVoiceOneMenuOption: SuiConfiguredMenuOption = {
|
|
20
87
|
handler: async (menu: SuiMenuBase) => {
|
|
21
|
-
menu.view.populateVoice(0);
|
|
88
|
+
await menu.view.populateVoice(0);
|
|
22
89
|
}, display: (menu: SuiMenuBase) => {
|
|
23
90
|
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
24
91
|
const mm = menu.view.tracker.selections[i].measure;
|
|
@@ -39,11 +106,11 @@ const selectVoiceOneMenuOption: SuiConfiguredMenuOption = {
|
|
|
39
106
|
*/
|
|
40
107
|
const selectVoiceTwoMenuOption: SuiConfiguredMenuOption = {
|
|
41
108
|
handler: async (menu: SuiMenuBase) => {
|
|
42
|
-
menu.view.populateVoice(1);
|
|
109
|
+
await menu.view.populateVoice(1);
|
|
43
110
|
}, display: (menu: SuiMenuBase) => {
|
|
44
111
|
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
45
112
|
const mm = menu.view.tracker.selections[i].measure;
|
|
46
|
-
if (mm.voices.length
|
|
113
|
+
if (mm.voices.length <= 4 && mm.voices.length > 1) {
|
|
47
114
|
return true;
|
|
48
115
|
}
|
|
49
116
|
}
|
|
@@ -60,7 +127,7 @@ const selectVoiceTwoMenuOption: SuiConfiguredMenuOption = {
|
|
|
60
127
|
*/
|
|
61
128
|
const selectVoiceThreeMenuOption: SuiConfiguredMenuOption = {
|
|
62
129
|
handler: async (menu: SuiMenuBase) => {
|
|
63
|
-
menu.view.populateVoice(2);
|
|
130
|
+
await menu.view.populateVoice(2);
|
|
64
131
|
}, display: (menu: SuiMenuBase) => {
|
|
65
132
|
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
66
133
|
const mm = menu.view.tracker.selections[i].measure;
|
|
@@ -81,7 +148,7 @@ const selectVoiceThreeMenuOption: SuiConfiguredMenuOption = {
|
|
|
81
148
|
*/
|
|
82
149
|
const selectVoiceFourMenuOption: SuiConfiguredMenuOption = {
|
|
83
150
|
handler: async (menu: SuiMenuBase) => {
|
|
84
|
-
menu.view.populateVoice(3);
|
|
151
|
+
await menu.view.populateVoice(3);
|
|
85
152
|
}, display: (menu: SuiMenuBase) => {
|
|
86
153
|
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
87
154
|
const mm = menu.view.tracker.selections[i].measure;
|
|
@@ -102,7 +169,7 @@ const selectVoiceFourMenuOption: SuiConfiguredMenuOption = {
|
|
|
102
169
|
*/
|
|
103
170
|
const removeVoiceMenuOption: SuiConfiguredMenuOption = {
|
|
104
171
|
handler: async (menu: SuiMenuBase) => {
|
|
105
|
-
menu.view.depopulateVoice();
|
|
172
|
+
await menu.view.depopulateVoice();
|
|
106
173
|
}, display: (menu: SuiMenuBase) => {
|
|
107
174
|
for (let i = 0; i < menu.view.tracker.selections.length; ++i) {
|
|
108
175
|
const mm = menu.view.tracker.selections[i].measure;
|
|
@@ -123,6 +190,15 @@ const removeVoiceMenuOption: SuiConfiguredMenuOption = {
|
|
|
123
190
|
* @category SuiMenu
|
|
124
191
|
*/
|
|
125
192
|
const SuiVoiceMenuOptions: SuiConfiguredMenuOption[] = [
|
|
126
|
-
|
|
193
|
+
new selectVoiceMenuOption(0),
|
|
194
|
+
new selectVoiceMenuOption(1),
|
|
195
|
+
new selectVoiceMenuOption(2),
|
|
196
|
+
new selectVoiceMenuOption(3),
|
|
197
|
+
new voiceSwapperMenuOption(0, 1),
|
|
198
|
+
new voiceSwapperMenuOption(0, 2),
|
|
199
|
+
new voiceSwapperMenuOption(0, 3),
|
|
200
|
+
new voiceSwapperMenuOption(1, 2),
|
|
201
|
+
new voiceSwapperMenuOption(1, 3),
|
|
202
|
+
new voiceSwapperMenuOption(2, 3),
|
|
127
203
|
removeVoiceMenuOption
|
|
128
204
|
];
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE HTML>
|
|
2
|
-
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="utf-8">
|
|
6
|
-
<title>Smoosic Unit Tests</title>
|
|
7
|
-
<link href="../styles/fonts.css" rel="stylesheet">
|
|
8
|
-
<link href="../styles/media.css" rel="stylesheet">
|
|
9
|
-
<link href="../styles/ribbon.css" rel="stylesheet">
|
|
10
|
-
<link href="../styles/dialogs.css" rel="stylesheet">
|
|
11
|
-
<link href="../styles/menus.css" rel="stylesheet">
|
|
12
|
-
<link href="../styles/piano.css" rel="stylesheet">
|
|
13
|
-
<link href="../styles/tree.css" rel="stylesheet">
|
|
14
|
-
<link href="../qunit.css" rel="stylesheet">
|
|
15
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js"
|
|
16
|
-
integrity="sha512-uVSVjE7zYsGz4ag0HEzfugJ78oHCI1KhdkivjQro8ABL/PRiEO4ROwvrolYAcZnky0Fl/baWKYilQfWvESliRA=="
|
|
17
|
-
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
18
|
-
<!-- script type="text/javascript" src="../../../vex_smoosic/vexflow_smoosic/build/vexflow-debug.js"></script -->
|
|
19
|
-
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.slim.js"></script>
|
|
20
|
-
<script type="text/javascript" src="../smoosic.js"></script>
|
|
21
|
-
<script type="text/javascript">
|
|
22
|
-
document.addEventListener("DOMContentLoaded", function (event) {
|
|
23
|
-
Smo.createLoadTests();
|
|
24
|
-
});
|
|
25
|
-
</script>
|
|
26
|
-
</head>
|
|
27
|
-
|
|
28
|
-
<body>
|
|
29
|
-
<div id="qunit"></div>
|
|
30
|
-
<div id="qunit-fixture"></div>
|
|
31
|
-
<!-- audio crossOrigin="anonymous" id="sample" src="https://aarondavidnewman.github.io/Smoosic/build/sound/piano_middle_C.mp3" / -->
|
|
32
|
-
<div id="outer-container" style="overflow:auto">
|
|
33
|
-
<div id="container1">
|
|
34
|
-
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
</body>
|
|
39
|
-
|
|
40
|
-
</html>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE HTML>
|
|
2
|
-
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title>Smoosic Editor</title>
|
|
6
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/fonts.css" rel="stylesheet">
|
|
7
|
-
<link href="../styles/media.css" rel="stylesheet">
|
|
8
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/ribbon.css" rel="stylesheet">
|
|
9
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/dialogs.css" rel="stylesheet">
|
|
10
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/menus.css" rel="stylesheet">
|
|
11
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/piano.css" rel="stylesheet">
|
|
12
|
-
<link href="https://aarondavidnewman.github.io/Smoosic/build/styles/tree.css" rel="stylesheet">
|
|
13
|
-
<script type="text/javascript" src="https://aarondavidnewman.github.io/vexflow_smoosic/releases/vexflow-debug.js"></script>
|
|
14
|
-
<!-- script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js" integrity="sha512-uVSVjE7zYsGz4ag0HEzfugJ78oHCI1KhdkivjQro8ABL/PRiEO4ROwvrolYAcZnky0Fl/baWKYilQfWvESliRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script -->
|
|
15
|
-
<!-- script type="text/javascript" src="../../../vex_smoosic/vexflow_smoosic/build/vexflow-debug.js"></script -->
|
|
16
|
-
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.slim.js" ></script>
|
|
17
|
-
<script type="text/javascript" src="../jszip.js"></script>
|
|
18
|
-
<script type="text/javascript" src="../smoosic.js" ></script>
|
|
19
|
-
<script type="text/javascript">
|
|
20
|
-
document.addEventListener("DOMContentLoaded", function (event) {
|
|
21
|
-
var config = { smoPath: '..', mode: 'translate', language: 'de', scoreDomContainer: 'smoo' };
|
|
22
|
-
Smo.SuiApplication.configure(config);
|
|
23
|
-
});
|
|
24
|
-
</script>
|
|
25
|
-
</head>
|
|
26
|
-
<body>
|
|
27
|
-
<sub id="link-hdr"><a href="https://github.com/AaronDavidNewman/smoosic">Github site</a> |
|
|
28
|
-
<a href="https://aarondavidnewman.github.io/Smoosic/release/docs/modules.html">source documentation</a> |
|
|
29
|
-
<a href="https://aarondavidnewman.github.io/Smoosic/changes.html">change notes</a> |
|
|
30
|
-
<a href="https://aarondavidnewman.github.io/Smoosic/release/html/smoosic.html">application</a><button class="close-header"><span class="icon icon-cross"></span></button></sub>
|
|
31
|
-
<!-- audio crossOrigin="anonymous" id="sample" src="https://aarondavidnewman.github.io/Smoosic/build/sound/piano_middle_C.mp3" / -->
|
|
32
|
-
<div id="smoo">
|
|
33
|
-
</div>
|
|
34
|
-
</body>
|
|
35
|
-
</html>
|