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/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);
@@ -105222,6 +105230,7 @@ var pxt;
105222
105230
  .then(resp => handleResponseAsync(resp));
105223
105231
  }
105224
105232
  function handleResponseAsync(resp) {
105233
+ var _a, _b, _c;
105225
105234
  const code = resp.statusCode;
105226
105235
  const errorData = pxt.Util.jsonTryParse(resp.text) || {};
105227
105236
  pxt.debug(`upload result: ${code}`);
@@ -105229,16 +105238,22 @@ var pxt;
105229
105238
  pxt.log(`create new translation file: ${filename}`);
105230
105239
  return uploadAsync("add-file", {});
105231
105240
  }
105232
- else if (code == 404 && errorData.error && errorData.error.code == 17) {
105241
+ else if (code == 404 && ((_a = errorData.error) === null || _a === void 0 ? void 0 : _a.code) == 17) {
105233
105242
  return createDirectoryAsync(branch, prj, key, filename.replace(/\/[^\/]+$/, ""), incr)
105234
105243
  .then(() => startAsync());
105235
105244
  }
105236
- else if (!errorData.success && errorData.error && errorData.error.code == 53) {
105245
+ else if (!errorData.success && ((_b = errorData.error) === null || _b === void 0 ? void 0 : _b.code) == 53) {
105237
105246
  // file is being updated
105238
105247
  pxt.log(`${filename} being updated, waiting 5s and retry...`);
105239
105248
  return pxt.U.delay(5000) // wait 5s and try again
105240
105249
  .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
105241
105250
  }
105251
+ else if (code == 429 && ((_c = errorData.error) === null || _c === void 0 ? void 0 : _c.code) == 55) {
105252
+ // Too many concurrent requests
105253
+ pxt.log(`Maximum concurrent requests reached, waiting 10s and retry...`);
105254
+ return pxt.U.delay(10 * 1000) // wait 10s and try again
105255
+ .then(() => uploadTranslationAsync(branch, prj, key, filename, data));
105256
+ }
105242
105257
  else if (code == 200 || errorData.success) {
105243
105258
  // something crowdin reports 500 with success=true
105244
105259
  return Promise.resolve();
@@ -106421,6 +106436,7 @@ var pxt;
106421
106436
  const url = new URL(`https://${endpointName}.streaming.media.azure.net/${videoID}/manifest(format=mpd-time-csf).mpd`);
106422
106437
  if (startTime) {
106423
106438
  url.hash = `t=${startTime}`;
106439
+ url.searchParams.append("startTime", startTime);
106424
106440
  }
106425
106441
  if (endTime) {
106426
106442
  url.searchParams.append("endTime", endTime);
@@ -110312,6 +110328,8 @@ var pxt;
110312
110328
  sprite_1.IMAGE_PREFIX = "image";
110313
110329
  sprite_1.ANIMATION_NAMESPACE = "myAnimations";
110314
110330
  sprite_1.ANIMATION_PREFIX = "anim";
110331
+ sprite_1.SONG_NAMESPACE = "mySongs";
110332
+ sprite_1.SONG_PREFIX = "song";
110315
110333
  /**
110316
110334
  * 16-color sprite
110317
110335
  */
@@ -111367,6 +111385,1044 @@ var pxt;
111367
111385
  })(shared = storage.shared || (storage.shared = {}));
111368
111386
  })(storage = pxt.storage || (pxt.storage = {}));
111369
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 = {}));
111370
112426
  /// <reference path="../localtypings/pxtpackage.d.ts"/>
111371
112427
  /// <reference path="../localtypings/pxtparts.d.ts"/>
111372
112428
  /// <reference path="../localtypings/pxtarget.d.ts"/>
@@ -115431,6 +116487,7 @@ var pxt;
115431
116487
  pxt.IMAGE_MIME_TYPE = "image/x-mkcd-f4";
115432
116488
  pxt.TILEMAP_MIME_TYPE = "application/mkcd-tilemap";
115433
116489
  pxt.ANIMATION_MIME_TYPE = "application/mkcd-animation";
116490
+ pxt.SONG_MIME_TYPE = "application/mkcd-song";
115434
116491
  class AssetCollection {
115435
116492
  constructor() {
115436
116493
  this.assets = [];
@@ -115617,21 +116674,24 @@ var pxt;
115617
116674
  tilemaps: new AssetCollection(),
115618
116675
  tiles: new AssetCollection(),
115619
116676
  animations: new AssetCollection(),
115620
- images: new AssetCollection()
116677
+ images: new AssetCollection(),
116678
+ songs: new AssetCollection(),
115621
116679
  };
115622
116680
  this.state = {
115623
116681
  revision: this.nextID++,
115624
116682
  tilemaps: new AssetCollection(),
115625
116683
  tiles: new AssetCollection(),
115626
116684
  animations: new AssetCollection(),
115627
- images: new AssetCollection()
116685
+ images: new AssetCollection(),
116686
+ songs: new AssetCollection(),
115628
116687
  };
115629
116688
  this.gallery = {
115630
116689
  revision: 0,
115631
116690
  tilemaps: new AssetCollection(),
115632
116691
  tiles: new AssetCollection(),
115633
116692
  animations: new AssetCollection(),
115634
- images: new AssetCollection()
116693
+ images: new AssetCollection(),
116694
+ songs: new AssetCollection(),
115635
116695
  };
115636
116696
  this.undoStack = [];
115637
116697
  this.redoStack = [];
@@ -115733,6 +116793,19 @@ var pxt;
115733
116793
  };
115734
116794
  return this.state.images.add(newImage);
115735
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
+ }
115736
116809
  updateTile(tile) {
115737
116810
  this.onChange();
115738
116811
  const existing = this.resolveProjectTileByInternalID(tile.internalID);
@@ -115769,6 +116842,7 @@ var pxt;
115769
116842
  const blob = {};
115770
116843
  this.state.images.serializeToJRes(blob);
115771
116844
  this.state.animations.serializeToJRes(blob);
116845
+ this.state.songs.serializeToJRes(blob);
115772
116846
  blob["*"] = {
115773
116847
  "mimeType": "image/x-mkcd-f4",
115774
116848
  "dataEncoding": "base64",
@@ -115850,6 +116924,7 @@ var pxt;
115850
116924
  tilemaps: this.state.tilemaps.clone(),
115851
116925
  animations: this.state.animations.clone(),
115852
116926
  tiles: this.state.tiles.clone(),
116927
+ songs: this.state.songs.clone(),
115853
116928
  };
115854
116929
  }
115855
116930
  undo() {
@@ -115862,6 +116937,7 @@ var pxt;
115862
116937
  this.state.images.applyDiff(undo.images, true);
115863
116938
  this.state.tilemaps.applyDiff(undo.tilemaps, true);
115864
116939
  this.state.animations.applyDiff(undo.animations, true);
116940
+ this.state.songs.applyDiff(undo.songs, true);
115865
116941
  this.state.revision = undo.beforeRevision;
115866
116942
  this.redoStack.push(undo);
115867
116943
  this.committedState = this.cloneState();
@@ -115875,6 +116951,7 @@ var pxt;
115875
116951
  this.state.images.applyDiff(redo.images);
115876
116952
  this.state.tilemaps.applyDiff(redo.tilemaps);
115877
116953
  this.state.animations.applyDiff(redo.animations);
116954
+ this.state.songs.applyDiff(redo.songs);
115878
116955
  this.state.revision = redo.afterRevision;
115879
116956
  this.undoStack.push(redo);
115880
116957
  this.committedState = this.cloneState();
@@ -115891,7 +116968,8 @@ var pxt;
115891
116968
  tiles: this.state.tiles.diff(this.committedState.tiles),
115892
116969
  images: this.state.images.diff(this.committedState.images),
115893
116970
  tilemaps: this.state.tilemaps.diff(this.committedState.tilemaps),
115894
- 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)
115895
116973
  });
115896
116974
  this.committedState = this.cloneState();
115897
116975
  this.cleanupTemporaryAssets();
@@ -115921,16 +116999,8 @@ var pxt;
115921
116999
  }
115922
117000
  isNameTaken(assetType, name) {
115923
117001
  const isTaken = (id) => {
115924
- switch (assetType) {
115925
- case "image" /* AssetType.Image */:
115926
- return this.state.images.isIDTaken(id) || this.gallery.images.isIDTaken(id);
115927
- case "tile" /* AssetType.Tile */:
115928
- return this.state.tiles.isIDTaken(id) || this.gallery.tiles.isIDTaken(id);
115929
- case "tilemap" /* AssetType.Tilemap */:
115930
- return this.state.tilemaps.isIDTaken(id) || this.gallery.tilemaps.isIDTaken(id);
115931
- case "animation" /* AssetType.Animation */:
115932
- return this.state.animations.isIDTaken(id) || this.gallery.animations.isIDTaken(id);
115933
- }
117002
+ return getAssetCollection(this.state, assetType).isIDTaken(id) ||
117003
+ getAssetCollection(this.gallery, assetType).isIDTaken(id);
115934
117004
  };
115935
117005
  const shortId = getShortIDCore(assetType, name);
115936
117006
  const checkShortId = shortId && shortId !== name;
@@ -115956,6 +117026,10 @@ var pxt;
115956
117026
  * assets.animation`shortId`
115957
117027
  * assets.animation`displayName`
115958
117028
  *
117029
+ * SONGS:
117030
+ * assets.song`shortId`
117031
+ * assets.song`displayName`
117032
+ *
115959
117033
  * TILEMAPS:
115960
117034
  * tilemap`shortId`
115961
117035
  *
@@ -115994,6 +117068,11 @@ var pxt;
115994
117068
  if (displayName)
115995
117069
  assetTsRefs += `|assets.animation\`${displayName}\``;
115996
117070
  break;
117071
+ case "song" /* pxt.AssetType.Song */:
117072
+ assetTsRefs = `assets.song\`${shortId}\``;
117073
+ if (displayName)
117074
+ assetTsRefs += `|assets.song\`${displayName}\``;
117075
+ break;
115997
117076
  default:
115998
117077
  assetTsRefs = `assets.image\`${shortId}\``;
115999
117078
  if (displayName)
@@ -116016,6 +117095,11 @@ var pxt;
116016
117095
  if (displayName)
116017
117096
  assetPyRefs += `|assets.animation\("""${displayName}"""\)`;
116018
117097
  break;
117098
+ case "song" /* pxt.AssetType.Song */:
117099
+ assetPyRefs = `assets.song\("""${shortId}"""\)`;
117100
+ if (displayName)
117101
+ assetPyRefs += `|assets.song\("""${displayName}"""\)`;
117102
+ break;
116019
117103
  default:
116020
117104
  assetPyRefs = `assets.image\("""${shortId}"""\)`;
116021
117105
  if (displayName)
@@ -116041,65 +117125,29 @@ var pxt;
116041
117125
  return false;
116042
117126
  }
116043
117127
  lookupAsset(assetType, name) {
116044
- switch (assetType) {
116045
- case "image" /* AssetType.Image */:
116046
- return this.state.images.getByID(name) || this.gallery.images.getByID(name);
116047
- case "tile" /* AssetType.Tile */:
116048
- return this.state.tiles.getByID(name) || this.gallery.tiles.getByID(name);
116049
- case "tilemap" /* AssetType.Tilemap */:
116050
- return this.state.tilemaps.getByID(name) || this.gallery.tilemaps.getByID(name);
116051
- case "animation" /* AssetType.Animation */:
116052
- return this.state.animations.getByID(name) || this.gallery.animations.getByID(name);
116053
- }
117128
+ return getAssetCollection(this.state, assetType).getByID(name) ||
117129
+ getAssetCollection(this.gallery, assetType).getByID(name);
116054
117130
  }
116055
117131
  lookupAssetByName(assetType, name) {
116056
- switch (assetType) {
116057
- case "image" /* AssetType.Image */:
116058
- return this.state.images.getByDisplayName(name);
116059
- case "tile" /* AssetType.Tile */:
116060
- return this.state.tiles.getByDisplayName(name);
116061
- case "tilemap" /* AssetType.Tilemap */:
116062
- return this.state.tilemaps.getByDisplayName(name);
116063
- case "animation" /* AssetType.Animation */:
116064
- return this.state.animations.getByDisplayName(name);
116065
- }
117132
+ return getAssetCollection(this.state, assetType).getByDisplayName(name);
116066
117133
  }
116067
117134
  getAssets(type) {
116068
- switch (type) {
116069
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot();
116070
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot();
116071
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot();
116072
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot();
116073
- }
117135
+ return getAssetCollection(this.state, type).getSnapshot();
116074
117136
  }
116075
117137
  getGalleryAssets(type) {
116076
- switch (type) {
116077
- case "image" /* AssetType.Image */: return this.gallery.images.getSnapshot();
116078
- case "tile" /* AssetType.Tile */: return this.gallery.tiles.getSnapshot();
116079
- case "tilemap" /* AssetType.Tilemap */: return this.gallery.tilemaps.getSnapshot();
116080
- case "animation" /* AssetType.Animation */: return this.gallery.animations.getSnapshot();
116081
- }
117138
+ return getAssetCollection(this.gallery, type).getSnapshot();
116082
117139
  }
116083
117140
  lookupBlockAsset(type, blockID) {
116084
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; };
116085
- switch (type) {
116086
- case "image" /* AssetType.Image */: return this.state.images.getSnapshot(filter)[0];
116087
- case "tile" /* AssetType.Tile */: return this.state.tiles.getSnapshot(filter)[0];
116088
- case "tilemap" /* AssetType.Tilemap */: return this.state.tilemaps.getSnapshot(filter)[0];
116089
- case "animation" /* AssetType.Animation */: return this.state.animations.getSnapshot(filter)[0];
116090
- }
117142
+ return getAssetCollection(this.state, type).getSnapshot(filter)[0];
116091
117143
  }
116092
117144
  updateAsset(asset) {
116093
117145
  this.onChange();
116094
117146
  switch (asset.type) {
116095
- case "image" /* AssetType.Image */:
116096
- return this.state.images.update(asset.id, asset);
116097
117147
  case "tile" /* AssetType.Tile */:
116098
117148
  return this.updateTile(asset);
116099
- case "tilemap" /* AssetType.Tilemap */:
116100
- return this.state.tilemaps.update(asset.id, asset);
116101
- case "animation" /* AssetType.Animation */:
116102
- return this.state.animations.update(asset.id, asset);
117149
+ default:
117150
+ return getAssetCollection(this.state, asset.type).update(asset.id, asset);
116103
117151
  }
116104
117152
  }
116105
117153
  duplicateAsset(asset, displayName) {
@@ -116121,53 +117169,22 @@ var pxt;
116121
117169
  break;
116122
117170
  case "animation" /* AssetType.Animation */:
116123
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;
116124
117176
  }
116125
117177
  return newAsset;
116126
117178
  }
116127
117179
  removeAsset(asset) {
116128
117180
  this.onChange();
116129
- switch (asset.type) {
116130
- case "image" /* AssetType.Image */:
116131
- return this.state.images.removeByID(asset.id);
116132
- case "tile" /* AssetType.Tile */:
116133
- return this.state.tiles.removeByID(asset.id);
116134
- case "tilemap" /* AssetType.Tilemap */:
116135
- return this.state.tilemaps.removeByID(asset.id);
116136
- case "animation" /* AssetType.Animation */:
116137
- return this.state.animations.removeByID(asset.id);
116138
- }
117181
+ getAssetCollection(this.state, asset.type).removeByID(asset.id);
116139
117182
  }
116140
117183
  addChangeListener(asset, listener) {
116141
- switch (asset.type) {
116142
- case "image" /* AssetType.Image */:
116143
- this.state.images.addListener(asset.internalID, listener);
116144
- break;
116145
- case "tile" /* AssetType.Tile */:
116146
- this.state.tiles.addListener(asset.internalID, listener);
116147
- break;
116148
- case "tilemap" /* AssetType.Tilemap */:
116149
- this.state.tilemaps.addListener(asset.internalID, listener);
116150
- break;
116151
- case "animation" /* AssetType.Animation */:
116152
- this.state.animations.addListener(asset.internalID, listener);
116153
- break;
116154
- }
117184
+ getAssetCollection(this.state, asset.type).addListener(asset.internalID, listener);
116155
117185
  }
116156
117186
  removeChangeListener(type, listener) {
116157
- switch (type) {
116158
- case "image" /* AssetType.Image */:
116159
- this.state.images.removeListener(listener);
116160
- break;
116161
- case "tile" /* AssetType.Tile */:
116162
- this.state.tiles.removeListener(listener);
116163
- break;
116164
- case "tilemap" /* AssetType.Tilemap */:
116165
- this.state.tilemaps.removeListener(listener);
116166
- break;
116167
- case "animation" /* AssetType.Animation */:
116168
- this.state.animations.removeListener(listener);
116169
- break;
116170
- }
117187
+ getAssetCollection(this.state, type).removeListener(listener);
116171
117188
  }
116172
117189
  loadPackage(pack) {
116173
117190
  const allPackages = pack.sortedDeps();
@@ -116192,7 +117209,7 @@ var pxt;
116192
117209
  this.gallery.images.add(image);
116193
117210
  }
116194
117211
  }
116195
- else {
117212
+ else if (image.type === "animation" /* AssetType.Animation */) {
116196
117213
  if (isProject) {
116197
117214
  this.state.animations.add(image);
116198
117215
  }
@@ -116200,6 +117217,14 @@ var pxt;
116200
117217
  this.gallery.animations.add(image);
116201
117218
  }
116202
117219
  }
117220
+ else {
117221
+ if (isProject) {
117222
+ this.state.songs.add(image);
117223
+ }
117224
+ else {
117225
+ this.gallery.songs.add(image);
117226
+ }
117227
+ }
116203
117228
  }
116204
117229
  }
116205
117230
  for (const tm of getTilemaps(pack.parseJRes())) {
@@ -116276,6 +117301,9 @@ var pxt;
116276
117301
  this.state.animations.add(animation);
116277
117302
  }
116278
117303
  }
117304
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
117305
+ this.state.songs.add(this.generateSong(entry));
117306
+ }
116279
117307
  }
116280
117308
  for (const animation of toInflate) {
116281
117309
  this.state.animations.add(this.inflateAnimation(animation, this.state.images.getSnapshot()));
@@ -116286,6 +117314,7 @@ var pxt;
116286
117314
  cleanupCollection(this.state.tiles);
116287
117315
  cleanupCollection(this.state.tilemaps);
116288
117316
  cleanupCollection(this.state.animations);
117317
+ cleanupCollection(this.state.songs);
116289
117318
  function cleanupCollection(collection) {
116290
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)); });
116291
117320
  const toRemove = [];
@@ -116315,6 +117344,17 @@ var pxt;
116315
117344
  bitmap: pxt.sprite.getBitmapFromJResURL(`data:${pxt.IMAGE_MIME_TYPE};base64,${entry.data}`).data()
116316
117345
  };
116317
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
+ }
116318
117358
  generateAnimation(entry) {
116319
117359
  if (entry.dataEncoding === "json") {
116320
117360
  let data;
@@ -116368,6 +117408,8 @@ var pxt;
116368
117408
  return this.generateNewIDInternal("tile" /* AssetType.Tile */, pxt.sprite.TILE_PREFIX, pxt.sprite.TILE_NAMESPACE);
116369
117409
  case "tilemap" /* AssetType.Tilemap */:
116370
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);
116371
117413
  }
116372
117414
  }
116373
117415
  generateNewIDInternal(type, varPrefix, namespaceString) {
@@ -116405,6 +117447,9 @@ var pxt;
116405
117447
  assets.push(animation);
116406
117448
  }
116407
117449
  }
117450
+ else if (entry.mimeType === pxt.SONG_MIME_TYPE) {
117451
+ assets.push(this.generateSong(entry));
117452
+ }
116408
117453
  }
116409
117454
  for (const animation of toInflate) {
116410
117455
  assets.push(this.inflateAnimation(animation, assets));
@@ -116465,6 +117510,7 @@ var pxt;
116465
117510
  let out = "";
116466
117511
  const imageEntries = [];
116467
117512
  const animationEntries = [];
117513
+ const songEntries = [];
116468
117514
  for (const key of entries) {
116469
117515
  if (key === "*")
116470
117516
  continue;
@@ -116491,10 +117537,17 @@ var pxt;
116491
117537
  expression: `[${animation.frames.map(f => pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(f), "typescript")).join(", ")}]`
116492
117538
  });
116493
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
+ }
116494
117546
  }
116495
117547
  const warning = lf("Auto-generated code. Do not edit.");
116496
117548
  out += emitFactoryHelper("image", imageEntries);
116497
117549
  out += emitFactoryHelper("animation", animationEntries);
117550
+ out += emitFactoryHelper("song", songEntries);
116498
117551
  return `// ${warning}\nnamespace ${pxt.sprite.IMAGES_NAMESPACE} {\n${out}\n}\n// ${warning}\n`;
116499
117552
  }
116500
117553
  pxt.emitProjectImages = emitProjectImages;
@@ -116538,6 +117591,8 @@ var pxt;
116538
117591
  return Object.assign(Object.assign({}, asset), { frames: asset.frames.map(frame => cloneBitmap(frame)) });
116539
117592
  case "tilemap" /* AssetType.Tilemap */:
116540
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) });
116541
117596
  }
116542
117597
  }
116543
117598
  pxt.cloneAsset = cloneAsset;
@@ -116571,6 +117626,13 @@ var pxt;
116571
117626
  case "animation" /* AssetType.Animation */:
116572
117627
  allJRes[id] = serializeAnimation(asset);
116573
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;
116574
117636
  }
116575
117637
  }
116576
117638
  function assetEquals(a, b) {
@@ -116590,6 +117652,8 @@ var pxt;
116590
117652
  return a.interval === bAnimation.interval && pxt.U.arrayEquals(a.frames, bAnimation.frames, pxt.sprite.bitmapEquals);
116591
117653
  case "tilemap" /* AssetType.Tilemap */:
116592
117654
  return a.data.equals(b.data);
117655
+ case "song" /* AssetType.Song */:
117656
+ return pxt.assets.music.songEquals(a.song, b.song);
116593
117657
  }
116594
117658
  }
116595
117659
  pxt.assetEquals = assetEquals;
@@ -116629,11 +117693,13 @@ var pxt;
116629
117693
  return `assets.animation${leftTick}${shortId}${rightTick}`;
116630
117694
  case "tilemap" /* AssetType.Tilemap */:
116631
117695
  return `tilemap${leftTick}${shortId}${rightTick}`;
117696
+ case "song" /* AssetType.Song */:
117697
+ return `assets.song${leftTick}${shortId}${rightTick}`;
116632
117698
  }
116633
117699
  }
116634
117700
  pxt.getTSReferenceForAsset = getTSReferenceForAsset;
116635
117701
  function parseAssetTSReference(ts) {
116636
- 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);
116637
117703
  if (match) {
116638
117704
  const type = match[1] || match[2];
116639
117705
  const name = match[3].trim();
@@ -116657,6 +117723,8 @@ var pxt;
116657
117723
  return project.lookupAssetByName("tilemap" /* AssetType.Tilemap */, name) || project.lookupAsset("tilemap" /* AssetType.Tilemap */, name);
116658
117724
  case "animation":
116659
117725
  return project.lookupAssetByName("animation" /* AssetType.Animation */, name);
117726
+ case "song":
117727
+ return project.lookupAssetByName("song" /* AssetType.Song */, name);
116660
117728
  }
116661
117729
  }
116662
117730
  return undefined;
@@ -116672,6 +117740,8 @@ var pxt;
116672
117740
  return lf("level");
116673
117741
  case "animation" /* pxt.AssetType.Animation */:
116674
117742
  return lf("myAnim");
117743
+ case "song" /* pxt.AssetType.Song */:
117744
+ return lf("mySong");
116675
117745
  default:
116676
117746
  return lf("asset");
116677
117747
  }
@@ -116696,6 +117766,9 @@ var pxt;
116696
117766
  case "animation" /* AssetType.Animation */:
116697
117767
  prefix = pxt.sprite.ANIMATION_NAMESPACE + ".";
116698
117768
  break;
117769
+ case "song" /* AssetType.Song */:
117770
+ prefix = pxt.sprite.SONG_NAMESPACE + ".";
117771
+ break;
116699
117772
  }
116700
117773
  if (prefix) {
116701
117774
  if (id.startsWith(prefix)) {
@@ -116780,6 +117853,15 @@ var pxt;
116780
117853
  function read16Bit(buf, offset) {
116781
117854
  return buf[offset] | (buf[offset + 1] << 8);
116782
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
+ }
116783
117865
  })(pxt || (pxt = {}));
116784
117866
  var pxt;
116785
117867
  (function (pxt) {
@@ -120724,7 +121806,7 @@ var pxt;
120724
121806
  return undefined;
120725
121807
  if (scriptid[0] == "_" && scriptid.length == 13)
120726
121808
  return scriptid;
120727
- if (scriptid.length == 23 && /^[0-9\-]+$/.test(scriptid))
121809
+ if (scriptid.length == 23 && /^[0-9\-]+$/.test(scriptid) || scriptid.length == 24 && /^S[0-9\-]+$/.test(scriptid))
120728
121810
  return scriptid;
120729
121811
  return undefined;
120730
121812
  }
@@ -154609,7 +155691,7 @@ var pxsim;
154609
155691
  channel.gain.gain.value = 0;
154610
155692
  channel.gain.gain.setValueAtTime(volume, context().currentTime);
154611
155693
  channel.gain.connect(destination);
154612
- if (channels.length > 5)
155694
+ if (channels.length > 20)
154613
155695
  channels[0].remove();
154614
155696
  channels.push(channel);
154615
155697
  const checkCancel = () => {
@@ -154679,7 +155761,7 @@ var pxsim;
154679
155761
  let resolved = false;
154680
155762
  let ctx = context();
154681
155763
  let channel = new Channel();
154682
- if (channels.length > 5)
155764
+ if (channels.length > 20)
154683
155765
  channels[0].remove();
154684
155766
  channels.push(channel);
154685
155767
  channel.gain = ctx.createGain();
@@ -154713,6 +155795,10 @@ var pxsim;
154713
155795
  const endVolume = readUint16(instructions, i + 8);
154714
155796
  const endFrequency = readUint16(instructions, i + 10);
154715
155797
  totalDuration += duration;
155798
+ if (wave === 0) {
155799
+ currentTime += duration;
155800
+ continue;
155801
+ }
154716
155802
  const isSquareWave = 11 <= wave && wave <= 15;
154717
155803
  if (!oscillators[wave]) {
154718
155804
  oscillators[wave] = getGenerator(wave, startFrequency);
@@ -154755,7 +155841,8 @@ var pxsim;
154755
155841
  return;
154756
155842
  }
154757
155843
  const { frequency, volume } = findFrequencyAndVolumeAtTime((time - startTime) * 1000, instructions);
154758
- onPull(frequency, volume / 1024);
155844
+ if (onPull)
155845
+ onPull(frequency, volume / 1024);
154759
155846
  requestAnimationFrame(handleAnimationFrame);
154760
155847
  };
154761
155848
  requestAnimationFrame(handleAnimationFrame);
@@ -158167,7 +159254,8 @@ function pxtFileList(pref) {
158167
159254
  .concat(nodeutil.allFiles(pref + "built/web/fonts", { maxDepth: 1 }))
158168
159255
  .concat(nodeutil.allFiles(pref + "built/web/vs", { maxDepth: 4 }))
158169
159256
  .concat(nodeutil.allFiles(pref + "built/web/skillmap", { maxDepth: 4 }))
158170
- .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 }));
158171
159259
  }
158172
159260
  function semverCmp(a, b) {
158173
159261
  let parse = (s) => {
@@ -158248,7 +159336,8 @@ function ciAsync() {
158248
159336
  .then(() => buildWebStringsAsync())
158249
159337
  .then(() => crowdin.execCrowdinAsync("upload", "built/webstrings.json"))
158250
159338
  .then(() => crowdin.execCrowdinAsync("upload", "built/skillmap-strings.json"))
158251
- .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"));
158252
159341
  if (uploadApiStrings)
158253
159342
  p = p.then(() => crowdin.execCrowdinAsync("upload", "built/strings.json"));
158254
159343
  if (uploadDocs || uploadApiStrings)
@@ -158767,6 +159856,7 @@ function uploadCoreAsync(opts) {
158767
159856
  "asseteditorUrl": opts.localDir + "asseteditor.html",
158768
159857
  "skillmapUrl": opts.localDir + "skillmap.html",
158769
159858
  "authcodeUrl": opts.localDir + "authcode.html",
159859
+ "multiplayerUrl": opts.localDir + "multiplayer.html",
158770
159860
  "isStatic": true,
158771
159861
  };
158772
159862
  const targetImagePaths = targetImages.map(k => `${opts.localDir}${path.join('./docs', logos[k])}`);
@@ -158813,14 +159903,16 @@ function uploadCoreAsync(opts) {
158813
159903
  "multi.html",
158814
159904
  "asseteditor.html",
158815
159905
  "skillmap.html",
158816
- "authcode.html"
159906
+ "authcode.html",
159907
+ "multiplayer.html",
158817
159908
  ];
158818
159909
  // expandHtml is manually called on these files before upload
158819
159910
  // runs <!-- @include --> substitutions, fills in locale, etc
158820
159911
  let expandFiles = [
158821
159912
  "index.html",
158822
159913
  "skillmap.html",
158823
- "authcode.html"
159914
+ "authcode.html",
159915
+ "multiplayer.html",
158824
159916
  ];
158825
159917
  nodeutil.mkdirP("built/uploadrepl");
158826
159918
  function encodeURLs(urls) {
@@ -159614,33 +160706,29 @@ async function buildSemanticUIAsync(parsed) {
159614
160706
  ]
159615
160707
  });
159616
160708
  }
159617
- // Generate react-common css for skillmap and authcode
159618
- const skillmapFile = isPxtCore ? "react-common/styles/react-common-skillmap-core.less" :
159619
- "node_modules/pxt-core/react-common/styles/react-common-skillmap.less";
159620
- await nodeutil.spawnAsync({
159621
- cmd: "node",
159622
- args: [
159623
- lessCPath,
159624
- skillmapFile,
159625
- "built/web/react-common-skillmap.css",
159626
- "--include-path=" + lessIncludePaths
159627
- ]
159628
- });
159629
- const authcodeFile = isPxtCore ? "react-common/styles/react-common-authcode-core.less" :
159630
- "node_modules/pxt-core/react-common/styles/react-common-authcode.less";
159631
- await nodeutil.spawnAsync({
159632
- cmd: "node",
159633
- args: [
159634
- lessCPath,
159635
- authcodeFile,
159636
- "built/web/react-common-authcode.css",
159637
- "--include-path=" + lessIncludePaths
159638
- ]
159639
- });
159640
- let skillmapCss = await readFileAsync(`built/web/react-common-skillmap.css`, "utf8");
159641
- skillmapCss = await linkFontAsync("fa-solid-900", skillmapCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
159642
- skillmapCss = await linkFontAsync("fa-regular-400", skillmapCss, fontAwesomeSource, "\\.\\.\\/webfonts\\/");
159643
- 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
+ ]);
159644
160732
  // Run postcss with autoprefixer and rtlcss
159645
160733
  pxt.debug("running postcss");
159646
160734
  const postcss = require('postcss');
@@ -159660,7 +160748,7 @@ async function buildSemanticUIAsync(parsed) {
159660
160748
  autoprefixer: { browsers: browserList, add: true }
159661
160749
  });
159662
160750
  const rtlcss = require("rtlcss");
159663
- 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"];
159664
160752
  for (const cssFile of files) {
159665
160753
  const css = await readFileAsync(`built/web/${cssFile}`, "utf8");
159666
160754
  const processed = await postcss([cssnano])
@@ -159671,9 +160759,13 @@ async function buildSemanticUIAsync(parsed) {
159671
160759
  await writeFileAsync(`built/web/rtl${cssFile}`, processedRtl.css, "utf8");
159672
160760
  }
159673
160761
  if (!isPxtCore) {
159674
- // 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
159675
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");
159676
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");
159677
160769
  }
159678
160770
  }
159679
160771
  async function linkFontAsync(font, semCss, sourceDir = "node_modules/semantic-ui-less/themes/default/assets/fonts/", refDir = "fonts\\/") {
@@ -159692,47 +160784,13 @@ function buildWebStringsAsync() {
159692
160784
  nodeutil.writeFileSync("built/webstrings.json", nodeutil.stringify(webstringsJson()));
159693
160785
  return Promise.resolve();
159694
160786
  }
159695
- function buildSkillMapAsync(parsed) {
160787
+ function buildReactAppAsync(app, parsed, opts) {
160788
+ opts = opts || {
160789
+ copyAssets: true
160790
+ };
159696
160791
  // local serve
159697
- const skillmapRoot = "node_modules/pxt-core/skillmap";
159698
- const reactScriptsConfigRoot = `${skillmapRoot}/node_modules/react-scripts/config`;
160792
+ const appRoot = `node_modules/pxt-core/${app}`;
159699
160793
  const docsPath = parsed.flags["docs"];
159700
- return rimrafAsync(`${skillmapRoot}/public/blb`, {})
159701
- .then(() => rimrafAsync(`${skillmapRoot}/build/assets`, {}))
159702
- .then(() => rimrafAsync(`${skillmapRoot}/public/docs`, {}))
159703
- .then(() => rimrafAsync(`${skillmapRoot}/public/static`, {}))
159704
- .then(() => {
159705
- // read pxtarget.json, save into 'pxtTargetBundle' global variable
159706
- let cfg = readLocalPxTarget();
159707
- nodeutil.writeFileSync(`${skillmapRoot}/public/blb/target.js`, "// eslint-disable-next-line \n" + targetJsPrefix + JSON.stringify(cfg));
159708
- nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
159709
- nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
159710
- nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
159711
- nodeutil.cp("node_modules/pxt-core/built/web/react-common-skillmap.css", `${skillmapRoot}/public/blb`);
159712
- // copy 'assets' over from docs/static
159713
- nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
159714
- // copy default react-scripts webpack config into a webpack.config.base file if necessary
159715
- if (!fs.existsSync(`${reactScriptsConfigRoot}/webpack.config.base.js`)) {
159716
- nodeutil.cp(`${reactScriptsConfigRoot}/webpack.config.js`, reactScriptsConfigRoot, "webpack.config.base.js");
159717
- }
159718
- // wrap the config in our webpack.config.override for build customization
159719
- nodeutil.cp(`${skillmapRoot}/webpack.config.override.js`, reactScriptsConfigRoot, "webpack.config.js");
159720
- if (docsPath) {
159721
- // copy docs over from specified path
159722
- nodeutil.cpR(`docs/${docsPath}`, `${skillmapRoot}/public/docs/${docsPath}`);
159723
- nodeutil.cpR(`docs/static/${docsPath}`, `${skillmapRoot}/public/static/${docsPath}`);
159724
- }
159725
- return nodeutil.spawnAsync({
159726
- cmd: os.platform() === "win32" ? "npm.cmd" : "npm",
159727
- args: ["run-script", "start"],
159728
- cwd: skillmapRoot,
159729
- shell: true
159730
- });
159731
- });
159732
- }
159733
- function buildAuthcodeAsync(parsed) {
159734
- // local serve
159735
- const appRoot = "node_modules/pxt-core/authcode";
159736
160794
  return rimrafAsync(`${appRoot}/public/blb`, {})
159737
160795
  .then(() => rimrafAsync(`${appRoot}/build/assets`, {}))
159738
160796
  .then(() => rimrafAsync(`${appRoot}/public/docs`, {}))
@@ -159744,9 +160802,16 @@ function buildAuthcodeAsync(parsed) {
159744
160802
  nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${appRoot}/public/blb`);
159745
160803
  nodeutil.cp("built/web/semantic.css", `${appRoot}/public/blb`);
159746
160804
  nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${appRoot}/public/blb`);
159747
- nodeutil.cp("node_modules/pxt-core/built/web/react-common-authcode.css", `${appRoot}/public/blb`);
159748
- // copy 'assets' over from docs/static
159749
- 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
+ }
159750
160815
  return nodeutil.spawnAsync({
159751
160816
  cmd: os.platform() === "win32" ? "npm.cmd" : "npm",
159752
160817
  args: ["run-script", "start"],
@@ -159755,6 +160820,15 @@ function buildAuthcodeAsync(parsed) {
159755
160820
  });
159756
160821
  });
159757
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
+ }
159758
160832
  function updateDefaultProjects(cfg) {
159759
160833
  let defaultProjects = [
159760
160834
  pxt.BLOCKS_PROJECT_NAME,
@@ -164146,9 +165220,30 @@ ${pxt.crowdin.KEY_VARIABLE} - crowdin key
164146
165220
  flags: {
164147
165221
  serve: {
164148
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"
164149
165228
  }
164150
165229
  }
164151
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);
164152
165247
  advancedCommand("augmentdocs", "test markdown docs replacements", augmnetDocsAsync, "<temlate.md> <doc.md>");
164153
165248
  advancedCommand("crowdin", "upload, download, clean, stats files to/from crowdin", pc => crowdin.execCrowdinAsync.apply(undefined, pc.args), "<cmd> <path> [output]");
164154
165249
  advancedCommand("hidlist", "list HID devices", hid.listAsync);