pxt-core 7.5.8 → 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.
- package/built/pxt.js +1002 -2
- package/built/pxtblockly.js +428 -50
- package/built/pxtblocks.d.ts +34 -0
- package/built/pxtblocks.js +428 -50
- package/built/pxtlib.d.ts +19 -1
- package/built/pxtlib.js +125 -1
- package/built/pxtsim.d.ts +222 -0
- package/built/pxtsim.js +877 -1
- package/built/target.js +1 -1
- package/built/web/icons.css +49 -10
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtblockly.js +1 -1
- package/built/web/pxtblocks.js +1 -1
- package/built/web/pxtembed.js +2 -2
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtsim.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/react-common-authcode.css +104 -1
- package/built/web/react-common-skillmap.css +1 -1
- package/built/web/rtlreact-common-skillmap.css +1 -1
- package/built/web/rtlsemantic.css +2 -2
- package/built/web/semantic.css +2 -2
- package/built/web/skillmap/js/main.b5f3628d.chunk.js +1 -0
- package/docfiles/footer.html +1 -1
- package/docfiles/script.html +1 -1
- package/docfiles/thin-footer.html +1 -1
- package/localtypings/pxtarget.d.ts +1 -0
- package/package.json +1 -1
- package/react-common/components/controls/Button.tsx +7 -3
- package/react-common/components/controls/DraggableGraph.tsx +242 -0
- package/react-common/components/controls/Dropdown.tsx +121 -0
- package/react-common/components/controls/FocusList.tsx +17 -8
- package/react-common/components/controls/Input.tsx +13 -3
- package/react-common/components/controls/RadioButtonGroup.tsx +66 -0
- package/react-common/components/util.tsx +23 -0
- package/react-common/styles/controls/DraggableGraph.less +13 -0
- package/react-common/styles/controls/Dropdown.less +64 -0
- package/react-common/styles/controls/RadioButtonGroup.less +36 -0
- package/react-common/styles/react-common-variables.less +24 -0
- package/react-common/styles/react-common.less +3 -0
- package/theme/pxt.less +1 -0
- package/theme/soundeffecteditor.less +132 -0
- package/webapp/public/skillmap.html +1 -1
- 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) {
|