pxt-core 8.2.3 → 8.2.4
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/backendutils.js +1 -1
- package/built/gdb.js +3 -3
- package/built/pxt.js +224 -90
- package/built/pxtblockly.js +21 -1
- package/built/pxtblocks.d.ts +1 -0
- package/built/pxtblocks.js +21 -1
- package/built/pxteditor.js +2 -1
- package/built/pxtlib.d.ts +1 -0
- package/built/pxtlib.js +103 -7
- package/built/pxtsim.d.ts +1 -1
- package/built/pxtsim.js +121 -83
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtblockly.js +1 -1
- package/built/web/pxtblocks.js +1 -1
- package/built/web/pxteditor.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/package.json +1 -1
package/built/backendutils.js
CHANGED
|
@@ -689,7 +689,7 @@ var pxt;
|
|
|
689
689
|
docs.prepTemplate = prepTemplate;
|
|
690
690
|
function setupRenderer(renderer) {
|
|
691
691
|
renderer.image = function (href, title, text) {
|
|
692
|
-
const endpointName = "
|
|
692
|
+
const endpointName = "makecodeprodmediaeastus-usea";
|
|
693
693
|
if (href.startsWith("youtube:")) {
|
|
694
694
|
let out = '<div class="tutorial-video-embed"><iframe class="yt-embed" src="https://www.youtube.com/embed/' + href.split(":").pop()
|
|
695
695
|
+ '" title="' + text + '" frameborder="0" ' + 'allowFullScreen ' + 'allow="autoplay; picture-in-picture"></iframe></div>';
|
package/built/gdb.js
CHANGED
|
@@ -38,16 +38,16 @@ function getBMPSerialPortsAsync() {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
else if (process.platform == "darwin") {
|
|
41
|
-
return cpExecAsync("
|
|
41
|
+
return cpExecAsync("system_profiler SPUSBDataType")
|
|
42
42
|
.then(({ stdout, stderr }) => {
|
|
43
43
|
let res = [];
|
|
44
44
|
let inBMP = false;
|
|
45
45
|
stdout.split(/\n/).forEach(ln => {
|
|
46
|
-
if (ln.indexOf("
|
|
46
|
+
if (ln.indexOf(" Black Magic Probe") >= 0)
|
|
47
47
|
inBMP = true;
|
|
48
48
|
if (!inBMP)
|
|
49
49
|
return;
|
|
50
|
-
let m = /
|
|
50
|
+
let m = / Serial Number: (\w+)/.exec(ln);
|
|
51
51
|
if (m) {
|
|
52
52
|
inBMP = false;
|
|
53
53
|
res.push("/dev/cu.usbmodem" + m[1] + "1");
|
package/built/pxt.js
CHANGED
|
@@ -106399,7 +106399,7 @@ var pxt;
|
|
|
106399
106399
|
docs.prepTemplate = prepTemplate;
|
|
106400
106400
|
function setupRenderer(renderer) {
|
|
106401
106401
|
renderer.image = function (href, title, text) {
|
|
106402
|
-
const endpointName = "
|
|
106402
|
+
const endpointName = "makecodeprodmediaeastus-usea";
|
|
106403
106403
|
if (href.startsWith("youtube:")) {
|
|
106404
106404
|
let out = '<div class="tutorial-video-embed"><iframe class="yt-embed" src="https://www.youtube.com/embed/' + href.split(":").pop()
|
|
106405
106405
|
+ '" title="' + text + '" frameborder="0" ' + 'allowFullScreen ' + 'allow="autoplay; picture-in-picture"></iframe></div>';
|
|
@@ -108186,14 +108186,17 @@ var pxt;
|
|
|
108186
108186
|
return false;
|
|
108187
108187
|
}
|
|
108188
108188
|
function isRepoBanned(repo, config) {
|
|
108189
|
+
var _a, _b;
|
|
108189
108190
|
if (isOrgBanned(repo, config))
|
|
108190
108191
|
return true;
|
|
108191
108192
|
if (!config)
|
|
108192
108193
|
return false; // don't know
|
|
108193
|
-
if (!repo
|
|
108194
|
+
if (!repo)
|
|
108194
108195
|
return true;
|
|
108196
|
+
const repoFull = (_a = repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
108197
|
+
const repoSlug = (_b = repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
108195
108198
|
if (config.bannedRepos
|
|
108196
|
-
&& config.bannedRepos.some(fn => fn.toLowerCase() ==
|
|
108199
|
+
&& config.bannedRepos.some(fn => fn && (fn.toLowerCase() == repoFull || fn.toLowerCase() == repoSlug)))
|
|
108197
108200
|
return true;
|
|
108198
108201
|
return false;
|
|
108199
108202
|
}
|
|
@@ -108207,13 +108210,15 @@ var pxt;
|
|
|
108207
108210
|
return false;
|
|
108208
108211
|
}
|
|
108209
108212
|
function isRepoApproved(repo, config) {
|
|
108210
|
-
var _a;
|
|
108213
|
+
var _a, _b;
|
|
108211
108214
|
if (isOrgApproved(repo, config))
|
|
108212
108215
|
return true;
|
|
108213
|
-
|
|
108216
|
+
const repoFull = (_a = repo === null || repo === void 0 ? void 0 : repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
108217
|
+
const repoSlug = (_b = repo === null || repo === void 0 ? void 0 : repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
108218
|
+
if (!(config === null || config === void 0 ? void 0 : config.approvedRepoLib) || !(repoFull || repoSlug))
|
|
108214
108219
|
return false;
|
|
108215
|
-
if (
|
|
108216
|
-
|
|
108220
|
+
if (config.approvedRepoLib[repoFull]
|
|
108221
|
+
|| config.approvedRepoLib[repoSlug])
|
|
108217
108222
|
return true;
|
|
108218
108223
|
return false;
|
|
108219
108224
|
}
|
|
@@ -114591,6 +114596,97 @@ var pxt;
|
|
|
114591
114596
|
return outParts.join(" ");
|
|
114592
114597
|
}
|
|
114593
114598
|
}
|
|
114599
|
+
function soundToInstructionBuffer(sound, fxSteps, fxRange) {
|
|
114600
|
+
const { startFrequency, endFrequency, startVolume, endVolume, interpolation, duration } = sound;
|
|
114601
|
+
const steps = [];
|
|
114602
|
+
// Optimize the simple case
|
|
114603
|
+
if (sound.interpolation === "linear" && sound.effect === "none") {
|
|
114604
|
+
steps.push({
|
|
114605
|
+
frequency: startFrequency,
|
|
114606
|
+
volume: (startVolume / assets.MAX_VOLUME) * 1024,
|
|
114607
|
+
});
|
|
114608
|
+
steps.push({
|
|
114609
|
+
frequency: endFrequency,
|
|
114610
|
+
volume: (endVolume / assets.MAX_VOLUME) * 1024,
|
|
114611
|
+
});
|
|
114612
|
+
}
|
|
114613
|
+
else {
|
|
114614
|
+
fxSteps = Math.min(fxSteps, Math.floor(duration / 5));
|
|
114615
|
+
const getVolumeAt = (t) => ((startVolume + t * (endVolume - startVolume) / duration) / assets.MAX_VOLUME) * 1024;
|
|
114616
|
+
let getFrequencyAt;
|
|
114617
|
+
switch (interpolation) {
|
|
114618
|
+
case "linear":
|
|
114619
|
+
getFrequencyAt = t => startFrequency + t * (endFrequency - startFrequency) / duration;
|
|
114620
|
+
break;
|
|
114621
|
+
case "curve":
|
|
114622
|
+
getFrequencyAt = t => startFrequency + (endFrequency - startFrequency) * Math.sin(t / duration * (Math.PI / 2));
|
|
114623
|
+
break;
|
|
114624
|
+
case "logarithmic":
|
|
114625
|
+
getFrequencyAt = t => startFrequency + Math.log10(1 + 9 * (t / duration)) * (endFrequency - startFrequency);
|
|
114626
|
+
break;
|
|
114627
|
+
}
|
|
114628
|
+
const timeSlice = duration / fxSteps;
|
|
114629
|
+
for (let i = 0; i < fxSteps; i++) {
|
|
114630
|
+
const newStep = {
|
|
114631
|
+
frequency: Math.max(getFrequencyAt(i * timeSlice), 1),
|
|
114632
|
+
volume: getVolumeAt(i * timeSlice)
|
|
114633
|
+
};
|
|
114634
|
+
if (sound.effect === "tremolo") {
|
|
114635
|
+
if (i % 2 === 0) {
|
|
114636
|
+
newStep.volume = Math.max(newStep.volume - fxRange * 500, 0);
|
|
114637
|
+
}
|
|
114638
|
+
else {
|
|
114639
|
+
newStep.volume = Math.min(newStep.volume + fxRange * 500, 1023);
|
|
114640
|
+
}
|
|
114641
|
+
}
|
|
114642
|
+
else if (sound.effect === "vibrato") {
|
|
114643
|
+
if (i % 2 === 0) {
|
|
114644
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 100, 1);
|
|
114645
|
+
}
|
|
114646
|
+
else {
|
|
114647
|
+
newStep.frequency = newStep.frequency + fxRange * 100;
|
|
114648
|
+
}
|
|
114649
|
+
}
|
|
114650
|
+
else if (sound.effect === "warble") {
|
|
114651
|
+
if (i % 2 === 0) {
|
|
114652
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 1000, 1);
|
|
114653
|
+
}
|
|
114654
|
+
else {
|
|
114655
|
+
newStep.frequency = newStep.frequency + fxRange * 1000;
|
|
114656
|
+
}
|
|
114657
|
+
}
|
|
114658
|
+
steps.push(newStep);
|
|
114659
|
+
}
|
|
114660
|
+
}
|
|
114661
|
+
const out = new Uint8Array(12 * (steps.length - 1));
|
|
114662
|
+
const stepDuration = Math.floor(duration / (steps.length - 1));
|
|
114663
|
+
for (let i = 0; i < steps.length - 1; i++) {
|
|
114664
|
+
const offset = i * 12;
|
|
114665
|
+
out[offset] = waveToValue(sound.wave);
|
|
114666
|
+
set16BitNumber(out, offset + 2, steps[i].frequency);
|
|
114667
|
+
set16BitNumber(out, offset + 4, stepDuration);
|
|
114668
|
+
set16BitNumber(out, offset + 6, steps[i].volume);
|
|
114669
|
+
set16BitNumber(out, offset + 8, steps[i + 1].volume);
|
|
114670
|
+
set16BitNumber(out, offset + 10, steps[i + 1].frequency);
|
|
114671
|
+
}
|
|
114672
|
+
return out;
|
|
114673
|
+
}
|
|
114674
|
+
assets.soundToInstructionBuffer = soundToInstructionBuffer;
|
|
114675
|
+
function waveToValue(wave) {
|
|
114676
|
+
switch (wave) {
|
|
114677
|
+
case "square": return 15;
|
|
114678
|
+
case "sine": return 3;
|
|
114679
|
+
case "triangle": return 1;
|
|
114680
|
+
case "noise": return 18;
|
|
114681
|
+
case "sawtooth": return 2;
|
|
114682
|
+
}
|
|
114683
|
+
}
|
|
114684
|
+
function set16BitNumber(buf, offset, value) {
|
|
114685
|
+
const temp = new Uint8Array(2);
|
|
114686
|
+
new Uint16Array(temp.buffer)[0] = value | 0;
|
|
114687
|
+
buf[offset] = temp[0];
|
|
114688
|
+
buf[offset + 1] = temp[1];
|
|
114689
|
+
}
|
|
114594
114690
|
})(assets = pxt.assets || (pxt.assets = {}));
|
|
114595
114691
|
})(pxt || (pxt = {}));
|
|
114596
114692
|
// See https://github.com/microsoft/TouchDevelop-backend/blob/master/docs/streams.md
|
|
@@ -154227,92 +154323,10 @@ var pxsim;
|
|
|
154227
154323
|
.then(() => {
|
|
154228
154324
|
if (prevStop != instrStopId)
|
|
154229
154325
|
return Promise.resolve();
|
|
154230
|
-
return playInstructionsAsync(b);
|
|
154326
|
+
return playInstructionsAsync(b.data);
|
|
154231
154327
|
});
|
|
154232
154328
|
}
|
|
154233
154329
|
AudioContextManager.queuePlayInstructions = queuePlayInstructions;
|
|
154234
|
-
function playInstructionsAsync(b) {
|
|
154235
|
-
const prevStop = instrStopId;
|
|
154236
|
-
let ctx = context();
|
|
154237
|
-
let idx = 0;
|
|
154238
|
-
let ch = new Channel();
|
|
154239
|
-
let currWave = -1;
|
|
154240
|
-
let currFreq = -1;
|
|
154241
|
-
let timeOff = 0;
|
|
154242
|
-
if (channels.length > 5)
|
|
154243
|
-
channels[0].remove();
|
|
154244
|
-
channels.push(ch);
|
|
154245
|
-
/** Square waves are perceved as much louder than other sounds, so scale it down a bit to make it less jarring **/
|
|
154246
|
-
const scaleVol = (n, isSqWave) => (n / 1024) / 4 * (isSqWave ? .5 : 1);
|
|
154247
|
-
const finish = () => {
|
|
154248
|
-
ch.disconnectNodes();
|
|
154249
|
-
timeOff = 0;
|
|
154250
|
-
currWave = -1;
|
|
154251
|
-
currFreq = -1;
|
|
154252
|
-
};
|
|
154253
|
-
const loopAsync = () => {
|
|
154254
|
-
if (idx >= b.data.length || !b.data[idx])
|
|
154255
|
-
return pxsim.U.delay(timeOff).then(finish);
|
|
154256
|
-
const soundWaveIdx = b.data[idx];
|
|
154257
|
-
const freq = pxsim.BufferMethods.getNumber(b, pxsim.BufferMethods.NumberFormat.UInt16LE, idx + 2);
|
|
154258
|
-
const duration = pxsim.BufferMethods.getNumber(b, pxsim.BufferMethods.NumberFormat.UInt16LE, idx + 4);
|
|
154259
|
-
const startVol = pxsim.BufferMethods.getNumber(b, pxsim.BufferMethods.NumberFormat.UInt16LE, idx + 6);
|
|
154260
|
-
const endVol = pxsim.BufferMethods.getNumber(b, pxsim.BufferMethods.NumberFormat.UInt16LE, idx + 8);
|
|
154261
|
-
const endFreq = pxsim.BufferMethods.getNumber(b, pxsim.BufferMethods.NumberFormat.UInt16LE, idx + 10);
|
|
154262
|
-
const isSquareWave = 11 <= soundWaveIdx && soundWaveIdx <= 15;
|
|
154263
|
-
const isFilteredNoise = soundWaveIdx == 4 || (16 <= soundWaveIdx && soundWaveIdx <= 18);
|
|
154264
|
-
const scaledStart = scaleVol(startVol, isSquareWave);
|
|
154265
|
-
const scaledEnd = scaleVol(endVol, isSquareWave);
|
|
154266
|
-
if (!ctx || prevStop != instrStopId)
|
|
154267
|
-
return pxsim.U.delay(duration);
|
|
154268
|
-
if (currWave != soundWaveIdx || currFreq != freq || freq != endFreq) {
|
|
154269
|
-
if (ch.generator) {
|
|
154270
|
-
return pxsim.U.delay(timeOff)
|
|
154271
|
-
.then(() => {
|
|
154272
|
-
finish();
|
|
154273
|
-
return loopAsync();
|
|
154274
|
-
});
|
|
154275
|
-
}
|
|
154276
|
-
ch.generator = getGenerator(soundWaveIdx, freq);
|
|
154277
|
-
if (!ch.generator)
|
|
154278
|
-
return pxsim.U.delay(duration);
|
|
154279
|
-
currWave = soundWaveIdx;
|
|
154280
|
-
currFreq = freq;
|
|
154281
|
-
ch.gain = ctx.createGain();
|
|
154282
|
-
ch.gain.gain.value = 0;
|
|
154283
|
-
ch.gain.gain.setTargetAtTime(scaledStart, _context.currentTime, 0.015);
|
|
154284
|
-
if (endFreq != freq) {
|
|
154285
|
-
if (ch.generator.frequency != undefined) {
|
|
154286
|
-
// If generator is an OscillatorNode
|
|
154287
|
-
const param = ch.generator.frequency;
|
|
154288
|
-
param.linearRampToValueAtTime(endFreq, ctx.currentTime + ((timeOff + duration) / 1000));
|
|
154289
|
-
}
|
|
154290
|
-
else if (ch.generator.playbackRate != undefined) {
|
|
154291
|
-
// If generator is an AudioBufferSourceNode
|
|
154292
|
-
const param = ch.generator.playbackRate;
|
|
154293
|
-
const bufferSamplesPerWave = isFilteredNoise ? 4 : 1024;
|
|
154294
|
-
param.linearRampToValueAtTime(endFreq / (context().sampleRate / bufferSamplesPerWave), ctx.currentTime + ((timeOff + duration) / 1000));
|
|
154295
|
-
}
|
|
154296
|
-
}
|
|
154297
|
-
ch.generator.connect(ch.gain);
|
|
154298
|
-
ch.gain.connect(destination);
|
|
154299
|
-
ch.generator.start();
|
|
154300
|
-
}
|
|
154301
|
-
idx += 12;
|
|
154302
|
-
ch.gain.gain.setValueAtTime(scaledStart, ctx.currentTime + (timeOff / 1000));
|
|
154303
|
-
timeOff += duration;
|
|
154304
|
-
// To prevent clipping, we ramp to this value slightly earlier than intended. This is so that we
|
|
154305
|
-
// can go for a smooth ramp to 0 in ch.mute() without this operation interrupting it. If we had
|
|
154306
|
-
// more accurate timing this would not be necessary, but we'd probably have to do something like
|
|
154307
|
-
// running a metronome in a webworker to get the level of precision we need
|
|
154308
|
-
const endTime = scaledEnd !== 0 && duration > 50 ? ((timeOff - 50) / 1000) : ((timeOff - 10) / 1000);
|
|
154309
|
-
ch.gain.gain.linearRampToValueAtTime(scaledEnd, ctx.currentTime + endTime);
|
|
154310
|
-
return loopAsync();
|
|
154311
|
-
};
|
|
154312
|
-
return loopAsync()
|
|
154313
|
-
.then(() => ch.remove());
|
|
154314
|
-
}
|
|
154315
|
-
AudioContextManager.playInstructionsAsync = playInstructionsAsync;
|
|
154316
154330
|
function tone(frequency, gain) {
|
|
154317
154331
|
if (frequency < 0)
|
|
154318
154332
|
return;
|
|
@@ -154451,6 +154465,126 @@ var pxsim;
|
|
|
154451
154465
|
function frequencyFromMidiNoteNumber(note) {
|
|
154452
154466
|
return 440 * Math.pow(2, (note - 69) / 12);
|
|
154453
154467
|
}
|
|
154468
|
+
function playInstructionsAsync(instructions, isCancelled, onPull) {
|
|
154469
|
+
return new Promise(async (resolve) => {
|
|
154470
|
+
let resolved = false;
|
|
154471
|
+
let ctx = context();
|
|
154472
|
+
let channel = new Channel();
|
|
154473
|
+
if (channels.length > 5)
|
|
154474
|
+
channels[0].remove();
|
|
154475
|
+
channels.push(channel);
|
|
154476
|
+
channel.gain = ctx.createGain();
|
|
154477
|
+
channel.gain.gain.value = 1;
|
|
154478
|
+
channel.gain.connect(destination);
|
|
154479
|
+
const oscillators = {};
|
|
154480
|
+
const gains = {};
|
|
154481
|
+
let startTime = ctx.currentTime;
|
|
154482
|
+
let currentTime = startTime;
|
|
154483
|
+
let currentWave = 0;
|
|
154484
|
+
let totalDuration = 0;
|
|
154485
|
+
/** Square waves are perceved as much louder than other sounds, so scale it down a bit to make it less jarring **/
|
|
154486
|
+
const scaleVol = (n, isSqWave) => (n / 1024) / 4 * (isSqWave ? .5 : 1);
|
|
154487
|
+
const disconnectNodes = () => {
|
|
154488
|
+
if (resolved)
|
|
154489
|
+
return;
|
|
154490
|
+
resolved = true;
|
|
154491
|
+
channel.disconnectNodes();
|
|
154492
|
+
for (const wave of Object.keys(oscillators)) {
|
|
154493
|
+
oscillators[wave].stop();
|
|
154494
|
+
oscillators[wave].disconnect();
|
|
154495
|
+
gains[wave].disconnect();
|
|
154496
|
+
}
|
|
154497
|
+
resolve();
|
|
154498
|
+
};
|
|
154499
|
+
for (let i = 0; i < instructions.length; i += 12) {
|
|
154500
|
+
const wave = instructions[i];
|
|
154501
|
+
const startFrequency = readUint16(instructions, i + 2);
|
|
154502
|
+
const duration = readUint16(instructions, i + 4) / 1000;
|
|
154503
|
+
const startVolume = readUint16(instructions, i + 6);
|
|
154504
|
+
const endVolume = readUint16(instructions, i + 8);
|
|
154505
|
+
const endFrequency = readUint16(instructions, i + 10);
|
|
154506
|
+
totalDuration += duration;
|
|
154507
|
+
const isSquareWave = 11 <= wave && wave <= 15;
|
|
154508
|
+
if (!oscillators[wave]) {
|
|
154509
|
+
oscillators[wave] = getGenerator(wave, startFrequency);
|
|
154510
|
+
gains[wave] = ctx.createGain();
|
|
154511
|
+
gains[wave].gain.value = 0;
|
|
154512
|
+
gains[wave].connect(channel.gain);
|
|
154513
|
+
oscillators[wave].connect(gains[wave]);
|
|
154514
|
+
oscillators[wave].start();
|
|
154515
|
+
}
|
|
154516
|
+
if (currentWave && wave !== currentWave) {
|
|
154517
|
+
gains[currentWave].gain.setTargetAtTime(0, currentTime, 0.015);
|
|
154518
|
+
}
|
|
154519
|
+
const osc = oscillators[wave];
|
|
154520
|
+
const gain = gains[wave];
|
|
154521
|
+
if (osc instanceof OscillatorNode) {
|
|
154522
|
+
osc.frequency.setValueAtTime(startFrequency, currentTime);
|
|
154523
|
+
osc.frequency.linearRampToValueAtTime(endFrequency, currentTime + duration);
|
|
154524
|
+
}
|
|
154525
|
+
else {
|
|
154526
|
+
const isFilteredNoise = wave == 4 || (16 <= wave && wave <= 18);
|
|
154527
|
+
if (isFilteredNoise)
|
|
154528
|
+
osc.playbackRate.linearRampToValueAtTime(endFrequency / (ctx.sampleRate / 4), currentTime + duration);
|
|
154529
|
+
else if (wave != 5)
|
|
154530
|
+
osc.playbackRate.linearRampToValueAtTime(endFrequency / (ctx.sampleRate / 1024), currentTime + duration);
|
|
154531
|
+
}
|
|
154532
|
+
gain.gain.setValueAtTime(scaleVol(startVolume, isSquareWave), currentTime);
|
|
154533
|
+
gain.gain.linearRampToValueAtTime(scaleVol(endVolume, isSquareWave), currentTime + duration);
|
|
154534
|
+
currentWave = wave;
|
|
154535
|
+
currentTime += duration;
|
|
154536
|
+
}
|
|
154537
|
+
channel.gain.gain.setTargetAtTime(0, currentTime, 0.015);
|
|
154538
|
+
if (isCancelled || onPull) {
|
|
154539
|
+
const handleAnimationFrame = () => {
|
|
154540
|
+
const time = ctx.currentTime;
|
|
154541
|
+
if (time > startTime + totalDuration) {
|
|
154542
|
+
return;
|
|
154543
|
+
}
|
|
154544
|
+
if (isCancelled && isCancelled()) {
|
|
154545
|
+
disconnectNodes();
|
|
154546
|
+
return;
|
|
154547
|
+
}
|
|
154548
|
+
const { frequency, volume } = findFrequencyAndVolumeAtTime((time - startTime) * 1000, instructions);
|
|
154549
|
+
onPull(frequency, volume / 1024);
|
|
154550
|
+
requestAnimationFrame(handleAnimationFrame);
|
|
154551
|
+
};
|
|
154552
|
+
requestAnimationFrame(handleAnimationFrame);
|
|
154553
|
+
}
|
|
154554
|
+
await pxsim.U.delay(totalDuration * 1000);
|
|
154555
|
+
disconnectNodes();
|
|
154556
|
+
});
|
|
154557
|
+
}
|
|
154558
|
+
AudioContextManager.playInstructionsAsync = playInstructionsAsync;
|
|
154559
|
+
function readUint16(buf, offset) {
|
|
154560
|
+
const temp = new Uint8Array(2);
|
|
154561
|
+
temp[0] = buf[offset];
|
|
154562
|
+
temp[1] = buf[offset + 1];
|
|
154563
|
+
return new Uint16Array(temp.buffer)[0];
|
|
154564
|
+
}
|
|
154565
|
+
function findFrequencyAndVolumeAtTime(millis, instructions) {
|
|
154566
|
+
let currentTime = 0;
|
|
154567
|
+
for (let i = 0; i < instructions.length; i += 12) {
|
|
154568
|
+
const startFrequency = readUint16(instructions, i + 2);
|
|
154569
|
+
const duration = readUint16(instructions, i + 4);
|
|
154570
|
+
const startVolume = readUint16(instructions, i + 6);
|
|
154571
|
+
const endVolume = readUint16(instructions, i + 8);
|
|
154572
|
+
const endFrequency = readUint16(instructions, i + 10);
|
|
154573
|
+
if (currentTime + duration < millis) {
|
|
154574
|
+
currentTime += duration;
|
|
154575
|
+
continue;
|
|
154576
|
+
}
|
|
154577
|
+
const offset = (millis - currentTime) / duration;
|
|
154578
|
+
return {
|
|
154579
|
+
frequency: startFrequency + (endFrequency - startFrequency) * offset,
|
|
154580
|
+
volume: startVolume + (endVolume - startVolume) * offset,
|
|
154581
|
+
};
|
|
154582
|
+
}
|
|
154583
|
+
return {
|
|
154584
|
+
frequency: -1,
|
|
154585
|
+
volume: -1
|
|
154586
|
+
};
|
|
154587
|
+
}
|
|
154454
154588
|
function sendMidiMessage(buf) {
|
|
154455
154589
|
const data = buf.data;
|
|
154456
154590
|
if (!data.length) // garbage.
|
package/built/pxtblockly.js
CHANGED
|
@@ -15424,6 +15424,8 @@ var pxtblockly;
|
|
|
15424
15424
|
this.options.interpolationFieldName = "interpolation";
|
|
15425
15425
|
if (!this.options.effectFieldName)
|
|
15426
15426
|
this.options.effectFieldName = "effect";
|
|
15427
|
+
if (!this.options.useMixerSynthesizer)
|
|
15428
|
+
this.options.useMixerSynthesizer = false;
|
|
15427
15429
|
this.redrawPreview();
|
|
15428
15430
|
if (this.sourceBlock_.workspace) {
|
|
15429
15431
|
this.workspace = this.sourceBlock_.workspace;
|
|
@@ -15540,7 +15542,8 @@ var pxtblockly;
|
|
|
15540
15542
|
this.updateSiblingBlocks(newSound);
|
|
15541
15543
|
this.redrawPreview();
|
|
15542
15544
|
},
|
|
15543
|
-
initialSound: initialSound
|
|
15545
|
+
initialSound: initialSound,
|
|
15546
|
+
useMixerSynthesizer: isTrue(this.options.useMixerSynthesizer)
|
|
15544
15547
|
};
|
|
15545
15548
|
const fv = pxt.react.getFieldEditorView("soundeffect-editor", initialSound, opts, widgetDiv);
|
|
15546
15549
|
const block = this.sourceBlock_;
|
|
@@ -15734,6 +15737,23 @@ var pxtblockly;
|
|
|
15734
15737
|
function reverseLookup(map, value) {
|
|
15735
15738
|
return Object.keys(map).find(k => map[k] === value);
|
|
15736
15739
|
}
|
|
15740
|
+
function isTrue(value) {
|
|
15741
|
+
if (!value)
|
|
15742
|
+
return false;
|
|
15743
|
+
if (typeof value === "string") {
|
|
15744
|
+
switch (value.toLowerCase().trim()) {
|
|
15745
|
+
case "1":
|
|
15746
|
+
case "yes":
|
|
15747
|
+
case "y":
|
|
15748
|
+
case "on":
|
|
15749
|
+
case "true":
|
|
15750
|
+
return true;
|
|
15751
|
+
default:
|
|
15752
|
+
return false;
|
|
15753
|
+
}
|
|
15754
|
+
}
|
|
15755
|
+
return !!value;
|
|
15756
|
+
}
|
|
15737
15757
|
})(pxtblockly || (pxtblockly = {}));
|
|
15738
15758
|
/// <reference path="../../localtypings/blockly.d.ts"/>
|
|
15739
15759
|
/// <reference path="../../built/pxtsim.d.ts"/>
|
package/built/pxtblocks.d.ts
CHANGED
|
@@ -1187,6 +1187,7 @@ declare namespace pxtblockly {
|
|
|
1187
1187
|
waveFieldName: string;
|
|
1188
1188
|
interpolationFieldName: string;
|
|
1189
1189
|
effectFieldName: string;
|
|
1190
|
+
useMixerSynthesizer: any;
|
|
1190
1191
|
}
|
|
1191
1192
|
class FieldSoundEffect extends FieldBase<FieldSoundEffectParams> {
|
|
1192
1193
|
protected mostRecentValue: pxt.assets.Sound;
|
package/built/pxtblocks.js
CHANGED
|
@@ -11862,6 +11862,8 @@ var pxtblockly;
|
|
|
11862
11862
|
this.options.interpolationFieldName = "interpolation";
|
|
11863
11863
|
if (!this.options.effectFieldName)
|
|
11864
11864
|
this.options.effectFieldName = "effect";
|
|
11865
|
+
if (!this.options.useMixerSynthesizer)
|
|
11866
|
+
this.options.useMixerSynthesizer = false;
|
|
11865
11867
|
this.redrawPreview();
|
|
11866
11868
|
if (this.sourceBlock_.workspace) {
|
|
11867
11869
|
this.workspace = this.sourceBlock_.workspace;
|
|
@@ -11978,7 +11980,8 @@ var pxtblockly;
|
|
|
11978
11980
|
this.updateSiblingBlocks(newSound);
|
|
11979
11981
|
this.redrawPreview();
|
|
11980
11982
|
},
|
|
11981
|
-
initialSound: initialSound
|
|
11983
|
+
initialSound: initialSound,
|
|
11984
|
+
useMixerSynthesizer: isTrue(this.options.useMixerSynthesizer)
|
|
11982
11985
|
};
|
|
11983
11986
|
const fv = pxt.react.getFieldEditorView("soundeffect-editor", initialSound, opts, widgetDiv);
|
|
11984
11987
|
const block = this.sourceBlock_;
|
|
@@ -12172,6 +12175,23 @@ var pxtblockly;
|
|
|
12172
12175
|
function reverseLookup(map, value) {
|
|
12173
12176
|
return Object.keys(map).find(k => map[k] === value);
|
|
12174
12177
|
}
|
|
12178
|
+
function isTrue(value) {
|
|
12179
|
+
if (!value)
|
|
12180
|
+
return false;
|
|
12181
|
+
if (typeof value === "string") {
|
|
12182
|
+
switch (value.toLowerCase().trim()) {
|
|
12183
|
+
case "1":
|
|
12184
|
+
case "yes":
|
|
12185
|
+
case "y":
|
|
12186
|
+
case "on":
|
|
12187
|
+
case "true":
|
|
12188
|
+
return true;
|
|
12189
|
+
default:
|
|
12190
|
+
return false;
|
|
12191
|
+
}
|
|
12192
|
+
}
|
|
12193
|
+
return !!value;
|
|
12194
|
+
}
|
|
12175
12195
|
})(pxtblockly || (pxtblockly = {}));
|
|
12176
12196
|
/// <reference path="../../localtypings/blockly.d.ts"/>
|
|
12177
12197
|
/// <reference path="../../built/pxtsim.d.ts"/>
|
package/built/pxteditor.js
CHANGED
|
@@ -1055,7 +1055,8 @@ var pxt;
|
|
|
1055
1055
|
onClose: () => this.fv.hide(),
|
|
1056
1056
|
onSoundChange: (newValue) => this.value = newValue,
|
|
1057
1057
|
initialSound: this.value,
|
|
1058
|
-
useFlex: true
|
|
1058
|
+
useFlex: true,
|
|
1059
|
+
useMixerSynthesizer: pxt.appTarget.id !== "microbit" // FIXME
|
|
1059
1060
|
};
|
|
1060
1061
|
}
|
|
1061
1062
|
}
|
package/built/pxtlib.d.ts
CHANGED
|
@@ -2333,6 +2333,7 @@ declare namespace pxt.assets {
|
|
|
2333
2333
|
const MAX_VOLUME = 255;
|
|
2334
2334
|
function renderSoundPath(sound: pxt.assets.Sound, width: number, height: number): string;
|
|
2335
2335
|
function renderWaveSnapshot(frequency: number, volume: number, wave: SoundWaveForm, width: number, height: number, timeBase: number): string;
|
|
2336
|
+
function soundToInstructionBuffer(sound: Sound, fxSteps: number, fxRange: number): Uint8Array;
|
|
2336
2337
|
}
|
|
2337
2338
|
declare namespace pxt.streams {
|
|
2338
2339
|
interface JsonStreamField {
|
package/built/pxtlib.js
CHANGED
|
@@ -8713,7 +8713,7 @@ var pxt;
|
|
|
8713
8713
|
docs.prepTemplate = prepTemplate;
|
|
8714
8714
|
function setupRenderer(renderer) {
|
|
8715
8715
|
renderer.image = function (href, title, text) {
|
|
8716
|
-
const endpointName = "
|
|
8716
|
+
const endpointName = "makecodeprodmediaeastus-usea";
|
|
8717
8717
|
if (href.startsWith("youtube:")) {
|
|
8718
8718
|
let out = '<div class="tutorial-video-embed"><iframe class="yt-embed" src="https://www.youtube.com/embed/' + href.split(":").pop()
|
|
8719
8719
|
+ '" title="' + text + '" frameborder="0" ' + 'allowFullScreen ' + 'allow="autoplay; picture-in-picture"></iframe></div>';
|
|
@@ -10500,14 +10500,17 @@ var pxt;
|
|
|
10500
10500
|
return false;
|
|
10501
10501
|
}
|
|
10502
10502
|
function isRepoBanned(repo, config) {
|
|
10503
|
+
var _a, _b;
|
|
10503
10504
|
if (isOrgBanned(repo, config))
|
|
10504
10505
|
return true;
|
|
10505
10506
|
if (!config)
|
|
10506
10507
|
return false; // don't know
|
|
10507
|
-
if (!repo
|
|
10508
|
+
if (!repo)
|
|
10508
10509
|
return true;
|
|
10510
|
+
const repoFull = (_a = repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
10511
|
+
const repoSlug = (_b = repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
10509
10512
|
if (config.bannedRepos
|
|
10510
|
-
&& config.bannedRepos.some(fn => fn.toLowerCase() ==
|
|
10513
|
+
&& config.bannedRepos.some(fn => fn && (fn.toLowerCase() == repoFull || fn.toLowerCase() == repoSlug)))
|
|
10511
10514
|
return true;
|
|
10512
10515
|
return false;
|
|
10513
10516
|
}
|
|
@@ -10521,13 +10524,15 @@ var pxt;
|
|
|
10521
10524
|
return false;
|
|
10522
10525
|
}
|
|
10523
10526
|
function isRepoApproved(repo, config) {
|
|
10524
|
-
var _a;
|
|
10527
|
+
var _a, _b;
|
|
10525
10528
|
if (isOrgApproved(repo, config))
|
|
10526
10529
|
return true;
|
|
10527
|
-
|
|
10530
|
+
const repoFull = (_a = repo === null || repo === void 0 ? void 0 : repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
10531
|
+
const repoSlug = (_b = repo === null || repo === void 0 ? void 0 : repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
10532
|
+
if (!(config === null || config === void 0 ? void 0 : config.approvedRepoLib) || !(repoFull || repoSlug))
|
|
10528
10533
|
return false;
|
|
10529
|
-
if (
|
|
10530
|
-
|
|
10534
|
+
if (config.approvedRepoLib[repoFull]
|
|
10535
|
+
|| config.approvedRepoLib[repoSlug])
|
|
10531
10536
|
return true;
|
|
10532
10537
|
return false;
|
|
10533
10538
|
}
|
|
@@ -16905,6 +16910,97 @@ var pxt;
|
|
|
16905
16910
|
return outParts.join(" ");
|
|
16906
16911
|
}
|
|
16907
16912
|
}
|
|
16913
|
+
function soundToInstructionBuffer(sound, fxSteps, fxRange) {
|
|
16914
|
+
const { startFrequency, endFrequency, startVolume, endVolume, interpolation, duration } = sound;
|
|
16915
|
+
const steps = [];
|
|
16916
|
+
// Optimize the simple case
|
|
16917
|
+
if (sound.interpolation === "linear" && sound.effect === "none") {
|
|
16918
|
+
steps.push({
|
|
16919
|
+
frequency: startFrequency,
|
|
16920
|
+
volume: (startVolume / assets.MAX_VOLUME) * 1024,
|
|
16921
|
+
});
|
|
16922
|
+
steps.push({
|
|
16923
|
+
frequency: endFrequency,
|
|
16924
|
+
volume: (endVolume / assets.MAX_VOLUME) * 1024,
|
|
16925
|
+
});
|
|
16926
|
+
}
|
|
16927
|
+
else {
|
|
16928
|
+
fxSteps = Math.min(fxSteps, Math.floor(duration / 5));
|
|
16929
|
+
const getVolumeAt = (t) => ((startVolume + t * (endVolume - startVolume) / duration) / assets.MAX_VOLUME) * 1024;
|
|
16930
|
+
let getFrequencyAt;
|
|
16931
|
+
switch (interpolation) {
|
|
16932
|
+
case "linear":
|
|
16933
|
+
getFrequencyAt = t => startFrequency + t * (endFrequency - startFrequency) / duration;
|
|
16934
|
+
break;
|
|
16935
|
+
case "curve":
|
|
16936
|
+
getFrequencyAt = t => startFrequency + (endFrequency - startFrequency) * Math.sin(t / duration * (Math.PI / 2));
|
|
16937
|
+
break;
|
|
16938
|
+
case "logarithmic":
|
|
16939
|
+
getFrequencyAt = t => startFrequency + Math.log10(1 + 9 * (t / duration)) * (endFrequency - startFrequency);
|
|
16940
|
+
break;
|
|
16941
|
+
}
|
|
16942
|
+
const timeSlice = duration / fxSteps;
|
|
16943
|
+
for (let i = 0; i < fxSteps; i++) {
|
|
16944
|
+
const newStep = {
|
|
16945
|
+
frequency: Math.max(getFrequencyAt(i * timeSlice), 1),
|
|
16946
|
+
volume: getVolumeAt(i * timeSlice)
|
|
16947
|
+
};
|
|
16948
|
+
if (sound.effect === "tremolo") {
|
|
16949
|
+
if (i % 2 === 0) {
|
|
16950
|
+
newStep.volume = Math.max(newStep.volume - fxRange * 500, 0);
|
|
16951
|
+
}
|
|
16952
|
+
else {
|
|
16953
|
+
newStep.volume = Math.min(newStep.volume + fxRange * 500, 1023);
|
|
16954
|
+
}
|
|
16955
|
+
}
|
|
16956
|
+
else if (sound.effect === "vibrato") {
|
|
16957
|
+
if (i % 2 === 0) {
|
|
16958
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 100, 1);
|
|
16959
|
+
}
|
|
16960
|
+
else {
|
|
16961
|
+
newStep.frequency = newStep.frequency + fxRange * 100;
|
|
16962
|
+
}
|
|
16963
|
+
}
|
|
16964
|
+
else if (sound.effect === "warble") {
|
|
16965
|
+
if (i % 2 === 0) {
|
|
16966
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 1000, 1);
|
|
16967
|
+
}
|
|
16968
|
+
else {
|
|
16969
|
+
newStep.frequency = newStep.frequency + fxRange * 1000;
|
|
16970
|
+
}
|
|
16971
|
+
}
|
|
16972
|
+
steps.push(newStep);
|
|
16973
|
+
}
|
|
16974
|
+
}
|
|
16975
|
+
const out = new Uint8Array(12 * (steps.length - 1));
|
|
16976
|
+
const stepDuration = Math.floor(duration / (steps.length - 1));
|
|
16977
|
+
for (let i = 0; i < steps.length - 1; i++) {
|
|
16978
|
+
const offset = i * 12;
|
|
16979
|
+
out[offset] = waveToValue(sound.wave);
|
|
16980
|
+
set16BitNumber(out, offset + 2, steps[i].frequency);
|
|
16981
|
+
set16BitNumber(out, offset + 4, stepDuration);
|
|
16982
|
+
set16BitNumber(out, offset + 6, steps[i].volume);
|
|
16983
|
+
set16BitNumber(out, offset + 8, steps[i + 1].volume);
|
|
16984
|
+
set16BitNumber(out, offset + 10, steps[i + 1].frequency);
|
|
16985
|
+
}
|
|
16986
|
+
return out;
|
|
16987
|
+
}
|
|
16988
|
+
assets.soundToInstructionBuffer = soundToInstructionBuffer;
|
|
16989
|
+
function waveToValue(wave) {
|
|
16990
|
+
switch (wave) {
|
|
16991
|
+
case "square": return 15;
|
|
16992
|
+
case "sine": return 3;
|
|
16993
|
+
case "triangle": return 1;
|
|
16994
|
+
case "noise": return 18;
|
|
16995
|
+
case "sawtooth": return 2;
|
|
16996
|
+
}
|
|
16997
|
+
}
|
|
16998
|
+
function set16BitNumber(buf, offset, value) {
|
|
16999
|
+
const temp = new Uint8Array(2);
|
|
17000
|
+
new Uint16Array(temp.buffer)[0] = value | 0;
|
|
17001
|
+
buf[offset] = temp[0];
|
|
17002
|
+
buf[offset + 1] = temp[1];
|
|
17003
|
+
}
|
|
16908
17004
|
})(assets = pxt.assets || (pxt.assets = {}));
|
|
16909
17005
|
})(pxt || (pxt = {}));
|
|
16910
17006
|
// See https://github.com/microsoft/TouchDevelop-backend/blob/master/docs/streams.md
|