pxt-core 8.4.2 → 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 (77) hide show
  1. package/built/backendutils.js +1 -0
  2. package/built/cli.js +83 -75
  3. package/built/pxt.js +1264 -176
  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/pxtlib.d.ts +91 -5
  8. package/built/pxtlib.js +1173 -98
  9. package/built/pxtsim.js +8 -3
  10. package/built/server.js +4 -0
  11. package/built/target.js +1 -1
  12. package/built/web/main.js +1 -1
  13. package/built/web/multiplayer/css/main.2dd69ed8.css +4 -0
  14. package/built/web/multiplayer/js/main.f3b8f930.js +2 -0
  15. package/built/web/pxtapp.js +1 -1
  16. package/built/web/pxtasseteditor.js +1 -1
  17. package/built/web/pxtblockly.js +1 -1
  18. package/built/web/pxtblocks.js +1 -1
  19. package/built/web/pxtembed.js +2 -2
  20. package/built/web/pxtlib.js +1 -1
  21. package/built/web/pxtsim.js +1 -1
  22. package/built/web/pxtworker.js +2 -2
  23. package/built/web/react-common-authcode.css +4 -6993
  24. package/built/web/react-common-multiplayer.css +13 -0
  25. package/built/web/react-common-skillmap.css +1 -1
  26. package/built/web/rtlreact-common-authcode.css +13 -0
  27. package/built/web/rtlreact-common-multiplayer.css +13 -0
  28. package/built/web/rtlreact-common-skillmap.css +1 -1
  29. package/built/web/rtlsemantic.css +1 -1
  30. package/built/web/semantic.css +1 -1
  31. package/built/web/skillmap/js/main.a6cf40e1.chunk.js +1 -0
  32. package/common-docs/identity/sign-in.md +17 -3
  33. package/common-docs/static/music-editor/apple.png +0 -0
  34. package/common-docs/static/music-editor/burger.png +0 -0
  35. package/common-docs/static/music-editor/cake.png +0 -0
  36. package/common-docs/static/music-editor/car.png +0 -0
  37. package/common-docs/static/music-editor/cat.png +0 -0
  38. package/common-docs/static/music-editor/cherry.png +0 -0
  39. package/common-docs/static/music-editor/clam.png +0 -0
  40. package/common-docs/static/music-editor/computer.png +0 -0
  41. package/common-docs/static/music-editor/crab.png +0 -0
  42. package/common-docs/static/music-editor/dog.png +0 -0
  43. package/common-docs/static/music-editor/duck.png +0 -0
  44. package/common-docs/static/music-editor/egg.png +0 -0
  45. package/common-docs/static/music-editor/explosion.png +0 -0
  46. package/common-docs/static/music-editor/fish.png +0 -0
  47. package/common-docs/static/music-editor/ice-cream.png +0 -0
  48. package/common-docs/static/music-editor/lemon.png +0 -0
  49. package/common-docs/static/music-editor/metronomeWorker.js +35 -0
  50. package/common-docs/static/music-editor/snake.png +0 -0
  51. package/common-docs/static/music-editor/star.png +0 -0
  52. package/common-docs/static/music-editor/strawberry.png +0 -0
  53. package/common-docs/static/music-editor/taco.png +0 -0
  54. package/common-docs/static/music-editor/treble-clef.svg +1 -0
  55. package/package.json +4 -2
  56. package/react-common/components/controls/Input.tsx +7 -3
  57. package/react-common/styles/controls/Button.less +9 -0
  58. package/react-common/styles/react-common-authcode-core.less +1 -1
  59. package/react-common/styles/react-common-authcode.less +1 -1
  60. package/react-common/styles/react-common-multiplayer-core.less +10 -0
  61. package/react-common/styles/react-common-multiplayer.less +12 -0
  62. package/theme/highcontrast.less +6 -0
  63. package/theme/music-editor/EditControls.less +22 -0
  64. package/theme/music-editor/MusicEditor.less +25 -0
  65. package/theme/music-editor/Note.less +16 -0
  66. package/theme/music-editor/NoteGroup.less +7 -0
  67. package/theme/music-editor/PlaybackControls.less +55 -0
  68. package/theme/music-editor/ScrollableWorkspace.less +3 -0
  69. package/theme/music-editor/Staff.less +31 -0
  70. package/theme/music-editor/Track.less +0 -0
  71. package/theme/music-editor/TrackSelector.less +48 -0
  72. package/theme/music-editor/Workspace.less +3 -0
  73. package/theme/pxt.less +1 -0
  74. package/theme/tutorial-sidebar.less +3 -0
  75. package/webapp/public/multiplayer.html +1 -0
  76. package/webapp/public/skillmap.html +1 -1
  77. package/built/web/skillmap/js/main.6eec9e0f.chunk.js +0 -1
package/built/pxt.js CHANGED
@@ -97902,6 +97902,9 @@ var pxt;
97902
97902
  this.setUserProfileAsync(this.state$.profile);
97903
97903
  this.setUserPreferencesAsync(this.state$.preferences);
97904
97904
  }
97905
+ async authTokenAsync() {
97906
+ return await pxt.storage.shared.getAsync(AUTH_CONTAINER, CSRF_TOKEN_KEY);
97907
+ }
97905
97908
  /**
97906
97909
  * Starts the process of authenticating the user against the given identity
97907
97910
  * provider. Upon success the backend will write an http-only session cookie
@@ -98386,6 +98389,11 @@ var pxt;
98386
98389
  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;
98387
98390
  }
98388
98391
  auth.userName = userName;
98392
+ function firstName(user) {
98393
+ const userName = pxt.auth.userName(user);
98394
+ return (userName === null || userName === void 0 ? void 0 : userName.split(" ").shift()) || userName;
98395
+ }
98396
+ auth.firstName = firstName;
98389
98397
  function userInitials(user) {
98390
98398
  const username = pxt.auth.userName(user);
98391
98399
  return ts.pxtc.Util.initials(username);
@@ -106428,6 +106436,7 @@ var pxt;
106428
106436
  const url = new URL(`https://${endpointName}.streaming.media.azure.net/${videoID}/manifest(format=mpd-time-csf).mpd`);
106429
106437
  if (startTime) {
106430
106438
  url.hash = `t=${startTime}`;
106439
+ url.searchParams.append("startTime", startTime);
106431
106440
  }
106432
106441
  if (endTime) {
106433
106442
  url.searchParams.append("endTime", endTime);
@@ -110319,6 +110328,8 @@ var pxt;
110319
110328
  sprite_1.IMAGE_PREFIX = "image";
110320
110329
  sprite_1.ANIMATION_NAMESPACE = "myAnimations";
110321
110330
  sprite_1.ANIMATION_PREFIX = "anim";
110331
+ sprite_1.SONG_NAMESPACE = "mySongs";
110332
+ sprite_1.SONG_PREFIX = "song";
110322
110333
  /**
110323
110334
  * 16-color sprite
110324
110335
  */
@@ -111374,6 +111385,1044 @@ var pxt;
111374
111385
  })(shared = storage.shared || (storage.shared = {}));
111375
111386
  })(storage = pxt.storage || (pxt.storage = {}));
111376
111387
  })(pxt || (pxt = {}));
111388
+ var pxt;
111389
+ (function (pxt) {
111390
+ var assets;
111391
+ (function (assets) {
111392
+ var music;
111393
+ (function (music) {
111394
+ const BUFFER_SIZE = 12;
111395
+ function renderInstrument(instrument, noteFrequency, gateLength, volume) {
111396
+ var _a, _b, _c, _d, _e;
111397
+ const totalDuration = gateLength + instrument.ampEnvelope.release;
111398
+ const ampLFOInterval = ((_a = instrument.ampLFO) === null || _a === void 0 ? void 0 : _a.amplitude) ? Math.max(500 / instrument.ampLFO.frequency, 50) : 50;
111399
+ const pitchLFOInterval = ((_b = instrument.pitchLFO) === null || _b === void 0 ? void 0 : _b.amplitude) ? Math.max(500 / instrument.pitchLFO.frequency, 50) : 50;
111400
+ let timePoints = [0];
111401
+ let nextAETime = instrument.ampEnvelope.attack;
111402
+ let nextPETime = ((_c = instrument.pitchEnvelope) === null || _c === void 0 ? void 0 : _c.amplitude) ? instrument.pitchEnvelope.attack : totalDuration;
111403
+ let nextPLTime = ((_d = instrument.pitchLFO) === null || _d === void 0 ? void 0 : _d.amplitude) ? pitchLFOInterval : totalDuration;
111404
+ let nextALTime = ((_e = instrument.ampLFO) === null || _e === void 0 ? void 0 : _e.amplitude) ? ampLFOInterval : totalDuration;
111405
+ let time = 0;
111406
+ while (time < totalDuration) {
111407
+ if (nextAETime <= nextPETime && nextAETime <= nextPLTime && nextAETime <= nextALTime) {
111408
+ time = nextAETime;
111409
+ timePoints.push(nextAETime);
111410
+ if (time < instrument.ampEnvelope.attack + instrument.ampEnvelope.decay && instrument.ampEnvelope.attack + instrument.ampEnvelope.decay < gateLength) {
111411
+ nextAETime = instrument.ampEnvelope.attack + instrument.ampEnvelope.decay;
111412
+ }
111413
+ else if (time < gateLength) {
111414
+ nextAETime = gateLength;
111415
+ }
111416
+ else {
111417
+ nextAETime = totalDuration;
111418
+ }
111419
+ }
111420
+ else if (nextPETime <= nextPLTime && nextPETime <= nextALTime && nextPETime < totalDuration) {
111421
+ time = nextPETime;
111422
+ timePoints.push(nextPETime);
111423
+ if (time < instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay && instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay < gateLength) {
111424
+ nextPETime = instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay;
111425
+ }
111426
+ else if (time < gateLength) {
111427
+ nextPETime = gateLength;
111428
+ }
111429
+ else if (time < gateLength + instrument.pitchEnvelope.release) {
111430
+ nextPETime = Math.min(totalDuration, gateLength + instrument.pitchEnvelope.release);
111431
+ }
111432
+ else {
111433
+ nextPETime = totalDuration;
111434
+ }
111435
+ }
111436
+ else if (nextPLTime <= nextALTime && nextPLTime < totalDuration) {
111437
+ time = nextPLTime;
111438
+ timePoints.push(nextPLTime);
111439
+ nextPLTime += pitchLFOInterval;
111440
+ }
111441
+ else if (nextALTime < totalDuration) {
111442
+ time = nextALTime;
111443
+ timePoints.push(nextALTime);
111444
+ nextALTime += ampLFOInterval;
111445
+ }
111446
+ if (time >= totalDuration) {
111447
+ break;
111448
+ }
111449
+ if (nextAETime <= time) {
111450
+ if (time < instrument.ampEnvelope.attack + instrument.ampEnvelope.decay && instrument.ampEnvelope.attack + instrument.ampEnvelope.decay < gateLength) {
111451
+ nextAETime = instrument.ampEnvelope.attack + instrument.ampEnvelope.decay;
111452
+ }
111453
+ else if (time < gateLength) {
111454
+ nextAETime = gateLength;
111455
+ }
111456
+ else {
111457
+ nextAETime = totalDuration;
111458
+ }
111459
+ }
111460
+ if (nextPETime <= time) {
111461
+ if (time < instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay && instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay < gateLength) {
111462
+ nextPETime = instrument.pitchEnvelope.attack + instrument.pitchEnvelope.decay;
111463
+ }
111464
+ else if (time < gateLength) {
111465
+ nextPETime = gateLength;
111466
+ }
111467
+ else if (time < gateLength + instrument.pitchEnvelope.release) {
111468
+ nextPETime = Math.min(totalDuration, gateLength + instrument.pitchEnvelope.release);
111469
+ }
111470
+ else {
111471
+ nextPETime = totalDuration;
111472
+ }
111473
+ }
111474
+ while (nextALTime <= time) {
111475
+ nextALTime += ampLFOInterval;
111476
+ }
111477
+ while (nextPLTime <= time) {
111478
+ nextPLTime += pitchLFOInterval;
111479
+ }
111480
+ }
111481
+ let prevAmp = instrumentVolumeAtTime(instrument, gateLength, 0, volume) | 0;
111482
+ let prevPitch = instrumentPitchAtTime(instrument, noteFrequency, gateLength, 0) | 0;
111483
+ let prevTime = 0;
111484
+ let nextAmp;
111485
+ let nextPitch;
111486
+ const out = new Uint8Array(BUFFER_SIZE * (timePoints.length + 1));
111487
+ for (let i = 1; i < timePoints.length; i++) {
111488
+ if (timePoints[i] - prevTime < 5) {
111489
+ prevTime = timePoints[i];
111490
+ continue;
111491
+ }
111492
+ nextAmp = instrumentVolumeAtTime(instrument, gateLength, timePoints[i], volume) | 0;
111493
+ nextPitch = instrumentPitchAtTime(instrument, noteFrequency, gateLength, timePoints[i]) | 0;
111494
+ addNote(out, (i - 1) * 12, (timePoints[i] - prevTime) | 0, prevAmp, nextAmp, instrument.waveform, prevPitch, nextPitch);
111495
+ prevAmp = nextAmp;
111496
+ prevPitch = nextPitch;
111497
+ prevTime = timePoints[i];
111498
+ }
111499
+ addNote(out, timePoints.length * 12, 10, prevAmp, 0, instrument.waveform, prevPitch, prevPitch);
111500
+ return out;
111501
+ }
111502
+ music.renderInstrument = renderInstrument;
111503
+ function renderDrumInstrument(sound, volume) {
111504
+ let prevAmp = sound.startVolume;
111505
+ let prevFreq = sound.startFrequency;
111506
+ const scaleVolume = (value) => (value / 1024) * volume;
111507
+ let out = new Uint8Array((sound.steps.length + 1) * BUFFER_SIZE);
111508
+ for (let i = 0; i < sound.steps.length; i++) {
111509
+ 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);
111510
+ prevAmp = sound.steps[i].volume;
111511
+ prevFreq = sound.steps[i].frequency;
111512
+ }
111513
+ addNote(out, sound.steps.length * BUFFER_SIZE, 10, scaleVolume(prevAmp), 0, sound.steps[sound.steps.length - 1].waveform, prevFreq, prevFreq);
111514
+ return out;
111515
+ }
111516
+ music.renderDrumInstrument = renderDrumInstrument;
111517
+ function instrumentPitchAtTime(instrument, noteFrequency, gateLength, time) {
111518
+ var _a, _b;
111519
+ let mod = 0;
111520
+ if ((_a = instrument.pitchEnvelope) === null || _a === void 0 ? void 0 : _a.amplitude) {
111521
+ mod += envelopeValueAtTime(instrument.pitchEnvelope, time, gateLength);
111522
+ }
111523
+ if ((_b = instrument.pitchLFO) === null || _b === void 0 ? void 0 : _b.amplitude) {
111524
+ mod += lfoValueAtTime(instrument.pitchLFO, time);
111525
+ }
111526
+ return Math.max(noteFrequency + mod, 0);
111527
+ }
111528
+ function instrumentVolumeAtTime(instrument, gateLength, time, maxVolume) {
111529
+ var _a;
111530
+ let mod = 0;
111531
+ if (instrument.ampEnvelope.amplitude) {
111532
+ mod += envelopeValueAtTime(instrument.ampEnvelope, time, gateLength);
111533
+ }
111534
+ if ((_a = instrument.ampLFO) === null || _a === void 0 ? void 0 : _a.amplitude) {
111535
+ mod += lfoValueAtTime(instrument.ampLFO, time);
111536
+ }
111537
+ return ((Math.max(Math.min(mod, instrument.ampEnvelope.amplitude), 0) / 1024) * maxVolume) | 0;
111538
+ }
111539
+ function envelopeValueAtTime(envelope, time, gateLength) {
111540
+ const adjustedSustain = (envelope.sustain / 1024) * envelope.amplitude;
111541
+ if (time > gateLength) {
111542
+ if (time - gateLength > envelope.release)
111543
+ return 0;
111544
+ else if (time < envelope.attack) {
111545
+ const height = (envelope.amplitude / envelope.attack) * gateLength;
111546
+ return height - ((height / envelope.release) * (time - gateLength));
111547
+ }
111548
+ else if (time < envelope.attack + envelope.decay) {
111549
+ const height2 = envelope.amplitude - ((envelope.amplitude - adjustedSustain) / envelope.decay) * (gateLength - envelope.attack);
111550
+ return height2 - ((height2 / envelope.release) * (time - gateLength));
111551
+ }
111552
+ else {
111553
+ return adjustedSustain - (adjustedSustain / envelope.release) * (time - gateLength);
111554
+ }
111555
+ }
111556
+ else if (time < envelope.attack) {
111557
+ return (envelope.amplitude / envelope.attack) * time;
111558
+ }
111559
+ else if (time < envelope.attack + envelope.decay) {
111560
+ return envelope.amplitude - ((envelope.amplitude - adjustedSustain) / envelope.decay) * (time - envelope.attack);
111561
+ }
111562
+ else {
111563
+ return adjustedSustain;
111564
+ }
111565
+ }
111566
+ function lfoValueAtTime(lfo, time) {
111567
+ return Math.cos(((time / 1000) * lfo.frequency) * 2 * Math.PI) * lfo.amplitude;
111568
+ }
111569
+ function set16BitNumber(buf, offset, value) {
111570
+ const temp = new Uint8Array(2);
111571
+ new Uint16Array(temp.buffer)[0] = value | 0;
111572
+ buf[offset] = temp[0];
111573
+ buf[offset + 1] = temp[1];
111574
+ }
111575
+ function get16BitNumber(buf, offset) {
111576
+ const temp = new Uint8Array(2);
111577
+ temp[0] = buf[offset];
111578
+ temp[1] = buf[offset + 1];
111579
+ return new Uint16Array(temp.buffer)[0];
111580
+ }
111581
+ function addNote(sndInstr, sndInstrPtr, ms, beg, end, soundWave, hz, endHz) {
111582
+ if (ms > 0) {
111583
+ sndInstr[sndInstrPtr] = soundWave;
111584
+ sndInstr[sndInstrPtr + 1] = 0;
111585
+ set16BitNumber(sndInstr, sndInstrPtr + 2, hz);
111586
+ set16BitNumber(sndInstr, sndInstrPtr + 4, ms);
111587
+ set16BitNumber(sndInstr, sndInstrPtr + 6, (beg * 255) >> 6);
111588
+ set16BitNumber(sndInstr, sndInstrPtr + 8, (end * 255) >> 6);
111589
+ set16BitNumber(sndInstr, sndInstrPtr + 10, endHz);
111590
+ sndInstrPtr += BUFFER_SIZE;
111591
+ }
111592
+ sndInstr[sndInstrPtr] = 0;
111593
+ return sndInstrPtr;
111594
+ }
111595
+ function encodeSongToHex(song) {
111596
+ const encoded = encodeSong(song);
111597
+ return pxt.U.toHex(encoded);
111598
+ }
111599
+ music.encodeSongToHex = encodeSongToHex;
111600
+ function decodeSongFromHex(hex) {
111601
+ const bytes = pxt.U.fromHex(hex);
111602
+ return decodeSong(bytes);
111603
+ }
111604
+ music.decodeSongFromHex = decodeSongFromHex;
111605
+ /**
111606
+ * Byte encoding format for songs
111607
+ * FIXME: should this all be word aligned?
111608
+ *
111609
+ * song(7 + length of all tracks bytes)
111610
+ * 0 version
111611
+ * 1 beats per minute
111612
+ * 3 beats per measure
111613
+ * 4 ticks per beat
111614
+ * 5 measures
111615
+ * 6 number of tracks
111616
+ * ...tracks
111617
+ *
111618
+ * track(6 + instrument length + note length bytes)
111619
+ * 0 id
111620
+ * 1 flags
111621
+ * 2 instruments byte length
111622
+ * 4...instrument
111623
+ * notes byte length
111624
+ * ...note events
111625
+ *
111626
+ * instrument(27 bytes)
111627
+ * 0 waveform
111628
+ * 1 amp attack
111629
+ * 3 amp decay
111630
+ * 5 amp sustain
111631
+ * 7 amp release
111632
+ * 9 amp amp
111633
+ * 11 pitch attack
111634
+ * 13 pitch decay
111635
+ * 15 pitch sustain
111636
+ * 17 pitch release
111637
+ * 19 pitch amp
111638
+ * 21 amp lfo freq
111639
+ * 22 amp lfo amp
111640
+ * 24 pitch lfo freq
111641
+ * 25 pitch lfo amp
111642
+ *
111643
+ * drum(5 + 7 * steps bytes)
111644
+ * 0 steps
111645
+ * 1 start freq
111646
+ * 3 start amp
111647
+ * 5...steps
111648
+ *
111649
+ * drum step(7 bytes)
111650
+ * 0 waveform
111651
+ * 1 freq
111652
+ * 3 volume
111653
+ * 5 duration
111654
+ *
111655
+ * note event(5 + 1 * polyphony bytes)
111656
+ * 0 start tick
111657
+ * 2 end tick
111658
+ * 4 polyphony
111659
+ * 5...notes(1 byte each)
111660
+ *
111661
+ */
111662
+ function encodeSong(song) {
111663
+ const encodedTracks = song.tracks
111664
+ .filter((track) => track.notes.length > 0)
111665
+ .map(encodeTrack);
111666
+ const trackLength = encodedTracks.reduce((d, c) => c.length + d, 0);
111667
+ const out = new Uint8Array(7 + trackLength);
111668
+ out[0] = 0; // encoding version
111669
+ set16BitNumber(out, 1, song.beatsPerMinute);
111670
+ out[3] = song.beatsPerMeasure;
111671
+ out[4] = song.ticksPerBeat;
111672
+ out[5] = song.measures;
111673
+ out[6] = encodedTracks.length;
111674
+ let current = 7;
111675
+ for (const track of encodedTracks) {
111676
+ out.set(track, current);
111677
+ current += track.length;
111678
+ }
111679
+ return out;
111680
+ }
111681
+ function decodeSong(buf) {
111682
+ const res = {
111683
+ beatsPerMinute: get16BitNumber(buf, 1),
111684
+ beatsPerMeasure: buf[3],
111685
+ ticksPerBeat: buf[4],
111686
+ measures: buf[5],
111687
+ tracks: []
111688
+ };
111689
+ let current = 7;
111690
+ while (current < buf.length) {
111691
+ const [track, pointer] = decodeTrack(buf, current);
111692
+ current = pointer;
111693
+ res.tracks.push(track);
111694
+ }
111695
+ return res;
111696
+ }
111697
+ function encodeInstrument(instrument) {
111698
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
111699
+ const out = new Uint8Array(28);
111700
+ out[0] = instrument.waveform;
111701
+ set16BitNumber(out, 1, instrument.ampEnvelope.attack);
111702
+ set16BitNumber(out, 3, instrument.ampEnvelope.decay);
111703
+ set16BitNumber(out, 5, instrument.ampEnvelope.sustain);
111704
+ set16BitNumber(out, 7, instrument.ampEnvelope.release);
111705
+ set16BitNumber(out, 9, instrument.ampEnvelope.amplitude);
111706
+ set16BitNumber(out, 11, ((_a = instrument.pitchEnvelope) === null || _a === void 0 ? void 0 : _a.attack) || 0);
111707
+ set16BitNumber(out, 13, ((_b = instrument.pitchEnvelope) === null || _b === void 0 ? void 0 : _b.decay) || 0);
111708
+ set16BitNumber(out, 15, ((_c = instrument.pitchEnvelope) === null || _c === void 0 ? void 0 : _c.sustain) || 0);
111709
+ set16BitNumber(out, 17, ((_d = instrument.pitchEnvelope) === null || _d === void 0 ? void 0 : _d.release) || 0);
111710
+ set16BitNumber(out, 19, ((_e = instrument.pitchEnvelope) === null || _e === void 0 ? void 0 : _e.amplitude) || 0);
111711
+ out[21] = ((_f = instrument.ampLFO) === null || _f === void 0 ? void 0 : _f.frequency) || 0;
111712
+ set16BitNumber(out, 22, ((_g = instrument.ampLFO) === null || _g === void 0 ? void 0 : _g.amplitude) || 0);
111713
+ out[24] = ((_h = instrument.pitchLFO) === null || _h === void 0 ? void 0 : _h.frequency) || 0;
111714
+ set16BitNumber(out, 25, ((_j = instrument.pitchLFO) === null || _j === void 0 ? void 0 : _j.amplitude) || 0);
111715
+ return out;
111716
+ }
111717
+ function decodeInstrument(buf, offset) {
111718
+ return {
111719
+ waveform: buf[offset],
111720
+ ampEnvelope: {
111721
+ attack: get16BitNumber(buf, offset + 1),
111722
+ decay: get16BitNumber(buf, offset + 3),
111723
+ sustain: get16BitNumber(buf, offset + 5),
111724
+ release: get16BitNumber(buf, offset + 7),
111725
+ amplitude: get16BitNumber(buf, offset + 9),
111726
+ },
111727
+ pitchEnvelope: {
111728
+ attack: get16BitNumber(buf, offset + 11),
111729
+ decay: get16BitNumber(buf, offset + 13),
111730
+ sustain: get16BitNumber(buf, offset + 15),
111731
+ release: get16BitNumber(buf, offset + 17),
111732
+ amplitude: get16BitNumber(buf, offset + 19),
111733
+ },
111734
+ ampLFO: {
111735
+ frequency: buf[offset + 21],
111736
+ amplitude: get16BitNumber(buf, 22)
111737
+ },
111738
+ pitchLFO: {
111739
+ frequency: buf[offset + 24],
111740
+ amplitude: get16BitNumber(buf, 25)
111741
+ }
111742
+ };
111743
+ }
111744
+ function decodeTrack(buf, offset) {
111745
+ if (buf[offset + 1]) {
111746
+ return decodeDrumTrack(buf, offset);
111747
+ }
111748
+ return decodeMelodicTrack(buf, offset);
111749
+ }
111750
+ function encodeDrumInstrument(drum) {
111751
+ const out = new Uint8Array(5 + 7 * drum.steps.length);
111752
+ out[0] = drum.steps.length;
111753
+ set16BitNumber(out, 1, drum.startFrequency);
111754
+ set16BitNumber(out, 3, drum.startVolume);
111755
+ for (let i = 0; i < drum.steps.length; i++) {
111756
+ const start = 5 + i * 7;
111757
+ out[start] = drum.steps[i].waveform;
111758
+ set16BitNumber(out, start + 1, drum.steps[i].frequency);
111759
+ set16BitNumber(out, start + 3, drum.steps[i].volume);
111760
+ set16BitNumber(out, start + 5, drum.steps[i].duration);
111761
+ }
111762
+ return out;
111763
+ }
111764
+ function decodeDrumInstrument(buf, offset) {
111765
+ const res = {
111766
+ startFrequency: get16BitNumber(buf, offset + 1),
111767
+ startVolume: get16BitNumber(buf, offset + 3),
111768
+ steps: []
111769
+ };
111770
+ for (let i = 0; i < buf[offset]; i++) {
111771
+ const start = offset + 5 + i * 7;
111772
+ res.steps.push({
111773
+ waveform: buf[start],
111774
+ frequency: get16BitNumber(buf, start + 1),
111775
+ volume: get16BitNumber(buf, start + 3),
111776
+ duration: get16BitNumber(buf, start + 5)
111777
+ });
111778
+ }
111779
+ return res;
111780
+ }
111781
+ function encodeNoteEvent(event) {
111782
+ const out = new Uint8Array(5 + event.notes.length);
111783
+ set16BitNumber(out, 0, event.startTick);
111784
+ set16BitNumber(out, 2, event.endTick);
111785
+ out[4] = event.notes.length;
111786
+ for (let i = 0; i < event.notes.length; i++) {
111787
+ out[5 + i] = event.notes[i];
111788
+ }
111789
+ return out;
111790
+ }
111791
+ function decodeNoteEvent(buf, offset) {
111792
+ const res = {
111793
+ startTick: get16BitNumber(buf, offset),
111794
+ endTick: get16BitNumber(buf, offset + 2),
111795
+ notes: []
111796
+ };
111797
+ for (let i = 0; i < buf[offset + 4]; i++) {
111798
+ res.notes.push(buf[offset + 5 + i]);
111799
+ }
111800
+ return res;
111801
+ }
111802
+ function encodeTrack(track) {
111803
+ if (track.drums)
111804
+ return encodeDrumTrack(track);
111805
+ return encodeMelodicTrack(track);
111806
+ }
111807
+ function encodeMelodicTrack(track) {
111808
+ const encodedInstrument = encodeInstrument(track.instrument);
111809
+ const encodedNotes = track.notes.map(encodeNoteEvent);
111810
+ const noteLength = encodedNotes.reduce((d, c) => c.length + d, 0);
111811
+ const out = new Uint8Array(6 + encodedInstrument.length + noteLength);
111812
+ out[0] = track.id;
111813
+ out[1] = 0;
111814
+ set16BitNumber(out, 2, encodedInstrument.length);
111815
+ let current = 4;
111816
+ out.set(encodedInstrument, current);
111817
+ current += encodedInstrument.length;
111818
+ set16BitNumber(out, current, noteLength);
111819
+ current += 2;
111820
+ for (const note of encodedNotes) {
111821
+ out.set(note, current);
111822
+ current += note.length;
111823
+ }
111824
+ return out;
111825
+ }
111826
+ function decodeMelodicTrack(buf, offset) {
111827
+ const res = {
111828
+ id: buf[offset],
111829
+ instrument: decodeInstrument(buf, offset + 4),
111830
+ notes: []
111831
+ };
111832
+ const noteStart = offset + 4 + get16BitNumber(buf, offset + 2);
111833
+ const noteLength = get16BitNumber(buf, noteStart);
111834
+ let currentOffset = noteStart + 2;
111835
+ while (currentOffset < noteStart + 2 + noteLength) {
111836
+ res.notes.push(decodeNoteEvent(buf, currentOffset));
111837
+ currentOffset += 5 + res.notes[res.notes.length - 1].notes.length;
111838
+ }
111839
+ return [res, currentOffset];
111840
+ }
111841
+ function encodeDrumTrack(track) {
111842
+ const encodedDrums = track.drums.map(encodeDrumInstrument);
111843
+ const drumLength = encodedDrums.reduce((d, c) => c.length + d, 0);
111844
+ const encodedNotes = track.notes.map(encodeNoteEvent);
111845
+ const noteLength = encodedNotes.reduce((d, c) => c.length + d, 0);
111846
+ const out = new Uint8Array(6 + drumLength + noteLength);
111847
+ out[0] = track.id;
111848
+ out[1] = 1;
111849
+ set16BitNumber(out, 2, drumLength);
111850
+ let current = 4;
111851
+ for (const drum of encodedDrums) {
111852
+ out.set(drum, current);
111853
+ current += drum.length;
111854
+ }
111855
+ set16BitNumber(out, current, noteLength);
111856
+ current += 2;
111857
+ for (const note of encodedNotes) {
111858
+ out.set(note, current);
111859
+ current += note.length;
111860
+ }
111861
+ return out;
111862
+ }
111863
+ function decodeDrumTrack(buf, offset) {
111864
+ const res = {
111865
+ id: buf[offset],
111866
+ instrument: { ampEnvelope: { attack: 0, decay: 0, sustain: 0, release: 0, amplitude: 0 }, waveform: 0 },
111867
+ notes: [],
111868
+ drums: []
111869
+ };
111870
+ const drumByteLength = get16BitNumber(buf, offset + 2);
111871
+ let currentOffset = offset + 4;
111872
+ while (currentOffset < offset + 4 + drumByteLength) {
111873
+ res.drums.push(decodeDrumInstrument(buf, currentOffset));
111874
+ currentOffset += 5 + 7 * res.drums[res.drums.length - 1].steps.length;
111875
+ }
111876
+ const noteLength = get16BitNumber(buf, currentOffset);
111877
+ currentOffset += 2;
111878
+ while (currentOffset < offset + 4 + drumByteLength + noteLength) {
111879
+ res.notes.push(decodeNoteEvent(buf, currentOffset));
111880
+ currentOffset += 5 + res.notes[res.notes.length - 1].notes.length;
111881
+ }
111882
+ return [res, currentOffset];
111883
+ }
111884
+ function cloneSong(song) {
111885
+ 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() }))) }))) });
111886
+ }
111887
+ music.cloneSong = cloneSong;
111888
+ function songEquals(a, b) {
111889
+ return naiveEqualCheck(a, b);
111890
+ }
111891
+ music.songEquals = songEquals;
111892
+ function naiveEqualCheck(a, b) {
111893
+ if (typeof a !== typeof b)
111894
+ return false;
111895
+ else if (typeof a !== "object")
111896
+ return a === b;
111897
+ else if (Array.isArray(a)) {
111898
+ if (a.length !== b.length)
111899
+ return false;
111900
+ for (let i = 0; i < a.length; i++) {
111901
+ if (!naiveEqualCheck(a[i], b[i]))
111902
+ return false;
111903
+ }
111904
+ return true;
111905
+ }
111906
+ const aKeys = Object.keys(a);
111907
+ const bKeys = Object.keys(b);
111908
+ if (aKeys.length !== bKeys.length)
111909
+ return false;
111910
+ for (const key of aKeys) {
111911
+ if (bKeys.indexOf(key) === -1)
111912
+ return false;
111913
+ if (!naiveEqualCheck(a[key], b[key]))
111914
+ return false;
111915
+ }
111916
+ return true;
111917
+ }
111918
+ function inflateSong(song) {
111919
+ const base = getEmptySong(1);
111920
+ song.tracks = base.tracks.map((track, index) => {
111921
+ const existing = song.tracks.find(t => t.id === index);
111922
+ if (existing)
111923
+ track.notes = existing.notes;
111924
+ return track;
111925
+ });
111926
+ }
111927
+ music.inflateSong = inflateSong;
111928
+ function getEmptySong(measures) {
111929
+ return {
111930
+ ticksPerBeat: 8,
111931
+ beatsPerMeasure: 4,
111932
+ beatsPerMinute: 120,
111933
+ measures,
111934
+ tracks: [
111935
+ {
111936
+ id: 0,
111937
+ name: lf("Duck"),
111938
+ notes: [],
111939
+ iconURI: "/static/music-editor/duck.png",
111940
+ instrument: {
111941
+ waveform: 15,
111942
+ octave: 4,
111943
+ ampEnvelope: {
111944
+ attack: 5,
111945
+ decay: 530,
111946
+ sustain: 705,
111947
+ release: 450,
111948
+ amplitude: 1024
111949
+ },
111950
+ pitchEnvelope: {
111951
+ attack: 5,
111952
+ decay: 40,
111953
+ sustain: 0,
111954
+ release: 100,
111955
+ amplitude: 40
111956
+ },
111957
+ ampLFO: {
111958
+ frequency: 3,
111959
+ amplitude: 20
111960
+ },
111961
+ pitchLFO: {
111962
+ frequency: 6,
111963
+ amplitude: 2
111964
+ }
111965
+ }
111966
+ },
111967
+ {
111968
+ id: 1,
111969
+ name: lf("Cat"),
111970
+ notes: [],
111971
+ iconURI: "/static/music-editor/cat.png",
111972
+ instrument: {
111973
+ waveform: 12,
111974
+ octave: 5,
111975
+ ampEnvelope: {
111976
+ attack: 150,
111977
+ decay: 100,
111978
+ sustain: 365,
111979
+ release: 400,
111980
+ amplitude: 1024
111981
+ },
111982
+ pitchEnvelope: {
111983
+ attack: 120,
111984
+ decay: 300,
111985
+ sustain: 0,
111986
+ release: 100,
111987
+ amplitude: 50
111988
+ },
111989
+ pitchLFO: {
111990
+ frequency: 10,
111991
+ amplitude: 6
111992
+ }
111993
+ }
111994
+ },
111995
+ {
111996
+ id: 2,
111997
+ name: lf("Dog"),
111998
+ notes: [],
111999
+ iconURI: "/static/music-editor/dog.png",
112000
+ instrument: {
112001
+ waveform: 1,
112002
+ octave: 4,
112003
+ ampEnvelope: {
112004
+ attack: 10,
112005
+ decay: 100,
112006
+ sustain: 500,
112007
+ release: 100,
112008
+ amplitude: 1024
112009
+ },
112010
+ pitchLFO: {
112011
+ frequency: 5,
112012
+ amplitude: 0
112013
+ }
112014
+ }
112015
+ },
112016
+ {
112017
+ id: 3,
112018
+ name: lf("Fish"),
112019
+ notes: [],
112020
+ iconURI: "/static/music-editor/fish.png",
112021
+ instrument: {
112022
+ waveform: 1,
112023
+ octave: 3,
112024
+ ampEnvelope: {
112025
+ attack: 220,
112026
+ decay: 105,
112027
+ sustain: 1024,
112028
+ release: 350,
112029
+ amplitude: 1024
112030
+ },
112031
+ ampLFO: {
112032
+ frequency: 5,
112033
+ amplitude: 100
112034
+ },
112035
+ pitchLFO: {
112036
+ frequency: 1,
112037
+ amplitude: 4
112038
+ }
112039
+ }
112040
+ },
112041
+ {
112042
+ id: 4,
112043
+ name: lf("Car"),
112044
+ notes: [],
112045
+ iconURI: "/static/music-editor/car.png",
112046
+ instrument: {
112047
+ waveform: 16,
112048
+ octave: 4,
112049
+ ampEnvelope: {
112050
+ attack: 5,
112051
+ decay: 100,
112052
+ sustain: 1024,
112053
+ release: 30,
112054
+ amplitude: 1024
112055
+ },
112056
+ pitchLFO: {
112057
+ frequency: 10,
112058
+ amplitude: 4
112059
+ }
112060
+ }
112061
+ },
112062
+ {
112063
+ id: 5,
112064
+ name: lf("Computer"),
112065
+ notes: [],
112066
+ iconURI: "/static/music-editor/computer.png",
112067
+ instrument: {
112068
+ waveform: 15,
112069
+ octave: 1,
112070
+ ampEnvelope: {
112071
+ attack: 10,
112072
+ decay: 100,
112073
+ sustain: 500,
112074
+ release: 10,
112075
+ amplitude: 1024
112076
+ }
112077
+ }
112078
+ },
112079
+ {
112080
+ id: 6,
112081
+ name: lf("Burger"),
112082
+ notes: [],
112083
+ iconURI: "/static/music-editor/burger.png",
112084
+ instrument: {
112085
+ waveform: 1,
112086
+ octave: 1,
112087
+ ampEnvelope: {
112088
+ attack: 10,
112089
+ decay: 100,
112090
+ sustain: 500,
112091
+ release: 100,
112092
+ amplitude: 1024
112093
+ }
112094
+ }
112095
+ },
112096
+ {
112097
+ id: 7,
112098
+ name: lf("Cherry"),
112099
+ notes: [],
112100
+ iconURI: "/static/music-editor/cherry.png",
112101
+ instrument: {
112102
+ waveform: 2,
112103
+ octave: 3,
112104
+ ampEnvelope: {
112105
+ attack: 10,
112106
+ decay: 100,
112107
+ sustain: 500,
112108
+ release: 100,
112109
+ amplitude: 1024
112110
+ }
112111
+ }
112112
+ },
112113
+ {
112114
+ id: 8,
112115
+ name: lf("Lemon"),
112116
+ notes: [],
112117
+ iconURI: "/static/music-editor/lemon.png",
112118
+ instrument: {
112119
+ waveform: 15,
112120
+ octave: 2,
112121
+ ampEnvelope: {
112122
+ attack: 10,
112123
+ decay: 100,
112124
+ sustain: 500,
112125
+ release: 10,
112126
+ amplitude: 1024
112127
+ }
112128
+ }
112129
+ },
112130
+ {
112131
+ id: 9,
112132
+ name: lf("Explosion"),
112133
+ notes: [],
112134
+ iconURI: "/static/music-editor/explosion.png",
112135
+ instrument: {
112136
+ waveform: 11,
112137
+ octave: 4,
112138
+ ampEnvelope: {
112139
+ attack: 10,
112140
+ decay: 100,
112141
+ sustain: 500,
112142
+ release: 100,
112143
+ amplitude: 1024
112144
+ }
112145
+ },
112146
+ drums: [
112147
+ {
112148
+ startFrequency: 100,
112149
+ startVolume: 1024,
112150
+ steps: [
112151
+ {
112152
+ waveform: 3,
112153
+ frequency: 120,
112154
+ duration: 10,
112155
+ volume: 1024
112156
+ },
112157
+ {
112158
+ waveform: 3,
112159
+ frequency: 1,
112160
+ duration: 100,
112161
+ volume: 0
112162
+ }
112163
+ ]
112164
+ },
112165
+ {
112166
+ startFrequency: 1,
112167
+ startVolume: 1024,
112168
+ steps: [
112169
+ {
112170
+ waveform: 5,
112171
+ frequency: 1,
112172
+ duration: 20,
112173
+ volume: 0
112174
+ }
112175
+ ]
112176
+ },
112177
+ {
112178
+ startFrequency: 1,
112179
+ startVolume: 1024,
112180
+ steps: [
112181
+ {
112182
+ waveform: 5,
112183
+ frequency: 1,
112184
+ duration: 20,
112185
+ volume: 480
112186
+ },
112187
+ {
112188
+ waveform: 5,
112189
+ frequency: 1,
112190
+ duration: 20,
112191
+ volume: 260
112192
+ },
112193
+ {
112194
+ waveform: 5,
112195
+ frequency: 1,
112196
+ duration: 20,
112197
+ volume: 200
112198
+ },
112199
+ {
112200
+ waveform: 5,
112201
+ frequency: 1,
112202
+ duration: 200,
112203
+ volume: 0
112204
+ },
112205
+ ]
112206
+ },
112207
+ {
112208
+ startFrequency: 175,
112209
+ startVolume: 1024,
112210
+ steps: [
112211
+ {
112212
+ waveform: 1,
112213
+ frequency: 200,
112214
+ duration: 10,
112215
+ volume: 1024
112216
+ },
112217
+ {
112218
+ waveform: 1,
112219
+ frequency: 150,
112220
+ duration: 20,
112221
+ volume: 1024
112222
+ },
112223
+ {
112224
+ waveform: 5,
112225
+ frequency: 1,
112226
+ duration: 20,
112227
+ volume: 100
112228
+ },
112229
+ {
112230
+ waveform: 5,
112231
+ frequency: 1,
112232
+ duration: 300,
112233
+ volume: 0
112234
+ },
112235
+ ]
112236
+ },
112237
+ {
112238
+ startFrequency: 100,
112239
+ startVolume: 1024,
112240
+ steps: [
112241
+ {
112242
+ waveform: 3,
112243
+ frequency: 120,
112244
+ duration: 10,
112245
+ volume: 1024
112246
+ },
112247
+ {
112248
+ waveform: 1,
112249
+ frequency: 120,
112250
+ duration: 100,
112251
+ volume: 0
112252
+ }
112253
+ ]
112254
+ },
112255
+ {
112256
+ startFrequency: 1,
112257
+ startVolume: 1024,
112258
+ steps: [
112259
+ {
112260
+ waveform: 5,
112261
+ frequency: 1,
112262
+ duration: 20,
112263
+ volume: 0
112264
+ }
112265
+ ]
112266
+ },
112267
+ {
112268
+ startFrequency: 1,
112269
+ startVolume: 1024,
112270
+ steps: [
112271
+ {
112272
+ waveform: 5,
112273
+ frequency: 1,
112274
+ duration: 20,
112275
+ volume: 480
112276
+ },
112277
+ {
112278
+ waveform: 5,
112279
+ frequency: 1,
112280
+ duration: 20,
112281
+ volume: 260
112282
+ },
112283
+ {
112284
+ waveform: 5,
112285
+ frequency: 1,
112286
+ duration: 20,
112287
+ volume: 200
112288
+ },
112289
+ {
112290
+ waveform: 5,
112291
+ frequency: 1,
112292
+ duration: 200,
112293
+ volume: 0
112294
+ },
112295
+ ]
112296
+ },
112297
+ {
112298
+ startFrequency: 175,
112299
+ startVolume: 1024,
112300
+ steps: [
112301
+ {
112302
+ waveform: 1,
112303
+ frequency: 200,
112304
+ duration: 10,
112305
+ volume: 1024
112306
+ },
112307
+ {
112308
+ waveform: 1,
112309
+ frequency: 150,
112310
+ duration: 20,
112311
+ volume: 1024
112312
+ },
112313
+ {
112314
+ waveform: 5,
112315
+ frequency: 1,
112316
+ duration: 20,
112317
+ volume: 100
112318
+ },
112319
+ {
112320
+ waveform: 5,
112321
+ frequency: 1,
112322
+ duration: 300,
112323
+ volume: 0
112324
+ },
112325
+ ]
112326
+ },
112327
+ {
112328
+ startFrequency: 100,
112329
+ startVolume: 1024,
112330
+ steps: [
112331
+ {
112332
+ waveform: 3,
112333
+ frequency: 120,
112334
+ duration: 10,
112335
+ volume: 1024
112336
+ },
112337
+ {
112338
+ waveform: 1,
112339
+ frequency: 120,
112340
+ duration: 100,
112341
+ volume: 0
112342
+ }
112343
+ ]
112344
+ },
112345
+ {
112346
+ startFrequency: 1,
112347
+ startVolume: 1024,
112348
+ steps: [
112349
+ {
112350
+ waveform: 5,
112351
+ frequency: 1,
112352
+ duration: 20,
112353
+ volume: 0
112354
+ }
112355
+ ]
112356
+ },
112357
+ {
112358
+ startFrequency: 1,
112359
+ startVolume: 1024,
112360
+ steps: [
112361
+ {
112362
+ waveform: 5,
112363
+ frequency: 1,
112364
+ duration: 20,
112365
+ volume: 480
112366
+ },
112367
+ {
112368
+ waveform: 5,
112369
+ frequency: 1,
112370
+ duration: 20,
112371
+ volume: 260
112372
+ },
112373
+ {
112374
+ waveform: 5,
112375
+ frequency: 1,
112376
+ duration: 20,
112377
+ volume: 200
112378
+ },
112379
+ {
112380
+ waveform: 5,
112381
+ frequency: 1,
112382
+ duration: 200,
112383
+ volume: 0
112384
+ },
112385
+ ]
112386
+ },
112387
+ {
112388
+ startFrequency: 175,
112389
+ startVolume: 1024,
112390
+ steps: [
112391
+ {
112392
+ waveform: 1,
112393
+ frequency: 200,
112394
+ duration: 10,
112395
+ volume: 1024
112396
+ },
112397
+ {
112398
+ waveform: 1,
112399
+ frequency: 150,
112400
+ duration: 20,
112401
+ volume: 1024
112402
+ },
112403
+ {
112404
+ waveform: 5,
112405
+ frequency: 1,
112406
+ duration: 20,
112407
+ volume: 100
112408
+ },
112409
+ {
112410
+ waveform: 5,
112411
+ frequency: 1,
112412
+ duration: 300,
112413
+ volume: 0
112414
+ },
112415
+ ]
112416
+ }
112417
+ ]
112418
+ }
112419
+ ]
112420
+ };
112421
+ }
112422
+ music.getEmptySong = getEmptySong;
112423
+ })(music = assets.music || (assets.music = {}));
112424
+ })(assets = pxt.assets || (pxt.assets = {}));
112425
+ })(pxt || (pxt = {}));
111377
112426
  /// <reference path="../localtypings/pxtpackage.d.ts"/>
111378
112427
  /// <reference path="../localtypings/pxtparts.d.ts"/>
111379
112428
  /// <reference path="../localtypings/pxtarget.d.ts"/>
@@ -115438,6 +116487,7 @@ var pxt;
115438
116487
  pxt.IMAGE_MIME_TYPE = "image/x-mkcd-f4";
115439
116488
  pxt.TILEMAP_MIME_TYPE = "application/mkcd-tilemap";
115440
116489
  pxt.ANIMATION_MIME_TYPE = "application/mkcd-animation";
116490
+ pxt.SONG_MIME_TYPE = "application/mkcd-song";
115441
116491
  class AssetCollection {
115442
116492
  constructor() {
115443
116493
  this.assets = [];
@@ -115624,21 +116674,24 @@ var pxt;
115624
116674
  tilemaps: new AssetCollection(),
115625
116675
  tiles: new AssetCollection(),
115626
116676
  animations: new AssetCollection(),
115627
- images: new AssetCollection()
116677
+ images: new AssetCollection(),
116678
+ songs: new AssetCollection(),
115628
116679
  };
115629
116680
  this.state = {
115630
116681
  revision: this.nextID++,
115631
116682
  tilemaps: new AssetCollection(),
115632
116683
  tiles: new AssetCollection(),
115633
116684
  animations: new AssetCollection(),
115634
- images: new AssetCollection()
116685
+ images: new AssetCollection(),
116686
+ songs: new AssetCollection(),
115635
116687
  };
115636
116688
  this.gallery = {
115637
116689
  revision: 0,
115638
116690
  tilemaps: new AssetCollection(),
115639
116691
  tiles: new AssetCollection(),
115640
116692
  animations: new AssetCollection(),
115641
- images: new AssetCollection()
116693
+ images: new AssetCollection(),
116694
+ songs: new AssetCollection(),
115642
116695
  };
115643
116696
  this.undoStack = [];
115644
116697
  this.redoStack = [];
@@ -115740,6 +116793,19 @@ var pxt;
115740
116793
  };
115741
116794
  return this.state.images.add(newImage);
115742
116795
  }
116796
+ createNewSong(data, displayName) {
116797
+ this.onChange();
116798
+ const newSong = {
116799
+ internalID: this.getNewInternalId(),
116800
+ id: this.generateNewID("song" /* AssetType.Song */),
116801
+ type: "song" /* AssetType.Song */,
116802
+ song: pxt.assets.music.cloneSong(data),
116803
+ meta: {
116804
+ displayName
116805
+ },
116806
+ };
116807
+ return this.state.songs.add(newSong);
116808
+ }
115743
116809
  updateTile(tile) {
115744
116810
  this.onChange();
115745
116811
  const existing = this.resolveProjectTileByInternalID(tile.internalID);
@@ -115776,6 +116842,7 @@ var pxt;
115776
116842
  const blob = {};
115777
116843
  this.state.images.serializeToJRes(blob);
115778
116844
  this.state.animations.serializeToJRes(blob);
116845
+ this.state.songs.serializeToJRes(blob);
115779
116846
  blob["*"] = {
115780
116847
  "mimeType": "image/x-mkcd-f4",
115781
116848
  "dataEncoding": "base64",
@@ -115857,6 +116924,7 @@ var pxt;
115857
116924
  tilemaps: this.state.tilemaps.clone(),
115858
116925
  animations: this.state.animations.clone(),
115859
116926
  tiles: this.state.tiles.clone(),
116927
+ songs: this.state.songs.clone(),
115860
116928
  };
115861
116929
  }
115862
116930
  undo() {
@@ -115869,6 +116937,7 @@ var pxt;
115869
116937
  this.state.images.applyDiff(undo.images, true);
115870
116938
  this.state.tilemaps.applyDiff(undo.tilemaps, true);
115871
116939
  this.state.animations.applyDiff(undo.animations, true);
116940
+ this.state.songs.applyDiff(undo.songs, true);
115872
116941
  this.state.revision = undo.beforeRevision;
115873
116942
  this.redoStack.push(undo);
115874
116943
  this.committedState = this.cloneState();
@@ -115882,6 +116951,7 @@ var pxt;
115882
116951
  this.state.images.applyDiff(redo.images);
115883
116952
  this.state.tilemaps.applyDiff(redo.tilemaps);
115884
116953
  this.state.animations.applyDiff(redo.animations);
116954
+ this.state.songs.applyDiff(redo.songs);
115885
116955
  this.state.revision = redo.afterRevision;
115886
116956
  this.undoStack.push(redo);
115887
116957
  this.committedState = this.cloneState();
@@ -115898,7 +116968,8 @@ var pxt;
115898
116968
  tiles: this.state.tiles.diff(this.committedState.tiles),
115899
116969
  images: this.state.images.diff(this.committedState.images),
115900
116970
  tilemaps: this.state.tilemaps.diff(this.committedState.tilemaps),
115901
- animations: this.state.animations.diff(this.committedState.animations)
116971
+ animations: this.state.animations.diff(this.committedState.animations),
116972
+ songs: this.state.songs.diff(this.committedState.songs)
115902
116973
  });
115903
116974
  this.committedState = this.cloneState();
115904
116975
  this.cleanupTemporaryAssets();
@@ -115928,16 +116999,8 @@ var pxt;
115928
116999
  }
115929
117000
  isNameTaken(assetType, name) {
115930
117001
  const isTaken = (id) => {
115931
- switch (assetType) {
115932
- case "image" /* AssetType.Image */:
115933
- return this.state.images.isIDTaken(id) || this.gallery.images.isIDTaken(id);
115934
- case "tile" /* AssetType.Tile */:
115935
- return this.state.tiles.isIDTaken(id) || this.gallery.tiles.isIDTaken(id);
115936
- case "tilemap" /* AssetType.Tilemap */:
115937
- return this.state.tilemaps.isIDTaken(id) || this.gallery.tilemaps.isIDTaken(id);
115938
- case "animation" /* AssetType.Animation */:
115939
- return this.state.animations.isIDTaken(id) || this.gallery.animations.isIDTaken(id);
115940
- }
117002
+ return getAssetCollection(this.state, assetType).isIDTaken(id) ||
117003
+ getAssetCollection(this.gallery, assetType).isIDTaken(id);
115941
117004
  };
115942
117005
  const shortId = getShortIDCore(assetType, name);
115943
117006
  const checkShortId = shortId && shortId !== name;
@@ -115963,6 +117026,10 @@ var pxt;
115963
117026
  * assets.animation`shortId`
115964
117027
  * assets.animation`displayName`
115965
117028
  *
117029
+ * SONGS:
117030
+ * assets.song`shortId`
117031
+ * assets.song`displayName`
117032
+ *
115966
117033
  * TILEMAPS:
115967
117034
  * tilemap`shortId`
115968
117035
  *
@@ -116001,6 +117068,11 @@ var pxt;
116001
117068
  if (displayName)
116002
117069
  assetTsRefs += `|assets.animation\`${displayName}\``;
116003
117070
  break;
117071
+ case "song" /* pxt.AssetType.Song */:
117072
+ assetTsRefs = `assets.song\`${shortId}\``;
117073
+ if (displayName)
117074
+ assetTsRefs += `|assets.song\`${displayName}\``;
117075
+ break;
116004
117076
  default:
116005
117077
  assetTsRefs = `assets.image\`${shortId}\``;
116006
117078
  if (displayName)
@@ -116023,6 +117095,11 @@ var pxt;
116023
117095
  if (displayName)
116024
117096
  assetPyRefs += `|assets.animation\("""${displayName}"""\)`;
116025
117097
  break;
117098
+ case "song" /* pxt.AssetType.Song */:
117099
+ assetPyRefs = `assets.song\("""${shortId}"""\)`;
117100
+ if (displayName)
117101
+ assetPyRefs += `|assets.song\("""${displayName}"""\)`;
117102
+ break;
116026
117103
  default:
116027
117104
  assetPyRefs = `assets.image\("""${shortId}"""\)`;
116028
117105
  if (displayName)
@@ -116048,65 +117125,29 @@ var pxt;
116048
117125
  return false;
116049
117126
  }
116050
117127
  lookupAsset(assetType, name) {
116051
- switch (assetType) {
116052
- case "image" /* AssetType.Image */:
116053
- return this.state.images.getByID(name) || this.gallery.images.getByID(name);
116054
- case "tile" /* AssetType.Tile */:
116055
- return this.state.tiles.getByID(name) || this.gallery.tiles.getByID(name);
116056
- case "tilemap" /* AssetType.Tilemap */:
116057
- return this.state.tilemaps.getByID(name) || this.gallery.tilemaps.getByID(name);
116058
- case "animation" /* AssetType.Animation */:
116059
- return this.state.animations.getByID(name) || this.gallery.animations.getByID(name);
116060
- }
117128
+ return getAssetCollection(this.state, assetType).getByID(name) ||
117129
+ getAssetCollection(this.gallery, assetType).getByID(name);
116061
117130
  }
116062
117131
  lookupAssetByName(assetType, name) {
116063
- switch (assetType) {
116064
- case "image" /* AssetType.Image */:
116065
- return this.state.images.getByDisplayName(name);
116066
- case "tile" /* AssetType.Tile */:
116067
- return this.state.tiles.getByDisplayName(name);
116068
- case "tilemap" /* AssetType.Tilemap */:
116069
- return this.state.tilemaps.getByDisplayName(name);
116070
- case "animation" /* AssetType.Animation */:
116071
- return this.state.animations.getByDisplayName(name);
116072
- }
117132
+ return getAssetCollection(this.state, assetType).getByDisplayName(name);
116073
117133
  }
116074
117134
  getAssets(type) {
116075
- switch (type) {
116076
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot();
116077
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot();
116078
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot();
116079
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot();
116080
- }
117135
+ return getAssetCollection(this.state, type).getSnapshot();
116081
117136
  }
116082
117137
  getGalleryAssets(type) {
116083
- switch (type) {
116084
- case "image" /* AssetType.Image */: return this.gallery.images.getSnapshot();
116085
- case "tile" /* AssetType.Tile */: return this.gallery.tiles.getSnapshot();
116086
- case "tilemap" /* AssetType.Tilemap */: return this.gallery.tilemaps.getSnapshot();
116087
- case "animation" /* AssetType.Animation */: return this.gallery.animations.getSnapshot();
116088
- }
117138
+ return getAssetCollection(this.gallery, type).getSnapshot();
116089
117139
  }
116090
117140
  lookupBlockAsset(type, blockID) {
116091
117141
  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; };
116092
- switch (type) {
116093
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot(filter)[0];
116094
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot(filter)[0];
116095
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot(filter)[0];
116096
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot(filter)[0];
116097
- }
117142
+ return getAssetCollection(this.state, type).getSnapshot(filter)[0];
116098
117143
  }
116099
117144
  updateAsset(asset) {
116100
117145
  this.onChange();
116101
117146
  switch (asset.type) {
116102
- case "image" /* AssetType.Image */:
116103
- return this.state.images.update(asset.id, asset);
116104
117147
  case "tile" /* AssetType.Tile */:
116105
117148
  return this.updateTile(asset);
116106
- case "tilemap" /* AssetType.Tilemap */:
116107
- return this.state.tilemaps.update(asset.id, asset);
116108
- case "animation" /* AssetType.Animation */:
116109
- return this.state.animations.update(asset.id, asset);
117149
+ default:
117150
+ return getAssetCollection(this.state, asset.type).update(asset.id, asset);
116110
117151
  }
116111
117152
  }
116112
117153
  duplicateAsset(asset, displayName) {
@@ -116128,53 +117169,22 @@ var pxt;
116128
117169
  break;
116129
117170
  case "animation" /* AssetType.Animation */:
116130
117171
  newAsset = this.createNewAnimationFromData(clone.frames, clone.interval, name);
117172
+ break;
117173
+ case "song" /* AssetType.Song */:
117174
+ newAsset = this.createNewSong(asset.song, name);
117175
+ break;
116131
117176
  }
116132
117177
  return newAsset;
116133
117178
  }
116134
117179
  removeAsset(asset) {
116135
117180
  this.onChange();
116136
- switch (asset.type) {
116137
- case "image" /* AssetType.Image */:
116138
- return this.state.images.removeByID(asset.id);
116139
- case "tile" /* AssetType.Tile */:
116140
- return this.state.tiles.removeByID(asset.id);
116141
- case "tilemap" /* AssetType.Tilemap */:
116142
- return this.state.tilemaps.removeByID(asset.id);
116143
- case "animation" /* AssetType.Animation */:
116144
- return this.state.animations.removeByID(asset.id);
116145
- }
117181
+ getAssetCollection(this.state, asset.type).removeByID(asset.id);
116146
117182
  }
116147
117183
  addChangeListener(asset, listener) {
116148
- switch (asset.type) {
116149
- case "image" /* AssetType.Image */:
116150
- this.state.images.addListener(asset.internalID, listener);
116151
- break;
116152
- case "tile" /* AssetType.Tile */:
116153
- this.state.tiles.addListener(asset.internalID, listener);
116154
- break;
116155
- case "tilemap" /* AssetType.Tilemap */:
116156
- this.state.tilemaps.addListener(asset.internalID, listener);
116157
- break;
116158
- case "animation" /* AssetType.Animation */:
116159
- this.state.animations.addListener(asset.internalID, listener);
116160
- break;
116161
- }
117184
+ getAssetCollection(this.state, asset.type).addListener(asset.internalID, listener);
116162
117185
  }
116163
117186
  removeChangeListener(type, listener) {
116164
- switch (type) {
116165
- case "image" /* AssetType.Image */:
116166
- this.state.images.removeListener(listener);
116167
- break;
116168
- case "tile" /* AssetType.Tile */:
116169
- this.state.tiles.removeListener(listener);
116170
- break;
116171
- case "tilemap" /* AssetType.Tilemap */:
116172
- this.state.tilemaps.removeListener(listener);
116173
- break;
116174
- case "animation" /* AssetType.Animation */:
116175
- this.state.animations.removeListener(listener);
116176
- break;
116177
- }
117187
+ getAssetCollection(this.state, type).removeListener(listener);
116178
117188
  }
116179
117189
  loadPackage(pack) {
116180
117190
  const allPackages = pack.sortedDeps();
@@ -116199,7 +117209,7 @@ var pxt;
116199
117209
  this.gallery.images.add(image);
116200
117210
  }
116201
117211
  }
116202
- else {
117212
+ else if (image.type === "animation" /* AssetType.Animation */) {
116203
117213
  if (isProject) {
116204
117214
  this.state.animations.add(image);
116205
117215
  }
@@ -116207,6 +117217,14 @@ var pxt;
116207
117217
  this.gallery.animations.add(image);
116208
117218
  }
116209
117219
  }
117220
+ else {
117221
+ if (isProject) {
117222
+ this.state.songs.add(image);
117223
+ }
117224
+ else {
117225
+ this.gallery.songs.add(image);
117226
+ }
117227
+ }
116210
117228
  }
116211
117229
  }
116212
117230
  for (const tm of getTilemaps(pack.parseJRes())) {
@@ -116283,6 +117301,9 @@ var pxt;
116283
117301
  this.state.animations.add(animation);
116284
117302
  }
116285
117303
  }
117304
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
117305
+ this.state.songs.add(this.generateSong(entry));
117306
+ }
116286
117307
  }
116287
117308
  for (const animation of toInflate) {
116288
117309
  this.state.animations.add(this.inflateAnimation(animation, this.state.images.getSnapshot()));
@@ -116293,6 +117314,7 @@ var pxt;
116293
117314
  cleanupCollection(this.state.tiles);
116294
117315
  cleanupCollection(this.state.tilemaps);
116295
117316
  cleanupCollection(this.state.animations);
117317
+ cleanupCollection(this.state.songs);
116296
117318
  function cleanupCollection(collection) {
116297
117319
  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)); });
116298
117320
  const toRemove = [];
@@ -116322,6 +117344,17 @@ var pxt;
116322
117344
  bitmap: pxt.sprite.getBitmapFromJResURL(`data:${pxt.IMAGE_MIME_TYPE};base64,${entry.data}`).data()
116323
117345
  };
116324
117346
  }
117347
+ generateSong(entry) {
117348
+ return {
117349
+ internalID: this.getNewInternalId(),
117350
+ type: "song" /* AssetType.Song */,
117351
+ id: entry.id,
117352
+ meta: {
117353
+ displayName: entry.displayName
117354
+ },
117355
+ song: pxt.assets.music.decodeSongFromHex(entry.data)
117356
+ };
117357
+ }
116325
117358
  generateAnimation(entry) {
116326
117359
  if (entry.dataEncoding === "json") {
116327
117360
  let data;
@@ -116375,6 +117408,8 @@ var pxt;
116375
117408
  return this.generateNewIDInternal("tile" /* AssetType.Tile */, pxt.sprite.TILE_PREFIX, pxt.sprite.TILE_NAMESPACE);
116376
117409
  case "tilemap" /* AssetType.Tilemap */:
116377
117410
  return this.generateNewIDInternal("tilemap" /* AssetType.Tilemap */, lf("level"));
117411
+ case "song" /* AssetType.Song */:
117412
+ return this.generateNewIDInternal("song" /* AssetType.Song */, pxt.sprite.SONG_PREFIX, pxt.sprite.SONG_NAMESPACE);
116378
117413
  }
116379
117414
  }
116380
117415
  generateNewIDInternal(type, varPrefix, namespaceString) {
@@ -116412,6 +117447,9 @@ var pxt;
116412
117447
  assets.push(animation);
116413
117448
  }
116414
117449
  }
117450
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
117451
+ assets.push(this.generateSong(entry));
117452
+ }
116415
117453
  }
116416
117454
  for (const animation of toInflate) {
116417
117455
  assets.push(this.inflateAnimation(animation, assets));
@@ -116472,6 +117510,7 @@ var pxt;
116472
117510
  let out = "";
116473
117511
  const imageEntries = [];
116474
117512
  const animationEntries = [];
117513
+ const songEntries = [];
116475
117514
  for (const key of entries) {
116476
117515
  if (key === "*")
116477
117516
  continue;
@@ -116498,10 +117537,17 @@ var pxt;
116498
117537
  expression: `[${animation.frames.map(f => pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(f), "typescript")).join(", ")}]`
116499
117538
  });
116500
117539
  }
117540
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
117541
+ songEntries.push({
117542
+ keys: [getShortIDCore("song" /* AssetType.Song */, key, true), entry.displayName],
117543
+ expression: `hex\`${entry.data}\``
117544
+ });
117545
+ }
116501
117546
  }
116502
117547
  const warning = lf("Auto-generated code. Do not edit.");
116503
117548
  out += emitFactoryHelper("image", imageEntries);
116504
117549
  out += emitFactoryHelper("animation", animationEntries);
117550
+ out += emitFactoryHelper("song", songEntries);
116505
117551
  return `// ${warning}\nnamespace ${pxt.sprite.IMAGES_NAMESPACE} {\n${out}\n}\n// ${warning}\n`;
116506
117552
  }
116507
117553
  pxt.emitProjectImages = emitProjectImages;
@@ -116545,6 +117591,8 @@ var pxt;
116545
117591
  return Object.assign(Object.assign({}, asset), { frames: asset.frames.map(frame => cloneBitmap(frame)) });
116546
117592
  case "tilemap" /* AssetType.Tilemap */:
116547
117593
  return Object.assign(Object.assign({}, asset), { data: asset.data.cloneData() });
117594
+ case "song" /* AssetType.Song */:
117595
+ return Object.assign(Object.assign({}, asset), { song: pxt.assets.music.cloneSong(asset.song) });
116548
117596
  }
116549
117597
  }
116550
117598
  pxt.cloneAsset = cloneAsset;
@@ -116578,6 +117626,13 @@ var pxt;
116578
117626
  case "animation" /* AssetType.Animation */:
116579
117627
  allJRes[id] = serializeAnimation(asset);
116580
117628
  break;
117629
+ case "song" /* AssetType.Song */:
117630
+ allJRes[id] = {
117631
+ data: pxt.assets.music.encodeSongToHex(asset.song),
117632
+ mimeType: pxt.SONG_MIME_TYPE,
117633
+ displayName: asset.meta.displayName
117634
+ };
117635
+ break;
116581
117636
  }
116582
117637
  }
116583
117638
  function assetEquals(a, b) {
@@ -116597,6 +117652,8 @@ var pxt;
116597
117652
  return a.interval === bAnimation.interval && pxt.U.arrayEquals(a.frames, bAnimation.frames, pxt.sprite.bitmapEquals);
116598
117653
  case "tilemap" /* AssetType.Tilemap */:
116599
117654
  return a.data.equals(b.data);
117655
+ case "song" /* AssetType.Song */:
117656
+ return pxt.assets.music.songEquals(a.song, b.song);
116600
117657
  }
116601
117658
  }
116602
117659
  pxt.assetEquals = assetEquals;
@@ -116636,11 +117693,13 @@ var pxt;
116636
117693
  return `assets.animation${leftTick}${shortId}${rightTick}`;
116637
117694
  case "tilemap" /* AssetType.Tilemap */:
116638
117695
  return `tilemap${leftTick}${shortId}${rightTick}`;
117696
+ case "song" /* AssetType.Song */:
117697
+ return `assets.song${leftTick}${shortId}${rightTick}`;
116639
117698
  }
116640
117699
  }
116641
117700
  pxt.getTSReferenceForAsset = getTSReferenceForAsset;
116642
117701
  function parseAssetTSReference(ts) {
116643
- const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap))|(tilemap))\s*(?:`|\(""")([^`"]+)(?:`|"""\))\s*$/m.exec(ts);
117702
+ const match = /^\s*(?:(?:assets\s*\.\s*(image|tile|animation|tilemap|song))|(tilemap))\s*(?:`|\(""")([^`"]+)(?:`|"""\))\s*$/m.exec(ts);
116644
117703
  if (match) {
116645
117704
  const type = match[1] || match[2];
116646
117705
  const name = match[3].trim();
@@ -116664,6 +117723,8 @@ var pxt;
116664
117723
  return project.lookupAssetByName("tilemap" /* AssetType.Tilemap */, name) || project.lookupAsset("tilemap" /* AssetType.Tilemap */, name);
116665
117724
  case "animation":
116666
117725
  return project.lookupAssetByName("animation" /* AssetType.Animation */, name);
117726
+ case "song":
117727
+ return project.lookupAssetByName("song" /* AssetType.Song */, name);
116667
117728
  }
116668
117729
  }
116669
117730
  return undefined;
@@ -116679,6 +117740,8 @@ var pxt;
116679
117740
  return lf("level");
116680
117741
  case "animation" /* pxt.AssetType.Animation */:
116681
117742
  return lf("myAnim");
117743
+ case "song" /* pxt.AssetType.Song */:
117744
+ return lf("mySong");
116682
117745
  default:
116683
117746
  return lf("asset");
116684
117747
  }
@@ -116703,6 +117766,9 @@ var pxt;
116703
117766
  case "animation" /* AssetType.Animation */:
116704
117767
  prefix = pxt.sprite.ANIMATION_NAMESPACE + ".";
116705
117768
  break;
117769
+ case "song" /* AssetType.Song */:
117770
+ prefix = pxt.sprite.SONG_NAMESPACE + ".";
117771
+ break;
116706
117772
  }
116707
117773
  if (prefix) {
116708
117774
  if (id.startsWith(prefix)) {
@@ -116787,6 +117853,15 @@ var pxt;
116787
117853
  function read16Bit(buf, offset) {
116788
117854
  return buf[offset] | (buf[offset + 1] << 8);
116789
117855
  }
117856
+ function getAssetCollection(snapshot, type) {
117857
+ switch (type) {
117858
+ case "animation" /* AssetType.Animation */: return snapshot.animations;
117859
+ case "image" /* AssetType.Image */: return snapshot.images;
117860
+ case "tile" /* AssetType.Tile */: return snapshot.tiles;
117861
+ case "tilemap" /* AssetType.Tilemap */: return snapshot.tilemaps;
117862
+ case "song" /* AssetType.Song */: return snapshot.songs;
117863
+ }
117864
+ }
116790
117865
  })(pxt || (pxt = {}));
116791
117866
  var pxt;
116792
117867
  (function (pxt) {
@@ -154616,7 +155691,7 @@ var pxsim;
154616
155691
  channel.gain.gain.value = 0;
154617
155692
  channel.gain.gain.setValueAtTime(volume, context().currentTime);
154618
155693
  channel.gain.connect(destination);
154619
- if (channels.length > 5)
155694
+ if (channels.length > 20)
154620
155695
  channels[0].remove();
154621
155696
  channels.push(channel);
154622
155697
  const checkCancel = () => {
@@ -154686,7 +155761,7 @@ var pxsim;
154686
155761
  let resolved = false;
154687
155762
  let ctx = context();
154688
155763
  let channel = new Channel();
154689
- if (channels.length > 5)
155764
+ if (channels.length > 20)
154690
155765
  channels[0].remove();
154691
155766
  channels.push(channel);
154692
155767
  channel.gain = ctx.createGain();
@@ -154720,6 +155795,10 @@ var pxsim;
154720
155795
  const endVolume = readUint16(instructions, i + 8);
154721
155796
  const endFrequency = readUint16(instructions, i + 10);
154722
155797
  totalDuration += duration;
155798
+ if (wave === 0) {
155799
+ currentTime += duration;
155800
+ continue;
155801
+ }
154723
155802
  const isSquareWave = 11 <= wave && wave <= 15;
154724
155803
  if (!oscillators[wave]) {
154725
155804
  oscillators[wave] = getGenerator(wave, startFrequency);
@@ -154762,7 +155841,8 @@ var pxsim;
154762
155841
  return;
154763
155842
  }
154764
155843
  const { frequency, volume } = findFrequencyAndVolumeAtTime((time - startTime) * 1000, instructions);
154765
- onPull(frequency, volume / 1024);
155844
+ if (onPull)
155845
+ onPull(frequency, volume / 1024);
154766
155846
  requestAnimationFrame(handleAnimationFrame);
154767
155847
  };
154768
155848
  requestAnimationFrame(handleAnimationFrame);
@@ -158174,7 +159254,8 @@ function pxtFileList(pref) {
158174
159254
  .concat(nodeutil.allFiles(pref + "built/web/fonts", { maxDepth: 1 }))
158175
159255
  .concat(nodeutil.allFiles(pref + "built/web/vs", { maxDepth: 4 }))
158176
159256
  .concat(nodeutil.allFiles(pref + "built/web/skillmap", { maxDepth: 4 }))
158177
- .concat(nodeutil.allFiles(pref + "built/web/authcode", { maxDepth: 4 }));
159257
+ .concat(nodeutil.allFiles(pref + "built/web/authcode", { maxDepth: 4 }))
159258
+ .concat(nodeutil.allFiles(pref + "built/web/multiplayer", { maxDepth: 4 }));
158178
159259
  }
158179
159260
  function semverCmp(a, b) {
158180
159261
  let parse = (s) => {
@@ -158255,7 +159336,8 @@ function ciAsync() {
158255
159336
  .then(() => buildWebStringsAsync())
158256
159337
  .then(() => crowdin.execCrowdinAsync("upload", "built/webstrings.json"))
158257
159338
  .then(() => crowdin.execCrowdinAsync("upload", "built/skillmap-strings.json"))
158258
- .then(() => crowdin.execCrowdinAsync("upload", "built/authcode-strings.json"));
159339
+ .then(() => crowdin.execCrowdinAsync("upload", "built/authcode-strings.json"))
159340
+ .then(() => crowdin.execCrowdinAsync("upload", "built/multiplayer-strings.json"));
158259
159341
  if (uploadApiStrings)
158260
159342
  p = p.then(() => crowdin.execCrowdinAsync("upload", "built/strings.json"));
158261
159343
  if (uploadDocs || uploadApiStrings)
@@ -158774,6 +159856,7 @@ function uploadCoreAsync(opts) {
158774
159856
  "asseteditorUrl": opts.localDir + "asseteditor.html",
158775
159857
  "skillmapUrl": opts.localDir + "skillmap.html",
158776
159858
  "authcodeUrl": opts.localDir + "authcode.html",
159859
+ "multiplayerUrl": opts.localDir + "multiplayer.html",
158777
159860
  "isStatic": true,
158778
159861
  };
158779
159862
  const targetImagePaths = targetImages.map(k => `${opts.localDir}${path.join('./docs', logos[k])}`);
@@ -158820,14 +159903,16 @@ function uploadCoreAsync(opts) {
158820
159903
  "multi.html",
158821
159904
  "asseteditor.html",
158822
159905
  "skillmap.html",
158823
- "authcode.html"
159906
+ "authcode.html",
159907
+ "multiplayer.html",
158824
159908
  ];
158825
159909
  // expandHtml is manually called on these files before upload
158826
159910
  // runs <!-- @include --> substitutions, fills in locale, etc
158827
159911
  let expandFiles = [
158828
159912
  "index.html",
158829
159913
  "skillmap.html",
158830
- "authcode.html"
159914
+ "authcode.html",
159915
+ "multiplayer.html",
158831
159916
  ];
158832
159917
  nodeutil.mkdirP("built/uploadrepl");
158833
159918
  function encodeURLs(urls) {
@@ -159621,33 +160706,29 @@ async function buildSemanticUIAsync(parsed) {
159621
160706
  ]
159622
160707
  });
159623
160708
  }
159624
- // Generate react-common css for skillmap and authcode
159625
- const skillmapFile = isPxtCore ? "react-common/styles/react-common-skillmap-core.less" :
159626
- "node_modules/pxt-core/react-common/styles/react-common-skillmap.less";
159627
- await nodeutil.spawnAsync({
159628
- cmd: "node",
159629
- args: [
159630
- lessCPath,
159631
- skillmapFile,
159632
- "built/web/react-common-skillmap.css",
159633
- "--include-path=" + lessIncludePaths
159634
- ]
159635
- });
159636
- const authcodeFile = isPxtCore ? "react-common/styles/react-common-authcode-core.less" :
159637
- "node_modules/pxt-core/react-common/styles/react-common-authcode.less";
159638
- await nodeutil.spawnAsync({
159639
- cmd: "node",
159640
- args: [
159641
- lessCPath,
159642
- authcodeFile,
159643
- "built/web/react-common-authcode.css",
159644
- "--include-path=" + lessIncludePaths
159645
- ]
159646
- });
159647
- let skillmapCss = await readFileAsync(`built/web/react-common-skillmap.css`, "utf8");
159648
- skillmapCss = await linkFontAsync("fa-solid-900", skillmapCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
159649
- skillmapCss = await linkFontAsync("fa-regular-400", skillmapCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
159650
- await writeFileAsync(`built/web/react-common-skillmap.css`, skillmapCss, "utf8");
160709
+ async function generateReactCommonCss(app) {
160710
+ const appFile = isPxtCore ? `react-common/styles/react-common-${app}-core.less` :
160711
+ `node_modules/pxt-core/react-common/styles/react-common-${app}.less`;
160712
+ await nodeutil.spawnAsync({
160713
+ cmd: "node",
160714
+ args: [
160715
+ lessCPath,
160716
+ appFile,
160717
+ `built/web/react-common-${app}.css`,
160718
+ "--include-path=" + lessIncludePaths
160719
+ ]
160720
+ });
160721
+ let appCss = await readFileAsync(`built/web/react-common-${app}.css`, "utf8");
160722
+ appCss = await linkFontAsync("fa-solid-900", appCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
160723
+ appCss = await linkFontAsync("fa-regular-400", appCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
160724
+ await writeFileAsync(`built/web/react-common-${app}.css`, appCss, "utf8");
160725
+ }
160726
+ // Generate react-common css for skillmap, authcode, and multiplayer
160727
+ await Promise.all([
160728
+ generateReactCommonCss("skillmap"),
160729
+ generateReactCommonCss("authcode"),
160730
+ generateReactCommonCss("multiplayer")
160731
+ ]);
159651
160732
  // Run postcss with autoprefixer and rtlcss
159652
160733
  pxt.debug("running postcss");
159653
160734
  const postcss = require('postcss');
@@ -159667,7 +160748,7 @@ async function buildSemanticUIAsync(parsed) {
159667
160748
  autoprefixer: { browsers: browserList, add: true }
159668
160749
  });
159669
160750
  const rtlcss = require("rtlcss");
159670
- const files = ["semantic.css", "blockly.css", "react-common-skillmap.css"];
160751
+ const files = ["semantic.css", "blockly.css", "react-common-skillmap.css", "react-common-authcode.css", "react-common-multiplayer.css"];
159671
160752
  for (const cssFile of files) {
159672
160753
  const css = await readFileAsync(`built/web/${cssFile}`, "utf8");
159673
160754
  const processed = await postcss([cssnano])
@@ -159678,9 +160759,13 @@ async function buildSemanticUIAsync(parsed) {
159678
160759
  await writeFileAsync(`built/web/rtl${cssFile}`, processedRtl.css, "utf8");
159679
160760
  }
159680
160761
  if (!isPxtCore) {
159681
- // This is just to support the local skillmap serve for development
160762
+ // This is just to support the local skillmap/cra-app serve for development
159682
160763
  nodeutil.cp("built/web/react-common-skillmap.css", "node_modules/pxt-core/skillmap/public/blb");
160764
+ nodeutil.cp("built/web/react-common-authcode.css", "node_modules/pxt-core/authcode/public/blb");
160765
+ nodeutil.cp("built/web/react-common-multiplayer.css", "node_modules/pxt-core/multiplayer/public/blb");
159683
160766
  nodeutil.cp("built/web/semantic.css", "node_modules/pxt-core/skillmap/public/blb");
160767
+ nodeutil.cp("built/web/semantic.css", "node_modules/pxt-core/authcode/public/blb");
160768
+ nodeutil.cp("built/web/semantic.css", "node_modules/pxt-core/multiplayer/public/blb");
159684
160769
  }
159685
160770
  }
159686
160771
  async function linkFontAsync(font, semCss, sourceDir = "node_modules/semantic-ui-less/themes/default/assets/fonts/", refDir = "fonts\\/") {
@@ -159699,47 +160784,13 @@ function buildWebStringsAsync() {
159699
160784
  nodeutil.writeFileSync("built/webstrings.json", nodeutil.stringify(webstringsJson()));
159700
160785
  return Promise.resolve();
159701
160786
  }
159702
- function buildSkillMapAsync(parsed) {
160787
+ function buildReactAppAsync(app, parsed, opts) {
160788
+ opts = opts || {
160789
+ copyAssets: true
160790
+ };
159703
160791
  // local serve
159704
- const skillmapRoot = "node_modules/pxt-core/skillmap";
159705
- const reactScriptsConfigRoot = `${skillmapRoot}/node_modules/react-scripts/config`;
160792
+ const appRoot = `node_modules/pxt-core/${app}`;
159706
160793
  const docsPath = parsed.flags["docs"];
159707
- return rimrafAsync(`${skillmapRoot}/public/blb`, {})
159708
- .then(() => rimrafAsync(`${skillmapRoot}/build/assets`, {}))
159709
- .then(() => rimrafAsync(`${skillmapRoot}/public/docs`, {}))
159710
- .then(() => rimrafAsync(`${skillmapRoot}/public/static`, {}))
159711
- .then(() => {
159712
- // read pxtarget.json, save into 'pxtTargetBundle' global variable
159713
- let cfg = readLocalPxTarget();
159714
- nodeutil.writeFileSync(`${skillmapRoot}/public/blb/target.js`, "// eslint-disable-next-line \n" + targetJsPrefix + JSON.stringify(cfg));
159715
- nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
159716
- nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
159717
- nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
159718
- nodeutil.cp("node_modules/pxt-core/built/web/react-common-skillmap.css", `${skillmapRoot}/public/blb`);
159719
- // copy 'assets' over from docs/static
159720
- nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
159721
- // copy default react-scripts webpack config into a webpack.config.base file if necessary
159722
- if (!fs.existsSync(`${reactScriptsConfigRoot}/webpack.config.base.js`)) {
159723
- nodeutil.cp(`${reactScriptsConfigRoot}/webpack.config.js`, reactScriptsConfigRoot, "webpack.config.base.js");
159724
- }
159725
- // wrap the config in our webpack.config.override for build customization
159726
- nodeutil.cp(`${skillmapRoot}/webpack.config.override.js`, reactScriptsConfigRoot, "webpack.config.js");
159727
- if (docsPath) {
159728
- // copy docs over from specified path
159729
- nodeutil.cpR(`docs/${docsPath}`, `${skillmapRoot}/public/docs/${docsPath}`);
159730
- nodeutil.cpR(`docs/static/${docsPath}`, `${skillmapRoot}/public/static/${docsPath}`);
159731
- }
159732
- return nodeutil.spawnAsync({
159733
- cmd: os.platform() === "win32" ? "npm.cmd" : "npm",
159734
- args: ["run-script", "start"],
159735
- cwd: skillmapRoot,
159736
- shell: true
159737
- });
159738
- });
159739
- }
159740
- function buildAuthcodeAsync(parsed) {
159741
- // local serve
159742
- const appRoot = "node_modules/pxt-core/authcode";
159743
160794
  return rimrafAsync(`${appRoot}/public/blb`, {})
159744
160795
  .then(() => rimrafAsync(`${appRoot}/build/assets`, {}))
159745
160796
  .then(() => rimrafAsync(`${appRoot}/public/docs`, {}))
@@ -159751,9 +160802,16 @@ function buildAuthcodeAsync(parsed) {
159751
160802
  nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${appRoot}/public/blb`);
159752
160803
  nodeutil.cp("built/web/semantic.css", `${appRoot}/public/blb`);
159753
160804
  nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${appRoot}/public/blb`);
159754
- nodeutil.cp("node_modules/pxt-core/built/web/react-common-authcode.css", `${appRoot}/public/blb`);
159755
- // copy 'assets' over from docs/static
159756
- nodeutil.cpR("docs/static/authcode/assets", `${appRoot}/public/assets`);
160805
+ nodeutil.cp(`node_modules/pxt-core/built/web/react-common-${app}.css`, `${appRoot}/public/blb`);
160806
+ if (opts.copyAssets) {
160807
+ // copy 'assets' over from docs/static
160808
+ nodeutil.cpR(`docs/static/${app}/assets`, `${appRoot}/public/assets`);
160809
+ }
160810
+ if (docsPath) {
160811
+ // copy docs over from specified path
160812
+ nodeutil.cpR(`docs/${docsPath}`, `${appRoot}/public/docs/${docsPath}`);
160813
+ nodeutil.cpR(`docs/static/${docsPath}`, `${appRoot}/public/static/${docsPath}`);
160814
+ }
159757
160815
  return nodeutil.spawnAsync({
159758
160816
  cmd: os.platform() === "win32" ? "npm.cmd" : "npm",
159759
160817
  args: ["run-script", "start"],
@@ -159762,6 +160820,15 @@ function buildAuthcodeAsync(parsed) {
159762
160820
  });
159763
160821
  });
159764
160822
  }
160823
+ function buildSkillMapAsync(parsed) {
160824
+ return buildReactAppAsync("skillmap", parsed);
160825
+ }
160826
+ function buildAuthcodeAsync(parsed) {
160827
+ return buildReactAppAsync("authcode", parsed, { copyAssets: false });
160828
+ }
160829
+ function buildMultiplayerAsync(parsed) {
160830
+ return buildReactAppAsync("multiplayer", parsed, { copyAssets: false });
160831
+ }
159765
160832
  function updateDefaultProjects(cfg) {
159766
160833
  let defaultProjects = [
159767
160834
  pxt.BLOCKS_PROJECT_NAME,
@@ -164153,9 +165220,30 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
164153
165220
  flags: {
164154
165221
  serve: {
164155
165222
  description: "Serve the authcode app locally after building (npm start)"
165223
+ },
165224
+ docs: {
165225
+ description: "Path to local docs folder to copy into authcode",
165226
+ type: "string",
165227
+ argument: "docs"
164156
165228
  }
164157
165229
  }
164158
165230
  }, buildAuthcodeAsync);
165231
+ p.defineCommand({
165232
+ name: "buildmultiplayer",
165233
+ aliases: ["multiplayer", "mp"],
165234
+ advanced: true,
165235
+ help: "Serves the multiplayer webapp",
165236
+ flags: {
165237
+ serve: {
165238
+ description: "Serve the multiplayer app locally after building (npm start)"
165239
+ },
165240
+ docs: {
165241
+ description: "Path to local docs folder to copy into multiplayer",
165242
+ type: "string",
165243
+ argument: "docs"
165244
+ }
165245
+ }
165246
+ }, buildMultiplayerAsync);
164159
165247
  advancedCommand("augmentdocs", "test markdown docs replacements", augmnetDocsAsync, "<temlate.md> <doc.md>");
164160
165248
  advancedCommand("crowdin", "upload, download, clean, stats files to/from crowdin", pc => crowdin.execCrowdinAsync.apply(undefined, pc.args), "<cmd> <path> [output]");
164161
165249
  advancedCommand("hidlist", "list HID devices", hid.listAsync);