abcjs 6.0.0-beta.7 → 6.0.0
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/.github/workflows/tests.yml +29 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/CONTRIBUTING.md +1 -0
- package/LICENSE.md +1 -1
- package/README.md +92 -3
- package/RELEASE.md +957 -1
- package/abcjs-audio.css +14 -5
- package/dist/.gitignore +1 -2
- package/dist/abcjs-basic-min.js +3 -0
- package/dist/abcjs-basic-min.js.LICENSE +23 -0
- package/dist/abcjs-basic.js +28231 -0
- package/dist/abcjs-basic.js.map +1 -0
- package/dist/abcjs-plugin-min.js +3 -0
- package/dist/abcjs-plugin-min.js.LICENSE +23 -0
- package/dist/report-basic.html +37 -0
- package/dist/report-before-glyph-compress.html +37 -0
- package/dist/report-brown-ts-target-es5.html +37 -0
- package/dist/report-dev-orig-no-babel.html +37 -0
- package/dist/report-synth.html +37 -0
- package/docker-build.sh +1 -0
- package/glyphs.json +1 -0
- package/index.js +27 -2
- package/{static-wrappers/license.js → license.js} +1 -1
- package/package.json +26 -29
- package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
- package/src/api/abc_animation.js +1 -17
- package/src/api/abc_tablatures.js +144 -0
- package/src/api/abc_timing_callbacks.js +234 -116
- package/src/api/abc_tunebook.js +18 -67
- package/src/api/abc_tunebook_svg.js +38 -46
- package/src/data/abc_tune.js +232 -972
- package/src/data/deline-tune.js +199 -0
- package/src/edit/abc_editarea.js +112 -0
- package/src/edit/abc_editor.js +95 -221
- package/src/midi/abc_midi_create.js +48 -50
- package/src/parse/abc_common.js +0 -14
- package/src/parse/abc_parse.js +167 -1321
- package/src/parse/abc_parse_book.js +62 -0
- package/src/parse/abc_parse_directive.js +164 -41
- package/src/parse/abc_parse_header.js +116 -145
- package/src/parse/abc_parse_key_voice.js +26 -20
- package/src/parse/abc_parse_music.js +1337 -0
- package/src/parse/abc_tokenizer.js +21 -15
- package/src/parse/abc_transpose.js +3 -15
- package/src/parse/tune-builder.js +896 -0
- package/src/parse/wrap_lines.js +205 -453
- package/src/synth/abc_midi_flattener.js +1292 -0
- package/src/{midi → synth}/abc_midi_renderer.js +44 -17
- package/src/synth/abc_midi_sequencer.js +648 -0
- package/src/synth/active-audio-context.js +3 -14
- package/src/synth/cents-to-factor.js +10 -0
- package/src/synth/create-note-map.js +21 -32
- package/src/synth/create-synth-control.js +20 -103
- package/src/synth/create-synth.js +185 -77
- package/src/synth/download-buffer.js +7 -21
- package/src/synth/get-midi-file.js +13 -20
- package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
- package/src/synth/images/loop.svg.js +65 -0
- package/src/synth/images/pause.svg.js +10 -0
- package/src/synth/images/play.svg.js +9 -0
- package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
- package/src/synth/instrument-index-to-name.js +1 -16
- package/src/synth/load-note.js +37 -76
- package/src/synth/pitch-to-note-name.js +0 -15
- package/src/synth/pitches-to-perc.js +64 -0
- package/src/synth/place-note.js +78 -68
- package/src/synth/play-event.js +17 -18
- package/src/synth/register-audio-context.js +11 -23
- package/src/synth/sounds-cache.js +0 -15
- package/src/synth/supports-audio.js +9 -23
- package/src/synth/synth-controller.js +80 -49
- package/src/synth/synth-sequence.js +20 -34
- package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
- package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
- package/src/tablatures/instruments/string-patterns.js +277 -0
- package/src/tablatures/instruments/string-tablature.js +56 -0
- package/src/tablatures/instruments/tab-note.js +282 -0
- package/src/tablatures/instruments/tab-notes.js +41 -0
- package/src/tablatures/instruments/violin/tab-violin.js +47 -0
- package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
- package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
- package/src/tablatures/tab-absolute-elements.js +310 -0
- package/src/tablatures/tab-common.js +29 -0
- package/src/tablatures/tab-renderer.js +243 -0
- package/src/tablatures/transposer.js +110 -0
- package/src/test/abc_midi_lint.js +5 -22
- package/src/test/abc_midi_sequencer_lint.js +11 -14
- package/src/test/abc_parser_lint.js +136 -32
- package/src/test/abc_vertical_lint.js +94 -32
- package/src/test/rendering-lint.js +38 -5
- package/src/write/abc_absolute_element.js +112 -120
- package/src/write/abc_abstract_engraver.js +102 -253
- package/src/write/abc_beam_element.js +30 -290
- package/src/write/abc_brace_element.js +12 -121
- package/src/write/abc_create_clef.js +21 -32
- package/src/write/abc_create_key_signature.js +8 -26
- package/src/write/abc_create_note_head.js +107 -0
- package/src/write/abc_create_time_signature.js +2 -21
- package/src/write/abc_crescendo_element.js +3 -50
- package/src/write/abc_decoration.js +7 -30
- package/src/write/abc_dynamic_decoration.js +3 -37
- package/src/write/abc_ending_element.js +1 -57
- package/src/write/abc_engraver_controller.js +111 -234
- package/src/write/abc_glyphs.js +9 -19
- package/src/write/abc_relative_element.js +57 -97
- package/src/write/abc_renderer.js +10 -832
- package/src/write/abc_spacing.js +0 -15
- package/src/write/abc_staff_group_element.js +14 -349
- package/src/write/abc_tempo_element.js +9 -117
- package/src/write/abc_tie_element.js +5 -68
- package/src/write/abc_triplet_element.js +6 -124
- package/src/write/abc_voice_element.js +7 -222
- package/src/write/add-chord.js +103 -0
- package/src/write/add-text-if.js +33 -0
- package/src/write/bottom-text.js +79 -0
- package/src/write/calcHeight.js +17 -0
- package/src/write/classes.js +100 -0
- package/src/write/draw/absolute.js +68 -0
- package/src/write/draw/beam.js +56 -0
- package/src/write/draw/brace.js +106 -0
- package/src/write/draw/crescendo.js +38 -0
- package/src/write/draw/debug-box.js +8 -0
- package/src/write/draw/draw.js +56 -0
- package/src/write/draw/dynamics.js +20 -0
- package/src/write/draw/ending.js +46 -0
- package/src/write/draw/group-elements.js +66 -0
- package/src/write/draw/horizontal-line.js +25 -0
- package/src/write/draw/non-music.js +50 -0
- package/src/write/draw/print-line.js +24 -0
- package/src/write/draw/print-path.js +7 -0
- package/src/write/draw/print-stem.js +30 -0
- package/src/write/draw/print-symbol.js +59 -0
- package/src/write/draw/print-vertical-line.js +18 -0
- package/src/write/draw/relative.js +77 -0
- package/src/write/draw/round-number.js +5 -0
- package/src/write/draw/selectables.js +59 -0
- package/src/write/draw/separator.js +16 -0
- package/src/write/draw/set-paper-size.js +45 -0
- package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
- package/src/write/draw/staff-group.js +226 -0
- package/src/write/draw/staff-line.js +9 -0
- package/src/write/draw/staff.js +33 -0
- package/src/write/draw/tab-line.js +40 -0
- package/src/write/draw/tempo.js +45 -0
- package/src/write/draw/text.js +71 -0
- package/src/write/draw/tie.js +97 -0
- package/src/write/draw/triplet.js +46 -0
- package/src/write/draw/voice.js +102 -0
- package/src/write/format-jazz-chord.js +15 -0
- package/src/write/free-text.js +41 -0
- package/src/write/get-font-and-attr.js +37 -0
- package/src/write/get-text-size.js +56 -0
- package/src/write/highlight.js +11 -0
- package/src/write/layout/VoiceElements.js +121 -0
- package/src/write/layout/beam.js +213 -0
- package/src/write/layout/get-left-edge-of-staff.js +56 -0
- package/src/write/layout/getBarYAt.js +6 -0
- package/src/write/layout/layout.js +94 -0
- package/src/write/layout/setUpperAndLowerElements.js +232 -0
- package/src/write/layout/staffGroup.js +146 -0
- package/src/write/layout/triplet.js +75 -0
- package/src/write/layout/voice.js +137 -0
- package/src/write/selection.js +188 -70
- package/src/write/separator.js +10 -0
- package/src/write/set-class.js +21 -0
- package/src/write/subtitle.js +12 -0
- package/src/write/svg.js +95 -43
- package/src/write/top-text.js +54 -0
- package/src/write/unhighlight.js +11 -0
- package/temp.txt +17 -0
- package/test.js +27 -64
- package/types/index.d.ts +1095 -0
- package/version.js +1 -1
- package/.babelrc +0 -5
- package/.eslintrc +0 -3
- package/.gitmodules +0 -3
- package/abcjs-midi.css +0 -166
- package/build-utils/loadPresets.js +0 -14
- package/build-utils/presets/webpack.analyze.js +0 -6
- package/build-utils/presets/webpack.optimize.js +0 -30
- package/build-utils/webpack.development.js +0 -14
- package/build-utils/webpack.production.js +0 -35
- package/deploy-docs.sh +0 -25
- package/docs/README.md +0 -33
- package/fix-versions.sh +0 -23
- package/mei.js +0 -43
- package/midi.js +0 -62
- package/src/api/abc_tunebook_midi.js +0 -116
- package/src/midi/abc_midi_controls.js +0 -701
- package/src/midi/abc_midi_flattener.js +0 -1119
- package/src/midi/abc_midi_js_preparer.js +0 -243
- package/src/midi/abc_midi_sequencer.js +0 -401
- package/src/midi/abc_midi_ui_generator.js +0 -86
- package/src/plugin/abc_plugin_midi.js +0 -220
- package/src/synth/images/loop.svg +0 -61
- package/src/synth/images/pause.svg +0 -6
- package/src/synth/images/play.svg +0 -5
- package/src/transform/abc2abc_write.js +0 -395
- package/static-wrappers/basic.js +0 -2
- package/static-wrappers/midi.js +0 -2
- package/static-wrappers/plugin-midi.js +0 -6
- package/static-wrappers/plugin.js +0 -6
- package/webpack.config.js +0 -29
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
// Copyright (C) 2019-2020 Paul Rosen (paul at paulrosen dot net)
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
4
|
-
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
5
|
-
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
6
|
-
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
-
//
|
|
8
|
-
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
-
//
|
|
10
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
11
|
-
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
12
|
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
13
|
-
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
14
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
15
|
-
|
|
16
1
|
// Convert the input structure to a more useful structure where each item has a length of its own.
|
|
17
2
|
|
|
18
3
|
var instrumentIndexToName = require('./instrument-index-to-name');
|
|
@@ -25,26 +10,30 @@ var createNoteMap = function(sequence) {
|
|
|
25
10
|
// TODO-PER: handle more than one note in a track
|
|
26
11
|
var nextNote = {};
|
|
27
12
|
var currentInstrument = instrumentIndexToName[0];
|
|
13
|
+
// ev.start and ev.duration are in whole notes. Need to turn them into
|
|
28
14
|
sequence.tracks.forEach(function(track, i) {
|
|
29
|
-
var currentTime = 0;
|
|
30
15
|
track.forEach(function(ev) {
|
|
31
16
|
switch (ev.cmd) {
|
|
32
|
-
case "
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
17
|
+
case "note":
|
|
18
|
+
// ev contains:
|
|
19
|
+
// {"cmd":"note","pitch":72,"volume":95,"start":0.125,"duration":0.25,"instrument":0,"gap":0}
|
|
20
|
+
// where start and duration are in whole notes, gap is in 1/1920 of a second (i.e. MIDI ticks)
|
|
21
|
+
if (ev.duration > 0) {
|
|
22
|
+
var gap = ev.gap ? ev.gap : 0;
|
|
23
|
+
var len = ev.duration;
|
|
24
|
+
gap = Math.min(gap, len * 2 / 3);
|
|
25
|
+
var obj = {
|
|
41
26
|
pitch: ev.pitch,
|
|
42
|
-
instrument:
|
|
43
|
-
start:
|
|
44
|
-
end:
|
|
45
|
-
volume:
|
|
46
|
-
}
|
|
47
|
-
|
|
27
|
+
instrument: currentInstrument,
|
|
28
|
+
start: Math.round((ev.start) * 1000000)/1000000,
|
|
29
|
+
end: Math.round((ev.start + len - gap) * 1000000)/1000000,
|
|
30
|
+
volume: ev.volume
|
|
31
|
+
};
|
|
32
|
+
if (ev.style)
|
|
33
|
+
obj.style = ev.style;
|
|
34
|
+
if (ev.cents)
|
|
35
|
+
obj.cents = ev.cents;
|
|
36
|
+
map[i].push(obj);
|
|
48
37
|
}
|
|
49
38
|
break;
|
|
50
39
|
case "program":
|
|
@@ -55,7 +44,7 @@ var createNoteMap = function(sequence) {
|
|
|
55
44
|
break;
|
|
56
45
|
default:
|
|
57
46
|
// TODO-PER: handle other event types
|
|
58
|
-
console.log("
|
|
47
|
+
console.log("Unhandled midi event", ev);
|
|
59
48
|
}
|
|
60
49
|
});
|
|
61
50
|
});
|
|
@@ -1,109 +1,13 @@
|
|
|
1
|
-
// Copyright (C) 2019-2020 Paul Rosen (paul at paulrosen dot net)
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
4
|
-
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
5
|
-
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
6
|
-
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
-
//
|
|
8
|
-
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
-
//
|
|
10
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
11
|
-
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
12
|
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
13
|
-
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
14
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
15
|
-
|
|
16
1
|
var supportsAudio = require('./supports-audio');
|
|
17
2
|
var registerAudioContext = require('./register-audio-context');
|
|
18
3
|
var activeAudioContext = require('./active-audio-context');
|
|
19
4
|
var parseCommon = require('../parse/abc_common');
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var loopImage = '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" preserveAspectRatio="xMidYMid meet">\n' +
|
|
27
|
-
'<g transform="translate(0,700) scale(0.1,-0.1)" >\n' +
|
|
28
|
-
'<path d="M3111 6981 c-20 -37 -90 -55 -364 -96 -120 -18 -190 -33 -244 -55 ' +
|
|
29
|
-
'-42 -17 -124 -42 -182 -56 -78 -18 -119 -34 -157 -60 -28 -19 -86 -46 -128 ' +
|
|
30
|
-
'-60 -43 -13 -107 -42 -144 -64 -37 -23 -84 -46 -106 -52 -21 -7 -56 -29 -79 ' +
|
|
31
|
-
'-50 -22 -22 -61 -50 -86 -63 -26 -13 -67 -40 -91 -60 -24 -20 -65 -47 -90 -60 ' +
|
|
32
|
-
'-25 -13 -53 -31 -61 -41 -8 -9 -32 -30 -54 -46 -75 -54 -486 -460 -512 -507 ' +
|
|
33
|
-
'-15 -25 -48 -69 -75 -98 -26 -28 -48 -57 -48 -63 0 -6 -18 -29 -39 -53 -21 ' +
|
|
34
|
-
'-23 -56 -71 -77 -107 -20 -36 -50 -80 -65 -97 -16 -18 -33 -52 -40 -75 -12 ' +
|
|
35
|
-
'-47 -47 -115 -84 -166 -13 -18 -30 -56 -38 -83 -8 -27 -34 -80 -56 -118 -33 ' +
|
|
36
|
-
'-53 -46 -91 -62 -167 -12 -63 -34 -127 -59 -179 -42 -84 -60 -166 -60 -270 0 ' +
|
|
37
|
-
'-90 26 -122 125 -154 54 -17 96 -19 430 -20 305 -1 381 2 430 14 82 22 140 51 ' +
|
|
38
|
-
'153 78 6 12 22 47 37 77 14 30 38 77 54 103 15 27 34 73 40 103 7 30 28 78 48 ' +
|
|
39
|
-
'107 19 28 44 74 55 101 10 28 34 67 53 87 18 20 49 61 68 90 19 30 44 63 57 ' +
|
|
40
|
-
'74 13 11 36 40 52 65 59 94 232 270 306 313 20 11 57 37 82 58 25 20 70 52 ' +
|
|
41
|
-
'100 72 30 19 66 47 79 61 13 14 49 35 80 46 30 12 80 37 111 56 31 19 95 45 ' +
|
|
42
|
-
'143 58 48 12 110 37 139 55 63 40 127 55 323 76 83 9 208 28 279 41 156 29 ' +
|
|
43
|
-
'165 29 330 4 453 -71 514 -84 606 -130 31 -16 83 -36 116 -45 32 -9 84 -34 ' +
|
|
44
|
-
'115 -56 31 -21 82 -48 113 -60 32 -11 72 -33 89 -48 18 -16 59 -45 92 -65 33 ' +
|
|
45
|
-
'-21 74 -51 90 -66 17 -15 49 -40 73 -54 52 -32 65 -61 50 -113 -8 -31 -61 -90 ' +
|
|
46
|
-
'-277 -308 -300 -303 -361 -382 -369 -481 -2 -29 0 -66 6 -81 13 -40 88 -138 ' +
|
|
47
|
-
'115 -151 12 -6 54 -26 92 -44 l70 -33 945 -2 c520 -1 975 2 1012 7 64 8 191 ' +
|
|
48
|
-
'50 231 76 11 7 33 34 50 60 22 34 42 51 65 58 l32 9 0 1101 0 1102 -32 9 c-21 ' +
|
|
49
|
-
'7 -44 26 -64 55 -60 84 -77 97 -140 110 -44 9 -76 10 -127 2 -59 -9 -77 -17 ' +
|
|
50
|
-
'-134 -62 -37 -28 -172 -155 -301 -281 -129 -127 -249 -237 -267 -245 -25 -10 ' +
|
|
51
|
-
'-41 -11 -71 -2 -58 15 -112 45 -124 69 -6 11 -35 35 -64 54 -28 18 -58 41 -66 ' +
|
|
52
|
-
'50 -8 9 -41 35 -75 58 -33 22 -77 56 -99 75 -21 18 -64 46 -95 61 -31 14 -73 ' +
|
|
53
|
-
'39 -93 55 -20 15 -70 40 -110 55 -40 15 -97 44 -127 64 -29 21 -78 44 -107 53 ' +
|
|
54
|
-
'-30 8 -77 31 -105 51 -42 28 -73 39 -173 60 -68 14 -154 39 -196 58 -95 43 ' +
|
|
55
|
-
'-131 51 -343 76 -209 24 -242 32 -279 70 l-30 29 -328 0 c-312 0 -330 -1 -339 ' +
|
|
56
|
-
'-19z"></path>\n' +
|
|
57
|
-
'<path d="M254 2875 c-89 -16 -107 -26 -145 -78 -32 -44 -62 -66 -91 -67 -17 0 ' +
|
|
58
|
-
'-18 -61 -18 -1140 l0 -1140 24 0 c16 0 41 -17 72 -50 40 -42 61 -55 117 -72 ' +
|
|
59
|
-
'l69 -21 82 23 c44 12 96 30 114 39 18 9 148 132 290 272 141 141 267 261 279 ' +
|
|
60
|
-
'268 51 26 86 14 176 -61 32 -26 62 -48 66 -48 5 0 36 -25 70 -55 34 -30 74 ' +
|
|
61
|
-
'-61 89 -69 15 -8 37 -28 50 -45 12 -17 50 -45 84 -62 34 -17 78 -44 98 -60 19 ' +
|
|
62
|
-
'-16 61 -37 93 -48 32 -11 81 -37 107 -56 27 -20 76 -45 109 -56 33 -12 75 -31 ' +
|
|
63
|
-
'93 -44 62 -45 93 -58 191 -82 54 -12 130 -37 168 -54 68 -29 180 -58 226 -59 ' +
|
|
64
|
-
'62 0 183 -64 183 -96 0 -12 88 -14 639 -14 l639 0 12 30 c18 44 76 66 233 89 ' +
|
|
65
|
-
'89 14 160 30 200 47 34 15 106 42 159 60 54 18 112 44 130 57 47 35 85 52 146 ' +
|
|
66
|
-
'67 29 7 76 28 105 48 29 20 77 48 107 63 30 15 66 39 80 54 14 15 50 40 81 56 ' +
|
|
67
|
-
'31 15 78 46 104 69 26 22 61 46 79 54 17 7 43 26 56 42 14 16 41 41 60 56 64 ' +
|
|
68
|
-
'48 380 362 408 405 15 23 40 51 55 63 15 12 36 38 46 58 11 21 37 57 58 82 22 ' +
|
|
69
|
-
'25 49 62 62 83 13 20 38 56 57 78 19 23 50 74 69 113 19 39 46 86 59 104 14 ' +
|
|
70
|
-
'18 34 62 46 98 12 36 32 77 45 92 31 38 60 97 80 167 9 33 26 76 37 95 29 50 ' +
|
|
71
|
-
'47 103 68 206 10 52 32 117 51 155 29 56 33 74 34 140 0 94 -10 108 -101 138 ' +
|
|
72
|
-
'-61 20 -83 21 -463 21 -226 0 -421 -4 -451 -10 -63 -12 -86 -30 -110 -85 -10 ' +
|
|
73
|
-
'-22 -33 -63 -52 -92 -21 -31 -42 -80 -53 -123 -11 -44 -32 -93 -56 -128 -20 ' +
|
|
74
|
-
'-32 -47 -83 -59 -115 -12 -32 -37 -77 -56 -100 -19 -23 -50 -65 -69 -94 -19 ' +
|
|
75
|
-
'-29 -44 -57 -54 -63 -11 -5 -29 -27 -42 -47 -52 -85 -234 -277 -300 -315 -25 ' +
|
|
76
|
-
'-15 -53 -38 -62 -51 -9 -14 -42 -39 -74 -57 -32 -18 -75 -48 -95 -66 -21 -18 ' +
|
|
77
|
-
'-59 -44 -85 -58 -26 -13 -72 -40 -100 -59 -35 -24 -78 -41 -128 -52 -47 -11 ' +
|
|
78
|
-
'-99 -31 -139 -56 -69 -42 -94 -49 -391 -110 -245 -51 -425 -66 -595 -50 -168 ' +
|
|
79
|
-
'16 -230 27 -330 61 -47 16 -123 35 -170 44 -98 17 -123 25 -172 58 -20 14 -71 ' +
|
|
80
|
-
'37 -114 53 -44 15 -95 40 -115 56 -20 16 -70 42 -110 59 -40 16 -88 45 -108 ' +
|
|
81
|
-
'63 -20 19 -55 46 -78 61 -24 14 -49 35 -55 47 -7 11 -34 33 -60 49 -50 31 -65 ' +
|
|
82
|
-
'61 -53 102 4 13 130 147 281 298 236 238 277 283 299 335 15 32 35 71 46 86 ' +
|
|
83
|
-
'12 18 19 44 19 76 0 42 -8 63 -53 138 -92 151 11 139 -1207 141 -798 2 -1030 ' +
|
|
84
|
-
'0 -1086 -11z"></path>\n' +
|
|
85
|
-
'</g>\n' +
|
|
86
|
-
'</svg>\n';
|
|
87
|
-
var playImage = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" class="abcjs-play-svg">\n' +
|
|
88
|
-
' <g>\n' +
|
|
89
|
-
' <polygon points="4 0 23 12.5 4 25"/>\n' +
|
|
90
|
-
' </g>\n' +
|
|
91
|
-
'</svg>';
|
|
92
|
-
var pauseImage = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" class="abcjs-pause-svg">\n' +
|
|
93
|
-
' <g>\n' +
|
|
94
|
-
' <rect width="8.23" height="25"/>\n' +
|
|
95
|
-
' <rect width="8.23" height="25" x="17"/>\n' +
|
|
96
|
-
' </g>\n' +
|
|
97
|
-
'</svg>';
|
|
98
|
-
var loadingImage = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="abcjs-loading-svg">\n' +
|
|
99
|
-
' <circle cx="50" cy="50" fill="none" stroke-width="20" r="35" stroke-dasharray="160 55"></circle>\n' +
|
|
100
|
-
'</svg>';
|
|
101
|
-
var resetImage = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25">\n' +
|
|
102
|
-
' <g>\n' +
|
|
103
|
-
' <polygon points="5 12.5 24 0 24 25"/>\n' +
|
|
104
|
-
' <rect width="3" height="25" x="0" y="0"/>\n' +
|
|
105
|
-
' </g>\n' +
|
|
106
|
-
'</svg>';
|
|
5
|
+
|
|
6
|
+
var loopImage = require('./images/loop.svg.js');
|
|
7
|
+
var playImage = require('./images/play.svg.js');
|
|
8
|
+
var pauseImage = require('./images/pause.svg.js');
|
|
9
|
+
var loadingImage = require('./images/loading.svg.js');
|
|
10
|
+
var resetImage = require('./images/reset.svg.js');
|
|
107
11
|
|
|
108
12
|
function CreateSynthControl(parent, options) {
|
|
109
13
|
var self = this;
|
|
@@ -135,10 +39,22 @@ function CreateSynthControl(parent, options) {
|
|
|
135
39
|
buildDom(self.parent, self.options);
|
|
136
40
|
attachListeners(self);
|
|
137
41
|
|
|
42
|
+
self.disable = function(isDisabled) {
|
|
43
|
+
var el = self.parent.querySelector(".abcjs-inline-audio");
|
|
44
|
+
if (isDisabled)
|
|
45
|
+
el.classList.add("abcjs-disabled");
|
|
46
|
+
else
|
|
47
|
+
el.classList.remove("abcjs-disabled");
|
|
48
|
+
};
|
|
49
|
+
self.setWarp = function(tempo, warp) {
|
|
50
|
+
var el = self.parent.querySelector(".abcjs-midi-tempo");
|
|
51
|
+
el.value = Math.round(warp);
|
|
52
|
+
self.setTempo(tempo)
|
|
53
|
+
};
|
|
138
54
|
self.setTempo = function(tempo) {
|
|
139
55
|
var el = self.parent.querySelector(".abcjs-midi-current-tempo");
|
|
140
56
|
if (el)
|
|
141
|
-
el.innerHTML = tempo;
|
|
57
|
+
el.innerHTML = Math.round(tempo);
|
|
142
58
|
};
|
|
143
59
|
self.resetAll = function() {
|
|
144
60
|
var pushedButtons = self.parent.querySelectorAll(".abcjs-pushed");
|
|
@@ -235,6 +151,7 @@ function buildDom(parent, options) {
|
|
|
235
151
|
var bpm = options.bpm ? options.bpm : "BPM";
|
|
236
152
|
html += '<span class="abcjs-tempo-wrapper"><label><input class="abcjs-midi-tempo" type="number" min="1" max="300" value="100" title="' + warpTitle + '" aria-label="' + warpAria + '">%</label><span> (<span class="abcjs-midi-current-tempo"></span> ' + bpm + ')</span></span>\n';
|
|
237
153
|
}
|
|
154
|
+
html += '<div class="abcjs-css-warning" style="font-size: 12px;color:red;border: 1px solid red;text-align: center;width: 300px;margin-top: 4px;font-weight: bold;border-radius: 4px;">CSS required: load abcjs-audio.css</div>';
|
|
238
155
|
html += '</div>\n';
|
|
239
156
|
parent.innerHTML = html;
|
|
240
157
|
}
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
// Copyright (C) 2019-2020 Paul Rosen (paul at paulrosen dot net)
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
4
|
-
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
5
|
-
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
6
|
-
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
-
//
|
|
8
|
-
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
-
//
|
|
10
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
11
|
-
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
12
|
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
13
|
-
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
14
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
15
|
-
|
|
16
1
|
var getNote = require('./load-note');
|
|
17
2
|
var createNoteMap = require('./create-note-map');
|
|
18
3
|
var registerAudioContext = require('./register-audio-context');
|
|
@@ -21,22 +6,23 @@ var supportsAudio = require('./supports-audio');
|
|
|
21
6
|
var pitchToNoteName = require('./pitch-to-note-name');
|
|
22
7
|
var instrumentIndexToName = require('./instrument-index-to-name');
|
|
23
8
|
var downloadBuffer = require('./download-buffer');
|
|
24
|
-
var sequence = require('../midi/abc_midi_sequencer');
|
|
25
|
-
var flatten = require('../midi/abc_midi_flattener');
|
|
26
9
|
var placeNote = require('./place-note');
|
|
10
|
+
var soundsCache = require('./sounds-cache');
|
|
27
11
|
|
|
28
12
|
// TODO-PER: remove the midi tests from here: I don't think the object can be constructed unless it passes.
|
|
29
13
|
var notSupportedMessage = "MIDI is not supported in this browser.";
|
|
30
14
|
|
|
15
|
+
var originalSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/abcjs/";
|
|
16
|
+
// These are the original soundfonts supplied. They will need a volume boost:
|
|
31
17
|
var defaultSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/";
|
|
32
|
-
|
|
18
|
+
var alternateSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/MusyngKite/";
|
|
33
19
|
|
|
34
20
|
function CreateSynth() {
|
|
35
21
|
var self = this;
|
|
36
22
|
self.audioBufferPossible = undefined;
|
|
37
23
|
self.directSource = []; // type: AudioBufferSourceNode
|
|
38
|
-
self.startTimeSec = undefined; // the time that the
|
|
39
|
-
self.pausedTimeSec = undefined; // the
|
|
24
|
+
self.startTimeSec = undefined; // the time (in seconds) that the audio started: used for pause to get the pausedTimeSec.
|
|
25
|
+
self.pausedTimeSec = undefined; // the position (in seconds) that the audio was paused: used for resume.
|
|
40
26
|
self.audioBuffers = []; // cache of the buffers so starting play can be fast.
|
|
41
27
|
self.duration = undefined; // the duration of the tune in seconds.
|
|
42
28
|
self.isRunning = false; // whether there is currently a sound buffer running.
|
|
@@ -53,38 +39,117 @@ function CreateSynth() {
|
|
|
53
39
|
self.audioBufferPossible = self._deviceCapable();
|
|
54
40
|
if (!self.audioBufferPossible)
|
|
55
41
|
return Promise.reject({ status: "NotSupported", message: notSupportedMessage});
|
|
56
|
-
self.soundFontUrl = options.soundFontUrl ? options.soundFontUrl : defaultSoundFontUrl;
|
|
57
|
-
self.millisecondsPerMeasure = options.millisecondsPerMeasure ? options.millisecondsPerMeasure : (options.visualObj ? options.visualObj.millisecondsPerMeasure() : 1000);
|
|
58
42
|
var params = options.options ? options.options : {};
|
|
43
|
+
self.soundFontUrl = params.soundFontUrl ? params.soundFontUrl : defaultSoundFontUrl;
|
|
44
|
+
if (self.soundFontUrl[self.soundFontUrl.length-1] !== '/')
|
|
45
|
+
self.soundFontUrl += '/';
|
|
46
|
+
if (params.soundFontVolumeMultiplier || params.soundFontVolumeMultiplier === 0)
|
|
47
|
+
self.soundFontVolumeMultiplier = params.soundFontVolumeMultiplier;
|
|
48
|
+
else if (self.soundFontUrl === defaultSoundFontUrl || self.soundFontUrl === alternateSoundFontUrl)
|
|
49
|
+
self.soundFontVolumeMultiplier = 3.0;
|
|
50
|
+
else if (self.soundFontUrl === originalSoundFontUrl)
|
|
51
|
+
self.soundFontVolumeMultiplier = 0.4;
|
|
52
|
+
else
|
|
53
|
+
self.soundFontVolumeMultiplier = 1.0;
|
|
54
|
+
if (params.programOffsets)
|
|
55
|
+
self.programOffsets = params.programOffsets;
|
|
56
|
+
else if (self.soundFontUrl === originalSoundFontUrl)
|
|
57
|
+
self.programOffsets = {
|
|
58
|
+
"bright_acoustic_piano": 20,
|
|
59
|
+
"honkytonk_piano": 20,
|
|
60
|
+
"electric_piano_1": 30,
|
|
61
|
+
"electric_piano_2": 30,
|
|
62
|
+
"harpsichord": 40,
|
|
63
|
+
"clavinet": 20,
|
|
64
|
+
"celesta": 20,
|
|
65
|
+
"glockenspiel": 40,
|
|
66
|
+
"vibraphone": 30,
|
|
67
|
+
"marimba": 35,
|
|
68
|
+
"xylophone": 30,
|
|
69
|
+
"tubular_bells": 35,
|
|
70
|
+
"dulcimer": 30,
|
|
71
|
+
"drawbar_organ": 20,
|
|
72
|
+
"percussive_organ": 25,
|
|
73
|
+
"rock_organ": 20,
|
|
74
|
+
"church_organ": 40,
|
|
75
|
+
"reed_organ": 40,
|
|
76
|
+
"accordion": 40,
|
|
77
|
+
"harmonica": 40,
|
|
78
|
+
"acoustic_guitar_nylon": 20,
|
|
79
|
+
"acoustic_guitar_steel": 30,
|
|
80
|
+
"electric_guitar_jazz": 25,
|
|
81
|
+
"electric_guitar_clean": 15,
|
|
82
|
+
"electric_guitar_muted": 35,
|
|
83
|
+
"overdriven_guitar": 25,
|
|
84
|
+
"distortion_guitar": 20,
|
|
85
|
+
"guitar_harmonics": 30,
|
|
86
|
+
"electric_bass_finger": 15,
|
|
87
|
+
"electric_bass_pick": 30,
|
|
88
|
+
"fretless_bass": 40,
|
|
89
|
+
"violin": 105,
|
|
90
|
+
"viola": 50,
|
|
91
|
+
"cello": 40,
|
|
92
|
+
"contrabass": 60,
|
|
93
|
+
"trumpet": 10,
|
|
94
|
+
"trombone": 90,
|
|
95
|
+
"alto_sax": 20,
|
|
96
|
+
"tenor_sax": 20,
|
|
97
|
+
"clarinet": 20,
|
|
98
|
+
"flute": 50,
|
|
99
|
+
"banjo": 50,
|
|
100
|
+
"woodblock": 20,
|
|
101
|
+
};
|
|
102
|
+
else
|
|
103
|
+
self.programOffsets = {};
|
|
104
|
+
var p = params.fadeLength !== undefined ? parseInt(params.fadeLength,10) : NaN;
|
|
105
|
+
self.fadeLength = isNaN(p) ? 200 : p;
|
|
106
|
+
p = params.noteEnd !== undefined ? parseInt(params.noteEnd,10) : NaN;
|
|
107
|
+
self.noteEnd = isNaN(p) ? 0 : p;
|
|
108
|
+
|
|
59
109
|
self.pan = params.pan;
|
|
60
110
|
self.meterSize = 1;
|
|
61
111
|
if (options.visualObj) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
112
|
+
self.flattened = options.visualObj.setUpAudio(params);
|
|
113
|
+
var meter = options.visualObj.getMeterFraction();
|
|
114
|
+
if (meter.den)
|
|
115
|
+
self.meterSize = options.visualObj.getMeterFraction().num / options.visualObj.getMeterFraction().den;
|
|
65
116
|
} else if (options.sequence)
|
|
66
117
|
self.flattened = options.sequence;
|
|
67
118
|
else
|
|
68
119
|
return Promise.reject(new Error("Must pass in either a visualObj or a sequence"));
|
|
120
|
+
self.millisecondsPerMeasure = options.millisecondsPerMeasure ? options.millisecondsPerMeasure : (options.visualObj ? options.visualObj.millisecondsPerMeasure(self.flattened.tempo) : 1000);
|
|
121
|
+
self.beatsPerMeasure = options.visualObj ? options.visualObj.getBeatsPerMeasure() : 4;
|
|
69
122
|
self.sequenceCallback = params.sequenceCallback;
|
|
70
123
|
self.callbackContext = params.callbackContext;
|
|
71
|
-
self.onEnded =
|
|
124
|
+
self.onEnded = params.onEnded;
|
|
72
125
|
|
|
73
126
|
var allNotes = {};
|
|
127
|
+
var cached = [];
|
|
128
|
+
var errorNotes = [];
|
|
74
129
|
var currentInstrument = instrumentIndexToName[0];
|
|
75
130
|
self.flattened.tracks.forEach(function(track) {
|
|
76
131
|
track.forEach(function(event) {
|
|
77
132
|
if (event.cmd === "program" && instrumentIndexToName[event.instrument])
|
|
78
133
|
currentInstrument = instrumentIndexToName[event.instrument];
|
|
79
134
|
if (event.pitch !== undefined) {
|
|
80
|
-
var pitchNumber = event.pitch
|
|
135
|
+
var pitchNumber = event.pitch;
|
|
81
136
|
var noteName = pitchToNoteName[pitchNumber];
|
|
82
137
|
if (noteName) {
|
|
83
138
|
if (!allNotes[currentInstrument])
|
|
84
139
|
allNotes[currentInstrument] = {};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
140
|
+
if (!soundsCache[currentInstrument] || !soundsCache[currentInstrument][noteName])
|
|
141
|
+
allNotes[currentInstrument][noteName] = true;
|
|
142
|
+
else {
|
|
143
|
+
var label2 = currentInstrument+":"+noteName
|
|
144
|
+
if (cached.indexOf(label2) < 0)
|
|
145
|
+
cached.push(label2);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
var label = currentInstrument+":"+noteName
|
|
149
|
+
console.log("Can't find note: ", pitchNumber, label);
|
|
150
|
+
if (errorNotes.indexOf(label) < 0)
|
|
151
|
+
errorNotes.push(label)
|
|
152
|
+
}
|
|
88
153
|
}
|
|
89
154
|
});
|
|
90
155
|
});
|
|
@@ -106,14 +171,23 @@ function CreateSynth() {
|
|
|
106
171
|
}
|
|
107
172
|
|
|
108
173
|
return new Promise(function(resolve, reject) {
|
|
109
|
-
var results =
|
|
174
|
+
var results = {
|
|
175
|
+
cached: cached,
|
|
176
|
+
error: errorNotes,
|
|
177
|
+
loaded: []
|
|
178
|
+
};
|
|
110
179
|
|
|
111
180
|
var index = 0;
|
|
112
181
|
var next = function() {
|
|
113
182
|
if (index < batches.length) {
|
|
114
183
|
self._loadBatch(batches[index], self.soundFontUrl, startTime).then(function(data) {
|
|
115
184
|
startTime = activeAudioContext().currentTime;
|
|
116
|
-
|
|
185
|
+
if (data) {
|
|
186
|
+
if (data.error)
|
|
187
|
+
results.error = results.error.concat(data.error);
|
|
188
|
+
if (data.loaded)
|
|
189
|
+
results.loaded = results.loaded.concat(data.loaded);
|
|
190
|
+
}
|
|
117
191
|
index++;
|
|
118
192
|
next();
|
|
119
193
|
}, reject);
|
|
@@ -167,13 +241,20 @@ function CreateSynth() {
|
|
|
167
241
|
}
|
|
168
242
|
self._loadBatch(newBatch, soundFontUrl, startTime, delay).then(function (response) {
|
|
169
243
|
resolve(response);
|
|
244
|
+
}).catch(function (error) {
|
|
245
|
+
reject(error);
|
|
170
246
|
});
|
|
171
247
|
}, delay);
|
|
172
248
|
});
|
|
173
|
-
} else
|
|
174
|
-
|
|
249
|
+
} else {
|
|
250
|
+
var list = [];
|
|
251
|
+
for (var j = 0; j < batch.length; j++)
|
|
252
|
+
list.push(batch[j].instrument+'/'+batch[j].note)
|
|
253
|
+
return Promise.reject(new Error("timeout attempting to load: " + list.join(", ")));
|
|
254
|
+
}
|
|
175
255
|
} else
|
|
176
256
|
return Promise.resolve({loaded: loaded, cached: cached, error: error});
|
|
257
|
+
}).catch(function (error) {
|
|
177
258
|
});
|
|
178
259
|
});
|
|
179
260
|
|
|
@@ -181,6 +262,7 @@ function CreateSynth() {
|
|
|
181
262
|
// At this point all of the notes are loaded. This function writes them into the output buffer.
|
|
182
263
|
// Most music has a lot of repeating notes. If a note is the same pitch, volume, length, etc. as another one,
|
|
183
264
|
// It saves a lot of time to just create it once and place it repeatedly where ever it needs to be.
|
|
265
|
+
var fadeTimeSec = self.fadeLength/1000;
|
|
184
266
|
self.isRunning = false;
|
|
185
267
|
if (!self.audioBufferPossible)
|
|
186
268
|
return Promise.reject(new Error(notSupportedMessage));
|
|
@@ -194,6 +276,7 @@ function CreateSynth() {
|
|
|
194
276
|
self.audioBuffers = [];
|
|
195
277
|
return resolve({ status: "empty", seconds: 0});
|
|
196
278
|
}
|
|
279
|
+
self.duration += fadeTimeSec;
|
|
197
280
|
var totalSamples = Math.floor(activeAudioContext().sampleRate * self.duration);
|
|
198
281
|
|
|
199
282
|
// There might be a previous run that needs to be turned off.
|
|
@@ -211,7 +294,7 @@ function CreateSynth() {
|
|
|
211
294
|
noteMapTracks.forEach(function(noteMap, trackNumber) {
|
|
212
295
|
var panDistance = panDistances && panDistances.length > trackNumber ? panDistances[trackNumber] : 0;
|
|
213
296
|
noteMap.forEach(function(note) {
|
|
214
|
-
var key = note.instrument + ':' + note.pitch + ':' +note.volume + ':' + (note.end-note.start) + ':' + panDistance + ':' + tempoMultiplier;
|
|
297
|
+
var key = note.instrument + ':' + note.pitch + ':' +note.volume + ':' + Math.round((note.end-note.start)*1000)/1000 + ':' + panDistance + ':' + tempoMultiplier + ':' + (note.cents ? note.cents : 0);
|
|
215
298
|
if (!uniqueSounds[key])
|
|
216
299
|
uniqueSounds[key] = [];
|
|
217
300
|
uniqueSounds[key].push(note.start);
|
|
@@ -224,8 +307,9 @@ function CreateSynth() {
|
|
|
224
307
|
for (var key2 = 0; key2 < Object.keys(uniqueSounds).length; key2++) {
|
|
225
308
|
var k = Object.keys(uniqueSounds)[key2];
|
|
226
309
|
var parts = k.split(":");
|
|
227
|
-
|
|
228
|
-
|
|
310
|
+
var cents = parts[6] !== undefined ? parseFloat(parts[6]) : 0;
|
|
311
|
+
parts = {instrument: parts[0], pitch: parseInt(parts[1], 10), volume: parseInt(parts[2], 10), len: parseFloat(parts[3]), pan: parseFloat(parts[4]), tempoMultiplier: parseFloat(parts[5]), cents: cents};
|
|
312
|
+
allPromises.push(placeNote(audioBuffer, activeAudioContext().sampleRate, parts, uniqueSounds[k], self.soundFontVolumeMultiplier, self.programOffsets[parts.instrument], fadeTimeSec, self.noteEnd/1000));
|
|
229
313
|
}
|
|
230
314
|
self.audioBuffers = [audioBuffer];
|
|
231
315
|
|
|
@@ -234,33 +318,53 @@ function CreateSynth() {
|
|
|
234
318
|
self.debugCallback("totalSamples = " + totalSamples);
|
|
235
319
|
self.debugCallback("creationTime = " + Math.floor((activeAudioContext().currentTime - startTime)*1000) + "ms");
|
|
236
320
|
}
|
|
321
|
+
function resolveData(me) {
|
|
322
|
+
var duration = me && me.audioBuffers && me.audioBuffers.length > 0 ? me.audioBuffers[0].duration : 0;
|
|
323
|
+
return { status: activeAudioContext().state, duration: duration}
|
|
324
|
+
}
|
|
237
325
|
Promise.all(allPromises).then(function() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
326
|
+
// Safari iOS can mess with the audioContext state, so resume if needed.
|
|
327
|
+
if (activeAudioContext().state === "suspended") {
|
|
328
|
+
activeAudioContext().resume().then(function () {
|
|
329
|
+
resolve(resolveData(self));
|
|
330
|
+
})
|
|
331
|
+
} else if (activeAudioContext().state === "interrupted") {
|
|
332
|
+
activeAudioContext().suspend().then(function () {
|
|
333
|
+
activeAudioContext().resume().then(function () {
|
|
334
|
+
resolve(resolveData(self));
|
|
335
|
+
})
|
|
336
|
+
})
|
|
337
|
+
} else {
|
|
338
|
+
resolve(resolveData(self));
|
|
339
|
+
}
|
|
242
340
|
});
|
|
243
341
|
});
|
|
244
342
|
};
|
|
245
343
|
|
|
246
344
|
function setPan(numTracks, panParam) {
|
|
345
|
+
// panParam, if it is set, can be either a number representing the separation between each track,
|
|
346
|
+
// or an array, which is the absolute pan position for each track.
|
|
247
347
|
if (panParam === null || panParam === undefined)
|
|
248
348
|
return null;
|
|
249
349
|
|
|
250
350
|
var panDistances = [];
|
|
251
351
|
if (panParam.length) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
352
|
+
// We received an array. If there are the same number of items in the pan array as the number of tracks,
|
|
353
|
+
// it all lines up perfectly. If there are more items in the pan array than the tracks then the excess items are ignored.
|
|
354
|
+
// If there are more tracks than items in the pan array then the remaining tracks are placed in the middle.
|
|
355
|
+
// If any of the pan numbers are out of range then they are adjusted.
|
|
356
|
+
for (var pp = 0; pp < numTracks; pp++) {
|
|
357
|
+
if (pp < panParam.length) {
|
|
255
358
|
var x = parseFloat(panParam[pp]);
|
|
256
|
-
if (x
|
|
257
|
-
|
|
258
|
-
else
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
359
|
+
if (x < -1)
|
|
360
|
+
x = -1;
|
|
361
|
+
else if (x > 1)
|
|
362
|
+
x = 1;
|
|
363
|
+
panDistances.push(x);
|
|
364
|
+
} else
|
|
365
|
+
panDistances.push(0)
|
|
263
366
|
}
|
|
367
|
+
return panDistances;
|
|
264
368
|
} else {
|
|
265
369
|
var panNumber = parseFloat(panParam);
|
|
266
370
|
// the separation needs to be no further than 2 (i.e. -1 to 1) so test to see if there are too many tracks for the passed in distance
|
|
@@ -290,18 +394,14 @@ function CreateSynth() {
|
|
|
290
394
|
|
|
291
395
|
// This is called after everything is set up, so it can quickly make sound
|
|
292
396
|
self.start = function() {
|
|
293
|
-
if (self.pausedTimeSec) {
|
|
294
|
-
self.resume();
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
397
|
if (!self.audioBufferPossible)
|
|
299
398
|
throw new Error(notSupportedMessage);
|
|
300
399
|
if (self.debugCallback)
|
|
301
400
|
self.debugCallback("start called");
|
|
302
401
|
|
|
303
|
-
self.
|
|
304
|
-
self.
|
|
402
|
+
var resumePosition = self.pausedTimeSec ? self.pausedTimeSec : 0;
|
|
403
|
+
self._kickOffSound(resumePosition);
|
|
404
|
+
self.startTimeSec = activeAudioContext().currentTime - resumePosition;
|
|
305
405
|
self.pausedTimeSec = undefined;
|
|
306
406
|
|
|
307
407
|
if (self.debugCallback)
|
|
@@ -314,26 +414,28 @@ function CreateSynth() {
|
|
|
314
414
|
if (self.debugCallback)
|
|
315
415
|
self.debugCallback("pause called");
|
|
316
416
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
self.pausedTimeSec = activeAudioContext().currentTime;
|
|
320
|
-
}
|
|
417
|
+
self.pausedTimeSec = self.stop();
|
|
418
|
+
return self.pausedTimeSec;
|
|
321
419
|
};
|
|
322
420
|
|
|
323
421
|
self.resume = function() {
|
|
324
|
-
|
|
325
|
-
throw new Error(notSupportedMessage);
|
|
326
|
-
if (self.debugCallback)
|
|
327
|
-
self.debugCallback("resume called");
|
|
328
|
-
|
|
329
|
-
var offset = self.pausedTimeSec - self.startTimeSec;
|
|
330
|
-
self.startTimeSec = activeAudioContext().currentTime - offset; // We move the start time in case there is another pause/resume.
|
|
331
|
-
self.pausedTimeSec = undefined;
|
|
332
|
-
self._kickOffSound(offset);
|
|
422
|
+
self.start();
|
|
333
423
|
};
|
|
334
424
|
|
|
335
|
-
self.seek = function(
|
|
336
|
-
var offset
|
|
425
|
+
self.seek = function(position, units) {
|
|
426
|
+
var offset;
|
|
427
|
+
switch (units) {
|
|
428
|
+
case "seconds":
|
|
429
|
+
offset = position;
|
|
430
|
+
break;
|
|
431
|
+
case "beats":
|
|
432
|
+
offset = position * self.millisecondsPerMeasure / self.beatsPerMeasure / 1000;
|
|
433
|
+
break;
|
|
434
|
+
default:
|
|
435
|
+
// this is "percent" or any illegal value
|
|
436
|
+
offset = (self.duration-self.fadeLength/1000) * position;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
337
439
|
|
|
338
440
|
// TODO-PER: can seek when paused or when playing
|
|
339
441
|
if (!self.audioBufferPossible)
|
|
@@ -344,11 +446,10 @@ function CreateSynth() {
|
|
|
344
446
|
if (self.isRunning) {
|
|
345
447
|
self.stop();
|
|
346
448
|
self._kickOffSound(offset);
|
|
449
|
+
} else {
|
|
450
|
+
self.pausedTimeSec = offset;
|
|
347
451
|
}
|
|
348
|
-
|
|
349
|
-
self.startTimeSec = activeAudioContext().currentTime - offset;
|
|
350
|
-
if (self.pausedTimeSec)
|
|
351
|
-
self.pausedTimeSec = self.startTimeSec + pauseDistance;
|
|
452
|
+
self.pausedTimeSec = offset;
|
|
352
453
|
};
|
|
353
454
|
|
|
354
455
|
self.stop = function() {
|
|
@@ -363,6 +464,13 @@ function CreateSynth() {
|
|
|
363
464
|
}
|
|
364
465
|
});
|
|
365
466
|
self.directSource = [];
|
|
467
|
+
var elapsed = activeAudioContext().currentTime - self.startTimeSec;
|
|
468
|
+
return elapsed;
|
|
469
|
+
};
|
|
470
|
+
self.finished = function() {
|
|
471
|
+
self.startTimeSec = undefined;
|
|
472
|
+
self.pausedTimeSec = undefined;
|
|
473
|
+
self.isRunning = false;
|
|
366
474
|
};
|
|
367
475
|
|
|
368
476
|
self.download = function() {
|