pxt-core 8.4.1 → 8.4.3

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 (82) hide show
  1. package/built/backendutils.js +1 -0
  2. package/built/cli.js +83 -75
  3. package/built/pxt.js +1274 -179
  4. package/built/pxtblockly.js +323 -40
  5. package/built/pxtblocks.d.ts +30 -7
  6. package/built/pxtblocks.js +324 -41
  7. package/built/pxteditor.d.ts +2 -0
  8. package/built/pxtlib.d.ts +91 -5
  9. package/built/pxtlib.js +1183 -101
  10. package/built/pxtsim.js +8 -3
  11. package/built/server.js +4 -0
  12. package/built/target.js +1 -1
  13. package/built/web/main.js +1 -1
  14. package/built/web/multiplayer/css/main.2dd69ed8.css +4 -0
  15. package/built/web/multiplayer/js/main.f3b8f930.js +2 -0
  16. package/built/web/pxtapp.js +1 -1
  17. package/built/web/pxtasseteditor.js +1 -1
  18. package/built/web/pxtblockly.js +1 -1
  19. package/built/web/pxtblocks.js +1 -1
  20. package/built/web/pxtembed.js +2 -2
  21. package/built/web/pxtlib.js +1 -1
  22. package/built/web/pxtsim.js +1 -1
  23. package/built/web/pxtworker.js +2 -2
  24. package/built/web/react-common-authcode.css +4 -6993
  25. package/built/web/react-common-multiplayer.css +13 -0
  26. package/built/web/react-common-skillmap.css +1 -1
  27. package/built/web/rtlreact-common-authcode.css +13 -0
  28. package/built/web/rtlreact-common-multiplayer.css +13 -0
  29. package/built/web/rtlreact-common-skillmap.css +1 -1
  30. package/built/web/rtlsemantic.css +1 -1
  31. package/built/web/semantic.css +1 -1
  32. package/built/web/skillmap/js/main.a6cf40e1.chunk.js +1 -0
  33. package/common-docs/identity/sign-in.md +17 -3
  34. package/common-docs/static/music-editor/apple.png +0 -0
  35. package/common-docs/static/music-editor/burger.png +0 -0
  36. package/common-docs/static/music-editor/cake.png +0 -0
  37. package/common-docs/static/music-editor/car.png +0 -0
  38. package/common-docs/static/music-editor/cat.png +0 -0
  39. package/common-docs/static/music-editor/cherry.png +0 -0
  40. package/common-docs/static/music-editor/clam.png +0 -0
  41. package/common-docs/static/music-editor/computer.png +0 -0
  42. package/common-docs/static/music-editor/crab.png +0 -0
  43. package/common-docs/static/music-editor/dog.png +0 -0
  44. package/common-docs/static/music-editor/duck.png +0 -0
  45. package/common-docs/static/music-editor/egg.png +0 -0
  46. package/common-docs/static/music-editor/explosion.png +0 -0
  47. package/common-docs/static/music-editor/fish.png +0 -0
  48. package/common-docs/static/music-editor/ice-cream.png +0 -0
  49. package/common-docs/static/music-editor/lemon.png +0 -0
  50. package/common-docs/static/music-editor/metronomeWorker.js +35 -0
  51. package/common-docs/static/music-editor/snake.png +0 -0
  52. package/common-docs/static/music-editor/star.png +0 -0
  53. package/common-docs/static/music-editor/strawberry.png +0 -0
  54. package/common-docs/static/music-editor/taco.png +0 -0
  55. package/common-docs/static/music-editor/treble-clef.svg +1 -0
  56. package/localtypings/projectheader.d.ts +1 -0
  57. package/package.json +4 -2
  58. package/react-common/components/controls/Input.tsx +7 -3
  59. package/react-common/components/share/Share.tsx +6 -2
  60. package/react-common/components/share/ShareInfo.tsx +12 -3
  61. package/react-common/styles/controls/Button.less +9 -0
  62. package/react-common/styles/react-common-authcode-core.less +1 -1
  63. package/react-common/styles/react-common-authcode.less +1 -1
  64. package/react-common/styles/react-common-multiplayer-core.less +10 -0
  65. package/react-common/styles/react-common-multiplayer.less +12 -0
  66. package/theme/highcontrast.less +14 -0
  67. package/theme/music-editor/EditControls.less +22 -0
  68. package/theme/music-editor/MusicEditor.less +25 -0
  69. package/theme/music-editor/Note.less +16 -0
  70. package/theme/music-editor/NoteGroup.less +7 -0
  71. package/theme/music-editor/PlaybackControls.less +55 -0
  72. package/theme/music-editor/ScrollableWorkspace.less +3 -0
  73. package/theme/music-editor/Staff.less +31 -0
  74. package/theme/music-editor/Track.less +0 -0
  75. package/theme/music-editor/TrackSelector.less +48 -0
  76. package/theme/music-editor/Workspace.less +3 -0
  77. package/theme/pxt.less +1 -0
  78. package/theme/tutorial-sidebar.less +19 -3
  79. package/theme/tutorial.less +2 -2
  80. package/webapp/public/multiplayer.html +1 -1
  81. package/webapp/public/skillmap.html +1 -1
  82. package/built/web/skillmap/js/main.6fa0eaff.chunk.js +0 -1
package/built/pxtlib.js CHANGED
@@ -216,6 +216,9 @@ var pxt;
216
216
  this.setUserProfileAsync(this.state$.profile);
217
217
  this.setUserPreferencesAsync(this.state$.preferences);
218
218
  }
219
+ async authTokenAsync() {
220
+ return await pxt.storage.shared.getAsync(AUTH_CONTAINER, CSRF_TOKEN_KEY);
221
+ }
219
222
  /**
220
223
  * Starts the process of authenticating the user against the given identity
221
224
  * provider. Upon success the backend will write an http-only session cookie
@@ -700,6 +703,11 @@ var pxt;
700
703
  return (_d = (_b = (_a = user === null || user === void 0 ? void 0 : user.idp) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : (_c = user === null || user === void 0 ? void 0 : user.idp) === null || _c === void 0 ? void 0 : _c.username) !== null && _d !== void 0 ? _d : EMPTY_USERNAME;
701
704
  }
702
705
  auth.userName = userName;
706
+ function firstName(user) {
707
+ const userName = pxt.auth.userName(user);
708
+ return (userName === null || userName === void 0 ? void 0 : userName.split(" ").shift()) || userName;
709
+ }
710
+ auth.firstName = firstName;
703
711
  function userInitials(user) {
704
712
  const username = pxt.auth.userName(user);
705
713
  return ts.pxtc.Util.initials(username);
@@ -7536,6 +7544,7 @@ var pxt;
7536
7544
  .then(resp => handleResponseAsync(resp));
7537
7545
  }
7538
7546
  function handleResponseAsync(resp) {
7547
+ var _a, _b, _c;
7539
7548
  const code = resp.statusCode;
7540
7549
  const errorData = pxt.Util.jsonTryParse(resp.text) || {};
7541
7550
  pxt.debug(`upload result: ${code}`);
@@ -7543,16 +7552,22 @@ var pxt;
7543
7552
  pxt.log(`create new translation file: ${filename}`);
7544
7553
  return uploadAsync("add-file", {});
7545
7554
  }
7546
- else if (code == 404 && errorData.error && errorData.error.code == 17) {
7555
+ else if (code == 404 && ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.code) == 17) {
7547
7556
  return createDirectoryAsync(branch, prj, key, filename.replace(/\/[^\/]+$/, ""), incr)
7548
7557
  .then(() => startAsync());
7549
7558
  }
7550
- else if (!errorData.success && errorData.error && errorData.error.code == 53) {
7559
+ else if (!errorData.success && ((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.code) == 53) {
7551
7560
  // file is being updated
7552
7561
  pxt.log(`${filename} being updated, waiting 5s and retry...`);
7553
7562
  return pxt.U.delay(5000) // wait 5s and try again
7554
7563
  .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
7555
7564
  }
7565
+ else if (code == 429 && ((_c = errorData.error) === null || _c === void 0 ? void 0 : _c.code) == 55) {
7566
+ // Too many concurrent requests
7567
+ pxt.log(`Maximum concurrent requests reached, waiting 10s and retry...`);
7568
+ return pxt.U.delay(10 * 1000) // wait 10s and try again
7569
+ .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
7570
+ }
7556
7571
  else if (code == 200 || errorData.success) {
7557
7572
  // something crowdin reports 500 with success=true
7558
7573
  return Promise.resolve();
@@ -8735,6 +8750,7 @@ var pxt;
8735
8750
  const url = new URL(`https://${endpointName}.streaming.media.azure.net/${videoID}/manifest(format=mpd-time-csf).mpd`);
8736
8751
  if (startTime) {
8737
8752
  url.hash = `t=${startTime}`;
8753
+ url.searchParams.append("startTime", startTime);
8738
8754
  }
8739
8755
  if (endTime) {
8740
8756
  url.searchParams.append("endTime", endTime);
@@ -12626,6 +12642,8 @@ var pxt;
12626
12642
  sprite_1.IMAGE_PREFIX = "image";
12627
12643
  sprite_1.ANIMATION_NAMESPACE = "myAnimations";
12628
12644
  sprite_1.ANIMATION_PREFIX = "anim";
12645
+ sprite_1.SONG_NAMESPACE = "mySongs";
12646
+ sprite_1.SONG_PREFIX = "song";
12629
12647
  /**
12630
12648
  * 16-color sprite
12631
12649
  */
@@ -13681,6 +13699,1044 @@ var pxt;
13681
13699
  })(shared = storage.shared || (storage.shared = {}));
13682
13700
  })(storage = pxt.storage || (pxt.storage = {}));
13683
13701
  })(pxt || (pxt = {}));
13702
+ var pxt;
13703
+ (function (pxt) {
13704
+ var assets;
13705
+ (function (assets) {
13706
+ var music;
13707
+ (function (music) {
13708
+ const BUFFER_SIZE = 12;
13709
+ function renderInstrument(instrument, noteFrequency, gateLength, volume) {
13710
+ var _a, _b, _c, _d, _e;
13711
+ const totalDuration = gateLength + instrument.ampEnvelope.release;
13712
+ const ampLFOInterval = ((_a = instrument.ampLFO) === null || _a === void 0 ? void 0 : _a.amplitude) ? Math.max(500 / instrument.ampLFO.frequency, 50) : 50;
13713
+ const pitchLFOInterval = ((_b = instrument.pitchLFO) === null || _b === void 0 ? void 0 : _b.amplitude) ? Math.max(500 / instrument.pitchLFO.frequency, 50) : 50;
13714
+ let timePoints = [0];
13715
+ let nextAETime = instrument.ampEnvelope.attack;
13716
+ let nextPETime = ((_c = instrument.pitchEnvelope) === null || _c === void 0 ? void 0 : _c.amplitude) ? instrument.pitchEnvelope.attack : totalDuration;
13717
+ let nextPLTime = ((_d = instrument.pitchLFO) === null || _d === void 0 ? void 0 : _d.amplitude) ? pitchLFOInterval : totalDuration;
13718
+ let nextALTime = ((_e = instrument.ampLFO) === null || _e === void 0 ? void 0 : _e.amplitude) ? ampLFOInterval : totalDuration;
13719
+ let time = 0;
13720
+ while (time < totalDuration) {
13721
+ if (nextAETime <= nextPETime && nextAETime <= nextPLTime && nextAETime <= nextALTime) {
13722
+ time = nextAETime;
13723
+ timePoints.push(nextAETime);
13724
+ if (time < instrument.ampEnvelope.attack + instrument.ampEnvelope.decay && instrument.ampEnvelope.attack + instrument.ampEnvelope.decay < gateLength) {
13725
+ nextAETime = instrument.ampEnvelope.attack + instrument.ampEnvelope.decay;
13726
+ }
13727
+ else if (time < gateLength) {
13728
+ nextAETime = gateLength;
13729
+ }
13730
+ else {
13731
+ nextAETime = totalDuration;
13732
+ }
13733
+ }
13734
+ else if (nextPETime <= nextPLTime && nextPETime <= nextALTime && nextPETime < totalDuration) {
13735
+ time = nextPETime;
13736
+ timePoints.push(nextPETime);
13737
+ if (time < instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay && instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay < gateLength) {
13738
+ nextPETime = instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay;
13739
+ }
13740
+ else if (time < gateLength) {
13741
+ nextPETime = gateLength;
13742
+ }
13743
+ else if (time < gateLength + instrument.pitchEnvelope.release) {
13744
+ nextPETime = Math.min(totalDuration, gateLength + instrument.pitchEnvelope.release);
13745
+ }
13746
+ else {
13747
+ nextPETime = totalDuration;
13748
+ }
13749
+ }
13750
+ else if (nextPLTime <= nextALTime && nextPLTime < totalDuration) {
13751
+ time = nextPLTime;
13752
+ timePoints.push(nextPLTime);
13753
+ nextPLTime += pitchLFOInterval;
13754
+ }
13755
+ else if (nextALTime < totalDuration) {
13756
+ time = nextALTime;
13757
+ timePoints.push(nextALTime);
13758
+ nextALTime += ampLFOInterval;
13759
+ }
13760
+ if (time >= totalDuration) {
13761
+ break;
13762
+ }
13763
+ if (nextAETime <= time) {
13764
+ if (time < instrument.ampEnvelope.attack + instrument.ampEnvelope.decay && instrument.ampEnvelope.attack + instrument.ampEnvelope.decay < gateLength) {
13765
+ nextAETime = instrument.ampEnvelope.attack + instrument.ampEnvelope.decay;
13766
+ }
13767
+ else if (time < gateLength) {
13768
+ nextAETime = gateLength;
13769
+ }
13770
+ else {
13771
+ nextAETime = totalDuration;
13772
+ }
13773
+ }
13774
+ if (nextPETime <= time) {
13775
+ if (time < instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay && instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay < gateLength) {
13776
+ nextPETime = instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay;
13777
+ }
13778
+ else if (time < gateLength) {
13779
+ nextPETime = gateLength;
13780
+ }
13781
+ else if (time < gateLength + instrument.pitchEnvelope.release) {
13782
+ nextPETime = Math.min(totalDuration, gateLength + instrument.pitchEnvelope.release);
13783
+ }
13784
+ else {
13785
+ nextPETime = totalDuration;
13786
+ }
13787
+ }
13788
+ while (nextALTime <= time) {
13789
+ nextALTime += ampLFOInterval;
13790
+ }
13791
+ while (nextPLTime <= time) {
13792
+ nextPLTime += pitchLFOInterval;
13793
+ }
13794
+ }
13795
+ let prevAmp = instrumentVolumeAtTime(instrument, gateLength, 0, volume) | 0;
13796
+ let prevPitch = instrumentPitchAtTime(instrument, noteFrequency, gateLength, 0) | 0;
13797
+ let prevTime = 0;
13798
+ let nextAmp;
13799
+ let nextPitch;
13800
+ const out = new Uint8Array(BUFFER_SIZE * (timePoints.length + 1));
13801
+ for (let i = 1; i < timePoints.length; i++) {
13802
+ if (timePoints[i] - prevTime < 5) {
13803
+ prevTime = timePoints[i];
13804
+ continue;
13805
+ }
13806
+ nextAmp = instrumentVolumeAtTime(instrument, gateLength, timePoints[i], volume) | 0;
13807
+ nextPitch = instrumentPitchAtTime(instrument, noteFrequency, gateLength, timePoints[i]) | 0;
13808
+ addNote(out, (i - 1) * 12, (timePoints[i] - prevTime) | 0, prevAmp, nextAmp, instrument.waveform, prevPitch, nextPitch);
13809
+ prevAmp = nextAmp;
13810
+ prevPitch = nextPitch;
13811
+ prevTime = timePoints[i];
13812
+ }
13813
+ addNote(out, timePoints.length * 12, 10, prevAmp, 0, instrument.waveform, prevPitch, prevPitch);
13814
+ return out;
13815
+ }
13816
+ music.renderInstrument = renderInstrument;
13817
+ function renderDrumInstrument(sound, volume) {
13818
+ let prevAmp = sound.startVolume;
13819
+ let prevFreq = sound.startFrequency;
13820
+ const scaleVolume = (value) => (value / 1024) * volume;
13821
+ let out = new Uint8Array((sound.steps.length + 1) * BUFFER_SIZE);
13822
+ for (let i = 0; i < sound.steps.length; i++) {
13823
+ addNote(out, i * BUFFER_SIZE, sound.steps[i].duration, scaleVolume(prevAmp), scaleVolume(sound.steps[i].volume), sound.steps[i].waveform, prevFreq, sound.steps[i].frequency);
13824
+ prevAmp = sound.steps[i].volume;
13825
+ prevFreq = sound.steps[i].frequency;
13826
+ }
13827
+ addNote(out, sound.steps.length * BUFFER_SIZE, 10, scaleVolume(prevAmp), 0, sound.steps[sound.steps.length - 1].waveform, prevFreq, prevFreq);
13828
+ return out;
13829
+ }
13830
+ music.renderDrumInstrument = renderDrumInstrument;
13831
+ function instrumentPitchAtTime(instrument, noteFrequency, gateLength, time) {
13832
+ var _a, _b;
13833
+ let mod = 0;
13834
+ if ((_a = instrument.pitchEnvelope) === null || _a === void 0 ? void 0 : _a.amplitude) {
13835
+ mod += envelopeValueAtTime(instrument.pitchEnvelope, time, gateLength);
13836
+ }
13837
+ if ((_b = instrument.pitchLFO) === null || _b === void 0 ? void 0 : _b.amplitude) {
13838
+ mod += lfoValueAtTime(instrument.pitchLFO, time);
13839
+ }
13840
+ return Math.max(noteFrequency + mod, 0);
13841
+ }
13842
+ function instrumentVolumeAtTime(instrument, gateLength, time, maxVolume) {
13843
+ var _a;
13844
+ let mod = 0;
13845
+ if (instrument.ampEnvelope.amplitude) {
13846
+ mod += envelopeValueAtTime(instrument.ampEnvelope, time, gateLength);
13847
+ }
13848
+ if ((_a = instrument.ampLFO) === null || _a === void 0 ? void 0 : _a.amplitude) {
13849
+ mod += lfoValueAtTime(instrument.ampLFO, time);
13850
+ }
13851
+ return ((Math.max(Math.min(mod, instrument.ampEnvelope.amplitude), 0) / 1024) * maxVolume) | 0;
13852
+ }
13853
+ function envelopeValueAtTime(envelope, time, gateLength) {
13854
+ const adjustedSustain = (envelope.sustain / 1024) * envelope.amplitude;
13855
+ if (time > gateLength) {
13856
+ if (time - gateLength > envelope.release)
13857
+ return 0;
13858
+ else if (time < envelope.attack) {
13859
+ const height = (envelope.amplitude / envelope.attack) * gateLength;
13860
+ return height - ((height / envelope.release) * (time - gateLength));
13861
+ }
13862
+ else if (time < envelope.attack + envelope.decay) {
13863
+ const height2 = envelope.amplitude - ((envelope.amplitude - adjustedSustain) / envelope.decay) * (gateLength - envelope.attack);
13864
+ return height2 - ((height2 / envelope.release) * (time - gateLength));
13865
+ }
13866
+ else {
13867
+ return adjustedSustain - (adjustedSustain / envelope.release) * (time - gateLength);
13868
+ }
13869
+ }
13870
+ else if (time < envelope.attack) {
13871
+ return (envelope.amplitude / envelope.attack) * time;
13872
+ }
13873
+ else if (time < envelope.attack + envelope.decay) {
13874
+ return envelope.amplitude - ((envelope.amplitude - adjustedSustain) / envelope.decay) * (time - envelope.attack);
13875
+ }
13876
+ else {
13877
+ return adjustedSustain;
13878
+ }
13879
+ }
13880
+ function lfoValueAtTime(lfo, time) {
13881
+ return Math.cos(((time / 1000) * lfo.frequency) * 2 * Math.PI) * lfo.amplitude;
13882
+ }
13883
+ function set16BitNumber(buf, offset, value) {
13884
+ const temp = new Uint8Array(2);
13885
+ new Uint16Array(temp.buffer)[0] = value | 0;
13886
+ buf[offset] = temp[0];
13887
+ buf[offset + 1] = temp[1];
13888
+ }
13889
+ function get16BitNumber(buf, offset) {
13890
+ const temp = new Uint8Array(2);
13891
+ temp[0] = buf[offset];
13892
+ temp[1] = buf[offset + 1];
13893
+ return new Uint16Array(temp.buffer)[0];
13894
+ }
13895
+ function addNote(sndInstr, sndInstrPtr, ms, beg, end, soundWave, hz, endHz) {
13896
+ if (ms > 0) {
13897
+ sndInstr[sndInstrPtr] = soundWave;
13898
+ sndInstr[sndInstrPtr + 1] = 0;
13899
+ set16BitNumber(sndInstr, sndInstrPtr + 2, hz);
13900
+ set16BitNumber(sndInstr, sndInstrPtr + 4, ms);
13901
+ set16BitNumber(sndInstr, sndInstrPtr + 6, (beg * 255) >> 6);
13902
+ set16BitNumber(sndInstr, sndInstrPtr + 8, (end * 255) >> 6);
13903
+ set16BitNumber(sndInstr, sndInstrPtr + 10, endHz);
13904
+ sndInstrPtr += BUFFER_SIZE;
13905
+ }
13906
+ sndInstr[sndInstrPtr] = 0;
13907
+ return sndInstrPtr;
13908
+ }
13909
+ function encodeSongToHex(song) {
13910
+ const encoded = encodeSong(song);
13911
+ return pxt.U.toHex(encoded);
13912
+ }
13913
+ music.encodeSongToHex = encodeSongToHex;
13914
+ function decodeSongFromHex(hex) {
13915
+ const bytes = pxt.U.fromHex(hex);
13916
+ return decodeSong(bytes);
13917
+ }
13918
+ music.decodeSongFromHex = decodeSongFromHex;
13919
+ /**
13920
+ * Byte encoding format for songs
13921
+ * FIXME: should this all be word aligned?
13922
+ *
13923
+ * song(7 + length of all tracks bytes)
13924
+ * 0 version
13925
+ * 1 beats per minute
13926
+ * 3 beats per measure
13927
+ * 4 ticks per beat
13928
+ * 5 measures
13929
+ * 6 number of tracks
13930
+ * ...tracks
13931
+ *
13932
+ * track(6 + instrument length + note length bytes)
13933
+ * 0 id
13934
+ * 1 flags
13935
+ * 2 instruments byte length
13936
+ * 4...instrument
13937
+ * notes byte length
13938
+ * ...note events
13939
+ *
13940
+ * instrument(27 bytes)
13941
+ * 0 waveform
13942
+ * 1 amp attack
13943
+ * 3 amp decay
13944
+ * 5 amp sustain
13945
+ * 7 amp release
13946
+ * 9 amp amp
13947
+ * 11 pitch attack
13948
+ * 13 pitch decay
13949
+ * 15 pitch sustain
13950
+ * 17 pitch release
13951
+ * 19 pitch amp
13952
+ * 21 amp lfo freq
13953
+ * 22 amp lfo amp
13954
+ * 24 pitch lfo freq
13955
+ * 25 pitch lfo amp
13956
+ *
13957
+ * drum(5 + 7 * steps bytes)
13958
+ * 0 steps
13959
+ * 1 start freq
13960
+ * 3 start amp
13961
+ * 5...steps
13962
+ *
13963
+ * drum step(7 bytes)
13964
+ * 0 waveform
13965
+ * 1 freq
13966
+ * 3 volume
13967
+ * 5 duration
13968
+ *
13969
+ * note event(5 + 1 * polyphony bytes)
13970
+ * 0 start tick
13971
+ * 2 end tick
13972
+ * 4 polyphony
13973
+ * 5...notes(1 byte each)
13974
+ *
13975
+ */
13976
+ function encodeSong(song) {
13977
+ const encodedTracks = song.tracks
13978
+ .filter((track) => track.notes.length > 0)
13979
+ .map(encodeTrack);
13980
+ const trackLength = encodedTracks.reduce((d, c) => c.length + d, 0);
13981
+ const out = new Uint8Array(7 + trackLength);
13982
+ out[0] = 0; // encoding version
13983
+ set16BitNumber(out, 1, song.beatsPerMinute);
13984
+ out[3] = song.beatsPerMeasure;
13985
+ out[4] = song.ticksPerBeat;
13986
+ out[5] = song.measures;
13987
+ out[6] = encodedTracks.length;
13988
+ let current = 7;
13989
+ for (const track of encodedTracks) {
13990
+ out.set(track, current);
13991
+ current += track.length;
13992
+ }
13993
+ return out;
13994
+ }
13995
+ function decodeSong(buf) {
13996
+ const res = {
13997
+ beatsPerMinute: get16BitNumber(buf, 1),
13998
+ beatsPerMeasure: buf[3],
13999
+ ticksPerBeat: buf[4],
14000
+ measures: buf[5],
14001
+ tracks: []
14002
+ };
14003
+ let current = 7;
14004
+ while (current < buf.length) {
14005
+ const [track, pointer] = decodeTrack(buf, current);
14006
+ current = pointer;
14007
+ res.tracks.push(track);
14008
+ }
14009
+ return res;
14010
+ }
14011
+ function encodeInstrument(instrument) {
14012
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
14013
+ const out = new Uint8Array(28);
14014
+ out[0] = instrument.waveform;
14015
+ set16BitNumber(out, 1, instrument.ampEnvelope.attack);
14016
+ set16BitNumber(out, 3, instrument.ampEnvelope.decay);
14017
+ set16BitNumber(out, 5, instrument.ampEnvelope.sustain);
14018
+ set16BitNumber(out, 7, instrument.ampEnvelope.release);
14019
+ set16BitNumber(out, 9, instrument.ampEnvelope.amplitude);
14020
+ set16BitNumber(out, 11, ((_a = instrument.pitchEnvelope) === null || _a === void 0 ? void 0 : _a.attack) || 0);
14021
+ set16BitNumber(out, 13, ((_b = instrument.pitchEnvelope) === null || _b === void 0 ? void 0 : _b.decay) || 0);
14022
+ set16BitNumber(out, 15, ((_c = instrument.pitchEnvelope) === null || _c === void 0 ? void 0 : _c.sustain) || 0);
14023
+ set16BitNumber(out, 17, ((_d = instrument.pitchEnvelope) === null || _d === void 0 ? void 0 : _d.release) || 0);
14024
+ set16BitNumber(out, 19, ((_e = instrument.pitchEnvelope) === null || _e === void 0 ? void 0 : _e.amplitude) || 0);
14025
+ out[21] = ((_f = instrument.ampLFO) === null || _f === void 0 ? void 0 : _f.frequency) || 0;
14026
+ set16BitNumber(out, 22, ((_g = instrument.ampLFO) === null || _g === void 0 ? void 0 : _g.amplitude) || 0);
14027
+ out[24] = ((_h = instrument.pitchLFO) === null || _h === void 0 ? void 0 : _h.frequency) || 0;
14028
+ set16BitNumber(out, 25, ((_j = instrument.pitchLFO) === null || _j === void 0 ? void 0 : _j.amplitude) || 0);
14029
+ return out;
14030
+ }
14031
+ function decodeInstrument(buf, offset) {
14032
+ return {
14033
+ waveform: buf[offset],
14034
+ ampEnvelope: {
14035
+ attack: get16BitNumber(buf, offset + 1),
14036
+ decay: get16BitNumber(buf, offset + 3),
14037
+ sustain: get16BitNumber(buf, offset + 5),
14038
+ release: get16BitNumber(buf, offset + 7),
14039
+ amplitude: get16BitNumber(buf, offset + 9),
14040
+ },
14041
+ pitchEnvelope: {
14042
+ attack: get16BitNumber(buf, offset + 11),
14043
+ decay: get16BitNumber(buf, offset + 13),
14044
+ sustain: get16BitNumber(buf, offset + 15),
14045
+ release: get16BitNumber(buf, offset + 17),
14046
+ amplitude: get16BitNumber(buf, offset + 19),
14047
+ },
14048
+ ampLFO: {
14049
+ frequency: buf[offset + 21],
14050
+ amplitude: get16BitNumber(buf, 22)
14051
+ },
14052
+ pitchLFO: {
14053
+ frequency: buf[offset + 24],
14054
+ amplitude: get16BitNumber(buf, 25)
14055
+ }
14056
+ };
14057
+ }
14058
+ function decodeTrack(buf, offset) {
14059
+ if (buf[offset + 1]) {
14060
+ return decodeDrumTrack(buf, offset);
14061
+ }
14062
+ return decodeMelodicTrack(buf, offset);
14063
+ }
14064
+ function encodeDrumInstrument(drum) {
14065
+ const out = new Uint8Array(5 + 7 * drum.steps.length);
14066
+ out[0] = drum.steps.length;
14067
+ set16BitNumber(out, 1, drum.startFrequency);
14068
+ set16BitNumber(out, 3, drum.startVolume);
14069
+ for (let i = 0; i < drum.steps.length; i++) {
14070
+ const start = 5 + i * 7;
14071
+ out[start] = drum.steps[i].waveform;
14072
+ set16BitNumber(out, start + 1, drum.steps[i].frequency);
14073
+ set16BitNumber(out, start + 3, drum.steps[i].volume);
14074
+ set16BitNumber(out, start + 5, drum.steps[i].duration);
14075
+ }
14076
+ return out;
14077
+ }
14078
+ function decodeDrumInstrument(buf, offset) {
14079
+ const res = {
14080
+ startFrequency: get16BitNumber(buf, offset + 1),
14081
+ startVolume: get16BitNumber(buf, offset + 3),
14082
+ steps: []
14083
+ };
14084
+ for (let i = 0; i < buf[offset]; i++) {
14085
+ const start = offset + 5 + i * 7;
14086
+ res.steps.push({
14087
+ waveform: buf[start],
14088
+ frequency: get16BitNumber(buf, start + 1),
14089
+ volume: get16BitNumber(buf, start + 3),
14090
+ duration: get16BitNumber(buf, start + 5)
14091
+ });
14092
+ }
14093
+ return res;
14094
+ }
14095
+ function encodeNoteEvent(event) {
14096
+ const out = new Uint8Array(5 + event.notes.length);
14097
+ set16BitNumber(out, 0, event.startTick);
14098
+ set16BitNumber(out, 2, event.endTick);
14099
+ out[4] = event.notes.length;
14100
+ for (let i = 0; i < event.notes.length; i++) {
14101
+ out[5 + i] = event.notes[i];
14102
+ }
14103
+ return out;
14104
+ }
14105
+ function decodeNoteEvent(buf, offset) {
14106
+ const res = {
14107
+ startTick: get16BitNumber(buf, offset),
14108
+ endTick: get16BitNumber(buf, offset + 2),
14109
+ notes: []
14110
+ };
14111
+ for (let i = 0; i < buf[offset + 4]; i++) {
14112
+ res.notes.push(buf[offset + 5 + i]);
14113
+ }
14114
+ return res;
14115
+ }
14116
+ function encodeTrack(track) {
14117
+ if (track.drums)
14118
+ return encodeDrumTrack(track);
14119
+ return encodeMelodicTrack(track);
14120
+ }
14121
+ function encodeMelodicTrack(track) {
14122
+ const encodedInstrument = encodeInstrument(track.instrument);
14123
+ const encodedNotes = track.notes.map(encodeNoteEvent);
14124
+ const noteLength = encodedNotes.reduce((d, c) => c.length + d, 0);
14125
+ const out = new Uint8Array(6 + encodedInstrument.length + noteLength);
14126
+ out[0] = track.id;
14127
+ out[1] = 0;
14128
+ set16BitNumber(out, 2, encodedInstrument.length);
14129
+ let current = 4;
14130
+ out.set(encodedInstrument, current);
14131
+ current += encodedInstrument.length;
14132
+ set16BitNumber(out, current, noteLength);
14133
+ current += 2;
14134
+ for (const note of encodedNotes) {
14135
+ out.set(note, current);
14136
+ current += note.length;
14137
+ }
14138
+ return out;
14139
+ }
14140
+ function decodeMelodicTrack(buf, offset) {
14141
+ const res = {
14142
+ id: buf[offset],
14143
+ instrument: decodeInstrument(buf, offset + 4),
14144
+ notes: []
14145
+ };
14146
+ const noteStart = offset + 4 + get16BitNumber(buf, offset + 2);
14147
+ const noteLength = get16BitNumber(buf, noteStart);
14148
+ let currentOffset = noteStart + 2;
14149
+ while (currentOffset < noteStart + 2 + noteLength) {
14150
+ res.notes.push(decodeNoteEvent(buf, currentOffset));
14151
+ currentOffset += 5 + res.notes[res.notes.length - 1].notes.length;
14152
+ }
14153
+ return [res, currentOffset];
14154
+ }
14155
+ function encodeDrumTrack(track) {
14156
+ const encodedDrums = track.drums.map(encodeDrumInstrument);
14157
+ const drumLength = encodedDrums.reduce((d, c) => c.length + d, 0);
14158
+ const encodedNotes = track.notes.map(encodeNoteEvent);
14159
+ const noteLength = encodedNotes.reduce((d, c) => c.length + d, 0);
14160
+ const out = new Uint8Array(6 + drumLength + noteLength);
14161
+ out[0] = track.id;
14162
+ out[1] = 1;
14163
+ set16BitNumber(out, 2, drumLength);
14164
+ let current = 4;
14165
+ for (const drum of encodedDrums) {
14166
+ out.set(drum, current);
14167
+ current += drum.length;
14168
+ }
14169
+ set16BitNumber(out, current, noteLength);
14170
+ current += 2;
14171
+ for (const note of encodedNotes) {
14172
+ out.set(note, current);
14173
+ current += note.length;
14174
+ }
14175
+ return out;
14176
+ }
14177
+ function decodeDrumTrack(buf, offset) {
14178
+ const res = {
14179
+ id: buf[offset],
14180
+ instrument: { ampEnvelope: { attack: 0, decay: 0, sustain: 0, release: 0, amplitude: 0 }, waveform: 0 },
14181
+ notes: [],
14182
+ drums: []
14183
+ };
14184
+ const drumByteLength = get16BitNumber(buf, offset + 2);
14185
+ let currentOffset = offset + 4;
14186
+ while (currentOffset < offset + 4 + drumByteLength) {
14187
+ res.drums.push(decodeDrumInstrument(buf, currentOffset));
14188
+ currentOffset += 5 + 7 * res.drums[res.drums.length - 1].steps.length;
14189
+ }
14190
+ const noteLength = get16BitNumber(buf, currentOffset);
14191
+ currentOffset += 2;
14192
+ while (currentOffset < offset + 4 + drumByteLength + noteLength) {
14193
+ res.notes.push(decodeNoteEvent(buf, currentOffset));
14194
+ currentOffset += 5 + res.notes[res.notes.length - 1].notes.length;
14195
+ }
14196
+ return [res, currentOffset];
14197
+ }
14198
+ function cloneSong(song) {
14199
+ return Object.assign(Object.assign({}, song), { tracks: song.tracks.map(track => (Object.assign(Object.assign({}, track), { instrument: track.instrument && Object.assign(Object.assign({}, track.instrument), { ampEnvelope: Object.assign({}, track.instrument.ampEnvelope), pitchEnvelope: track.instrument.pitchEnvelope && Object.assign({}, track.instrument.pitchEnvelope), ampLFO: track.instrument.ampLFO && Object.assign({}, track.instrument.ampLFO), pitchLFO: track.instrument.pitchLFO && Object.assign({}, track.instrument.pitchLFO) }), drums: track.drums && track.drums.map(drum => (Object.assign(Object.assign({}, drum), { steps: drum.steps.map(step => (Object.assign({}, step))) }))), notes: track.notes.map(noteEvent => (Object.assign(Object.assign({}, noteEvent), { notes: noteEvent.notes.slice() }))) }))) });
14200
+ }
14201
+ music.cloneSong = cloneSong;
14202
+ function songEquals(a, b) {
14203
+ return naiveEqualCheck(a, b);
14204
+ }
14205
+ music.songEquals = songEquals;
14206
+ function naiveEqualCheck(a, b) {
14207
+ if (typeof a !== typeof b)
14208
+ return false;
14209
+ else if (typeof a !== "object")
14210
+ return a === b;
14211
+ else if (Array.isArray(a)) {
14212
+ if (a.length !== b.length)
14213
+ return false;
14214
+ for (let i = 0; i < a.length; i++) {
14215
+ if (!naiveEqualCheck(a[i], b[i]))
14216
+ return false;
14217
+ }
14218
+ return true;
14219
+ }
14220
+ const aKeys = Object.keys(a);
14221
+ const bKeys = Object.keys(b);
14222
+ if (aKeys.length !== bKeys.length)
14223
+ return false;
14224
+ for (const key of aKeys) {
14225
+ if (bKeys.indexOf(key) === -1)
14226
+ return false;
14227
+ if (!naiveEqualCheck(a[key], b[key]))
14228
+ return false;
14229
+ }
14230
+ return true;
14231
+ }
14232
+ function inflateSong(song) {
14233
+ const base = getEmptySong(1);
14234
+ song.tracks = base.tracks.map((track, index) => {
14235
+ const existing = song.tracks.find(t => t.id === index);
14236
+ if (existing)
14237
+ track.notes = existing.notes;
14238
+ return track;
14239
+ });
14240
+ }
14241
+ music.inflateSong = inflateSong;
14242
+ function getEmptySong(measures) {
14243
+ return {
14244
+ ticksPerBeat: 8,
14245
+ beatsPerMeasure: 4,
14246
+ beatsPerMinute: 120,
14247
+ measures,
14248
+ tracks: [
14249
+ {
14250
+ id: 0,
14251
+ name: lf("Duck"),
14252
+ notes: [],
14253
+ iconURI: "/static/music-editor/duck.png",
14254
+ instrument: {
14255
+ waveform: 15,
14256
+ octave: 4,
14257
+ ampEnvelope: {
14258
+ attack: 5,
14259
+ decay: 530,
14260
+ sustain: 705,
14261
+ release: 450,
14262
+ amplitude: 1024
14263
+ },
14264
+ pitchEnvelope: {
14265
+ attack: 5,
14266
+ decay: 40,
14267
+ sustain: 0,
14268
+ release: 100,
14269
+ amplitude: 40
14270
+ },
14271
+ ampLFO: {
14272
+ frequency: 3,
14273
+ amplitude: 20
14274
+ },
14275
+ pitchLFO: {
14276
+ frequency: 6,
14277
+ amplitude: 2
14278
+ }
14279
+ }
14280
+ },
14281
+ {
14282
+ id: 1,
14283
+ name: lf("Cat"),
14284
+ notes: [],
14285
+ iconURI: "/static/music-editor/cat.png",
14286
+ instrument: {
14287
+ waveform: 12,
14288
+ octave: 5,
14289
+ ampEnvelope: {
14290
+ attack: 150,
14291
+ decay: 100,
14292
+ sustain: 365,
14293
+ release: 400,
14294
+ amplitude: 1024
14295
+ },
14296
+ pitchEnvelope: {
14297
+ attack: 120,
14298
+ decay: 300,
14299
+ sustain: 0,
14300
+ release: 100,
14301
+ amplitude: 50
14302
+ },
14303
+ pitchLFO: {
14304
+ frequency: 10,
14305
+ amplitude: 6
14306
+ }
14307
+ }
14308
+ },
14309
+ {
14310
+ id: 2,
14311
+ name: lf("Dog"),
14312
+ notes: [],
14313
+ iconURI: "/static/music-editor/dog.png",
14314
+ instrument: {
14315
+ waveform: 1,
14316
+ octave: 4,
14317
+ ampEnvelope: {
14318
+ attack: 10,
14319
+ decay: 100,
14320
+ sustain: 500,
14321
+ release: 100,
14322
+ amplitude: 1024
14323
+ },
14324
+ pitchLFO: {
14325
+ frequency: 5,
14326
+ amplitude: 0
14327
+ }
14328
+ }
14329
+ },
14330
+ {
14331
+ id: 3,
14332
+ name: lf("Fish"),
14333
+ notes: [],
14334
+ iconURI: "/static/music-editor/fish.png",
14335
+ instrument: {
14336
+ waveform: 1,
14337
+ octave: 3,
14338
+ ampEnvelope: {
14339
+ attack: 220,
14340
+ decay: 105,
14341
+ sustain: 1024,
14342
+ release: 350,
14343
+ amplitude: 1024
14344
+ },
14345
+ ampLFO: {
14346
+ frequency: 5,
14347
+ amplitude: 100
14348
+ },
14349
+ pitchLFO: {
14350
+ frequency: 1,
14351
+ amplitude: 4
14352
+ }
14353
+ }
14354
+ },
14355
+ {
14356
+ id: 4,
14357
+ name: lf("Car"),
14358
+ notes: [],
14359
+ iconURI: "/static/music-editor/car.png",
14360
+ instrument: {
14361
+ waveform: 16,
14362
+ octave: 4,
14363
+ ampEnvelope: {
14364
+ attack: 5,
14365
+ decay: 100,
14366
+ sustain: 1024,
14367
+ release: 30,
14368
+ amplitude: 1024
14369
+ },
14370
+ pitchLFO: {
14371
+ frequency: 10,
14372
+ amplitude: 4
14373
+ }
14374
+ }
14375
+ },
14376
+ {
14377
+ id: 5,
14378
+ name: lf("Computer"),
14379
+ notes: [],
14380
+ iconURI: "/static/music-editor/computer.png",
14381
+ instrument: {
14382
+ waveform: 15,
14383
+ octave: 1,
14384
+ ampEnvelope: {
14385
+ attack: 10,
14386
+ decay: 100,
14387
+ sustain: 500,
14388
+ release: 10,
14389
+ amplitude: 1024
14390
+ }
14391
+ }
14392
+ },
14393
+ {
14394
+ id: 6,
14395
+ name: lf("Burger"),
14396
+ notes: [],
14397
+ iconURI: "/static/music-editor/burger.png",
14398
+ instrument: {
14399
+ waveform: 1,
14400
+ octave: 1,
14401
+ ampEnvelope: {
14402
+ attack: 10,
14403
+ decay: 100,
14404
+ sustain: 500,
14405
+ release: 100,
14406
+ amplitude: 1024
14407
+ }
14408
+ }
14409
+ },
14410
+ {
14411
+ id: 7,
14412
+ name: lf("Cherry"),
14413
+ notes: [],
14414
+ iconURI: "/static/music-editor/cherry.png",
14415
+ instrument: {
14416
+ waveform: 2,
14417
+ octave: 3,
14418
+ ampEnvelope: {
14419
+ attack: 10,
14420
+ decay: 100,
14421
+ sustain: 500,
14422
+ release: 100,
14423
+ amplitude: 1024
14424
+ }
14425
+ }
14426
+ },
14427
+ {
14428
+ id: 8,
14429
+ name: lf("Lemon"),
14430
+ notes: [],
14431
+ iconURI: "/static/music-editor/lemon.png",
14432
+ instrument: {
14433
+ waveform: 15,
14434
+ octave: 2,
14435
+ ampEnvelope: {
14436
+ attack: 10,
14437
+ decay: 100,
14438
+ sustain: 500,
14439
+ release: 10,
14440
+ amplitude: 1024
14441
+ }
14442
+ }
14443
+ },
14444
+ {
14445
+ id: 9,
14446
+ name: lf("Explosion"),
14447
+ notes: [],
14448
+ iconURI: "/static/music-editor/explosion.png",
14449
+ instrument: {
14450
+ waveform: 11,
14451
+ octave: 4,
14452
+ ampEnvelope: {
14453
+ attack: 10,
14454
+ decay: 100,
14455
+ sustain: 500,
14456
+ release: 100,
14457
+ amplitude: 1024
14458
+ }
14459
+ },
14460
+ drums: [
14461
+ {
14462
+ startFrequency: 100,
14463
+ startVolume: 1024,
14464
+ steps: [
14465
+ {
14466
+ waveform: 3,
14467
+ frequency: 120,
14468
+ duration: 10,
14469
+ volume: 1024
14470
+ },
14471
+ {
14472
+ waveform: 3,
14473
+ frequency: 1,
14474
+ duration: 100,
14475
+ volume: 0
14476
+ }
14477
+ ]
14478
+ },
14479
+ {
14480
+ startFrequency: 1,
14481
+ startVolume: 1024,
14482
+ steps: [
14483
+ {
14484
+ waveform: 5,
14485
+ frequency: 1,
14486
+ duration: 20,
14487
+ volume: 0
14488
+ }
14489
+ ]
14490
+ },
14491
+ {
14492
+ startFrequency: 1,
14493
+ startVolume: 1024,
14494
+ steps: [
14495
+ {
14496
+ waveform: 5,
14497
+ frequency: 1,
14498
+ duration: 20,
14499
+ volume: 480
14500
+ },
14501
+ {
14502
+ waveform: 5,
14503
+ frequency: 1,
14504
+ duration: 20,
14505
+ volume: 260
14506
+ },
14507
+ {
14508
+ waveform: 5,
14509
+ frequency: 1,
14510
+ duration: 20,
14511
+ volume: 200
14512
+ },
14513
+ {
14514
+ waveform: 5,
14515
+ frequency: 1,
14516
+ duration: 200,
14517
+ volume: 0
14518
+ },
14519
+ ]
14520
+ },
14521
+ {
14522
+ startFrequency: 175,
14523
+ startVolume: 1024,
14524
+ steps: [
14525
+ {
14526
+ waveform: 1,
14527
+ frequency: 200,
14528
+ duration: 10,
14529
+ volume: 1024
14530
+ },
14531
+ {
14532
+ waveform: 1,
14533
+ frequency: 150,
14534
+ duration: 20,
14535
+ volume: 1024
14536
+ },
14537
+ {
14538
+ waveform: 5,
14539
+ frequency: 1,
14540
+ duration: 20,
14541
+ volume: 100
14542
+ },
14543
+ {
14544
+ waveform: 5,
14545
+ frequency: 1,
14546
+ duration: 300,
14547
+ volume: 0
14548
+ },
14549
+ ]
14550
+ },
14551
+ {
14552
+ startFrequency: 100,
14553
+ startVolume: 1024,
14554
+ steps: [
14555
+ {
14556
+ waveform: 3,
14557
+ frequency: 120,
14558
+ duration: 10,
14559
+ volume: 1024
14560
+ },
14561
+ {
14562
+ waveform: 1,
14563
+ frequency: 120,
14564
+ duration: 100,
14565
+ volume: 0
14566
+ }
14567
+ ]
14568
+ },
14569
+ {
14570
+ startFrequency: 1,
14571
+ startVolume: 1024,
14572
+ steps: [
14573
+ {
14574
+ waveform: 5,
14575
+ frequency: 1,
14576
+ duration: 20,
14577
+ volume: 0
14578
+ }
14579
+ ]
14580
+ },
14581
+ {
14582
+ startFrequency: 1,
14583
+ startVolume: 1024,
14584
+ steps: [
14585
+ {
14586
+ waveform: 5,
14587
+ frequency: 1,
14588
+ duration: 20,
14589
+ volume: 480
14590
+ },
14591
+ {
14592
+ waveform: 5,
14593
+ frequency: 1,
14594
+ duration: 20,
14595
+ volume: 260
14596
+ },
14597
+ {
14598
+ waveform: 5,
14599
+ frequency: 1,
14600
+ duration: 20,
14601
+ volume: 200
14602
+ },
14603
+ {
14604
+ waveform: 5,
14605
+ frequency: 1,
14606
+ duration: 200,
14607
+ volume: 0
14608
+ },
14609
+ ]
14610
+ },
14611
+ {
14612
+ startFrequency: 175,
14613
+ startVolume: 1024,
14614
+ steps: [
14615
+ {
14616
+ waveform: 1,
14617
+ frequency: 200,
14618
+ duration: 10,
14619
+ volume: 1024
14620
+ },
14621
+ {
14622
+ waveform: 1,
14623
+ frequency: 150,
14624
+ duration: 20,
14625
+ volume: 1024
14626
+ },
14627
+ {
14628
+ waveform: 5,
14629
+ frequency: 1,
14630
+ duration: 20,
14631
+ volume: 100
14632
+ },
14633
+ {
14634
+ waveform: 5,
14635
+ frequency: 1,
14636
+ duration: 300,
14637
+ volume: 0
14638
+ },
14639
+ ]
14640
+ },
14641
+ {
14642
+ startFrequency: 100,
14643
+ startVolume: 1024,
14644
+ steps: [
14645
+ {
14646
+ waveform: 3,
14647
+ frequency: 120,
14648
+ duration: 10,
14649
+ volume: 1024
14650
+ },
14651
+ {
14652
+ waveform: 1,
14653
+ frequency: 120,
14654
+ duration: 100,
14655
+ volume: 0
14656
+ }
14657
+ ]
14658
+ },
14659
+ {
14660
+ startFrequency: 1,
14661
+ startVolume: 1024,
14662
+ steps: [
14663
+ {
14664
+ waveform: 5,
14665
+ frequency: 1,
14666
+ duration: 20,
14667
+ volume: 0
14668
+ }
14669
+ ]
14670
+ },
14671
+ {
14672
+ startFrequency: 1,
14673
+ startVolume: 1024,
14674
+ steps: [
14675
+ {
14676
+ waveform: 5,
14677
+ frequency: 1,
14678
+ duration: 20,
14679
+ volume: 480
14680
+ },
14681
+ {
14682
+ waveform: 5,
14683
+ frequency: 1,
14684
+ duration: 20,
14685
+ volume: 260
14686
+ },
14687
+ {
14688
+ waveform: 5,
14689
+ frequency: 1,
14690
+ duration: 20,
14691
+ volume: 200
14692
+ },
14693
+ {
14694
+ waveform: 5,
14695
+ frequency: 1,
14696
+ duration: 200,
14697
+ volume: 0
14698
+ },
14699
+ ]
14700
+ },
14701
+ {
14702
+ startFrequency: 175,
14703
+ startVolume: 1024,
14704
+ steps: [
14705
+ {
14706
+ waveform: 1,
14707
+ frequency: 200,
14708
+ duration: 10,
14709
+ volume: 1024
14710
+ },
14711
+ {
14712
+ waveform: 1,
14713
+ frequency: 150,
14714
+ duration: 20,
14715
+ volume: 1024
14716
+ },
14717
+ {
14718
+ waveform: 5,
14719
+ frequency: 1,
14720
+ duration: 20,
14721
+ volume: 100
14722
+ },
14723
+ {
14724
+ waveform: 5,
14725
+ frequency: 1,
14726
+ duration: 300,
14727
+ volume: 0
14728
+ },
14729
+ ]
14730
+ }
14731
+ ]
14732
+ }
14733
+ ]
14734
+ };
14735
+ }
14736
+ music.getEmptySong = getEmptySong;
14737
+ })(music = assets.music || (assets.music = {}));
14738
+ })(assets = pxt.assets || (pxt.assets = {}));
14739
+ })(pxt || (pxt = {}));
13684
14740
  /// <reference path="../localtypings/pxtpackage.d.ts"/>
13685
14741
  /// <reference path="../localtypings/pxtparts.d.ts"/>
13686
14742
  /// <reference path="../localtypings/pxtarget.d.ts"/>
@@ -17745,6 +18801,7 @@ var pxt;
17745
18801
  pxt.IMAGE_MIME_TYPE = "image/x-mkcd-f4";
17746
18802
  pxt.TILEMAP_MIME_TYPE = "application/mkcd-tilemap";
17747
18803
  pxt.ANIMATION_MIME_TYPE = "application/mkcd-animation";
18804
+ pxt.SONG_MIME_TYPE = "application/mkcd-song";
17748
18805
  class AssetCollection {
17749
18806
  constructor() {
17750
18807
  this.assets = [];
@@ -17931,21 +18988,24 @@ var pxt;
17931
18988
  tilemaps: new AssetCollection(),
17932
18989
  tiles: new AssetCollection(),
17933
18990
  animations: new AssetCollection(),
17934
- images: new AssetCollection()
18991
+ images: new AssetCollection(),
18992
+ songs: new AssetCollection(),
17935
18993
  };
17936
18994
  this.state = {
17937
18995
  revision: this.nextID++,
17938
18996
  tilemaps: new AssetCollection(),
17939
18997
  tiles: new AssetCollection(),
17940
18998
  animations: new AssetCollection(),
17941
- images: new AssetCollection()
18999
+ images: new AssetCollection(),
19000
+ songs: new AssetCollection(),
17942
19001
  };
17943
19002
  this.gallery = {
17944
19003
  revision: 0,
17945
19004
  tilemaps: new AssetCollection(),
17946
19005
  tiles: new AssetCollection(),
17947
19006
  animations: new AssetCollection(),
17948
- images: new AssetCollection()
19007
+ images: new AssetCollection(),
19008
+ songs: new AssetCollection(),
17949
19009
  };
17950
19010
  this.undoStack = [];
17951
19011
  this.redoStack = [];
@@ -18047,6 +19107,19 @@ var pxt;
18047
19107
  };
18048
19108
  return this.state.images.add(newImage);
18049
19109
  }
19110
+ createNewSong(data, displayName) {
19111
+ this.onChange();
19112
+ const newSong = {
19113
+ internalID: this.getNewInternalId(),
19114
+ id: this.generateNewID("song" /* AssetType.Song */),
19115
+ type: "song" /* AssetType.Song */,
19116
+ song: pxt.assets.music.cloneSong(data),
19117
+ meta: {
19118
+ displayName
19119
+ },
19120
+ };
19121
+ return this.state.songs.add(newSong);
19122
+ }
18050
19123
  updateTile(tile) {
18051
19124
  this.onChange();
18052
19125
  const existing = this.resolveProjectTileByInternalID(tile.internalID);
@@ -18083,6 +19156,7 @@ var pxt;
18083
19156
  const blob = {};
18084
19157
  this.state.images.serializeToJRes(blob);
18085
19158
  this.state.animations.serializeToJRes(blob);
19159
+ this.state.songs.serializeToJRes(blob);
18086
19160
  blob["*"] = {
18087
19161
  "mimeType": "image/x-mkcd-f4",
18088
19162
  "dataEncoding": "base64",
@@ -18164,6 +19238,7 @@ var pxt;
18164
19238
  tilemaps: this.state.tilemaps.clone(),
18165
19239
  animations: this.state.animations.clone(),
18166
19240
  tiles: this.state.tiles.clone(),
19241
+ songs: this.state.songs.clone(),
18167
19242
  };
18168
19243
  }
18169
19244
  undo() {
@@ -18176,6 +19251,7 @@ var pxt;
18176
19251
  this.state.images.applyDiff(undo.images, true);
18177
19252
  this.state.tilemaps.applyDiff(undo.tilemaps, true);
18178
19253
  this.state.animations.applyDiff(undo.animations, true);
19254
+ this.state.songs.applyDiff(undo.songs, true);
18179
19255
  this.state.revision = undo.beforeRevision;
18180
19256
  this.redoStack.push(undo);
18181
19257
  this.committedState = this.cloneState();
@@ -18189,6 +19265,7 @@ var pxt;
18189
19265
  this.state.images.applyDiff(redo.images);
18190
19266
  this.state.tilemaps.applyDiff(redo.tilemaps);
18191
19267
  this.state.animations.applyDiff(redo.animations);
19268
+ this.state.songs.applyDiff(redo.songs);
18192
19269
  this.state.revision = redo.afterRevision;
18193
19270
  this.undoStack.push(redo);
18194
19271
  this.committedState = this.cloneState();
@@ -18205,7 +19282,8 @@ var pxt;
18205
19282
  tiles: this.state.tiles.diff(this.committedState.tiles),
18206
19283
  images: this.state.images.diff(this.committedState.images),
18207
19284
  tilemaps: this.state.tilemaps.diff(this.committedState.tilemaps),
18208
- animations: this.state.animations.diff(this.committedState.animations)
19285
+ animations: this.state.animations.diff(this.committedState.animations),
19286
+ songs: this.state.songs.diff(this.committedState.songs)
18209
19287
  });
18210
19288
  this.committedState = this.cloneState();
18211
19289
  this.cleanupTemporaryAssets();
@@ -18235,16 +19313,8 @@ var pxt;
18235
19313
  }
18236
19314
  isNameTaken(assetType, name) {
18237
19315
  const isTaken = (id) => {
18238
- switch (assetType) {
18239
- case "image" /* AssetType.Image */:
18240
- return this.state.images.isIDTaken(id) || this.gallery.images.isIDTaken(id);
18241
- case "tile" /* AssetType.Tile */:
18242
- return this.state.tiles.isIDTaken(id) || this.gallery.tiles.isIDTaken(id);
18243
- case "tilemap" /* AssetType.Tilemap */:
18244
- return this.state.tilemaps.isIDTaken(id) || this.gallery.tilemaps.isIDTaken(id);
18245
- case "animation" /* AssetType.Animation */:
18246
- return this.state.animations.isIDTaken(id) || this.gallery.animations.isIDTaken(id);
18247
- }
19316
+ return getAssetCollection(this.state, assetType).isIDTaken(id) ||
19317
+ getAssetCollection(this.gallery, assetType).isIDTaken(id);
18248
19318
  };
18249
19319
  const shortId = getShortIDCore(assetType, name);
18250
19320
  const checkShortId = shortId && shortId !== name;
@@ -18270,6 +19340,10 @@ var pxt;
18270
19340
  * assets.animation`shortId`
18271
19341
  * assets.animation`displayName`
18272
19342
  *
19343
+ * SONGS:
19344
+ * assets.song`shortId`
19345
+ * assets.song`displayName`
19346
+ *
18273
19347
  * TILEMAPS:
18274
19348
  * tilemap`shortId`
18275
19349
  *
@@ -18308,6 +19382,11 @@ var pxt;
18308
19382
  if (displayName)
18309
19383
  assetTsRefs += `|assets.animation\`${displayName}\``;
18310
19384
  break;
19385
+ case "song" /* pxt.AssetType.Song */:
19386
+ assetTsRefs = `assets.song\`${shortId}\``;
19387
+ if (displayName)
19388
+ assetTsRefs += `|assets.song\`${displayName}\``;
19389
+ break;
18311
19390
  default:
18312
19391
  assetTsRefs = `assets.image\`${shortId}\``;
18313
19392
  if (displayName)
@@ -18330,6 +19409,11 @@ var pxt;
18330
19409
  if (displayName)
18331
19410
  assetPyRefs += `|assets.animation\("""${displayName}"""\)`;
18332
19411
  break;
19412
+ case "song" /* pxt.AssetType.Song */:
19413
+ assetPyRefs = `assets.song\("""${shortId}"""\)`;
19414
+ if (displayName)
19415
+ assetPyRefs += `|assets.song\("""${displayName}"""\)`;
19416
+ break;
18333
19417
  default:
18334
19418
  assetPyRefs = `assets.image\("""${shortId}"""\)`;
18335
19419
  if (displayName)
@@ -18355,65 +19439,29 @@ var pxt;
18355
19439
  return false;
18356
19440
  }
18357
19441
  lookupAsset(assetType, name) {
18358
- switch (assetType) {
18359
- case "image" /* AssetType.Image */:
18360
- return this.state.images.getByID(name) || this.gallery.images.getByID(name);
18361
- case "tile" /* AssetType.Tile */:
18362
- return this.state.tiles.getByID(name) || this.gallery.tiles.getByID(name);
18363
- case "tilemap" /* AssetType.Tilemap */:
18364
- return this.state.tilemaps.getByID(name) || this.gallery.tilemaps.getByID(name);
18365
- case "animation" /* AssetType.Animation */:
18366
- return this.state.animations.getByID(name) || this.gallery.animations.getByID(name);
18367
- }
19442
+ return getAssetCollection(this.state, assetType).getByID(name) ||
19443
+ getAssetCollection(this.gallery, assetType).getByID(name);
18368
19444
  }
18369
19445
  lookupAssetByName(assetType, name) {
18370
- switch (assetType) {
18371
- case "image" /* AssetType.Image */:
18372
- return this.state.images.getByDisplayName(name);
18373
- case "tile" /* AssetType.Tile */:
18374
- return this.state.tiles.getByDisplayName(name);
18375
- case "tilemap" /* AssetType.Tilemap */:
18376
- return this.state.tilemaps.getByDisplayName(name);
18377
- case "animation" /* AssetType.Animation */:
18378
- return this.state.animations.getByDisplayName(name);
18379
- }
19446
+ return getAssetCollection(this.state, assetType).getByDisplayName(name);
18380
19447
  }
18381
19448
  getAssets(type) {
18382
- switch (type) {
18383
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot();
18384
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot();
18385
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot();
18386
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot();
18387
- }
19449
+ return getAssetCollection(this.state, type).getSnapshot();
18388
19450
  }
18389
19451
  getGalleryAssets(type) {
18390
- switch (type) {
18391
- case "image" /* AssetType.Image */: return this.gallery.images.getSnapshot();
18392
- case "tile" /* AssetType.Tile */: return this.gallery.tiles.getSnapshot();
18393
- case "tilemap" /* AssetType.Tilemap */: return this.gallery.tilemaps.getSnapshot();
18394
- case "animation" /* AssetType.Animation */: return this.gallery.animations.getSnapshot();
18395
- }
19452
+ return getAssetCollection(this.gallery, type).getSnapshot();
18396
19453
  }
18397
19454
  lookupBlockAsset(type, blockID) {
18398
19455
  let filter = (a) => { var _a, _b; return ((_b = (_a = a.meta) === null || _a === void 0 ? void 0 : _a.blockIDs) === null || _b === void 0 ? void 0 : _b.indexOf(blockID)) !== -1; };
18399
- switch (type) {
18400
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot(filter)[0];
18401
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot(filter)[0];
18402
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot(filter)[0];
18403
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot(filter)[0];
18404
- }
19456
+ return getAssetCollection(this.state, type).getSnapshot(filter)[0];
18405
19457
  }
18406
19458
  updateAsset(asset) {
18407
19459
  this.onChange();
18408
19460
  switch (asset.type) {
18409
- case "image" /* AssetType.Image */:
18410
- return this.state.images.update(asset.id, asset);
18411
19461
  case "tile" /* AssetType.Tile */:
18412
19462
  return this.updateTile(asset);
18413
- case "tilemap" /* AssetType.Tilemap */:
18414
- return this.state.tilemaps.update(asset.id, asset);
18415
- case "animation" /* AssetType.Animation */:
18416
- return this.state.animations.update(asset.id, asset);
19463
+ default:
19464
+ return getAssetCollection(this.state, asset.type).update(asset.id, asset);
18417
19465
  }
18418
19466
  }
18419
19467
  duplicateAsset(asset, displayName) {
@@ -18435,53 +19483,22 @@ var pxt;
18435
19483
  break;
18436
19484
  case "animation" /* AssetType.Animation */:
18437
19485
  newAsset = this.createNewAnimationFromData(clone.frames, clone.interval, name);
19486
+ break;
19487
+ case "song" /* AssetType.Song */:
19488
+ newAsset = this.createNewSong(asset.song, name);
19489
+ break;
18438
19490
  }
18439
19491
  return newAsset;
18440
19492
  }
18441
19493
  removeAsset(asset) {
18442
19494
  this.onChange();
18443
- switch (asset.type) {
18444
- case "image" /* AssetType.Image */:
18445
- return this.state.images.removeByID(asset.id);
18446
- case "tile" /* AssetType.Tile */:
18447
- return this.state.tiles.removeByID(asset.id);
18448
- case "tilemap" /* AssetType.Tilemap */:
18449
- return this.state.tilemaps.removeByID(asset.id);
18450
- case "animation" /* AssetType.Animation */:
18451
- return this.state.animations.removeByID(asset.id);
18452
- }
19495
+ getAssetCollection(this.state, asset.type).removeByID(asset.id);
18453
19496
  }
18454
19497
  addChangeListener(asset, listener) {
18455
- switch (asset.type) {
18456
- case "image" /* AssetType.Image */:
18457
- this.state.images.addListener(asset.internalID, listener);
18458
- break;
18459
- case "tile" /* AssetType.Tile */:
18460
- this.state.tiles.addListener(asset.internalID, listener);
18461
- break;
18462
- case "tilemap" /* AssetType.Tilemap */:
18463
- this.state.tilemaps.addListener(asset.internalID, listener);
18464
- break;
18465
- case "animation" /* AssetType.Animation */:
18466
- this.state.animations.addListener(asset.internalID, listener);
18467
- break;
18468
- }
19498
+ getAssetCollection(this.state, asset.type).addListener(asset.internalID, listener);
18469
19499
  }
18470
19500
  removeChangeListener(type, listener) {
18471
- switch (type) {
18472
- case "image" /* AssetType.Image */:
18473
- this.state.images.removeListener(listener);
18474
- break;
18475
- case "tile" /* AssetType.Tile */:
18476
- this.state.tiles.removeListener(listener);
18477
- break;
18478
- case "tilemap" /* AssetType.Tilemap */:
18479
- this.state.tilemaps.removeListener(listener);
18480
- break;
18481
- case "animation" /* AssetType.Animation */:
18482
- this.state.animations.removeListener(listener);
18483
- break;
18484
- }
19501
+ getAssetCollection(this.state, type).removeListener(listener);
18485
19502
  }
18486
19503
  loadPackage(pack) {
18487
19504
  const allPackages = pack.sortedDeps();
@@ -18506,7 +19523,7 @@ var pxt;
18506
19523
  this.gallery.images.add(image);
18507
19524
  }
18508
19525
  }
18509
- else {
19526
+ else if (image.type === "animation" /* AssetType.Animation */) {
18510
19527
  if (isProject) {
18511
19528
  this.state.animations.add(image);
18512
19529
  }
@@ -18514,6 +19531,14 @@ var pxt;
18514
19531
  this.gallery.animations.add(image);
18515
19532
  }
18516
19533
  }
19534
+ else {
19535
+ if (isProject) {
19536
+ this.state.songs.add(image);
19537
+ }
19538
+ else {
19539
+ this.gallery.songs.add(image);
19540
+ }
19541
+ }
18517
19542
  }
18518
19543
  }
18519
19544
  for (const tm of getTilemaps(pack.parseJRes())) {
@@ -18590,6 +19615,9 @@ var pxt;
18590
19615
  this.state.animations.add(animation);
18591
19616
  }
18592
19617
  }
19618
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
19619
+ this.state.songs.add(this.generateSong(entry));
19620
+ }
18593
19621
  }
18594
19622
  for (const animation of toInflate) {
18595
19623
  this.state.animations.add(this.inflateAnimation(animation, this.state.images.getSnapshot()));
@@ -18600,6 +19628,7 @@ var pxt;
18600
19628
  cleanupCollection(this.state.tiles);
18601
19629
  cleanupCollection(this.state.tilemaps);
18602
19630
  cleanupCollection(this.state.animations);
19631
+ cleanupCollection(this.state.songs);
18603
19632
  function cleanupCollection(collection) {
18604
19633
  const inactiveAssets = collection.getSnapshot(asset => { var _a; return !asset.meta.displayName && ((_a = asset.meta.blockIDs) === null || _a === void 0 ? void 0 : _a.some(id => activeBlockIDs.indexOf(id) === -1)); });
18605
19634
  const toRemove = [];
@@ -18629,6 +19658,17 @@ var pxt;
18629
19658
  bitmap: pxt.sprite.getBitmapFromJResURL(`data:${pxt.IMAGE_MIME_TYPE};base64,${entry.data}`).data()
18630
19659
  };
18631
19660
  }
19661
+ generateSong(entry) {
19662
+ return {
19663
+ internalID: this.getNewInternalId(),
19664
+ type: "song" /* AssetType.Song */,
19665
+ id: entry.id,
19666
+ meta: {
19667
+ displayName: entry.displayName
19668
+ },
19669
+ song: pxt.assets.music.decodeSongFromHex(entry.data)
19670
+ };
19671
+ }
18632
19672
  generateAnimation(entry) {
18633
19673
  if (entry.dataEncoding === "json") {
18634
19674
  let data;
@@ -18682,6 +19722,8 @@ var pxt;
18682
19722
  return this.generateNewIDInternal("tile" /* AssetType.Tile */, pxt.sprite.TILE_PREFIX, pxt.sprite.TILE_NAMESPACE);
18683
19723
  case "tilemap" /* AssetType.Tilemap */:
18684
19724
  return this.generateNewIDInternal("tilemap" /* AssetType.Tilemap */, lf("level"));
19725
+ case "song" /* AssetType.Song */:
19726
+ return this.generateNewIDInternal("song" /* AssetType.Song */, pxt.sprite.SONG_PREFIX, pxt.sprite.SONG_NAMESPACE);
18685
19727
  }
18686
19728
  }
18687
19729
  generateNewIDInternal(type, varPrefix, namespaceString) {
@@ -18719,6 +19761,9 @@ var pxt;
18719
19761
  assets.push(animation);
18720
19762
  }
18721
19763
  }
19764
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
19765
+ assets.push(this.generateSong(entry));
19766
+ }
18722
19767
  }
18723
19768
  for (const animation of toInflate) {
18724
19769
  assets.push(this.inflateAnimation(animation, assets));
@@ -18779,6 +19824,7 @@ var pxt;
18779
19824
  let out = "";
18780
19825
  const imageEntries = [];
18781
19826
  const animationEntries = [];
19827
+ const songEntries = [];
18782
19828
  for (const key of entries) {
18783
19829
  if (key === "*")
18784
19830
  continue;
@@ -18805,10 +19851,17 @@ var pxt;
18805
19851
  expression: `[${animation.frames.map(f => pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(f), "typescript")).join(", ")}]`
18806
19852
  });
18807
19853
  }
19854
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
19855
+ songEntries.push({
19856
+ keys: [getShortIDCore("song" /* AssetType.Song */, key, true), entry.displayName],
19857
+ expression: `hex\`${entry.data}\``
19858
+ });
19859
+ }
18808
19860
  }
18809
19861
  const warning = lf("Auto-generated code. Do not edit.");
18810
19862
  out += emitFactoryHelper("image", imageEntries);
18811
19863
  out += emitFactoryHelper("animation", animationEntries);
19864
+ out += emitFactoryHelper("song", songEntries);
18812
19865
  return `// ${warning}\nnamespace ${pxt.sprite.IMAGES_NAMESPACE} {\n${out}\n}\n// ${warning}\n`;
18813
19866
  }
18814
19867
  pxt.emitProjectImages = emitProjectImages;
@@ -18852,6 +19905,8 @@ var pxt;
18852
19905
  return Object.assign(Object.assign({}, asset), { frames: asset.frames.map(frame => cloneBitmap(frame)) });
18853
19906
  case "tilemap" /* AssetType.Tilemap */:
18854
19907
  return Object.assign(Object.assign({}, asset), { data: asset.data.cloneData() });
19908
+ case "song" /* AssetType.Song */:
19909
+ return Object.assign(Object.assign({}, asset), { song: pxt.assets.music.cloneSong(asset.song) });
18855
19910
  }
18856
19911
  }
18857
19912
  pxt.cloneAsset = cloneAsset;
@@ -18885,6 +19940,13 @@ var pxt;
18885
19940
  case "animation" /* AssetType.Animation */:
18886
19941
  allJRes[id] = serializeAnimation(asset);
18887
19942
  break;
19943
+ case "song" /* AssetType.Song */:
19944
+ allJRes[id] = {
19945
+ data: pxt.assets.music.encodeSongToHex(asset.song),
19946
+ mimeType: pxt.SONG_MIME_TYPE,
19947
+ displayName: asset.meta.displayName
19948
+ };
19949
+ break;
18888
19950
  }
18889
19951
  }
18890
19952
  function assetEquals(a, b) {
@@ -18904,6 +19966,8 @@ var pxt;
18904
19966
  return a.interval === bAnimation.interval && pxt.U.arrayEquals(a.frames, bAnimation.frames, pxt.sprite.bitmapEquals);
18905
19967
  case "tilemap" /* AssetType.Tilemap */:
18906
19968
  return a.data.equals(b.data);
19969
+ case "song" /* AssetType.Song */:
19970
+ return pxt.assets.music.songEquals(a.song, b.song);
18907
19971
  }
18908
19972
  }
18909
19973
  pxt.assetEquals = assetEquals;
@@ -18943,11 +20007,13 @@ var pxt;
18943
20007
  return `assets.animation${leftTick}${shortId}${rightTick}`;
18944
20008
  case "tilemap" /* AssetType.Tilemap */:
18945
20009
  return `tilemap${leftTick}${shortId}${rightTick}`;
20010
+ case "song" /* AssetType.Song */:
20011
+ return `assets.song${leftTick}${shortId}${rightTick}`;
18946
20012
  }
18947
20013
  }
18948
20014
  pxt.getTSReferenceForAsset = getTSReferenceForAsset;
18949
20015
  function parseAssetTSReference(ts) {
18950
- const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap))|(tilemap))\s*(?:`|\(""")([^`"]+)(?:`|"""\))\s*$/m.exec(ts);
20016
+ const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap|song))|(tilemap))\s*(?:`|\(""")([^`"]+)(?:`|"""\))\s*$/m.exec(ts);
18951
20017
  if (match) {
18952
20018
  const type = match[1] || match[2];
18953
20019
  const name = match[3].trim();
@@ -18971,6 +20037,8 @@ var pxt;
18971
20037
  return project.lookupAssetByName("tilemap" /* AssetType.Tilemap */, name) || project.lookupAsset("tilemap" /* AssetType.Tilemap */, name);
18972
20038
  case "animation":
18973
20039
  return project.lookupAssetByName("animation" /* AssetType.Animation */, name);
20040
+ case "song":
20041
+ return project.lookupAssetByName("song" /* AssetType.Song */, name);
18974
20042
  }
18975
20043
  }
18976
20044
  return undefined;
@@ -18986,6 +20054,8 @@ var pxt;
18986
20054
  return lf("level");
18987
20055
  case "animation" /* pxt.AssetType.Animation */:
18988
20056
  return lf("myAnim");
20057
+ case "song" /* pxt.AssetType.Song */:
20058
+ return lf("mySong");
18989
20059
  default:
18990
20060
  return lf("asset");
18991
20061
  }
@@ -19010,6 +20080,9 @@ var pxt;
19010
20080
  case "animation" /* AssetType.Animation */:
19011
20081
  prefix = pxt.sprite.ANIMATION_NAMESPACE + ".";
19012
20082
  break;
20083
+ case "song" /* AssetType.Song */:
20084
+ prefix = pxt.sprite.SONG_NAMESPACE + ".";
20085
+ break;
19013
20086
  }
19014
20087
  if (prefix) {
19015
20088
  if (id.startsWith(prefix)) {
@@ -19094,6 +20167,15 @@ var pxt;
19094
20167
  function read16Bit(buf, offset) {
19095
20168
  return buf[offset] | (buf[offset + 1] << 8);
19096
20169
  }
20170
+ function getAssetCollection(snapshot, type) {
20171
+ switch (type) {
20172
+ case "animation" /* AssetType.Animation */: return snapshot.animations;
20173
+ case "image" /* AssetType.Image */: return snapshot.images;
20174
+ case "tile" /* AssetType.Tile */: return snapshot.tiles;
20175
+ case "tilemap" /* AssetType.Tilemap */: return snapshot.tilemaps;
20176
+ case "song" /* AssetType.Song */: return snapshot.songs;
20177
+ }
20178
+ }
19097
20179
  })(pxt || (pxt = {}));
19098
20180
  var pxt;
19099
20181
  (function (pxt) {
@@ -23038,7 +24120,7 @@ var pxt;
23038
24120
  return undefined;
23039
24121
  if (scriptid[0] == "_" && scriptid.length == 13)
23040
24122
  return scriptid;
23041
- if (scriptid.length == 23 && /^[0-9\-]+$/.test(scriptid))
24123
+ if (scriptid.length == 23 && /^[0-9\-]+$/.test(scriptid) || scriptid.length == 24 && /^S[0-9\-]+$/.test(scriptid))
23042
24124
  return scriptid;
23043
24125
  return undefined;
23044
24126
  }