pxt-core 7.5.6 → 7.5.9

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 (47) hide show
  1. package/built/pxt.js +1002 -2
  2. package/built/pxtblockly.js +432 -52
  3. package/built/pxtblocks.d.ts +34 -0
  4. package/built/pxtblocks.js +432 -52
  5. package/built/pxtlib.d.ts +19 -1
  6. package/built/pxtlib.js +125 -1
  7. package/built/pxtsim.d.ts +222 -0
  8. package/built/pxtsim.js +877 -1
  9. package/built/target.js +1 -1
  10. package/built/web/icons.css +49 -10
  11. package/built/web/main.js +1 -1
  12. package/built/web/pxtapp.js +1 -1
  13. package/built/web/pxtasseteditor.js +1 -1
  14. package/built/web/pxtblockly.js +1 -1
  15. package/built/web/pxtblocks.js +1 -1
  16. package/built/web/pxtembed.js +2 -2
  17. package/built/web/pxtlib.js +1 -1
  18. package/built/web/pxtsim.js +1 -1
  19. package/built/web/pxtworker.js +1 -1
  20. package/built/web/react-common-authcode.css +104 -1
  21. package/built/web/react-common-skillmap.css +1 -1
  22. package/built/web/rtlreact-common-skillmap.css +1 -1
  23. package/built/web/rtlsemantic.css +2 -2
  24. package/built/web/semantic.css +2 -2
  25. package/built/web/skillmap/js/main.b5f3628d.chunk.js +1 -0
  26. package/docfiles/footer.html +1 -1
  27. package/docfiles/script.html +1 -1
  28. package/docfiles/thin-footer.html +1 -1
  29. package/localtypings/pxtarget.d.ts +1 -0
  30. package/package.json +1 -1
  31. package/react-common/components/controls/Button.tsx +7 -3
  32. package/react-common/components/controls/DraggableGraph.tsx +242 -0
  33. package/react-common/components/controls/Dropdown.tsx +121 -0
  34. package/react-common/components/controls/FocusList.tsx +17 -8
  35. package/react-common/components/controls/Input.tsx +13 -3
  36. package/react-common/components/controls/RadioButtonGroup.tsx +66 -0
  37. package/react-common/components/share/ShareInfo.tsx +1 -1
  38. package/react-common/components/util.tsx +23 -0
  39. package/react-common/styles/controls/DraggableGraph.less +13 -0
  40. package/react-common/styles/controls/Dropdown.less +64 -0
  41. package/react-common/styles/controls/RadioButtonGroup.less +36 -0
  42. package/react-common/styles/react-common-variables.less +24 -0
  43. package/react-common/styles/react-common.less +3 -0
  44. package/theme/pxt.less +1 -0
  45. package/theme/soundeffecteditor.less +132 -0
  46. package/webapp/public/skillmap.html +1 -1
  47. package/built/web/skillmap/js/main.2485091f.chunk.js +0 -1
package/built/pxt.js CHANGED
@@ -113530,7 +113530,8 @@ var ts;
113530
113530
  "topblock",
113531
113531
  "callInDebugger",
113532
113532
  "duplicateShadowOnDrag",
113533
- "argsNullable"
113533
+ "argsNullable",
113534
+ "compileHiddenArguments"
113534
113535
  ];
113535
113536
  function parseCommentString(cmt) {
113536
113537
  let res = {
@@ -114448,6 +114449,125 @@ var pxt;
114448
114449
  skillmap.IndexedDBWorkspace = IndexedDBWorkspace;
114449
114450
  })(skillmap = pxt.skillmap || (pxt.skillmap = {}));
114450
114451
  })(pxt || (pxt = {}));
114452
+ var pxt;
114453
+ (function (pxt) {
114454
+ var assets;
114455
+ (function (assets) {
114456
+ function renderSoundPath(sound, width, height) {
114457
+ const { startFrequency, endFrequency, startVolume, endVolume, wave, interpolation } = sound;
114458
+ const scale = (start, end, percent) => {
114459
+ return Math.pow(start, 1 - percent) * Math.pow(end, percent);
114460
+ };
114461
+ // To make the graph appear consistent with the implementation, use a seeded random for the noise waveform.
114462
+ // The numbers are still nonsense but at least this reflects that it's deterministic.
114463
+ const random = new SeededRandom(startFrequency + endFrequency + 1);
114464
+ let getFrequencyAt;
114465
+ switch (interpolation) {
114466
+ case "linear":
114467
+ getFrequencyAt = x => startFrequency + x * (endFrequency - startFrequency) / width;
114468
+ break;
114469
+ case "curve":
114470
+ getFrequencyAt = x => startFrequency + (endFrequency - startFrequency) * Math.sin(x / width * (Math.PI / 2));
114471
+ break;
114472
+ case "logarithmic":
114473
+ getFrequencyAt = x => startFrequency + Math.log10(1 + 9 * (x / width)) * (endFrequency - startFrequency);
114474
+ break;
114475
+ }
114476
+ if (wave === "noise") {
114477
+ getFrequencyAt = () => random.randomRange(500, 1000);
114478
+ }
114479
+ const getVolumeAt = (x) => ((endVolume - startVolume) / width) * x + startVolume;
114480
+ const volumeToAmplitude = (volume) => (volume / 1023) * (height - 2) / 2;
114481
+ const frequencyToWidth = (frequency) => Math.min(width, Math.max(10, (1 / scale(1, 4000, frequency / 4000)) * width / 2));
114482
+ const parts = [`M ${2} ${height / 2}`];
114483
+ let currentX = 0;
114484
+ while (currentX < width) {
114485
+ parts.push(renderHalfWavePart(volumeToAmplitude(getVolumeAt(currentX)), frequencyToWidth(getFrequencyAt(currentX)) / 2, wave, false, random));
114486
+ currentX += frequencyToWidth(getFrequencyAt(currentX)) / 2;
114487
+ parts.push(renderHalfWavePart(volumeToAmplitude(getVolumeAt(currentX)), frequencyToWidth(getFrequencyAt(currentX)) / 2, wave, true, random));
114488
+ currentX += frequencyToWidth(getFrequencyAt(currentX)) / 2;
114489
+ }
114490
+ return parts.join(" ");
114491
+ }
114492
+ assets.renderSoundPath = renderSoundPath;
114493
+ function renderWaveSnapshot(frequency, volume, wave, width, height, timeBase) {
114494
+ // To make the graph appear consistent with the implementation, use a seeded random for the noise waveform.
114495
+ // The numbers are still nonsense but at least this reflects that it's deterministic.
114496
+ const random = new SeededRandom(frequency);
114497
+ if (wave === "noise")
114498
+ frequency = random.randomRange(500, 1000);
114499
+ const amplitude = (volume / 1023) * (height - 2) / 2;
114500
+ const waveHalfWidth = (width / (frequency * timeBase / 1000)) / 2;
114501
+ let numSegments = Math.ceil(width / (waveHalfWidth * 2));
114502
+ if (numSegments % 2 === 1)
114503
+ numSegments++;
114504
+ // Center the wave because it makes an animation look better. The overflow will be clipped
114505
+ // by the outer svg
114506
+ const parts = [`M ${(width / 2) - (numSegments * waveHalfWidth)} ${height / 2}`];
114507
+ let currentX = 0;
114508
+ for (let i = 0; i < numSegments; i++) {
114509
+ parts.push(renderHalfWavePart(amplitude, waveHalfWidth, wave, false, random));
114510
+ currentX += waveHalfWidth;
114511
+ parts.push(renderHalfWavePart(amplitude, waveHalfWidth, wave, true, random));
114512
+ currentX += waveHalfWidth;
114513
+ }
114514
+ return parts.join(" ");
114515
+ }
114516
+ assets.renderWaveSnapshot = renderWaveSnapshot;
114517
+ class SeededRandom {
114518
+ constructor(seed) {
114519
+ this.seed = seed;
114520
+ this.lfsr = seed;
114521
+ }
114522
+ next() {
114523
+ const n = this.lfsr = (this.lfsr >> 1) ^ ((-(this.lfsr & 1)) & 0xb400);
114524
+ return n / 0xffff;
114525
+ }
114526
+ randomRange(min, max) {
114527
+ return min + (max - min) * this.next();
114528
+ }
114529
+ }
114530
+ function renderHalfWavePart(amplitude, width, wave, flip, random) {
114531
+ switch (wave) {
114532
+ case "triangle":
114533
+ return `l ${width / 2} ${flip ? amplitude : -amplitude} l ${width / 2} ${flip ? -amplitude : amplitude}`;
114534
+ case "square":
114535
+ return `v ${flip ? amplitude : -amplitude} h ${width} v ${flip ? -amplitude : amplitude}`;
114536
+ case "sawtooth":
114537
+ if (flip) {
114538
+ return `l ${width} ${amplitude} v ${-amplitude}`;
114539
+ }
114540
+ else {
114541
+ return `v ${-amplitude} l ${width} ${amplitude}`;
114542
+ }
114543
+ case "sine":
114544
+ return `q ${width / 2} ${(flip ? amplitude : -amplitude) * 1.9} ${width} 0`;
114545
+ case "noise":
114546
+ const outParts = [];
114547
+ const points = [];
114548
+ const slice = Math.min(4, width / 4);
114549
+ let positive = flip;
114550
+ for (let x = 0; x < width; x += slice) {
114551
+ points.push(random.randomRange(0, amplitude) * (positive ? 1 : -1));
114552
+ positive = !positive;
114553
+ }
114554
+ points[0] = flip ? amplitude : -amplitude;
114555
+ points[points.length - 1] = 0;
114556
+ let offset = 0;
114557
+ let x = 0;
114558
+ for (const point of points) {
114559
+ let dx = Math.min(slice, width - x);
114560
+ outParts.push(`v ${point - offset} h ${dx}`);
114561
+ offset = point;
114562
+ x += dx;
114563
+ if (x >= width)
114564
+ break;
114565
+ }
114566
+ return outParts.join(" ");
114567
+ }
114568
+ }
114569
+ })(assets = pxt.assets || (pxt.assets = {}));
114570
+ })(pxt || (pxt = {}));
114451
114571
  // See https://github.com/microsoft/TouchDevelop-backend/blob/master/docs/streams.md
114452
114572
  var pxt;
114453
114573
  (function (pxt) {
@@ -114855,6 +114975,10 @@ var pxt;
114855
114975
  cb(this.d);
114856
114976
  return this.update();
114857
114977
  }
114978
+ setD(d) {
114979
+ this.setAttribute("d", d);
114980
+ return this;
114981
+ }
114858
114982
  }
114859
114983
  svgUtil.Path = Path;
114860
114984
  class Image extends Drawable {
@@ -152823,7 +152947,7 @@ var pxsim;
152823
152947
  frame.id = 'sim-frame-' + this.nextId();
152824
152948
  frame.title = pxsim.localization.lf("Simulator");
152825
152949
  frame.allowFullscreen = true;
152826
- frame.setAttribute('allow', 'autoplay');
152950
+ frame.setAttribute('allow', 'autoplay;microphone');
152827
152951
  frame.setAttribute('sandbox', 'allow-same-origin allow-scripts');
152828
152952
  frame.className = 'no-select';
152829
152953
  const furl = (url || this.getSimUrl()) + '#' + frame.id;
@@ -154379,6 +154503,882 @@ var pxsim;
154379
154503
  })(svg = pxsim.svg || (pxsim.svg = {}));
154380
154504
  })(pxsim || (pxsim = {}));
154381
154505
  var pxsim;
154506
+ (function (pxsim) {
154507
+ var codal;
154508
+ (function (codal) {
154509
+ var music;
154510
+ (function (music) {
154511
+ var MusicalIntervals;
154512
+ (function (MusicalIntervals) {
154513
+ // #if CONFIG_ENABLED(JUST_SCALE)
154514
+ // const float MusicalIntervals.chromaticInterval[] = [1.000000, 1.059463, 1.122462, 1.189207, 1.259921, 1.334840, 1.414214, 1.498307, 1.587401, 1.681793, 1.781797, 1.887749];
154515
+ // #else
154516
+ // const float MusicalIntervals.chromaticInterval[] = [1.000000, 1.0417, 1.1250, 1.2000, 1.2500, 1.3333, 1.4063, 1.5000, 1.6000, 1.6667, 1.8000, 1.8750];
154517
+ // #endif
154518
+ MusicalIntervals.chromaticInterval = [1.000000, 1.0417, 1.1250, 1.2000, 1.2500, 1.3333, 1.4063, 1.5000, 1.6000, 1.6667, 1.8000, 1.8750];
154519
+ MusicalIntervals.majorScaleInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[2], MusicalIntervals.chromaticInterval[4], MusicalIntervals.chromaticInterval[5], MusicalIntervals.chromaticInterval[7], MusicalIntervals.chromaticInterval[9], MusicalIntervals.chromaticInterval[11]];
154520
+ MusicalIntervals.minorScaleInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[2], MusicalIntervals.chromaticInterval[3], MusicalIntervals.chromaticInterval[5], MusicalIntervals.chromaticInterval[7], MusicalIntervals.chromaticInterval[8], MusicalIntervals.chromaticInterval[10]];
154521
+ MusicalIntervals.pentatonicScaleInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[2], MusicalIntervals.chromaticInterval[4], MusicalIntervals.chromaticInterval[7], MusicalIntervals.chromaticInterval[9]];
154522
+ MusicalIntervals.majorTriadInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[4], MusicalIntervals.chromaticInterval[7]];
154523
+ MusicalIntervals.minorTriadInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[3], MusicalIntervals.chromaticInterval[7]];
154524
+ MusicalIntervals.diminishedInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[3], MusicalIntervals.chromaticInterval[6], MusicalIntervals.chromaticInterval[9]];
154525
+ MusicalIntervals.wholeToneInterval = [MusicalIntervals.chromaticInterval[0], MusicalIntervals.chromaticInterval[2], MusicalIntervals.chromaticInterval[4], MusicalIntervals.chromaticInterval[6], MusicalIntervals.chromaticInterval[8], MusicalIntervals.chromaticInterval[10]];
154526
+ })(MusicalIntervals = music.MusicalIntervals || (music.MusicalIntervals = {}));
154527
+ })(music = codal.music || (codal.music = {}));
154528
+ })(codal = pxsim.codal || (pxsim.codal = {}));
154529
+ })(pxsim || (pxsim = {}));
154530
+ (function (pxsim) {
154531
+ var codal;
154532
+ (function (codal) {
154533
+ var music;
154534
+ (function (music) {
154535
+ var MusicalProgressions;
154536
+ (function (MusicalProgressions) {
154537
+ MusicalProgressions.chromatic = { interval: music.MusicalIntervals.chromaticInterval, length: 12 };
154538
+ MusicalProgressions.majorScale = { interval: music.MusicalIntervals.majorScaleInterval, length: 7 };
154539
+ MusicalProgressions.minorScale = { interval: music.MusicalIntervals.minorScaleInterval, length: 7 };
154540
+ MusicalProgressions.pentatonicScale = { interval: music.MusicalIntervals.pentatonicScaleInterval, length: 5 };
154541
+ MusicalProgressions.majorTriad = { interval: music.MusicalIntervals.majorTriadInterval, length: 3 };
154542
+ MusicalProgressions.minorTriad = { interval: music.MusicalIntervals.minorTriadInterval, length: 3 };
154543
+ MusicalProgressions.diminished = { interval: music.MusicalIntervals.diminishedInterval, length: 4 };
154544
+ MusicalProgressions.wholeTone = { interval: music.MusicalIntervals.wholeToneInterval, length: 6 };
154545
+ /**
154546
+ * Determine the frequency of a given note in a given progressions
154547
+ *
154548
+ * @param root The root frequency of the progression
154549
+ * @param progression The Progression to use
154550
+ * @param offset The offset (interval) of the note to generate
154551
+ * @return The frequency of the note requested in Hz.
154552
+ */
154553
+ function calculateFrequencyFromProgression(root, progression, offset) {
154554
+ let octave = Math.floor(offset / progression.length);
154555
+ let index = offset % progression.length;
154556
+ return root * Math.pow(2, octave) * progression.interval[index];
154557
+ }
154558
+ MusicalProgressions.calculateFrequencyFromProgression = calculateFrequencyFromProgression;
154559
+ })(MusicalProgressions = music.MusicalProgressions || (music.MusicalProgressions = {}));
154560
+ })(music = codal.music || (codal.music = {}));
154561
+ })(codal = pxsim.codal || (pxsim.codal = {}));
154562
+ })(pxsim || (pxsim = {}));
154563
+ /**
154564
+ * Adapted from lancaster-university/codal-microbit-v2
154565
+ * https://github.com/lancaster-university/codal-microbit-v2/blob/master/source/SoundEmojiSynthesizer.cpp
154566
+ */
154567
+ var pxsim;
154568
+ (function (pxsim) {
154569
+ var codal;
154570
+ (function (codal) {
154571
+ var music;
154572
+ (function (music) {
154573
+ // https://github.com/lancaster-university/codal-microbit-v2/blob/master/inc/SoundEmojiSynthesizer.h#L30
154574
+ music.EMOJI_SYNTHESIZER_SAMPLE_RATE = 44100;
154575
+ music.EMOJI_SYNTHESIZER_TONE_WIDTH_F = 1024;
154576
+ music.EMOJI_SYNTHESIZER_TONE_WIDTH = 1024;
154577
+ music.EMOJI_SYNTHESIZER_BUFFER_SIZE = 512;
154578
+ music.EMOJI_SYNTHESIZER_TONE_EFFECT_PARAMETERS = 2;
154579
+ music.EMOJI_SYNTHESIZER_TONE_EFFECTS = 3;
154580
+ music.EMOJI_SYNTHESIZER_STATUS_ACTIVE = 0x1;
154581
+ music.EMOJI_SYNTHESIZER_STATUS_OUTPUT_SILENCE_AS_EMPTY = 0x2;
154582
+ music.EMOJI_SYNTHESIZER_STATUS_STOPPING = 0x4;
154583
+ class SoundEmojiSynthesizer {
154584
+ constructor(id, sampleRate = music.EMOJI_SYNTHESIZER_SAMPLE_RATE) {
154585
+ this.samplesPerStep = [];
154586
+ this.status = 0;
154587
+ this.effectPointer = 0;
154588
+ this.position = 0;
154589
+ this.bufferSize = music.EMOJI_SYNTHESIZER_BUFFER_SIZE;
154590
+ this.sampleRate = sampleRate;
154591
+ this.samplesToWrite = 0;
154592
+ this.samplesWritten = 0;
154593
+ this.sampleRange = 1023;
154594
+ this.orMask = 0;
154595
+ this.effectPointer = -1;
154596
+ this.volume = 1;
154597
+ }
154598
+ get effect() {
154599
+ return this.effectBuffer[this.effectPointer];
154600
+ }
154601
+ play(sound) {
154602
+ this.effectBuffer = sound;
154603
+ this.effectPointer = -1;
154604
+ this.nextSoundEffect();
154605
+ }
154606
+ nextSoundEffect() {
154607
+ const hadEffect = this.effect != null;
154608
+ if (this.status & music.EMOJI_SYNTHESIZER_STATUS_STOPPING) {
154609
+ this.effectPointer = null;
154610
+ this.effectBuffer = [];
154611
+ }
154612
+ // If a sequence of SoundEffects are being played, attempt to move on to the next.
154613
+ // If not, select the first in the buffer.
154614
+ if (this.effect)
154615
+ this.effectPointer++;
154616
+ else
154617
+ this.effectPointer = 0;
154618
+ // Validate that we have a valid sound effect. If not, record that we have nothing to play.
154619
+ if (this.effectPointer >= this.effectBuffer.length) {
154620
+ // if we have an effect with a negative duration, reset the buffer (unless there is an update pending)
154621
+ this.effectPointer = 0;
154622
+ if (this.effect.duration >= 0) {
154623
+ this.effectPointer = -1;
154624
+ this.effectBuffer = [];
154625
+ this.samplesWritten = 0;
154626
+ this.samplesToWrite = 0;
154627
+ this.position = 0;
154628
+ return hadEffect;
154629
+ }
154630
+ }
154631
+ // We have a valid buffer. Set up our synthesizer to the requested parameters.
154632
+ this.samplesToWrite = this.determineSampleCount(this.effect.duration);
154633
+ this.frequency = this.effect.frequency;
154634
+ this.volume = this.effect.volume;
154635
+ this.samplesWritten = 0;
154636
+ // validate and initialise per effect rendering state.
154637
+ for (let i = 0; i < music.EMOJI_SYNTHESIZER_TONE_EFFECTS; i++) {
154638
+ this.effect.effects[i].step = 0;
154639
+ this.effect.effects[i].steps = Math.max(this.effect.effects[i].steps, 1);
154640
+ this.samplesPerStep[i] = Math.floor(this.samplesToWrite / this.effect.effects[i].steps);
154641
+ }
154642
+ return false;
154643
+ }
154644
+ pull() {
154645
+ let done = false;
154646
+ let sample;
154647
+ let bufferEnd;
154648
+ while (!done) {
154649
+ if (this.samplesWritten == this.samplesToWrite || this.status & music.EMOJI_SYNTHESIZER_STATUS_STOPPING) {
154650
+ let renderComplete = this.nextSoundEffect();
154651
+ // If we have just completed active playout of an effect, and there are no more effects scheduled,
154652
+ // unblock any fibers that may be waiting to play a sound effect.
154653
+ if (this.samplesToWrite == 0 || this.status & music.EMOJI_SYNTHESIZER_STATUS_STOPPING) {
154654
+ done = true;
154655
+ if (renderComplete || this.status & music.EMOJI_SYNTHESIZER_STATUS_STOPPING) {
154656
+ this.status &= ~music.EMOJI_SYNTHESIZER_STATUS_STOPPING;
154657
+ // Event(id, DEVICE_SOUND_EMOJI_SYNTHESIZER_EVT_DONE);
154658
+ // lock.notify();
154659
+ }
154660
+ }
154661
+ }
154662
+ // If we have something to do, ensure our buffers are created.
154663
+ // We defer creation to avoid unnecessary heap allocation when generating silence.
154664
+ if (((this.samplesWritten < this.samplesToWrite) || !(this.status & music.EMOJI_SYNTHESIZER_STATUS_OUTPUT_SILENCE_AS_EMPTY)) && sample == null) {
154665
+ this.buffer = new Array(this.bufferSize);
154666
+ sample = 0;
154667
+ bufferEnd = this.buffer.length;
154668
+ }
154669
+ // Generate some samples with the current this.effect parameters.
154670
+ while (this.samplesWritten < this.samplesToWrite) {
154671
+ let skip = ((music.EMOJI_SYNTHESIZER_TONE_WIDTH_F * this.frequency) / this.sampleRate);
154672
+ let gain = (this.sampleRange * this.volume) / 1024;
154673
+ let offset = 512 - (512 * gain);
154674
+ let effectStepEnd = [];
154675
+ for (let i = 0; i < music.EMOJI_SYNTHESIZER_TONE_EFFECTS; i++) {
154676
+ effectStepEnd[i] = (this.samplesPerStep[i] * (this.effect.effects[i].step));
154677
+ if (this.effect.effects[i].step == this.effect.effects[i].steps - 1)
154678
+ effectStepEnd[i] = this.samplesToWrite;
154679
+ }
154680
+ let stepEndPosition = effectStepEnd[0];
154681
+ for (let i = 1; i < music.EMOJI_SYNTHESIZER_TONE_EFFECTS; i++)
154682
+ stepEndPosition = Math.min(stepEndPosition, effectStepEnd[i]);
154683
+ // Write samples until the end of the next this.effect-step
154684
+ while (this.samplesWritten < stepEndPosition) {
154685
+ // Stop processing when we've filled the requested this.buffer
154686
+ if (sample == bufferEnd) {
154687
+ // downStream.pullRequest();
154688
+ return this.buffer;
154689
+ }
154690
+ // Synthesize a sample
154691
+ let s = this.effect.tone.tonePrint(this.effect.tone.parameter, this.position);
154692
+ // Apply volume scaling and OR mask (if specified).
154693
+ this.buffer[sample] = (((s * gain) + offset)); // | this.orMask;
154694
+ // Move on our pointers.
154695
+ sample++;
154696
+ this.samplesWritten++;
154697
+ this.position += skip;
154698
+ // Keep our toneprint pointer in range
154699
+ while (this.position > music.EMOJI_SYNTHESIZER_TONE_WIDTH_F)
154700
+ this.position -= music.EMOJI_SYNTHESIZER_TONE_WIDTH_F;
154701
+ }
154702
+ // Invoke the this.effect function for any effects that are due.
154703
+ for (let i = 0; i < music.EMOJI_SYNTHESIZER_TONE_EFFECTS; i++) {
154704
+ if (this.samplesWritten == effectStepEnd[i]) {
154705
+ if (this.effect.effects[i].step < this.effect.effects[i].steps) {
154706
+ if (this.effect.effects[i].effect)
154707
+ this.effect.effects[i].effect(this, this.effect.effects[i]);
154708
+ this.effect.effects[i].step++;
154709
+ }
154710
+ }
154711
+ }
154712
+ }
154713
+ }
154714
+ // if we have no data to send, return an empty this.buffer (if requested)
154715
+ if (sample == null) {
154716
+ this.buffer = [];
154717
+ }
154718
+ else {
154719
+ // Pad the output this.buffer with silence if necessary.
154720
+ const silence = (this.sampleRange * 0.5); // | this.orMask;
154721
+ while (sample < bufferEnd) {
154722
+ this.buffer[sample] = silence;
154723
+ sample++;
154724
+ }
154725
+ }
154726
+ // Issue a Pull Request so that we are always receiver driven, and we're done.
154727
+ // downStream.pullRequest();
154728
+ return this.buffer;
154729
+ }
154730
+ determineSampleCount(playoutTime) {
154731
+ if (playoutTime < 0)
154732
+ playoutTime = -playoutTime;
154733
+ const seconds = playoutTime / 1000;
154734
+ return Math.floor(this.sampleRate * seconds);
154735
+ }
154736
+ totalDuration() {
154737
+ let duration = 0;
154738
+ for (const effect of this.effectBuffer)
154739
+ duration += effect.duration;
154740
+ return duration;
154741
+ }
154742
+ }
154743
+ music.SoundEmojiSynthesizer = SoundEmojiSynthesizer;
154744
+ })(music = codal.music || (codal.music = {}));
154745
+ })(codal = pxsim.codal || (pxsim.codal = {}));
154746
+ })(pxsim || (pxsim = {}));
154747
+ /**
154748
+ * Adapted from lancaster-university/codal-core
154749
+ * https://github.com/lancaster-university/codal-core/blob/master/source/streams/Synthesizer.cpp#L54
154750
+ */
154751
+ var pxsim;
154752
+ (function (pxsim) {
154753
+ var codal;
154754
+ (function (codal) {
154755
+ var music;
154756
+ (function (music) {
154757
+ var Synthesizer;
154758
+ (function (Synthesizer) {
154759
+ const sineTone = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 45, 46, 47, 49, 50, 51, 53, 54, 56, 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, 79, 81, 82, 84, 86, 87, 89, 91, 93, 95, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 141, 143, 145, 147, 149, 152, 154, 156, 158, 161, 163, 165, 167, 170, 172, 175, 177, 179, 182, 184, 187, 189, 191, 194, 196, 199, 201, 204, 206, 209, 211, 214, 216, 219, 222, 224, 227, 229, 232, 235, 237, 240, 243, 245, 248, 251, 253, 256, 259, 262, 264, 267, 270, 273, 275, 278, 281, 284, 287, 289, 292, 295, 298, 301, 304, 307, 309, 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, 381, 384, 387, 390, 393, 396, 399, 402, 405, 408, 411, 414, 417, 420, 424, 427, 430, 433, 436, 439, 442, 445, 448, 452, 455, 458, 461, 464, 467, 470, 473, 477, 480, 483, 486, 489, 492, 495, 498, 502, 505, 508, 511, 514, 517, 520, 524, 527, 530, 533, 536, 539, 542, 545, 549, 552, 555, 558, 561, 564, 567, 570, 574, 577, 580, 583, 586, 589, 592, 595, 598, 602, 605, 608, 611, 614, 617, 620, 623, 626, 629, 632, 635, 638, 641, 644, 647, 650, 653, 656, 659, 662, 665, 668, 671, 674, 677, 680, 683, 686, 689, 692, 695, 698, 701, 704, 707, 710, 713, 715, 718, 721, 724, 727, 730, 733, 735, 738, 741, 744, 747, 749, 752, 755, 758, 760, 763, 766, 769, 771, 774, 777, 779, 782, 785, 787, 790, 793, 795, 798, 800, 803, 806, 808, 811, 813, 816, 818, 821, 823, 826, 828, 831, 833, 835, 838, 840, 843, 845, 847, 850, 852, 855, 857, 859, 861, 864, 866, 868, 870, 873, 875, 877, 879, 881, 884, 886, 888, 890, 892, 894, 896, 898, 900, 902, 904, 906, 908, 910, 912, 914, 916, 918, 920, 922, 924, 926, 927, 929, 931, 933, 935, 936, 938, 940, 941, 943, 945, 946, 948, 950, 951, 953, 954, 956, 958, 959, 961, 962, 964, 965, 966, 968, 969, 971, 972, 973, 975, 976, 977, 979, 980, 981, 982, 984, 985, 986, 987, 988, 989, 990, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1006, 1007, 1008, 1009, 1009, 1010, 1011, 1011, 1012, 1013, 1013, 1014, 1014, 1015, 1015, 1016, 1016, 1017, 1017, 1018, 1018, 1019, 1019, 1019, 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1023, 1022];
154760
+ const TONE_WIDTH = 1024;
154761
+ function SineTone(arg, position) {
154762
+ position |= 0;
154763
+ let off = TONE_WIDTH - position;
154764
+ if (off < TONE_WIDTH / 2)
154765
+ position = off;
154766
+ return sineTone[position];
154767
+ }
154768
+ Synthesizer.SineTone = SineTone;
154769
+ function SawtoothTone(arg, position) {
154770
+ return position;
154771
+ }
154772
+ Synthesizer.SawtoothTone = SawtoothTone;
154773
+ function TriangleTone(arg, position) {
154774
+ return position < 512 ? position * 2 : (1023 - position) * 2;
154775
+ }
154776
+ Synthesizer.TriangleTone = TriangleTone;
154777
+ function NoiseTone(arg, position) {
154778
+ // deterministic, semi-random noise
154779
+ let mult = arg[0];
154780
+ if (mult == 0)
154781
+ mult = 7919;
154782
+ return (position * mult) & 1023;
154783
+ }
154784
+ Synthesizer.NoiseTone = NoiseTone;
154785
+ function SquareWaveTone(arg, position) {
154786
+ return position < 512 ? 1023 : 0;
154787
+ }
154788
+ Synthesizer.SquareWaveTone = SquareWaveTone;
154789
+ })(Synthesizer = music.Synthesizer || (music.Synthesizer = {}));
154790
+ })(music = codal.music || (codal.music = {}));
154791
+ })(codal = pxsim.codal || (pxsim.codal = {}));
154792
+ })(pxsim || (pxsim = {}));
154793
+ /**
154794
+ * Adapted from lancaster-university/codal-microbit-v2
154795
+ * https://github.com/lancaster-university/codal-microbit-v2/blob/master/source/SoundSynthesizerEffects.cpp
154796
+ */
154797
+ var pxsim;
154798
+ (function (pxsim) {
154799
+ var codal;
154800
+ (function (codal) {
154801
+ var music;
154802
+ (function (music) {
154803
+ var SoundSynthesizerEffects;
154804
+ (function (SoundSynthesizerEffects) {
154805
+ /*
154806
+ * Definitions of standard progressions.
154807
+ */
154808
+ /**
154809
+ * Root Frequency Interpolation Effect Functions
154810
+ */
154811
+ function noInterpolation(synth, context) {
154812
+ }
154813
+ SoundSynthesizerEffects.noInterpolation = noInterpolation;
154814
+ // Linear interpolate function.
154815
+ // parameter[0]: end frequency
154816
+ function linearInterpolation(synth, context) {
154817
+ let interval = (context.parameter[0] - synth.effect.frequency) / context.steps;
154818
+ synth.frequency = synth.effect.frequency + interval * context.step;
154819
+ }
154820
+ SoundSynthesizerEffects.linearInterpolation = linearInterpolation;
154821
+ // Linear interpolate function.
154822
+ // parameter[0]: end frequency
154823
+ function logarithmicInterpolation(synth, context) {
154824
+ synth.frequency = synth.effect.frequency + (Math.log10(Math.max(context.step, 0.1)) * (context.parameter[0] - synth.effect.frequency) / 1.95);
154825
+ }
154826
+ SoundSynthesizerEffects.logarithmicInterpolation = logarithmicInterpolation;
154827
+ // Curve interpolate function
154828
+ // parameter[0]: end frequency
154829
+ function curveInterpolation(synth, context) {
154830
+ synth.frequency = (Math.sin(context.step * 3.12159 / 180.0) * (context.parameter[0] - synth.effect.frequency) + synth.effect.frequency);
154831
+ }
154832
+ SoundSynthesizerEffects.curveInterpolation = curveInterpolation;
154833
+ // Cosine interpolate function
154834
+ // parameter[0]: end frequency
154835
+ function slowVibratoInterpolation(synth, context) {
154836
+ synth.frequency = Math.sin(context.step / 10) * context.parameter[0] + synth.effect.frequency;
154837
+ }
154838
+ SoundSynthesizerEffects.slowVibratoInterpolation = slowVibratoInterpolation;
154839
+ //warble function
154840
+ // parameter[0]: end frequency
154841
+ function warbleInterpolation(synth, context) {
154842
+ synth.frequency = (Math.sin(context.step) * (context.parameter[0] - synth.effect.frequency) + synth.effect.frequency);
154843
+ }
154844
+ SoundSynthesizerEffects.warbleInterpolation = warbleInterpolation;
154845
+ // Vibrato function
154846
+ // parameter[0]: end frequency
154847
+ function vibratoInterpolation(synth, context) {
154848
+ synth.frequency = synth.effect.frequency + Math.sin(context.step) * context.parameter[0];
154849
+ }
154850
+ SoundSynthesizerEffects.vibratoInterpolation = vibratoInterpolation;
154851
+ // Exponential rising function
154852
+ // parameter[0]: end frequency
154853
+ function exponentialRisingInterpolation(synth, context) {
154854
+ synth.frequency = synth.effect.frequency + Math.sin(0.01745329 * context.step) * context.parameter[0];
154855
+ }
154856
+ SoundSynthesizerEffects.exponentialRisingInterpolation = exponentialRisingInterpolation;
154857
+ // Exponential falling function
154858
+ function exponentialFallingInterpolation(synth, context) {
154859
+ synth.frequency = synth.effect.frequency + Math.cos(0.01745329 * context.step) * context.parameter[0];
154860
+ }
154861
+ SoundSynthesizerEffects.exponentialFallingInterpolation = exponentialFallingInterpolation;
154862
+ // Argeppio functions
154863
+ function appregrioAscending(synth, context) {
154864
+ synth.frequency = music.MusicalProgressions.calculateFrequencyFromProgression(synth.effect.frequency, context.parameter_p[0], context.step);
154865
+ }
154866
+ SoundSynthesizerEffects.appregrioAscending = appregrioAscending;
154867
+ function appregrioDescending(synth, context) {
154868
+ synth.frequency = music.MusicalProgressions.calculateFrequencyFromProgression(synth.effect.frequency, context.parameter_p[0], context.steps - context.step - 1);
154869
+ }
154870
+ SoundSynthesizerEffects.appregrioDescending = appregrioDescending;
154871
+ /**
154872
+ * Frequency Delta effects
154873
+ */
154874
+ // Frequency vibrato function
154875
+ // parameter[0]: vibrato frequency multiplier
154876
+ function frequencyVibratoEffect(synth, context) {
154877
+ if (context.step == 0)
154878
+ return;
154879
+ if (context.step % 2 == 0)
154880
+ synth.frequency /= context.parameter[0];
154881
+ else
154882
+ synth.frequency *= context.parameter[0];
154883
+ }
154884
+ SoundSynthesizerEffects.frequencyVibratoEffect = frequencyVibratoEffect;
154885
+ // Volume vibrato function
154886
+ // parameter[0]: vibrato volume multiplier
154887
+ function volumeVibratoEffect(synth, context) {
154888
+ if (context.step == 0)
154889
+ return;
154890
+ if (context.step % 2 == 0)
154891
+ synth.volume /= context.parameter[0];
154892
+ else
154893
+ synth.volume *= context.parameter[0];
154894
+ }
154895
+ SoundSynthesizerEffects.volumeVibratoEffect = volumeVibratoEffect;
154896
+ /**
154897
+ * Volume Delta effects
154898
+ */
154899
+ /** Simple ADSR enveleope effect.
154900
+ * parameter[0]: Centre volume
154901
+ * parameter[1]: End volume
154902
+ * effect.volume: start volume
154903
+ */
154904
+ function adsrVolumeEffect(synth, context) {
154905
+ let halfSteps = context.steps * 0.5;
154906
+ if (context.step <= halfSteps) {
154907
+ let delta = (context.parameter[0] - synth.effect.volume) / halfSteps;
154908
+ synth.volume = synth.effect.volume + context.step * delta;
154909
+ }
154910
+ else {
154911
+ let delta = (context.parameter[1] - context.parameter[0]) / halfSteps;
154912
+ synth.volume = context.parameter[0] + (context.step - halfSteps) * delta;
154913
+ }
154914
+ }
154915
+ SoundSynthesizerEffects.adsrVolumeEffect = adsrVolumeEffect;
154916
+ /**
154917
+ * Simple volume ramp effect
154918
+ * parameter[0]: End volume
154919
+ * effect.volume: start volume
154920
+ */
154921
+ function volumeRampEffect(synth, context) {
154922
+ let delta = (context.parameter[0] - synth.effect.volume) / context.steps;
154923
+ synth.volume = synth.effect.volume + context.step * delta;
154924
+ }
154925
+ SoundSynthesizerEffects.volumeRampEffect = volumeRampEffect;
154926
+ })(SoundSynthesizerEffects = music.SoundSynthesizerEffects || (music.SoundSynthesizerEffects = {}));
154927
+ })(music = codal.music || (codal.music = {}));
154928
+ })(codal = pxsim.codal || (pxsim.codal = {}));
154929
+ })(pxsim || (pxsim = {}));
154930
+ var pxsim;
154931
+ (function (pxsim) {
154932
+ var codal;
154933
+ (function (codal) {
154934
+ var music;
154935
+ (function (music) {
154936
+ let WaveShape;
154937
+ (function (WaveShape) {
154938
+ WaveShape[WaveShape["Sine"] = 0] = "Sine";
154939
+ WaveShape[WaveShape["Sawtooth"] = 1] = "Sawtooth";
154940
+ WaveShape[WaveShape["Triangle"] = 2] = "Triangle";
154941
+ WaveShape[WaveShape["Square"] = 3] = "Square";
154942
+ WaveShape[WaveShape["Noise"] = 4] = "Noise";
154943
+ })(WaveShape = music.WaveShape || (music.WaveShape = {}));
154944
+ let InterpolationEffect;
154945
+ (function (InterpolationEffect) {
154946
+ InterpolationEffect[InterpolationEffect["None"] = 0] = "None";
154947
+ InterpolationEffect[InterpolationEffect["Linear"] = 1] = "Linear";
154948
+ InterpolationEffect[InterpolationEffect["Curve"] = 2] = "Curve";
154949
+ InterpolationEffect[InterpolationEffect["ExponentialRising"] = 5] = "ExponentialRising";
154950
+ InterpolationEffect[InterpolationEffect["ExponentialFalling"] = 6] = "ExponentialFalling";
154951
+ InterpolationEffect[InterpolationEffect["ArpeggioRisingMajor"] = 8] = "ArpeggioRisingMajor";
154952
+ InterpolationEffect[InterpolationEffect["ArpeggioRisingMinor"] = 10] = "ArpeggioRisingMinor";
154953
+ InterpolationEffect[InterpolationEffect["ArpeggioRisingDiminished"] = 12] = "ArpeggioRisingDiminished";
154954
+ InterpolationEffect[InterpolationEffect["ArpeggioRisingChromatic"] = 14] = "ArpeggioRisingChromatic";
154955
+ InterpolationEffect[InterpolationEffect["ArpeggioRisingWholeTone"] = 16] = "ArpeggioRisingWholeTone";
154956
+ InterpolationEffect[InterpolationEffect["ArpeggioFallingMajor"] = 9] = "ArpeggioFallingMajor";
154957
+ InterpolationEffect[InterpolationEffect["ArpeggioFallingMinor"] = 11] = "ArpeggioFallingMinor";
154958
+ InterpolationEffect[InterpolationEffect["ArpeggioFallingDiminished"] = 13] = "ArpeggioFallingDiminished";
154959
+ InterpolationEffect[InterpolationEffect["ArpeggioFallingChromatic"] = 15] = "ArpeggioFallingChromatic";
154960
+ InterpolationEffect[InterpolationEffect["ArpeggioFallingWholeTone"] = 17] = "ArpeggioFallingWholeTone";
154961
+ InterpolationEffect[InterpolationEffect["Logarithmic"] = 18] = "Logarithmic";
154962
+ })(InterpolationEffect = music.InterpolationEffect || (music.InterpolationEffect = {}));
154963
+ let Effect;
154964
+ (function (Effect) {
154965
+ Effect[Effect["None"] = 0] = "None";
154966
+ Effect[Effect["Vibrato"] = 1] = "Vibrato";
154967
+ Effect[Effect["Tremolo"] = 2] = "Tremolo";
154968
+ Effect[Effect["Warble"] = 3] = "Warble";
154969
+ })(Effect = music.Effect || (music.Effect = {}));
154970
+ class Sound {
154971
+ constructor() {
154972
+ this.src = "000000000000000000000000000000000000000000000000000000000000000000000000";
154973
+ }
154974
+ get wave() {
154975
+ return this.getValue(0, 1);
154976
+ }
154977
+ set wave(value) {
154978
+ this.setValue(0, constrain(value, 0, 4), 1);
154979
+ }
154980
+ get volume() {
154981
+ return this.getValue(1, 4);
154982
+ }
154983
+ set volume(value) {
154984
+ this.setValue(1, constrain(value, 0, 1023), 4);
154985
+ }
154986
+ get frequency() {
154987
+ return this.getValue(5, 4);
154988
+ }
154989
+ set frequency(value) {
154990
+ this.setValue(5, value, 4);
154991
+ }
154992
+ get duration() {
154993
+ return this.getValue(9, 4);
154994
+ }
154995
+ set duration(value) {
154996
+ this.setValue(9, value, 4);
154997
+ }
154998
+ get shape() {
154999
+ return this.getValue(13, 2);
155000
+ }
155001
+ set shape(value) {
155002
+ this.setValue(13, value, 2);
155003
+ }
155004
+ get endFrequency() {
155005
+ return this.getValue(18, 4);
155006
+ }
155007
+ set endFrequency(value) {
155008
+ this.setValue(18, value, 4);
155009
+ }
155010
+ get endVolume() {
155011
+ return this.getValue(26, 4);
155012
+ }
155013
+ set endVolume(value) {
155014
+ this.setValue(26, constrain(value, 0, 1023), 4);
155015
+ }
155016
+ get steps() {
155017
+ return this.getValue(30, 4);
155018
+ }
155019
+ set steps(value) {
155020
+ this.setValue(30, value, 4);
155021
+ }
155022
+ get fx() {
155023
+ return this.getValue(34, 2);
155024
+ }
155025
+ set fx(value) {
155026
+ this.setValue(34, constrain(value, 0, 3), 2);
155027
+ }
155028
+ get fxParam() {
155029
+ return this.getValue(36, 4);
155030
+ }
155031
+ set fxParam(value) {
155032
+ this.setValue(36, value, 4);
155033
+ }
155034
+ get fxnSteps() {
155035
+ return this.getValue(40, 4);
155036
+ }
155037
+ set fxnSteps(value) {
155038
+ this.setValue(40, value, 4);
155039
+ }
155040
+ get frequencyRandomness() {
155041
+ return this.getValue(44, 4);
155042
+ }
155043
+ set frequencyRandomness(value) {
155044
+ this.setValue(44, value, 4);
155045
+ }
155046
+ get endFrequencyRandomness() {
155047
+ return this.getValue(48, 4);
155048
+ }
155049
+ set endFrequencyRandomness(value) {
155050
+ this.setValue(48, value, 4);
155051
+ }
155052
+ get volumeRandomness() {
155053
+ return this.getValue(52, 4);
155054
+ }
155055
+ set volumeRandomness(value) {
155056
+ this.setValue(52, value, 4);
155057
+ }
155058
+ get endVolumeRandomness() {
155059
+ return this.getValue(56, 4);
155060
+ }
155061
+ set endVolumeRandomness(value) {
155062
+ this.setValue(56, value, 4);
155063
+ }
155064
+ get durationRandomness() {
155065
+ return this.getValue(60, 4);
155066
+ }
155067
+ set durationRandomness(value) {
155068
+ this.setValue(60, value, 4);
155069
+ }
155070
+ get fxParamRandomness() {
155071
+ return this.getValue(64, 4);
155072
+ }
155073
+ set fxParamRandomness(value) {
155074
+ this.setValue(64, value, 4);
155075
+ }
155076
+ get fxnStepsRandomness() {
155077
+ return this.getValue(68, 4);
155078
+ }
155079
+ set fxnStepsRandomness(value) {
155080
+ this.setValue(68, value, 4);
155081
+ }
155082
+ copy() {
155083
+ const result = new Sound();
155084
+ result.src = this.src.slice(0);
155085
+ return result;
155086
+ }
155087
+ setValue(offset, value, length) {
155088
+ value = constrain(value | 0, 0, Math.pow(10, length) - 1);
155089
+ this.src = this.src.substr(0, offset) + formatNumber(value, length) + this.src.substr(offset + length);
155090
+ }
155091
+ getValue(offset, length) {
155092
+ return parseInt(this.src.substr(offset, length));
155093
+ }
155094
+ }
155095
+ music.Sound = Sound;
155096
+ function formatNumber(num, length) {
155097
+ let result = num + "";
155098
+ while (result.length < length)
155099
+ result = "0" + result;
155100
+ return result;
155101
+ }
155102
+ let soundPromise;
155103
+ function __playSoundExpression(notes, waitTillDone) {
155104
+ const cb = pxsim.getResume();
155105
+ if (!soundPromise)
155106
+ soundPromise = Promise.resolve();
155107
+ soundPromise = soundPromise.then(() => playSoundExpressionAsync(notes));
155108
+ if (!waitTillDone)
155109
+ cb();
155110
+ else
155111
+ soundPromise = soundPromise.then(cb);
155112
+ }
155113
+ music.__playSoundExpression = __playSoundExpression;
155114
+ function playSoundExpressionAsync(notes, isCancelled, onPull) {
155115
+ const synth = new music.SoundEmojiSynthesizer(0);
155116
+ const soundEffects = parseSoundEffects(notes);
155117
+ synth.play(soundEffects);
155118
+ let cancelled = false;
155119
+ return Promise.race([
155120
+ delayAsync(synth.totalDuration())
155121
+ .then(() => {
155122
+ // If safari didn't allow the sound to play for some reason,
155123
+ // it will get delayed until the user does something that
155124
+ // unmutes it. make sure we cancel it so that it doesn't
155125
+ // play long after it was supposed to
155126
+ cancelled = true;
155127
+ }),
155128
+ pxsim.AudioContextManager.playPCMBufferStreamAsync(() => {
155129
+ if (!synth.effect)
155130
+ return undefined;
155131
+ const buff = synth.pull();
155132
+ if (onPull)
155133
+ onPull(synth.frequency, synth.volume);
155134
+ const arr = new Float32Array(buff.length);
155135
+ for (let i = 0; i < buff.length; i++) {
155136
+ // Buffer is (0, 1023) we need to map it to (-1, 1)
155137
+ arr[i] = ((buff[i] - 512) / 512);
155138
+ }
155139
+ return arr;
155140
+ }, synth.sampleRate, 0.03, () => cancelled || (isCancelled && isCancelled()))
155141
+ ]);
155142
+ }
155143
+ music.playSoundExpressionAsync = playSoundExpressionAsync;
155144
+ function __stopSoundExpressions() {
155145
+ pxsim.AudioContextManager.stopAll();
155146
+ }
155147
+ music.__stopSoundExpressions = __stopSoundExpressions;
155148
+ /**
155149
+ * Adapted from lancaster-university/codal-microbit-v2
155150
+ * https://github.com/lancaster-university/codal-microbit-v2/blob/master/source/SoundExpressions.cpp
155151
+ */
155152
+ function parseSoundEffects(notes) {
155153
+ // https://github.com/lancaster-university/codal-microbit-v2/blob/master/source/SoundExpressions.cpp#L57
155154
+ // 72 characters of sound data comma separated
155155
+ const charsPerEffect = 72;
155156
+ const effectCount = Math.floor((notes.length + 1) / (charsPerEffect + 1));
155157
+ const expectedLength = effectCount * (charsPerEffect + 1) - 1;
155158
+ if (notes.length != expectedLength) {
155159
+ return [];
155160
+ }
155161
+ const soundEffects = [];
155162
+ for (let i = 0; i < effectCount; ++i) {
155163
+ const start = i * charsPerEffect + i;
155164
+ if (start > 0 && notes[start - 1] != ',') {
155165
+ return [];
155166
+ }
155167
+ const effect = blankSoundEffect();
155168
+ if (!parseSoundExpression(notes.substr(start), effect)) {
155169
+ return [];
155170
+ }
155171
+ soundEffects.push(effect);
155172
+ }
155173
+ return soundEffects;
155174
+ }
155175
+ function parseSoundExpression(soundChars, fx) {
155176
+ // https://github.com/lancaster-university/codal-microbit-v2/blob/master/source/SoundExpressions.cpp#L115
155177
+ // Encoded as a sequence of zero padded decimal strings.
155178
+ // This encoding is worth reconsidering if we can!
155179
+ // The ADSR effect (and perhaps others in future) has two parameters which cannot be expressed.
155180
+ // 72 chars total
155181
+ // [0] 0-4 wave
155182
+ let wave = parseInt(soundChars.substr(0, 1));
155183
+ // [1] 0000-1023 volume
155184
+ let effectVolume = parseInt(soundChars.substr(1, 4));
155185
+ // [5] 0000-9999 frequency
155186
+ let frequency = parseInt(soundChars.substr(5, 4));
155187
+ // [9] 0000-9999 duration
155188
+ let duration = parseInt(soundChars.substr(9, 4));
155189
+ // [13] 00 shape (specific known values)
155190
+ let shape = parseInt(soundChars.substr(13, 2));
155191
+ // [15] XXX unused/bug. This was startFrequency but we use frequency above.
155192
+ // [18] 0000-9999 end frequency
155193
+ let endFrequency = parseInt(soundChars.substr(18, 4));
155194
+ // [22] XXXX unused. This was start volume but we use volume above.
155195
+ // [26] 0000-1023 end volume
155196
+ let endVolume = parseInt(soundChars.substr(26, 4));
155197
+ // [30] 0000-9999 steps
155198
+ let steps = parseInt(soundChars.substr(30, 4));
155199
+ // [34] 00-03 fx choice
155200
+ let fxChoice = parseInt(soundChars.substr(34, 2));
155201
+ // [36] 0000-9999 fxParam
155202
+ let fxParam = parseInt(soundChars.substr(36, 4));
155203
+ // [40] 0000-9999 fxnSteps
155204
+ let fxnSteps = parseInt(soundChars.substr(40, 4));
155205
+ // Details that encoded randomness to be applied when frame is used:
155206
+ // Can the randomness cause any parameters to go out of range?
155207
+ // [44] 0000-9999 frequency random
155208
+ frequency = applyRandom(frequency, parseInt(soundChars.substr(44, 4)));
155209
+ // [48] 0000-9999 end frequency random
155210
+ endFrequency = applyRandom(endFrequency, parseInt(soundChars.substr(48, 4)));
155211
+ // [52] 0000-9999 volume random
155212
+ effectVolume = applyRandom(effectVolume, parseInt(soundChars.substr(52, 4)));
155213
+ // [56] 0000-9999 end volume random
155214
+ endVolume = applyRandom(endVolume, parseInt(soundChars.substr(56, 4)));
155215
+ // [60] 0000-9999 duration random
155216
+ duration = applyRandom(duration, parseInt(soundChars.substr(60, 4)));
155217
+ // [64] 0000-9999 fxParamRandom
155218
+ fxParam = applyRandom(fxParam, parseInt(soundChars.substr(64, 4)));
155219
+ // [68] 0000-9999 fxnStepsRandom
155220
+ fxnSteps = applyRandom(fxnSteps, parseInt(soundChars.substr(68, 4)));
155221
+ if (frequency == -1 || endFrequency == -1 || effectVolume == -1 || endVolume == -1 || duration == -1 || fxParam == -1 || fxnSteps == -1) {
155222
+ return false;
155223
+ }
155224
+ let volumeScaleFactor = 1;
155225
+ switch (wave) {
155226
+ case 0:
155227
+ fx.tone.tonePrint = music.Synthesizer.SineTone;
155228
+ break;
155229
+ case 1:
155230
+ fx.tone.tonePrint = music.Synthesizer.SawtoothTone;
155231
+ break;
155232
+ case 2:
155233
+ fx.tone.tonePrint = music.Synthesizer.TriangleTone;
155234
+ break;
155235
+ case 3:
155236
+ fx.tone.tonePrint = music.Synthesizer.SquareWaveTone;
155237
+ break;
155238
+ case 4:
155239
+ fx.tone.tonePrint = music.Synthesizer.NoiseTone;
155240
+ break;
155241
+ }
155242
+ fx.frequency = frequency;
155243
+ fx.duration = duration;
155244
+ fx.effects[0].steps = steps;
155245
+ switch (shape) {
155246
+ case 0:
155247
+ fx.effects[0].effect = music.SoundSynthesizerEffects.noInterpolation;
155248
+ break;
155249
+ case 1:
155250
+ fx.effects[0].effect = music.SoundSynthesizerEffects.linearInterpolation;
155251
+ fx.effects[0].parameter[0] = endFrequency;
155252
+ break;
155253
+ case 2:
155254
+ fx.effects[0].effect = music.SoundSynthesizerEffects.curveInterpolation;
155255
+ fx.effects[0].parameter[0] = endFrequency;
155256
+ break;
155257
+ case 5:
155258
+ fx.effects[0].effect = music.SoundSynthesizerEffects.exponentialRisingInterpolation;
155259
+ fx.effects[0].parameter[0] = endFrequency;
155260
+ break;
155261
+ case 6:
155262
+ fx.effects[0].effect = music.SoundSynthesizerEffects.exponentialFallingInterpolation;
155263
+ fx.effects[0].parameter[0] = endFrequency;
155264
+ break;
155265
+ case 8: // various ascending scales - see next switch
155266
+ case 10:
155267
+ case 12:
155268
+ case 14:
155269
+ case 16:
155270
+ fx.effects[0].effect = music.SoundSynthesizerEffects.appregrioAscending;
155271
+ break;
155272
+ case 9: // various descending scales - see next switch
155273
+ case 11:
155274
+ case 13:
155275
+ case 15:
155276
+ case 17:
155277
+ fx.effects[0].effect = music.SoundSynthesizerEffects.appregrioDescending;
155278
+ break;
155279
+ case 18:
155280
+ fx.effects[0].effect = music.SoundSynthesizerEffects.logarithmicInterpolation;
155281
+ fx.effects[0].parameter[0] = endFrequency;
155282
+ break;
155283
+ }
155284
+ // Scale
155285
+ switch (shape) {
155286
+ case 8:
155287
+ case 9:
155288
+ fx.effects[0].parameter_p[0] = music.MusicalProgressions.majorScale;
155289
+ break;
155290
+ case 10:
155291
+ case 11:
155292
+ fx.effects[0].parameter_p[0] = music.MusicalProgressions.minorScale;
155293
+ break;
155294
+ case 12:
155295
+ case 13:
155296
+ fx.effects[0].parameter_p[0] = music.MusicalProgressions.diminished;
155297
+ break;
155298
+ case 14:
155299
+ case 15:
155300
+ fx.effects[0].parameter_p[0] = music.MusicalProgressions.chromatic;
155301
+ break;
155302
+ case 16:
155303
+ case 17:
155304
+ fx.effects[0].parameter_p[0] = music.MusicalProgressions.wholeTone;
155305
+ break;
155306
+ }
155307
+ // Volume envelope
155308
+ let effectVolumeFloat = CLAMP(0, effectVolume, 1023) / 1023.0;
155309
+ let endVolumeFloat = CLAMP(0, endVolume, 1023) / 1023.0;
155310
+ fx.volume = volumeScaleFactor * effectVolumeFloat;
155311
+ fx.effects[1].effect = music.SoundSynthesizerEffects.volumeRampEffect;
155312
+ fx.effects[1].steps = 36;
155313
+ fx.effects[1].parameter[0] = volumeScaleFactor * endVolumeFloat;
155314
+ // Vibrato effect
155315
+ // Steps need to be spread across duration evenly.
155316
+ let normalizedFxnSteps = Math.round(fx.duration / 10000 * fxnSteps);
155317
+ switch (fxChoice) {
155318
+ case 1:
155319
+ fx.effects[2].steps = normalizedFxnSteps;
155320
+ fx.effects[2].effect = music.SoundSynthesizerEffects.frequencyVibratoEffect;
155321
+ fx.effects[2].parameter[0] = fxParam;
155322
+ break;
155323
+ case 2:
155324
+ fx.effects[2].steps = normalizedFxnSteps;
155325
+ fx.effects[2].effect = music.SoundSynthesizerEffects.volumeVibratoEffect;
155326
+ fx.effects[2].parameter[0] = fxParam;
155327
+ break;
155328
+ case 3:
155329
+ fx.effects[2].steps = normalizedFxnSteps;
155330
+ fx.effects[2].effect = music.SoundSynthesizerEffects.warbleInterpolation;
155331
+ fx.effects[2].parameter[0] = fxParam;
155332
+ break;
155333
+ }
155334
+ return true;
155335
+ }
155336
+ music.parseSoundExpression = parseSoundExpression;
155337
+ function random(max) {
155338
+ return Math.floor(Math.random() * max);
155339
+ }
155340
+ function CLAMP(min, value, max) {
155341
+ return Math.min(max, Math.max(min, value));
155342
+ }
155343
+ function applyRandom(value, rand) {
155344
+ if (value < 0 || rand < 0) {
155345
+ return -1;
155346
+ }
155347
+ const delta = random(rand * 2 + 1) - rand;
155348
+ return Math.abs(value + delta);
155349
+ }
155350
+ function blankSoundEffect() {
155351
+ const res = {
155352
+ frequency: 0,
155353
+ volume: 1,
155354
+ duration: 0,
155355
+ tone: {
155356
+ tonePrint: undefined,
155357
+ parameter: [0]
155358
+ },
155359
+ effects: []
155360
+ };
155361
+ for (let i = 0; i < music.EMOJI_SYNTHESIZER_TONE_EFFECTS; i++) {
155362
+ res.effects.push({
155363
+ effect: undefined,
155364
+ step: 0,
155365
+ steps: 0,
155366
+ parameter: [],
155367
+ parameter_p: []
155368
+ });
155369
+ }
155370
+ return res;
155371
+ }
155372
+ function delayAsync(millis) {
155373
+ return new Promise(resolve => setTimeout(resolve, millis));
155374
+ }
155375
+ function constrain(val, min, max) {
155376
+ return Math.min(Math.max(val, min), max);
155377
+ }
155378
+ })(music = codal.music || (codal.music = {}));
155379
+ })(codal = pxsim.codal || (pxsim.codal = {}));
155380
+ })(pxsim || (pxsim = {}));
155381
+ var pxsim;
154382
155382
  (function (pxsim) {
154383
155383
  class Button {
154384
155384
  constructor(id) {