pxt-core 8.2.2 → 8.2.5
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 +22 -4
- package/built/gdb.js +3 -3
- package/built/pxt-common.json +1 -1
- package/built/pxt.js +377 -109
- package/built/pxtblockly.js +21 -4
- package/built/pxtblocks.d.ts +1 -0
- package/built/pxtblocks.js +21 -4
- package/built/pxtcompiler.d.ts +1 -0
- package/built/pxtcompiler.js +34 -8
- package/built/pxteditor.d.ts +1 -0
- package/built/pxteditor.js +2 -1
- package/built/pxtlib.d.ts +15 -0
- package/built/pxtlib.js +219 -15
- package/built/pxtsim.d.ts +1 -1
- package/built/pxtsim.js +124 -86
- package/built/target.js +1 -1
- 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/pxtcompiler.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/built/web/rtlsemantic.css +1 -1
- package/built/web/semantic.css +1 -1
- package/package.json +1 -1
- package/theme/asset-editor.less +5 -0
- package/theme/greenscreen.less +4 -1
- package/theme/home.less +0 -5
- package/theme/tutorial-sidebar.less +42 -1
- package/theme/tutorial.less +8 -0
package/built/pxt.js
CHANGED
|
@@ -106399,14 +106399,32 @@ var pxt;
|
|
|
106399
106399
|
docs.prepTemplate = prepTemplate;
|
|
106400
106400
|
function setupRenderer(renderer) {
|
|
106401
106401
|
renderer.image = function (href, title, text) {
|
|
106402
|
-
|
|
106402
|
+
var _a, _b;
|
|
106403
|
+
const endpointName = "makecodeprodmediaeastus-usea";
|
|
106403
106404
|
if (href.startsWith("youtube:")) {
|
|
106404
|
-
let out = '<div class="tutorial-video-embed"><iframe src="https://www.youtube.com/embed/' + href.split(":").pop()
|
|
106405
|
-
+ '" title="' +
|
|
106405
|
+
let out = '<div class="tutorial-video-embed"><iframe class="yt-embed" src="https://www.youtube.com/embed/' + href.split(":").pop()
|
|
106406
|
+
+ '" title="' + text + '" frameborder="0" ' + 'allowFullScreen ' + 'allow="autoplay; picture-in-picture"></iframe></div>';
|
|
106406
106407
|
return out;
|
|
106407
106408
|
}
|
|
106408
106409
|
else if (href.startsWith("azuremedia:")) {
|
|
106409
|
-
let
|
|
106410
|
+
let videoID = href.split(":")[1];
|
|
106411
|
+
const flagsSplit = videoID.split("?");
|
|
106412
|
+
let startTime;
|
|
106413
|
+
let endTime;
|
|
106414
|
+
if (flagsSplit[1]) {
|
|
106415
|
+
videoID = flagsSplit[0];
|
|
106416
|
+
const passedParameters = flagsSplit[1];
|
|
106417
|
+
startTime = (_a = /start(?:time)?=(\d+)/i.exec(passedParameters)) === null || _a === void 0 ? void 0 : _a[1];
|
|
106418
|
+
endTime = (_b = /end(?:time)?=(\d+)/i.exec(passedParameters)) === null || _b === void 0 ? void 0 : _b[1];
|
|
106419
|
+
}
|
|
106420
|
+
const url = new URL(`https://${endpointName}.streaming.media.azure.net/${videoID}/manifest(format=mpd-time-csf).mpd`);
|
|
106421
|
+
if (startTime) {
|
|
106422
|
+
url.hash = `t=${startTime}`;
|
|
106423
|
+
}
|
|
106424
|
+
if (endTime) {
|
|
106425
|
+
url.searchParams.append("endTime", endTime);
|
|
106426
|
+
}
|
|
106427
|
+
let out = `<div class="tutorial-video-embed"><video class="ams-embed" controls src="${url.toString()}" /></div>`;
|
|
106410
106428
|
return out;
|
|
106411
106429
|
}
|
|
106412
106430
|
else {
|
|
@@ -108186,14 +108204,17 @@ var pxt;
|
|
|
108186
108204
|
return false;
|
|
108187
108205
|
}
|
|
108188
108206
|
function isRepoBanned(repo, config) {
|
|
108207
|
+
var _a, _b;
|
|
108189
108208
|
if (isOrgBanned(repo, config))
|
|
108190
108209
|
return true;
|
|
108191
108210
|
if (!config)
|
|
108192
108211
|
return false; // don't know
|
|
108193
|
-
if (!repo
|
|
108212
|
+
if (!repo)
|
|
108194
108213
|
return true;
|
|
108214
|
+
const repoFull = (_a = repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
108215
|
+
const repoSlug = (_b = repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
108195
108216
|
if (config.bannedRepos
|
|
108196
|
-
&& config.bannedRepos.some(fn => fn.toLowerCase() ==
|
|
108217
|
+
&& config.bannedRepos.some(fn => fn && (fn.toLowerCase() == repoFull || fn.toLowerCase() == repoSlug)))
|
|
108197
108218
|
return true;
|
|
108198
108219
|
return false;
|
|
108199
108220
|
}
|
|
@@ -108207,13 +108228,15 @@ var pxt;
|
|
|
108207
108228
|
return false;
|
|
108208
108229
|
}
|
|
108209
108230
|
function isRepoApproved(repo, config) {
|
|
108210
|
-
var _a;
|
|
108231
|
+
var _a, _b;
|
|
108211
108232
|
if (isOrgApproved(repo, config))
|
|
108212
108233
|
return true;
|
|
108213
|
-
|
|
108234
|
+
const repoFull = (_a = repo === null || repo === void 0 ? void 0 : repo.fullName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
108235
|
+
const repoSlug = (_b = repo === null || repo === void 0 ? void 0 : repo.slug) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
108236
|
+
if (!(config === null || config === void 0 ? void 0 : config.approvedRepoLib) || !(repoFull || repoSlug))
|
|
108214
108237
|
return false;
|
|
108215
|
-
if (
|
|
108216
|
-
|
|
108238
|
+
if (config.approvedRepoLib[repoFull]
|
|
108239
|
+
|| config.approvedRepoLib[repoSlug])
|
|
108217
108240
|
return true;
|
|
108218
108241
|
return false;
|
|
108219
108242
|
}
|
|
@@ -111956,7 +111979,7 @@ var pxt;
|
|
|
111956
111979
|
// and pulls from master
|
|
111957
111980
|
const modtag = (modid === null || modid === void 0 ? void 0 : modid.tag) || ((_a = mod.config) === null || _a === void 0 ? void 0 : _a.version);
|
|
111958
111981
|
const vertag = verid.tag;
|
|
111959
|
-
// if there is no tag on the current dependency,
|
|
111982
|
+
// if there is no tag on the current dependency,
|
|
111960
111983
|
// assume same as existing module version if any
|
|
111961
111984
|
if (modtag && !vertag) {
|
|
111962
111985
|
pxt.debug(`unversioned ${ver}, using ${modtag}`);
|
|
@@ -112415,6 +112438,8 @@ var pxt;
|
|
|
112415
112438
|
opts.otherMultiVariants.push(etarget);
|
|
112416
112439
|
}
|
|
112417
112440
|
else {
|
|
112441
|
+
etarget.target.isNative = opts.target.isNative;
|
|
112442
|
+
opts.target = etarget.target;
|
|
112418
112443
|
ext = einfo;
|
|
112419
112444
|
opts.otherMultiVariants = [];
|
|
112420
112445
|
}
|
|
@@ -113370,7 +113395,12 @@ var ts;
|
|
|
113370
113395
|
const left = param.substr(0, dotIdx);
|
|
113371
113396
|
let right = param.substr(dotIdx + 1);
|
|
113372
113397
|
right = pxtc.U.snakify(right).toUpperCase();
|
|
113373
|
-
|
|
113398
|
+
if (left) {
|
|
113399
|
+
return `${left}.${right}`;
|
|
113400
|
+
}
|
|
113401
|
+
else {
|
|
113402
|
+
return right;
|
|
113403
|
+
}
|
|
113374
113404
|
}
|
|
113375
113405
|
return param;
|
|
113376
113406
|
}
|
|
@@ -114591,6 +114621,97 @@ var pxt;
|
|
|
114591
114621
|
return outParts.join(" ");
|
|
114592
114622
|
}
|
|
114593
114623
|
}
|
|
114624
|
+
function soundToInstructionBuffer(sound, fxSteps, fxRange) {
|
|
114625
|
+
const { startFrequency, endFrequency, startVolume, endVolume, interpolation, duration } = sound;
|
|
114626
|
+
const steps = [];
|
|
114627
|
+
// Optimize the simple case
|
|
114628
|
+
if (sound.interpolation === "linear" && sound.effect === "none") {
|
|
114629
|
+
steps.push({
|
|
114630
|
+
frequency: startFrequency,
|
|
114631
|
+
volume: (startVolume / assets.MAX_VOLUME) * 1024,
|
|
114632
|
+
});
|
|
114633
|
+
steps.push({
|
|
114634
|
+
frequency: endFrequency,
|
|
114635
|
+
volume: (endVolume / assets.MAX_VOLUME) * 1024,
|
|
114636
|
+
});
|
|
114637
|
+
}
|
|
114638
|
+
else {
|
|
114639
|
+
fxSteps = Math.min(fxSteps, Math.floor(duration / 5));
|
|
114640
|
+
const getVolumeAt = (t) => ((startVolume + t * (endVolume - startVolume) / duration) / assets.MAX_VOLUME) * 1024;
|
|
114641
|
+
let getFrequencyAt;
|
|
114642
|
+
switch (interpolation) {
|
|
114643
|
+
case "linear":
|
|
114644
|
+
getFrequencyAt = t => startFrequency + t * (endFrequency - startFrequency) / duration;
|
|
114645
|
+
break;
|
|
114646
|
+
case "curve":
|
|
114647
|
+
getFrequencyAt = t => startFrequency + (endFrequency - startFrequency) * Math.sin(t / duration * (Math.PI / 2));
|
|
114648
|
+
break;
|
|
114649
|
+
case "logarithmic":
|
|
114650
|
+
getFrequencyAt = t => startFrequency + Math.log10(1 + 9 * (t / duration)) * (endFrequency - startFrequency);
|
|
114651
|
+
break;
|
|
114652
|
+
}
|
|
114653
|
+
const timeSlice = duration / fxSteps;
|
|
114654
|
+
for (let i = 0; i < fxSteps; i++) {
|
|
114655
|
+
const newStep = {
|
|
114656
|
+
frequency: Math.max(getFrequencyAt(i * timeSlice), 1),
|
|
114657
|
+
volume: getVolumeAt(i * timeSlice)
|
|
114658
|
+
};
|
|
114659
|
+
if (sound.effect === "tremolo") {
|
|
114660
|
+
if (i % 2 === 0) {
|
|
114661
|
+
newStep.volume = Math.max(newStep.volume - fxRange * 500, 0);
|
|
114662
|
+
}
|
|
114663
|
+
else {
|
|
114664
|
+
newStep.volume = Math.min(newStep.volume + fxRange * 500, 1023);
|
|
114665
|
+
}
|
|
114666
|
+
}
|
|
114667
|
+
else if (sound.effect === "vibrato") {
|
|
114668
|
+
if (i % 2 === 0) {
|
|
114669
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 100, 1);
|
|
114670
|
+
}
|
|
114671
|
+
else {
|
|
114672
|
+
newStep.frequency = newStep.frequency + fxRange * 100;
|
|
114673
|
+
}
|
|
114674
|
+
}
|
|
114675
|
+
else if (sound.effect === "warble") {
|
|
114676
|
+
if (i % 2 === 0) {
|
|
114677
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 1000, 1);
|
|
114678
|
+
}
|
|
114679
|
+
else {
|
|
114680
|
+
newStep.frequency = newStep.frequency + fxRange * 1000;
|
|
114681
|
+
}
|
|
114682
|
+
}
|
|
114683
|
+
steps.push(newStep);
|
|
114684
|
+
}
|
|
114685
|
+
}
|
|
114686
|
+
const out = new Uint8Array(12 * (steps.length - 1));
|
|
114687
|
+
const stepDuration = Math.floor(duration / (steps.length - 1));
|
|
114688
|
+
for (let i = 0; i < steps.length - 1; i++) {
|
|
114689
|
+
const offset = i * 12;
|
|
114690
|
+
out[offset] = waveToValue(sound.wave);
|
|
114691
|
+
set16BitNumber(out, offset + 2, steps[i].frequency);
|
|
114692
|
+
set16BitNumber(out, offset + 4, stepDuration);
|
|
114693
|
+
set16BitNumber(out, offset + 6, steps[i].volume);
|
|
114694
|
+
set16BitNumber(out, offset + 8, steps[i + 1].volume);
|
|
114695
|
+
set16BitNumber(out, offset + 10, steps[i + 1].frequency);
|
|
114696
|
+
}
|
|
114697
|
+
return out;
|
|
114698
|
+
}
|
|
114699
|
+
assets.soundToInstructionBuffer = soundToInstructionBuffer;
|
|
114700
|
+
function waveToValue(wave) {
|
|
114701
|
+
switch (wave) {
|
|
114702
|
+
case "square": return 15;
|
|
114703
|
+
case "sine": return 3;
|
|
114704
|
+
case "triangle": return 1;
|
|
114705
|
+
case "noise": return 18;
|
|
114706
|
+
case "sawtooth": return 2;
|
|
114707
|
+
}
|
|
114708
|
+
}
|
|
114709
|
+
function set16BitNumber(buf, offset, value) {
|
|
114710
|
+
const temp = new Uint8Array(2);
|
|
114711
|
+
new Uint16Array(temp.buffer)[0] = value | 0;
|
|
114712
|
+
buf[offset] = temp[0];
|
|
114713
|
+
buf[offset + 1] = temp[1];
|
|
114714
|
+
}
|
|
114594
114715
|
})(assets = pxt.assets || (pxt.assets = {}));
|
|
114595
114716
|
})(pxt || (pxt = {}));
|
|
114596
114717
|
// See https://github.com/microsoft/TouchDevelop-backend/blob/master/docs/streams.md
|
|
@@ -119193,6 +119314,18 @@ var ts;
|
|
|
119193
119314
|
}
|
|
119194
119315
|
}
|
|
119195
119316
|
assembler.Line = Line;
|
|
119317
|
+
const MAX_OBJ_USERS = 5;
|
|
119318
|
+
class AsmObject {
|
|
119319
|
+
constructor(id, description) {
|
|
119320
|
+
this.id = id;
|
|
119321
|
+
this.description = description;
|
|
119322
|
+
this.sizeAdj = 0;
|
|
119323
|
+
this.users = [];
|
|
119324
|
+
}
|
|
119325
|
+
get size() {
|
|
119326
|
+
return (this.endLocation - this.startLocation) - this.sizeAdj;
|
|
119327
|
+
}
|
|
119328
|
+
}
|
|
119196
119329
|
// File is the center of the action: parsing a file into a sequence of Lines
|
|
119197
119330
|
// and also emitting the binary (buf)
|
|
119198
119331
|
class File {
|
|
@@ -119217,6 +119350,11 @@ var ts;
|
|
|
119217
119350
|
this.throwOnError = false;
|
|
119218
119351
|
this.disablePeepHole = false;
|
|
119219
119352
|
this.stackAtLabel = {};
|
|
119353
|
+
this.codeSizeStats = false;
|
|
119354
|
+
this.labelToObject = {};
|
|
119355
|
+
this.idToObject = {};
|
|
119356
|
+
this.objSuspendStart = 0;
|
|
119357
|
+
this.labelsToObjectDone = false;
|
|
119220
119358
|
this.currLine = new Line(this, "<start>");
|
|
119221
119359
|
this.currLine.lineNo = 0;
|
|
119222
119360
|
this.ei = ei;
|
|
@@ -119236,6 +119374,15 @@ var ts;
|
|
|
119236
119374
|
pc() {
|
|
119237
119375
|
return this.location() + this.baseOffset;
|
|
119238
119376
|
}
|
|
119377
|
+
useLabel(name) {
|
|
119378
|
+
if (!this.currObject || name[0] == '.' || this.objSuspendStart)
|
|
119379
|
+
return;
|
|
119380
|
+
const obj = pxtc.U.lookup(this.labelToObject, name);
|
|
119381
|
+
if (!obj || obj == this.currObject)
|
|
119382
|
+
return;
|
|
119383
|
+
if (obj.users.length < MAX_OBJ_USERS && obj.users.indexOf(this.currObject) < 0)
|
|
119384
|
+
obj.users.push(this.currObject);
|
|
119385
|
+
}
|
|
119239
119386
|
// parsing of an "integer", well actually much more than
|
|
119240
119387
|
// just that
|
|
119241
119388
|
parseOneInt(s) {
|
|
@@ -119365,6 +119512,7 @@ var ts;
|
|
|
119365
119512
|
return name;
|
|
119366
119513
|
}
|
|
119367
119514
|
lookupLabel(name, direct = false) {
|
|
119515
|
+
this.useLabel(name);
|
|
119368
119516
|
let v = null;
|
|
119369
119517
|
let scoped = this.scopedName(name);
|
|
119370
119518
|
if (this.labels.hasOwnProperty(scoped)) {
|
|
@@ -119523,6 +119671,37 @@ var ts;
|
|
|
119523
119671
|
};
|
|
119524
119672
|
let num0;
|
|
119525
119673
|
switch (words[0]) {
|
|
119674
|
+
case ".object":
|
|
119675
|
+
if (!this.codeSizeStats) {
|
|
119676
|
+
// do nothing
|
|
119677
|
+
}
|
|
119678
|
+
else if (words[1] == "PUSH") {
|
|
119679
|
+
this.objSuspendStart = this.location();
|
|
119680
|
+
}
|
|
119681
|
+
else if (words[1] == "POP") {
|
|
119682
|
+
if (this.objSuspendStart)
|
|
119683
|
+
this.currObject.sizeAdj += this.location() - this.objSuspendStart;
|
|
119684
|
+
this.objSuspendStart = 0;
|
|
119685
|
+
}
|
|
119686
|
+
else {
|
|
119687
|
+
if (this.currObject)
|
|
119688
|
+
this.currObject.endLocation = this.location();
|
|
119689
|
+
this.currObject = pxtc.U.lookup(this.idToObject, words[1]);
|
|
119690
|
+
if (!this.currObject) {
|
|
119691
|
+
const str = l.text.replace(/^[^"]*/, "");
|
|
119692
|
+
let parsed = words[1];
|
|
119693
|
+
if (words.length > 2) {
|
|
119694
|
+
parsed = parseString(str.trim());
|
|
119695
|
+
if (parsed == null)
|
|
119696
|
+
this.directiveError(lf("expecting string in .object"));
|
|
119697
|
+
}
|
|
119698
|
+
this.currObject = new AsmObject(words[1], parsed);
|
|
119699
|
+
this.idToObject[words[1]] = this.currObject;
|
|
119700
|
+
}
|
|
119701
|
+
this.currObject.sizeAdj = 0;
|
|
119702
|
+
this.currObject.startLocation = this.location();
|
|
119703
|
+
}
|
|
119704
|
+
break;
|
|
119526
119705
|
case ".ascii":
|
|
119527
119706
|
case ".asciz":
|
|
119528
119707
|
case ".string":
|
|
@@ -119717,6 +119896,8 @@ var ts;
|
|
|
119717
119896
|
}
|
|
119718
119897
|
}
|
|
119719
119898
|
handleOneInstruction(ln, instr) {
|
|
119899
|
+
if (this.codeSizeStats && ln.ldlitLabel)
|
|
119900
|
+
this.useLabel(ln.ldlitLabel);
|
|
119720
119901
|
let op = instr.emit(ln);
|
|
119721
119902
|
if (!op.error) {
|
|
119722
119903
|
this.stack += op.stack;
|
|
@@ -119825,6 +120006,8 @@ var ts;
|
|
|
119825
120006
|
if (l.words.length == 0)
|
|
119826
120007
|
return;
|
|
119827
120008
|
if (l.type == "label") {
|
|
120009
|
+
if (this.currObject && !this.labelsToObjectDone && l.words[0][0] != '.')
|
|
120010
|
+
this.labelToObject[l.words[0]] = this.currObject;
|
|
119828
120011
|
let lblname = this.scopedName(l.words[0]);
|
|
119829
120012
|
this.prevLabel = lblname;
|
|
119830
120013
|
if (this.finalEmit) {
|
|
@@ -119865,6 +120048,8 @@ var ts;
|
|
|
119865
120048
|
pxtc.oops();
|
|
119866
120049
|
}
|
|
119867
120050
|
});
|
|
120051
|
+
this.labelsToObjectDone = true;
|
|
120052
|
+
this.currObject = null;
|
|
119868
120053
|
}
|
|
119869
120054
|
getSourceMap() {
|
|
119870
120055
|
const sourceMap = {};
|
|
@@ -119897,6 +120082,22 @@ var ts;
|
|
|
119897
120082
|
}
|
|
119898
120083
|
return sourceMap;
|
|
119899
120084
|
}
|
|
120085
|
+
getCodeSizeStats() {
|
|
120086
|
+
if (!this.codeSizeStats)
|
|
120087
|
+
return "";
|
|
120088
|
+
const objs = pxtc.U.values(this.idToObject);
|
|
120089
|
+
objs.sort((a, b) => b.size - a.size);
|
|
120090
|
+
let r = ";\n; Code size:\n;\n";
|
|
120091
|
+
for (const obj of objs) {
|
|
120092
|
+
r += `; ${(" " + obj.size).slice(-6)} ${obj.description} [${obj.id}]\n`;
|
|
120093
|
+
if (obj.users.length >= MAX_OBJ_USERS)
|
|
120094
|
+
r += `; by many, including ${obj.users[0].description}\n`;
|
|
120095
|
+
else
|
|
120096
|
+
for (const x of obj.users)
|
|
120097
|
+
r += `; by ${x.description} [${x.id}]\n`;
|
|
120098
|
+
}
|
|
120099
|
+
return r;
|
|
120100
|
+
}
|
|
119900
120101
|
getSource(clean, numStmts = 1, flashSize = 0) {
|
|
119901
120102
|
let lenPrev = 0;
|
|
119902
120103
|
let size = (lbl) => {
|
|
@@ -119912,8 +120113,11 @@ var ts;
|
|
|
119912
120113
|
let lenLiterals = size("_literals_end");
|
|
119913
120114
|
let lenAllCode = lenPrev;
|
|
119914
120115
|
let totalSize = (lenTotal + this.baseOffset) & 0xffffff;
|
|
119915
|
-
if (flashSize && totalSize > flashSize)
|
|
119916
|
-
|
|
120116
|
+
if (flashSize && totalSize > flashSize) {
|
|
120117
|
+
const e = new Error(lf("program too big by {0} bytes!", totalSize - flashSize));
|
|
120118
|
+
e.ksErrorCode = 9283;
|
|
120119
|
+
throw e;
|
|
120120
|
+
}
|
|
119917
120121
|
flashSize = flashSize || 128 * 1024;
|
|
119918
120122
|
let totalInfo = lf("; total bytes: {0} ({1}% of {2}k flash with {3} free)", totalSize, (100 * totalSize / flashSize).toFixed(1), (flashSize / 1024).toFixed(1), flashSize - totalSize);
|
|
119919
120123
|
let res =
|
|
@@ -119921,7 +120125,7 @@ var ts;
|
|
|
119921
120125
|
lf("; generated code sizes (bytes): {0} (incl. {1} user, {2} helpers, {3} vtables, {4} lits); src size {5}\n", lenAllCode, lenCode, lenHelpers, lenVtables, lenLiterals, lenTotal - lenAllCode) +
|
|
119922
120126
|
lf("; assembly: {0} lines; density: {1} bytes/stmt; ({2} stmts)\n", this.lines.length, Math.round(100 * lenCode / numStmts) / 100, numStmts) +
|
|
119923
120127
|
totalInfo + "\n" +
|
|
119924
|
-
this.stats + "\n\n";
|
|
120128
|
+
this.stats + this.getCodeSizeStats() + "\n\n";
|
|
119925
120129
|
let skipOne = false;
|
|
119926
120130
|
this.lines.forEach((ln, i) => {
|
|
119927
120131
|
if (ln.words[0] == "_stored_program") {
|
|
@@ -121722,6 +121926,7 @@ var ts;
|
|
|
121722
121926
|
const info = utf8AsmStringLiteral(strLit);
|
|
121723
121927
|
return `
|
|
121724
121928
|
.balign 4
|
|
121929
|
+
.object ${lbl}
|
|
121725
121930
|
${lbl}: ${this.obj_header(info.vt)}
|
|
121726
121931
|
${info.asm}
|
|
121727
121932
|
`;
|
|
@@ -121732,6 +121937,7 @@ var ts;
|
|
|
121732
121937
|
const align = /f{16}/i.test(data) ? 8 : 4;
|
|
121733
121938
|
return `
|
|
121734
121939
|
.balign ${align}
|
|
121940
|
+
.object ${lbl}
|
|
121735
121941
|
${lbl}: ${this.obj_header("pxt::buffer_vt")}
|
|
121736
121942
|
${hexLiteralAsm(data)}
|
|
121737
121943
|
`;
|
|
@@ -121841,6 +122047,7 @@ ${hexLiteralAsm(data)}
|
|
|
121841
122047
|
;
|
|
121842
122048
|
`);
|
|
121843
122049
|
let baseLabel = this.proc.label();
|
|
122050
|
+
this.write(`.object ${baseLabel} ${JSON.stringify(this.proc.getFullName())}`);
|
|
121844
122051
|
let preLabel = baseLabel + "_pre";
|
|
121845
122052
|
let bkptLabel = baseLabel + "_bkpt";
|
|
121846
122053
|
let locLabel = baseLabel + "_locals";
|
|
@@ -122205,9 +122412,13 @@ ${baseLabel}_nochk:
|
|
|
122205
122412
|
this.writeFailBranch();
|
|
122206
122413
|
});
|
|
122207
122414
|
}
|
|
122415
|
+
helperObject(desc) {
|
|
122416
|
+
return `.object _pxt_helper_${desc.replace(/[^\w]+/g, "_")} "helper: ${desc}"`;
|
|
122417
|
+
}
|
|
122208
122418
|
emitBindHelper() {
|
|
122209
122419
|
const maxArgs = 12;
|
|
122210
122420
|
this.write(`
|
|
122421
|
+
${this.helperObject("bind")}
|
|
122211
122422
|
.section code
|
|
122212
122423
|
_pxt_bind_helper:
|
|
122213
122424
|
push {r0, r2}
|
|
@@ -122682,6 +122893,7 @@ ${baseLabel}_nochk:
|
|
|
122682
122893
|
emitFieldMethods() {
|
|
122683
122894
|
for (let op of ["get", "set"]) {
|
|
122684
122895
|
this.write(`
|
|
122896
|
+
${this.helperObject(op)}
|
|
122685
122897
|
.section code
|
|
122686
122898
|
_pxt_map_${op}:
|
|
122687
122899
|
`);
|
|
@@ -122723,6 +122935,7 @@ ${baseLabel}_nochk:
|
|
|
122723
122935
|
}
|
|
122724
122936
|
emitArrayMethod(op, isBuffer) {
|
|
122725
122937
|
this.write(`
|
|
122938
|
+
${this.helperObject(op + " " + (isBuffer ? "buffer" : "array"))}
|
|
122726
122939
|
.section code
|
|
122727
122940
|
_pxt_${isBuffer ? "buffer" : "array"}_${op}:
|
|
122728
122941
|
`);
|
|
@@ -122807,6 +123020,7 @@ ${baseLabel}_nochk:
|
|
|
122807
123020
|
emitLambdaTrampoline() {
|
|
122808
123021
|
let r3 = pxtc.target.stackAlign ? "r3," : "";
|
|
122809
123022
|
this.write(`
|
|
123023
|
+
${this.helperObject("trampoline")}
|
|
122810
123024
|
.section code
|
|
122811
123025
|
_pxt_lambda_trampoline:
|
|
122812
123026
|
push {${r3} r4, r5, r6, r7, lr}
|
|
@@ -122846,6 +123060,7 @@ ${baseLabel}_nochk:
|
|
|
122846
123060
|
mov r11, r7
|
|
122847
123061
|
pop {${r3} r4, r5, r6, r7, pc}`);
|
|
122848
123062
|
this.write(`
|
|
123063
|
+
${this.helperObject("exn")}
|
|
122849
123064
|
.section code
|
|
122850
123065
|
; r0 - try frame
|
|
122851
123066
|
; r1 - handler PC
|
|
@@ -122874,6 +123089,7 @@ ${baseLabel}_nochk:
|
|
|
122874
123089
|
bx r1
|
|
122875
123090
|
`);
|
|
122876
123091
|
this.write(`
|
|
123092
|
+
${this.helperObject("stringconv")}
|
|
122877
123093
|
.section code
|
|
122878
123094
|
_pxt_stringConv:
|
|
122879
123095
|
`);
|
|
@@ -124188,6 +124404,7 @@ _numops_fromInt:
|
|
|
124188
124404
|
// this make sure to set the Z flag correctly
|
|
124189
124405
|
r += `
|
|
124190
124406
|
.section code
|
|
124407
|
+
.object _pxt_helper_cmp_${op}
|
|
124191
124408
|
_cmp_${op}:
|
|
124192
124409
|
lsls r2, r0, #31
|
|
124193
124410
|
beq .boxed
|
|
@@ -128773,7 +128990,8 @@ var ts;
|
|
|
128773
128990
|
lbl = "_ldlit_" + ++seq;
|
|
128774
128991
|
values[v] = lbl;
|
|
128775
128992
|
}
|
|
128776
|
-
line.
|
|
128993
|
+
line.ldlitLabel = line.words[3];
|
|
128994
|
+
line.update(`ldr ${reg}, ${lbl} ; ${line.ldlitLabel}`);
|
|
128777
128995
|
}
|
|
128778
128996
|
if (line === nextGoodSpot) {
|
|
128779
128997
|
nextGoodSpot = null;
|
|
@@ -128781,6 +128999,7 @@ var ts;
|
|
|
128781
128999
|
let jmplbl = "_jmpwords_" + ++seq;
|
|
128782
129000
|
if (needsJumpOver)
|
|
128783
129001
|
txtLines.push("bb " + jmplbl);
|
|
129002
|
+
txtLines.push(`.object PUSH`);
|
|
128784
129003
|
txtLines.push(".balign 4");
|
|
128785
129004
|
for (let v of Object.keys(values)) {
|
|
128786
129005
|
let lbl = values[v];
|
|
@@ -128788,6 +129007,7 @@ var ts;
|
|
|
128788
129007
|
}
|
|
128789
129008
|
if (needsJumpOver)
|
|
128790
129009
|
txtLines.push(jmplbl + ":");
|
|
129010
|
+
txtLines.push(`.object POP`);
|
|
128791
129011
|
for (let t of txtLines) {
|
|
128792
129012
|
f.buildLine(t, outlines);
|
|
128793
129013
|
let ll = outlines[outlines.length - 1];
|
|
@@ -130082,7 +130302,7 @@ var ts;
|
|
|
130082
130302
|
function inspect(n) {
|
|
130083
130303
|
console.log(stringKind(n));
|
|
130084
130304
|
}
|
|
130085
|
-
// next free error
|
|
130305
|
+
// next free error 9284
|
|
130086
130306
|
function userError(code, msg, secondary = false) {
|
|
130087
130307
|
let e = new Error(msg);
|
|
130088
130308
|
e.ksEmitterUserError = true;
|
|
@@ -136252,7 +136472,8 @@ var ts;
|
|
|
136252
136472
|
asmLabels[lbl] = true;
|
|
136253
136473
|
return "";
|
|
136254
136474
|
});
|
|
136255
|
-
let code = ".
|
|
136475
|
+
let code = ".object inlineasm\n" +
|
|
136476
|
+
".section code\n" +
|
|
136256
136477
|
"@stackmark func\n" +
|
|
136257
136478
|
"@scope user" + asmIdx++ + "\n" +
|
|
136258
136479
|
src + "\n" +
|
|
@@ -136785,6 +137006,7 @@ var ts;
|
|
|
136785
137006
|
for (let data of Object.keys(bin.doubles)) {
|
|
136786
137007
|
let lbl = bin.doubles[data];
|
|
136787
137008
|
bin.otherLiterals.push(`
|
|
137009
|
+
.object ${lbl}
|
|
136788
137010
|
.balign 4
|
|
136789
137011
|
${lbl}: ${snippets.obj_header("pxt::number_vt")}
|
|
136790
137012
|
.hex ${data}
|
|
@@ -136877,6 +137099,7 @@ ${lbl}: ${snippets.obj_header("pxt::number_vt")}
|
|
|
136877
137099
|
// ifaceInfo.mult = 0
|
|
136878
137100
|
let ptrSz = pxtc.target.shortPointers ? ".short" : ".word";
|
|
136879
137101
|
let s = `
|
|
137102
|
+
.object ${info.id}_VT
|
|
136880
137103
|
.balign 4
|
|
136881
137104
|
${info.id}_VT:
|
|
136882
137105
|
.short ${info.allfields.length * 4 + 4} ; size in bytes
|
|
@@ -136974,14 +137197,18 @@ ${hexfile.hexPrelude()}
|
|
|
136974
137197
|
asmsource += hexfile.asmTotalSource; // user-supplied asm
|
|
136975
137198
|
asmsource += "_code_end:\n\n";
|
|
136976
137199
|
pxtc.U.iterMap(bin.codeHelpers, (code, lbl) => {
|
|
136977
|
-
asmsource +=
|
|
137200
|
+
asmsource +=
|
|
137201
|
+
` .section code\n` +
|
|
137202
|
+
` .object _code_helper_${lbl}\n` +
|
|
137203
|
+
`${lbl}:\n` +
|
|
137204
|
+
`${code}\n`;
|
|
136978
137205
|
});
|
|
136979
137206
|
asmsource += snippets.arithmetic();
|
|
136980
137207
|
asmsource += "_helpers_end:\n\n";
|
|
136981
137208
|
bin.usedClassInfos.forEach(info => {
|
|
136982
137209
|
asmsource += vtableToAsm(info, opts, bin);
|
|
136983
137210
|
});
|
|
136984
|
-
asmsource += `\n.balign 4\n_pxt_iface_member_names:\n`;
|
|
137211
|
+
asmsource += `\n.balign 4\n.object _pxt_iface_member_names\n_pxt_iface_member_names:\n`;
|
|
136985
137212
|
asmsource += ` .word ${bin.ifaceMembers.length}\n`;
|
|
136986
137213
|
let idx = 0;
|
|
136987
137214
|
for (let d of bin.ifaceMembers) {
|
|
@@ -136990,7 +137217,7 @@ ${hexfile.hexPrelude()}
|
|
|
136990
137217
|
}
|
|
136991
137218
|
asmsource += ` .word 0\n`;
|
|
136992
137219
|
asmsource += "_vtables_end:\n\n";
|
|
136993
|
-
asmsource += `\n.balign 4\n_pxt_config_data:\n`;
|
|
137220
|
+
asmsource += `\n.balign 4\n.object _pxt_config_data\n_pxt_config_data:\n`;
|
|
136994
137221
|
const cfg = bin.res.configData || [];
|
|
136995
137222
|
// asmsource += ` .word ${cfg.length}, 0 ; num. entries`
|
|
136996
137223
|
for (let d of cfg) {
|
|
@@ -136999,7 +137226,7 @@ ${hexfile.hexPrelude()}
|
|
|
136999
137226
|
asmsource += ` .word 0\n\n`;
|
|
137000
137227
|
emitStrings(snippets, bin);
|
|
137001
137228
|
asmsource += bin.otherLiterals.join("");
|
|
137002
|
-
asmsource += `\n.balign 4\n.section code\n_pxt_perf_counters:\n`;
|
|
137229
|
+
asmsource += `\n.balign 4\n.section code\n.object _perf_counters\n_pxt_perf_counters:\n`;
|
|
137003
137230
|
asmsource += ` .word ${perfCounters.length}\n`;
|
|
137004
137231
|
let strs = "";
|
|
137005
137232
|
for (let i = 0; i < perfCounters.length; ++i) {
|
|
@@ -137032,6 +137259,8 @@ ${hexfile.hexPrelude()}
|
|
|
137032
137259
|
b.ei.testAssembler(); // just in case
|
|
137033
137260
|
if (target.switches.noPeepHole)
|
|
137034
137261
|
b.disablePeepHole = true;
|
|
137262
|
+
if (target.switches.size)
|
|
137263
|
+
b.codeSizeStats = true;
|
|
137035
137264
|
b.lookupExternalLabel = hexfile.lookupFunctionAddr;
|
|
137036
137265
|
b.normalizeExternalLabel = s => {
|
|
137037
137266
|
let inf = hexfile.lookupFunc(s);
|
|
@@ -137092,6 +137321,7 @@ ${hexfile.hexPrelude()}
|
|
|
137092
137321
|
}
|
|
137093
137322
|
return `
|
|
137094
137323
|
.balign 16
|
|
137324
|
+
.object _stored_program
|
|
137095
137325
|
_stored_program: .hex ${res}
|
|
137096
137326
|
`;
|
|
137097
137327
|
}
|
|
@@ -139639,7 +139869,7 @@ var ts;
|
|
|
139639
139869
|
}
|
|
139640
139870
|
const type = checker === null || checker === void 0 ? void 0 : checker.getTypeAtLocation(param);
|
|
139641
139871
|
const typeSymbol = service.getPxtSymbolFromTsSymbol(type === null || type === void 0 ? void 0 : type.symbol, apis, checker);
|
|
139642
|
-
if ((typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.fixedInstances) && python) {
|
|
139872
|
+
if (((typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.fixedInstances) || (typeSymbol === null || typeSymbol === void 0 ? void 0 : typeSymbol.attributes.emitAsConstant)) && python) {
|
|
139643
139873
|
return pxt.Util.snakify(paramDefl);
|
|
139644
139874
|
}
|
|
139645
139875
|
if (python) {
|
|
@@ -153272,7 +153502,7 @@ var pxsim;
|
|
|
153272
153502
|
}
|
|
153273
153503
|
}
|
|
153274
153504
|
createFrame(url) {
|
|
153275
|
-
var _a;
|
|
153505
|
+
var _a, _b;
|
|
153276
153506
|
const wrapper = document.createElement("div");
|
|
153277
153507
|
wrapper.className = `simframe ui embed`;
|
|
153278
153508
|
const frame = document.createElement('iframe');
|
|
@@ -153283,7 +153513,7 @@ var pxsim;
|
|
|
153283
153513
|
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts');
|
|
153284
153514
|
frame.className = 'no-select';
|
|
153285
153515
|
let furl = url || this.getSimUrl().toString();
|
|
153286
|
-
if (this._runOptions.hideSimButtons) {
|
|
153516
|
+
if ((_a = this._runOptions) === null || _a === void 0 ? void 0 : _a.hideSimButtons) {
|
|
153287
153517
|
const urlObject = new URL(furl);
|
|
153288
153518
|
urlObject.searchParams.append("hideSimButtons", "1");
|
|
153289
153519
|
furl = urlObject.toString();
|
|
@@ -153293,7 +153523,7 @@ var pxsim;
|
|
|
153293
153523
|
frame.frameBorder = "0";
|
|
153294
153524
|
frame.dataset['runid'] = this.runId;
|
|
153295
153525
|
frame.dataset['origin'] = new URL(furl).origin || "*";
|
|
153296
|
-
if ((
|
|
153526
|
+
if ((_b = this._runOptions) === null || _b === void 0 ? void 0 : _b.autofocus)
|
|
153297
153527
|
frame.setAttribute("autofocus", "true");
|
|
153298
153528
|
wrapper.appendChild(frame);
|
|
153299
153529
|
const i = document.createElement("i");
|
|
@@ -154227,92 +154457,10 @@ var pxsim;
|
|
|
154227
154457
|
.then(() => {
|
|
154228
154458
|
if (prevStop != instrStopId)
|
|
154229
154459
|
return Promise.resolve();
|
|
154230
|
-
return playInstructionsAsync(b);
|
|
154460
|
+
return playInstructionsAsync(b.data);
|
|
154231
154461
|
});
|
|
154232
154462
|
}
|
|
154233
154463
|
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
154464
|
function tone(frequency, gain) {
|
|
154317
154465
|
if (frequency < 0)
|
|
154318
154466
|
return;
|
|
@@ -154451,6 +154599,126 @@ var pxsim;
|
|
|
154451
154599
|
function frequencyFromMidiNoteNumber(note) {
|
|
154452
154600
|
return 440 * Math.pow(2, (note - 69) / 12);
|
|
154453
154601
|
}
|
|
154602
|
+
function playInstructionsAsync(instructions, isCancelled, onPull) {
|
|
154603
|
+
return new Promise(async (resolve) => {
|
|
154604
|
+
let resolved = false;
|
|
154605
|
+
let ctx = context();
|
|
154606
|
+
let channel = new Channel();
|
|
154607
|
+
if (channels.length > 5)
|
|
154608
|
+
channels[0].remove();
|
|
154609
|
+
channels.push(channel);
|
|
154610
|
+
channel.gain = ctx.createGain();
|
|
154611
|
+
channel.gain.gain.value = 1;
|
|
154612
|
+
channel.gain.connect(destination);
|
|
154613
|
+
const oscillators = {};
|
|
154614
|
+
const gains = {};
|
|
154615
|
+
let startTime = ctx.currentTime;
|
|
154616
|
+
let currentTime = startTime;
|
|
154617
|
+
let currentWave = 0;
|
|
154618
|
+
let totalDuration = 0;
|
|
154619
|
+
/** Square waves are perceved as much louder than other sounds, so scale it down a bit to make it less jarring **/
|
|
154620
|
+
const scaleVol = (n, isSqWave) => (n / 1024) / 4 * (isSqWave ? .5 : 1);
|
|
154621
|
+
const disconnectNodes = () => {
|
|
154622
|
+
if (resolved)
|
|
154623
|
+
return;
|
|
154624
|
+
resolved = true;
|
|
154625
|
+
channel.disconnectNodes();
|
|
154626
|
+
for (const wave of Object.keys(oscillators)) {
|
|
154627
|
+
oscillators[wave].stop();
|
|
154628
|
+
oscillators[wave].disconnect();
|
|
154629
|
+
gains[wave].disconnect();
|
|
154630
|
+
}
|
|
154631
|
+
resolve();
|
|
154632
|
+
};
|
|
154633
|
+
for (let i = 0; i < instructions.length; i += 12) {
|
|
154634
|
+
const wave = instructions[i];
|
|
154635
|
+
const startFrequency = readUint16(instructions, i + 2);
|
|
154636
|
+
const duration = readUint16(instructions, i + 4) / 1000;
|
|
154637
|
+
const startVolume = readUint16(instructions, i + 6);
|
|
154638
|
+
const endVolume = readUint16(instructions, i + 8);
|
|
154639
|
+
const endFrequency = readUint16(instructions, i + 10);
|
|
154640
|
+
totalDuration += duration;
|
|
154641
|
+
const isSquareWave = 11 <= wave && wave <= 15;
|
|
154642
|
+
if (!oscillators[wave]) {
|
|
154643
|
+
oscillators[wave] = getGenerator(wave, startFrequency);
|
|
154644
|
+
gains[wave] = ctx.createGain();
|
|
154645
|
+
gains[wave].gain.value = 0;
|
|
154646
|
+
gains[wave].connect(channel.gain);
|
|
154647
|
+
oscillators[wave].connect(gains[wave]);
|
|
154648
|
+
oscillators[wave].start();
|
|
154649
|
+
}
|
|
154650
|
+
if (currentWave && wave !== currentWave) {
|
|
154651
|
+
gains[currentWave].gain.setTargetAtTime(0, currentTime, 0.015);
|
|
154652
|
+
}
|
|
154653
|
+
const osc = oscillators[wave];
|
|
154654
|
+
const gain = gains[wave];
|
|
154655
|
+
if (osc instanceof OscillatorNode) {
|
|
154656
|
+
osc.frequency.setValueAtTime(startFrequency, currentTime);
|
|
154657
|
+
osc.frequency.linearRampToValueAtTime(endFrequency, currentTime + duration);
|
|
154658
|
+
}
|
|
154659
|
+
else {
|
|
154660
|
+
const isFilteredNoise = wave == 4 || (16 <= wave && wave <= 18);
|
|
154661
|
+
if (isFilteredNoise)
|
|
154662
|
+
osc.playbackRate.linearRampToValueAtTime(endFrequency / (ctx.sampleRate / 4), currentTime + duration);
|
|
154663
|
+
else if (wave != 5)
|
|
154664
|
+
osc.playbackRate.linearRampToValueAtTime(endFrequency / (ctx.sampleRate / 1024), currentTime + duration);
|
|
154665
|
+
}
|
|
154666
|
+
gain.gain.setValueAtTime(scaleVol(startVolume, isSquareWave), currentTime);
|
|
154667
|
+
gain.gain.linearRampToValueAtTime(scaleVol(endVolume, isSquareWave), currentTime + duration);
|
|
154668
|
+
currentWave = wave;
|
|
154669
|
+
currentTime += duration;
|
|
154670
|
+
}
|
|
154671
|
+
channel.gain.gain.setTargetAtTime(0, currentTime, 0.015);
|
|
154672
|
+
if (isCancelled || onPull) {
|
|
154673
|
+
const handleAnimationFrame = () => {
|
|
154674
|
+
const time = ctx.currentTime;
|
|
154675
|
+
if (time > startTime + totalDuration) {
|
|
154676
|
+
return;
|
|
154677
|
+
}
|
|
154678
|
+
if (isCancelled && isCancelled()) {
|
|
154679
|
+
disconnectNodes();
|
|
154680
|
+
return;
|
|
154681
|
+
}
|
|
154682
|
+
const { frequency, volume } = findFrequencyAndVolumeAtTime((time - startTime) * 1000, instructions);
|
|
154683
|
+
onPull(frequency, volume / 1024);
|
|
154684
|
+
requestAnimationFrame(handleAnimationFrame);
|
|
154685
|
+
};
|
|
154686
|
+
requestAnimationFrame(handleAnimationFrame);
|
|
154687
|
+
}
|
|
154688
|
+
await pxsim.U.delay(totalDuration * 1000);
|
|
154689
|
+
disconnectNodes();
|
|
154690
|
+
});
|
|
154691
|
+
}
|
|
154692
|
+
AudioContextManager.playInstructionsAsync = playInstructionsAsync;
|
|
154693
|
+
function readUint16(buf, offset) {
|
|
154694
|
+
const temp = new Uint8Array(2);
|
|
154695
|
+
temp[0] = buf[offset];
|
|
154696
|
+
temp[1] = buf[offset + 1];
|
|
154697
|
+
return new Uint16Array(temp.buffer)[0];
|
|
154698
|
+
}
|
|
154699
|
+
function findFrequencyAndVolumeAtTime(millis, instructions) {
|
|
154700
|
+
let currentTime = 0;
|
|
154701
|
+
for (let i = 0; i < instructions.length; i += 12) {
|
|
154702
|
+
const startFrequency = readUint16(instructions, i + 2);
|
|
154703
|
+
const duration = readUint16(instructions, i + 4);
|
|
154704
|
+
const startVolume = readUint16(instructions, i + 6);
|
|
154705
|
+
const endVolume = readUint16(instructions, i + 8);
|
|
154706
|
+
const endFrequency = readUint16(instructions, i + 10);
|
|
154707
|
+
if (currentTime + duration < millis) {
|
|
154708
|
+
currentTime += duration;
|
|
154709
|
+
continue;
|
|
154710
|
+
}
|
|
154711
|
+
const offset = (millis - currentTime) / duration;
|
|
154712
|
+
return {
|
|
154713
|
+
frequency: startFrequency + (endFrequency - startFrequency) * offset,
|
|
154714
|
+
volume: startVolume + (endVolume - startVolume) * offset,
|
|
154715
|
+
};
|
|
154716
|
+
}
|
|
154717
|
+
return {
|
|
154718
|
+
frequency: -1,
|
|
154719
|
+
volume: -1
|
|
154720
|
+
};
|
|
154721
|
+
}
|
|
154454
154722
|
function sendMidiMessage(buf) {
|
|
154455
154723
|
const data = buf.data;
|
|
154456
154724
|
if (!data.length) // garbage.
|