pxt-common-packages 10.1.7 → 10.1.10
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/common-sim.js +3 -3
- package/libs/azureiot/built/debug/binary.js +461 -461
- package/libs/color/built/debug/binary.js +8 -8
- package/libs/color-sensor/built/debug/binary.js +8 -8
- package/libs/controller/built/debug/binary.js +8032 -7916
- package/libs/controller---none/built/debug/binary.js +8011 -7895
- package/libs/datalogger/built/debug/binary.js +63 -63
- package/libs/edge-connector/built/debug/binary.js +8 -8
- package/libs/esp32/built/debug/binary.js +462 -462
- package/libs/game/built/debug/binary.js +7924 -7808
- package/libs/game/camera.ts +3 -4
- package/libs/game/physics.ts +30 -0
- package/libs/game/sprite.ts +0 -22
- package/libs/game---light/compat.ts +10 -0
- package/libs/game---light/pxt.json +1 -3
- package/libs/lcd/built/debug/binary.js +8 -8
- package/libs/light-spectrum-sensor/built/debug/binary.js +8 -8
- package/libs/lora/built/debug/binary.js +8 -8
- package/libs/matrix-keypad/built/debug/binary.js +8 -8
- package/libs/mixer/melody.ts +2 -2
- package/libs/mixer/pxt.json +1 -0
- package/libs/mixer/sim/music.ts +1 -1
- package/libs/mixer/soundEffect.ts +380 -0
- package/libs/mqtt/built/debug/binary.js +176 -176
- package/libs/net/built/debug/binary.js +176 -176
- package/libs/net-game/built/debug/binary.js +9712 -9596
- package/libs/palette/built/debug/binary.js +7923 -7807
- package/libs/pixel/built/debug/binary.js +8 -8
- package/libs/power/built/debug/binary.js +8 -8
- package/libs/proximity/built/debug/binary.js +8 -8
- package/libs/radio/built/debug/binary.js +8 -8
- package/libs/radio-broadcast/built/debug/binary.js +8 -8
- package/libs/rotary-encoder/built/debug/binary.js +8 -8
- package/libs/screen/built/debug/binary.js +50 -50
- package/libs/screen/sim/image.ts +2 -2
- package/libs/screen---st7735/screen.cpp +7 -0
- package/libs/servo/built/debug/binary.js +8 -8
- package/libs/sprite-scaling/built/debug/binary.js +7923 -7807
- package/libs/storyboard/built/debug/binary.js +7923 -7807
- package/package.json +2 -2
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
enum WaveShape {
|
|
2
|
+
//% block="sine"
|
|
3
|
+
Sine = 0,
|
|
4
|
+
//% block="sawtooth"
|
|
5
|
+
Sawtooth = 1,
|
|
6
|
+
//% block="triangle"
|
|
7
|
+
Triangle = 2,
|
|
8
|
+
//% block="square"
|
|
9
|
+
Square = 3,
|
|
10
|
+
//% block="noise"
|
|
11
|
+
Noise = 4
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
enum InterpolationCurve {
|
|
15
|
+
//% block="linear"
|
|
16
|
+
Linear,
|
|
17
|
+
//% block="curve"
|
|
18
|
+
Curve,
|
|
19
|
+
//% block="logarithmic"
|
|
20
|
+
Logarithmic
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
enum SoundExpressionEffect {
|
|
24
|
+
//% block="none"
|
|
25
|
+
None = 0,
|
|
26
|
+
//% block="vibrato"
|
|
27
|
+
Vibrato = 1,
|
|
28
|
+
//% block="tremolo"
|
|
29
|
+
Tremolo = 2,
|
|
30
|
+
//% block="warble"
|
|
31
|
+
Warble = 3
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
enum SoundExpressionPlayMode {
|
|
35
|
+
//% block="until done"
|
|
36
|
+
UntilDone,
|
|
37
|
+
//% block="in background"
|
|
38
|
+
InBackground
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
namespace music {
|
|
42
|
+
export class SoundEffect {
|
|
43
|
+
waveShape: WaveShape;
|
|
44
|
+
startFrequency: number;
|
|
45
|
+
endFrequency: number;
|
|
46
|
+
startVolume: number;
|
|
47
|
+
endVolume: number;
|
|
48
|
+
duration: number;
|
|
49
|
+
effect: SoundExpressionEffect;
|
|
50
|
+
interpolation: InterpolationCurve;
|
|
51
|
+
|
|
52
|
+
constructor() {
|
|
53
|
+
this.waveShape = WaveShape.Sine;
|
|
54
|
+
this.startFrequency = 5000;
|
|
55
|
+
this.endFrequency = 1;
|
|
56
|
+
this.startVolume = 255;
|
|
57
|
+
this.endVolume = 0;
|
|
58
|
+
this.duration = 1000;
|
|
59
|
+
this.effect = SoundExpressionEffect.None;
|
|
60
|
+
this.interpolation = InterpolationCurve.Linear;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
toBuffer(volume?: number) {
|
|
64
|
+
if (volume === undefined) volume = music.volume();
|
|
65
|
+
|
|
66
|
+
return soundToInstructionBuffer(
|
|
67
|
+
this.waveShape,
|
|
68
|
+
this.startFrequency,
|
|
69
|
+
this.endFrequency,
|
|
70
|
+
this.startVolume,
|
|
71
|
+
this.endVolume,
|
|
72
|
+
this.duration,
|
|
73
|
+
this.effect,
|
|
74
|
+
this.interpolation,
|
|
75
|
+
20,
|
|
76
|
+
1,
|
|
77
|
+
volume
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Play a SoundEffect.
|
|
85
|
+
* @param sound the SoundEffect to play
|
|
86
|
+
* @param mode the play mode, play until done or in the background
|
|
87
|
+
*/
|
|
88
|
+
//% blockId=soundExpression_playSoundEffect
|
|
89
|
+
//% block="play sound $sound $mode"
|
|
90
|
+
//% sound.shadow=soundExpression_createSoundEffect
|
|
91
|
+
//% weight=30
|
|
92
|
+
//% help=music/play-sound-effect
|
|
93
|
+
//% blockGap=8
|
|
94
|
+
//% group="Sounds"
|
|
95
|
+
export function playSoundEffect(sound: SoundEffect, mode: SoundExpressionPlayMode) {
|
|
96
|
+
const toPlay = sound.toBuffer(music.volume());
|
|
97
|
+
|
|
98
|
+
queuePlayInstructions(0, toPlay);
|
|
99
|
+
if (mode === SoundExpressionPlayMode.UntilDone) {
|
|
100
|
+
pause(sound.duration);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a sound expression from a set of sound effect parameters.
|
|
106
|
+
* @param waveShape waveform of the sound effect
|
|
107
|
+
* @param startFrequency starting frequency for the sound effect waveform
|
|
108
|
+
* @param endFrequency ending frequency for the sound effect waveform
|
|
109
|
+
* @param startVolume starting volume of the sound, or starting amplitude
|
|
110
|
+
* @param endVolume ending volume of the sound, or ending amplitude
|
|
111
|
+
* @param duration the amount of time in milliseconds (ms) that sound will play for
|
|
112
|
+
* @param effect the effect to apply to the waveform or volume
|
|
113
|
+
* @param interpolation interpolation method for frequency scaling
|
|
114
|
+
*/
|
|
115
|
+
//% blockId=soundExpression_createSoundEffect
|
|
116
|
+
//% help=music/create-sound-effect
|
|
117
|
+
//% block="$waveShape|| start frequency $startFrequency end frequency $endFrequency duration $duration start volume $startVolume end volume $endVolume effect $effect interpolation $interpolation"
|
|
118
|
+
//% waveShape.defl=WaveShape.Sine
|
|
119
|
+
//% waveShape.fieldEditor=soundeffect
|
|
120
|
+
//% waveShape.fieldOptions.useMixerSynthesizer=true
|
|
121
|
+
//% startFrequency.defl=5000
|
|
122
|
+
//% startFrequency.min=0
|
|
123
|
+
//% startFrequency.max=5000
|
|
124
|
+
//% endFrequency.defl=0
|
|
125
|
+
//% endFrequency.min=0
|
|
126
|
+
//% endFrequency.max=5000
|
|
127
|
+
//% startVolume.defl=255
|
|
128
|
+
//% startVolume.min=0
|
|
129
|
+
//% startVolume.max=255
|
|
130
|
+
//% endVolume.defl=0
|
|
131
|
+
//% endVolume.min=0
|
|
132
|
+
//% endVolume.max=255
|
|
133
|
+
//% duration.defl=500
|
|
134
|
+
//% duration.min=1
|
|
135
|
+
//% duration.max=9999
|
|
136
|
+
//% effect.defl=SoundExpressionEffect.None
|
|
137
|
+
//% interpolation.defl=InterpolationCurve.Linear
|
|
138
|
+
//% compileHiddenArguments=true
|
|
139
|
+
//% inlineInputMode="variable"
|
|
140
|
+
//% inlineInputModeLimit=3
|
|
141
|
+
//% expandableArgumentBreaks="3,5"
|
|
142
|
+
//% weight=20
|
|
143
|
+
//% group="Sounds"
|
|
144
|
+
export function createSoundEffect(waveShape: WaveShape, startFrequency: number, endFrequency: number, startVolume: number, endVolume: number, duration: number, effect: SoundExpressionEffect, interpolation: InterpolationCurve): SoundEffect {
|
|
145
|
+
const result = new SoundEffect();
|
|
146
|
+
|
|
147
|
+
result.waveShape = waveShape;
|
|
148
|
+
result.startFrequency = startFrequency;
|
|
149
|
+
result.endFrequency = endFrequency;
|
|
150
|
+
result.startVolume = startVolume;
|
|
151
|
+
result.endVolume = endVolume;
|
|
152
|
+
result.duration = duration;
|
|
153
|
+
result.effect = effect;
|
|
154
|
+
result.interpolation = interpolation;
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
interface Step {
|
|
160
|
+
frequency: number;
|
|
161
|
+
volume: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function soundToInstructionBuffer(waveShape: WaveShape, startFrequency: number, endFrequency: number, startVolume: number, endVolume: number, duration: number, effect: SoundExpressionEffect, interpolation: InterpolationCurve, fxSteps: number, fxRange: number, globalVolume: number) {
|
|
165
|
+
const steps: Step[] = [];
|
|
166
|
+
|
|
167
|
+
// Optimize the simple case
|
|
168
|
+
if (interpolation === InterpolationCurve.Linear && effect === SoundExpressionEffect.None) {
|
|
169
|
+
steps.push({
|
|
170
|
+
frequency: startFrequency,
|
|
171
|
+
volume: (startVolume / 255) * globalVolume,
|
|
172
|
+
})
|
|
173
|
+
steps.push({
|
|
174
|
+
frequency: endFrequency,
|
|
175
|
+
volume: (endVolume / 255) * globalVolume,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
|
|
180
|
+
fxSteps = Math.min(fxSteps, Math.floor(duration / 5))
|
|
181
|
+
|
|
182
|
+
const getVolumeAt = (t: number) => ((startVolume + t * (endVolume - startVolume) / duration) / 255) * globalVolume;
|
|
183
|
+
let getFrequencyAt: (t: number) => number;
|
|
184
|
+
|
|
185
|
+
switch (interpolation) {
|
|
186
|
+
case InterpolationCurve.Linear:
|
|
187
|
+
getFrequencyAt = t => startFrequency + t * (endFrequency - startFrequency) / duration;
|
|
188
|
+
break;
|
|
189
|
+
case InterpolationCurve.Curve:
|
|
190
|
+
getFrequencyAt = t => startFrequency + (endFrequency - startFrequency) * Math.sin(t / duration * (Math.PI / 2));
|
|
191
|
+
break;
|
|
192
|
+
case InterpolationCurve.Logarithmic:
|
|
193
|
+
getFrequencyAt = t => startFrequency + (Math.log(1 + 9 * (t / duration)) / Math.log(10)) * (endFrequency - startFrequency)
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const timeSlice = duration / fxSteps;
|
|
198
|
+
|
|
199
|
+
for (let i = 0; i < fxSteps; i++) {
|
|
200
|
+
const newStep = {
|
|
201
|
+
frequency: getFrequencyAt(i * timeSlice),
|
|
202
|
+
volume: getVolumeAt(i * timeSlice)
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
if (effect === SoundExpressionEffect.Tremolo) {
|
|
206
|
+
if (i % 2 === 0) {
|
|
207
|
+
newStep.volume = Math.max(newStep.volume - fxRange * 500, 0)
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
newStep.volume = Math.min(newStep.volume + fxRange * 500, 1023)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (effect === SoundExpressionEffect.Vibrato) {
|
|
214
|
+
if (i % 2 === 0) {
|
|
215
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 100, 0)
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
newStep.frequency = newStep.frequency + fxRange * 100
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (effect === SoundExpressionEffect.Warble) {
|
|
222
|
+
if (i % 2 === 0) {
|
|
223
|
+
newStep.frequency = Math.max(newStep.frequency - fxRange * 1000, 0)
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
newStep.frequency = newStep.frequency + fxRange * 1000
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
steps.push(newStep)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const out = control.createBuffer(12 * (steps.length - 1));
|
|
235
|
+
const stepDuration = Math.floor(duration / (steps.length - 1))
|
|
236
|
+
|
|
237
|
+
for (let i = 0; i < steps.length - 1; i++) {
|
|
238
|
+
const offset = i * 12;
|
|
239
|
+
out.setNumber(NumberFormat.UInt8LE, offset, waveToValue(waveShape));
|
|
240
|
+
out.setNumber(NumberFormat.UInt16LE, offset + 2, steps[i].frequency);
|
|
241
|
+
out.setNumber(NumberFormat.UInt16LE, offset + 4, stepDuration);
|
|
242
|
+
out.setNumber(NumberFormat.UInt16LE, offset + 6, steps[i].volume);
|
|
243
|
+
out.setNumber(NumberFormat.UInt16LE, offset + 8, steps[i + 1].volume);
|
|
244
|
+
out.setNumber(NumberFormat.UInt16LE, offset + 10, steps[i + 1].frequency);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return out;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function waveToValue(wave: WaveShape) {
|
|
251
|
+
switch (wave) {
|
|
252
|
+
case WaveShape.Square: return 15;
|
|
253
|
+
case WaveShape.Sine: return 3;
|
|
254
|
+
case WaveShape.Triangle: return 1;
|
|
255
|
+
case WaveShape.Noise: return 18;
|
|
256
|
+
case WaveShape.Sawtooth: return 2;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Generate a random similar sound effect to the given one.
|
|
263
|
+
*
|
|
264
|
+
* @param sound the sound effect
|
|
265
|
+
*/
|
|
266
|
+
//% blockId=soundExpression_generateSimilarSound
|
|
267
|
+
//% block="randomize $sound"
|
|
268
|
+
//% sound.shadow=soundExpression_createSoundEffect
|
|
269
|
+
//% weight=0 help=music/generate-similar-sound
|
|
270
|
+
//% blockGap=8
|
|
271
|
+
//% group="Sounds"
|
|
272
|
+
export function randomizeSound(sound: SoundEffect) {
|
|
273
|
+
const res = new SoundEffect();
|
|
274
|
+
res.waveShape = sound.waveShape;
|
|
275
|
+
res.startFrequency = sound.startFrequency;
|
|
276
|
+
res.endFrequency = sound.endFrequency;
|
|
277
|
+
res.startVolume = sound.startVolume;
|
|
278
|
+
res.endVolume = sound.endVolume;
|
|
279
|
+
res.duration = sound.duration;
|
|
280
|
+
res.effect = sound.effect;
|
|
281
|
+
res.interpolation = randomInterpolation();
|
|
282
|
+
|
|
283
|
+
res.duration = Math.clamp(
|
|
284
|
+
Math.min(100, res.duration),
|
|
285
|
+
Math.max(2000, res.duration),
|
|
286
|
+
res.duration + (Math.random() - 0.5) * res.duration,
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
if (res.waveShape === WaveShape.Noise) {
|
|
290
|
+
// The primary waveforms don't produce sounds that are similar to noise,
|
|
291
|
+
// but adding an effect sorta does
|
|
292
|
+
if (Math.percentChance(20)) {
|
|
293
|
+
res.waveShape = randomWave();
|
|
294
|
+
res.effect = randomEffect();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
res.waveShape = randomWave();
|
|
299
|
+
|
|
300
|
+
// Adding an effect can drastically alter the sound, so keep it
|
|
301
|
+
// at a low percent chance unless there already is one
|
|
302
|
+
if (res.effect !== SoundExpressionEffect.None || Math.percentChance(10)) {
|
|
303
|
+
res.effect = randomEffect();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Instead of randomly changing the frequency, change the slope and choose
|
|
308
|
+
// a new start frequency. This keeps a similar profile to the sound
|
|
309
|
+
const oldFrequencyDifference = res.endFrequency - res.startFrequency;
|
|
310
|
+
let newFrequencyDifference = oldFrequencyDifference + (oldFrequencyDifference * 2) * (Math.random() - 0.5);
|
|
311
|
+
|
|
312
|
+
if (Math.sign(oldFrequencyDifference) !== Math.sign(newFrequencyDifference)) {
|
|
313
|
+
newFrequencyDifference *= -1;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
newFrequencyDifference = Math.clamp(-5000, 5000, newFrequencyDifference);
|
|
317
|
+
|
|
318
|
+
res.startFrequency = Math.clamp(
|
|
319
|
+
Math.max(-newFrequencyDifference, 1),
|
|
320
|
+
Math.clamp(1, 5000, 5000 - newFrequencyDifference),
|
|
321
|
+
Math.random() * 5000,
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
res.endFrequency = Math.clamp(1, 5000, res.startFrequency + newFrequencyDifference);
|
|
325
|
+
|
|
326
|
+
// Same strategy for volume
|
|
327
|
+
const oldVolumeDifference = res.endVolume - res.startVolume;
|
|
328
|
+
let newVolumeDifference = oldVolumeDifference + oldVolumeDifference * (Math.random() - 0.5);
|
|
329
|
+
|
|
330
|
+
newVolumeDifference = Math.clamp(-255, 255, newVolumeDifference);
|
|
331
|
+
|
|
332
|
+
if (Math.sign(oldVolumeDifference) !== Math.sign(newVolumeDifference)) {
|
|
333
|
+
newVolumeDifference *= -1;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
res.startVolume = Math.clamp(
|
|
337
|
+
Math.max(-newVolumeDifference, 0),
|
|
338
|
+
Math.clamp(0, 255, 255 - newVolumeDifference),
|
|
339
|
+
Math.random() * 255,
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
res.endVolume = Math.clamp(0, 255, res.startVolume + newVolumeDifference);
|
|
343
|
+
|
|
344
|
+
return res;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function randomWave() {
|
|
348
|
+
switch (Math.randomRange(0, 3)) {
|
|
349
|
+
case 1: return WaveShape.Sawtooth;
|
|
350
|
+
case 2: return WaveShape.Square;
|
|
351
|
+
case 3: return WaveShape.Triangle;
|
|
352
|
+
case 0:
|
|
353
|
+
default:
|
|
354
|
+
return WaveShape.Sine;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function randomEffect() {
|
|
359
|
+
switch (Math.randomRange(0, 2)) {
|
|
360
|
+
case 1: return SoundExpressionEffect.Warble;
|
|
361
|
+
case 2: return SoundExpressionEffect.Tremolo;
|
|
362
|
+
case 0:
|
|
363
|
+
default:
|
|
364
|
+
return SoundExpressionEffect.Vibrato;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function randomInterpolation() {
|
|
369
|
+
switch (Math.randomRange(0, 2)) {
|
|
370
|
+
case 1: return InterpolationCurve.Linear;
|
|
371
|
+
case 2: return InterpolationCurve.Curve;
|
|
372
|
+
case 0:
|
|
373
|
+
default:
|
|
374
|
+
return InterpolationCurve.Logarithmic;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
//% shim=music::queuePlayInstructions
|
|
379
|
+
function queuePlayInstructions(timeDelta: number, buf: Buffer) { }
|
|
380
|
+
}
|