littlejsengine 1.8.9 → 1.9.1
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/README.md +17 -17
- package/build/littlejs.d.ts +352 -288
- package/build/littlejs.esm.js +695 -658
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +694 -658
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +629 -594
- package/examples/breakout/game.js +4 -4
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/game.js +1 -1
- package/examples/electron/index.html +2 -2
- package/examples/favicon.png +0 -0
- package/examples/js13k/build.js +1 -1
- package/examples/js13k/index.html +13 -13
- package/examples/module/game.js +1 -1
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/game.js +6 -6
- package/examples/platformer/gameCharacter.js +293 -0
- package/examples/platformer/gameEffects.js +8 -5
- package/examples/platformer/gameObjects.js +13 -13
- package/examples/platformer/gamePlayer.js +9 -293
- package/examples/platformer/index.html +7 -6
- package/examples/puzzle/game.js +3 -2
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/build.js +1 -1
- package/examples/starter/game.js +2 -2
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +35 -27
- package/examples/typescript/index.html +1 -1
- package/index.d.ts +2094 -0
- package/package.json +1 -1
- package/src/engine.js +28 -28
- package/src/engineAudio.js +57 -57
- package/src/engineDebug.js +66 -65
- package/src/engineDraw.js +64 -73
- package/src/engineExport.js +1 -0
- package/src/engineInput.js +57 -40
- package/src/engineMedals.js +32 -29
- package/src/engineObject.js +42 -27
- package/src/engineParticles.js +98 -72
- package/src/engineRelease.js +1 -1
- package/src/engineSettings.js +22 -22
- package/src/engineTileLayer.js +66 -60
- package/src/engineUtilities.js +49 -49
- package/src/engineWebGL.js +112 -135
- package/src/jsconfig.json +10 -0
package/package.json
CHANGED
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {String}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.
|
|
33
|
+
const engineVersion = '1.9.1';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update objects
|
|
36
36
|
* @type {Number}
|
|
@@ -71,14 +71,14 @@ let timeReal = 0;
|
|
|
71
71
|
|
|
72
72
|
/** Is the game paused? Causes time and objects to not be updated
|
|
73
73
|
* @type {Boolean}
|
|
74
|
-
* @default
|
|
74
|
+
* @default false
|
|
75
75
|
* @memberof Engine */
|
|
76
|
-
let paused =
|
|
76
|
+
let paused = false;
|
|
77
77
|
|
|
78
78
|
/** Set if game is paused
|
|
79
|
-
* @param {Boolean}
|
|
79
|
+
* @param {Boolean} isPaused
|
|
80
80
|
* @memberof Engine */
|
|
81
|
-
function setPaused(
|
|
81
|
+
function setPaused(isPaused) { paused = isPaused; }
|
|
82
82
|
|
|
83
83
|
// Frame time tracking
|
|
84
84
|
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
@@ -95,7 +95,7 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
95
95
|
* @memberof Engine */
|
|
96
96
|
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
|
|
97
97
|
{
|
|
98
|
-
ASSERT(Array.isArray(imageSources)
|
|
98
|
+
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
99
99
|
|
|
100
100
|
// internal update loop for engine
|
|
101
101
|
function engineUpdate(frameTimeMS=0)
|
|
@@ -105,12 +105,12 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
105
105
|
frameTimeLastMS = frameTimeMS;
|
|
106
106
|
if (debug || showWatermark)
|
|
107
107
|
averageFPS = lerp(.05, averageFPS, 1e3/(frameTimeDeltaMS||1));
|
|
108
|
-
const debugSpeedUp = debug && keyIsDown(
|
|
109
|
-
const debugSpeedDown = debug && keyIsDown(
|
|
108
|
+
const debugSpeedUp = debug && keyIsDown('Equal'); // +
|
|
109
|
+
const debugSpeedDown = debug && keyIsDown('Minus'); // -
|
|
110
110
|
if (debug) // +/- to speed/slow time
|
|
111
111
|
frameTimeDeltaMS *= debugSpeedUp ? 5 : debugSpeedDown ? .2 : 1;
|
|
112
112
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
113
|
-
frameTimeBufferMS +=
|
|
113
|
+
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
114
114
|
if (!debugSpeedUp)
|
|
115
115
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
|
|
116
116
|
|
|
@@ -220,7 +220,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
220
220
|
'user-select:none;' + // prevent mobile hold to select
|
|
221
221
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
222
222
|
'-webkit-touch-callout:none'; // compatibility for ios
|
|
223
|
-
document.body.style = styleBody;
|
|
223
|
+
document.body.style.cssText = styleBody;
|
|
224
224
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
225
225
|
mainContext = mainCanvas.getContext('2d');
|
|
226
226
|
|
|
@@ -233,10 +233,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
233
233
|
overlayContext = overlayCanvas.getContext('2d');
|
|
234
234
|
|
|
235
235
|
// set canvas style
|
|
236
|
-
const styleCanvas =
|
|
237
|
-
'position:absolute;' + // position
|
|
236
|
+
const styleCanvas = 'position:absolute;' + // position
|
|
238
237
|
'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
|
|
239
|
-
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
238
|
+
(glCanvas||mainCanvas).style.cssText = mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
240
239
|
|
|
241
240
|
// create promises for loading images
|
|
242
241
|
const promises = imageSources.map((src, textureIndex)=>
|
|
@@ -256,13 +255,13 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
256
255
|
showSplashScreen && promises.push(new Promise(resolve =>
|
|
257
256
|
{
|
|
258
257
|
let t = 0;
|
|
259
|
-
console.log(
|
|
258
|
+
console.log(`${engineName} Engine v${engineVersion}`);
|
|
260
259
|
updateSplash();
|
|
261
260
|
function updateSplash()
|
|
262
261
|
{
|
|
263
262
|
clearInput();
|
|
264
263
|
drawEngineSplashScreen(t+=.01);
|
|
265
|
-
t>1 ? resolve() : setTimeout(updateSplash,16);
|
|
264
|
+
t>1 ? resolve() : setTimeout(updateSplash, 16);
|
|
266
265
|
}
|
|
267
266
|
}));
|
|
268
267
|
|
|
@@ -323,7 +322,7 @@ function engineObjectsDestroy()
|
|
|
323
322
|
|
|
324
323
|
/** Triggers a callback for each object within a given area
|
|
325
324
|
* @param {Vector2} [pos] - Center of test area
|
|
326
|
-
* @param {Number} [size]
|
|
325
|
+
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
327
326
|
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
328
327
|
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
329
328
|
* @memberof Engine */
|
|
@@ -334,7 +333,7 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
334
333
|
for (const o of objects)
|
|
335
334
|
callbackFunction(o);
|
|
336
335
|
}
|
|
337
|
-
else if (size
|
|
336
|
+
else if (typeof size === 'object') // bounding box test
|
|
338
337
|
{
|
|
339
338
|
for (const o of objects)
|
|
340
339
|
isOverlapping(pos, size, o.pos, o.size) && callbackFunction(o);
|
|
@@ -352,23 +351,23 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
352
351
|
|
|
353
352
|
function drawEngineSplashScreen(t)
|
|
354
353
|
{
|
|
355
|
-
const x =
|
|
356
|
-
const w =
|
|
357
|
-
const h =
|
|
354
|
+
const x = overlayContext;
|
|
355
|
+
const w = overlayCanvas.width = innerWidth;
|
|
356
|
+
const h = overlayCanvas.height = innerHeight;
|
|
357
|
+
|
|
358
358
|
{
|
|
359
359
|
// background
|
|
360
360
|
const p3 = percent(t, 1, .8);
|
|
361
361
|
const p4 = percent(t, 0, .5);
|
|
362
362
|
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,Math.hypot(w,h)*.7);
|
|
363
|
-
g.addColorStop(0,hsl(0,0,lerp(p4,0,p3/2),p3));
|
|
364
|
-
g.addColorStop(1,hsl(0,0,0,p3));
|
|
363
|
+
g.addColorStop(0,hsl(0,0,lerp(p4,0,p3/2),p3).toString());
|
|
364
|
+
g.addColorStop(1,hsl(0,0,0,p3).toString());
|
|
365
365
|
x.save();
|
|
366
366
|
x.fillStyle = g;
|
|
367
367
|
x.fillRect(0,0,w,h);
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
// draw LittleJS logo...
|
|
371
|
-
|
|
372
371
|
const rect = (X, Y, W, H, C)=>
|
|
373
372
|
{
|
|
374
373
|
x.beginPath();
|
|
@@ -393,7 +392,7 @@ function drawEngineSplashScreen(t)
|
|
|
393
392
|
C ? x.fill() : x.stroke();
|
|
394
393
|
};
|
|
395
394
|
const color = (c=0, l=0) =>
|
|
396
|
-
hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]);
|
|
395
|
+
hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();
|
|
397
396
|
const alpha = wave(1,1,t);
|
|
398
397
|
const p = percent(alpha, .1, .5);
|
|
399
398
|
|
|
@@ -403,7 +402,7 @@ function drawEngineSplashScreen(t)
|
|
|
403
402
|
x.scale(size,size);
|
|
404
403
|
x.translate(-40,-35);
|
|
405
404
|
x.lineJoin = x.lineCap = 'round';
|
|
406
|
-
x.lineWidth = 1+p;
|
|
405
|
+
x.lineWidth = .1 + p*1.9;
|
|
407
406
|
|
|
408
407
|
// drawing effect
|
|
409
408
|
const p2 = percent(alpha,.1,1);
|
|
@@ -428,7 +427,7 @@ function drawEngineSplashScreen(t)
|
|
|
428
427
|
|
|
429
428
|
// little stack
|
|
430
429
|
rect(37,14,9,6,color(3,2));
|
|
431
|
-
rect(37,14,4,6,color(3,3));
|
|
430
|
+
rect(37,14,4.5,6,color(3,3));
|
|
432
431
|
rect(37,14,9,6);
|
|
433
432
|
|
|
434
433
|
// big stack
|
|
@@ -472,7 +471,8 @@ function drawEngineSplashScreen(t)
|
|
|
472
471
|
x.lineTo(53+(1+i*2.9)*p,40);
|
|
473
472
|
x.lineTo(53+(4+i*3.5)*p,54);
|
|
474
473
|
x.fillStyle = color(0,i%2+2);
|
|
475
|
-
x.fill()
|
|
474
|
+
x.fill();
|
|
475
|
+
i%2 && x.stroke();
|
|
476
476
|
}
|
|
477
477
|
|
|
478
478
|
// wheels
|
|
@@ -495,7 +495,7 @@ function drawEngineSplashScreen(t)
|
|
|
495
495
|
x.font = '900 16px arial';
|
|
496
496
|
x.textAlign = 'center';
|
|
497
497
|
x.textBaseline = 'top';
|
|
498
|
-
x.lineWidth = 1+p*3;
|
|
498
|
+
x.lineWidth = .1+p*3.9;
|
|
499
499
|
let w2 = 0;
|
|
500
500
|
for (let i=0; i<s.length; ++i)
|
|
501
501
|
w2 += x.measureText(s[i]).width;
|
package/src/engineAudio.js
CHANGED
|
@@ -54,13 +54,13 @@ class Sound
|
|
|
54
54
|
|
|
55
55
|
/** Play the sound
|
|
56
56
|
* @param {Vector2} [pos] - World space position to play the sound, sound is not attenuated if null
|
|
57
|
-
* @param {Number} [volume
|
|
58
|
-
* @param {Number} [pitch
|
|
59
|
-
* @param {Number} [randomnessScale
|
|
60
|
-
* @param {Boolean} [loop
|
|
57
|
+
* @param {Number} [volume] - How much to scale volume by (in addition to range fade)
|
|
58
|
+
* @param {Number} [pitch] - How much to scale pitch by (also adjusted by this.randomness)
|
|
59
|
+
* @param {Number} [randomnessScale] - How much to scale randomness
|
|
60
|
+
* @param {Boolean} [loop] - Should the sound loop
|
|
61
61
|
* @return {AudioBufferSourceNode} - The audio source node
|
|
62
62
|
*/
|
|
63
|
-
play(pos, volume=1, pitch=1, randomnessScale=1, loop=
|
|
63
|
+
play(pos, volume=1, pitch=1, randomnessScale=1, loop=false)
|
|
64
64
|
{
|
|
65
65
|
if (!soundEnable || !this.sampleChannels) return;
|
|
66
66
|
|
|
@@ -93,8 +93,13 @@ class Sound
|
|
|
93
93
|
{
|
|
94
94
|
if (this.source)
|
|
95
95
|
this.source.stop();
|
|
96
|
-
this.source =
|
|
96
|
+
this.source = undefined;
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
/** Get source of most recent instance of this sound that was played
|
|
100
|
+
* @return {AudioBufferSourceNode}
|
|
101
|
+
*/
|
|
102
|
+
getSource() { return this.source; }
|
|
98
103
|
|
|
99
104
|
/** Play the sound as a note with a semitone offset
|
|
100
105
|
* @param {Number} semitoneOffset - How many semitones to offset pitch
|
|
@@ -110,12 +115,7 @@ class Sound
|
|
|
110
115
|
*/
|
|
111
116
|
getDuration()
|
|
112
117
|
{ return this.sampleChannels && this.sampleChannels[0].length / this.sampleRate; }
|
|
113
|
-
|
|
114
|
-
/** Check if the last instance of this sound is playing
|
|
115
|
-
* @return {Boolean} - True if the sound is playing
|
|
116
|
-
*/
|
|
117
|
-
isPlaying() { return this.source && !this.source.ended; }
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
/** Check if sound is loading, for sounds fetched from a url
|
|
120
120
|
* @return {Boolean} - True if sound is loading and not ready to play
|
|
121
121
|
*/
|
|
@@ -136,13 +136,13 @@ class SoundWave extends Sound
|
|
|
136
136
|
{
|
|
137
137
|
/** Create a sound object and cache the wave file for later use
|
|
138
138
|
* @param {String} filename - Filename of audio file to load
|
|
139
|
-
* @param {Number} [randomness
|
|
139
|
+
* @param {Number} [randomness] - How much to randomize frequency each time sound plays
|
|
140
140
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
141
141
|
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
|
|
142
142
|
*/
|
|
143
143
|
constructor(filename, randomness=0, range, taper)
|
|
144
144
|
{
|
|
145
|
-
super(
|
|
145
|
+
super(undefined, range, taper);
|
|
146
146
|
this.randomness = randomness;
|
|
147
147
|
|
|
148
148
|
if (!soundEnable) return;
|
|
@@ -196,11 +196,11 @@ let soundDecoderContext; // audio context used only to decode audio files
|
|
|
196
196
|
class Music extends Sound
|
|
197
197
|
{
|
|
198
198
|
/** Create a music object and cache the zzfx music samples for later use
|
|
199
|
-
* @param {Array} zzfxMusic - Array of zzfx music parameters
|
|
199
|
+
* @param {[Array, Array, Array, Number]} zzfxMusic - Array of zzfx music parameters
|
|
200
200
|
*/
|
|
201
201
|
constructor(zzfxMusic)
|
|
202
202
|
{
|
|
203
|
-
super();
|
|
203
|
+
super(undefined);
|
|
204
204
|
|
|
205
205
|
if (!soundEnable) return;
|
|
206
206
|
this.randomness = 0;
|
|
@@ -213,17 +213,17 @@ class Music extends Sound
|
|
|
213
213
|
* @param {Boolean} [loop=1] - True if the music should loop
|
|
214
214
|
* @return {AudioBufferSourceNode} - The audio source node
|
|
215
215
|
*/
|
|
216
|
-
playMusic(volume, loop =
|
|
217
|
-
{ return super.play(
|
|
216
|
+
playMusic(volume, loop = false)
|
|
217
|
+
{ return super.play(undefined, volume, 1, 1, loop); }
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
221
221
|
* @param {String} url - Location of sound file to play
|
|
222
|
-
* @param {Number} [volume
|
|
223
|
-
* @param {Boolean} [loop
|
|
222
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
223
|
+
* @param {Boolean} [loop] - True if the music should loop
|
|
224
224
|
* @return {HTMLAudioElement} - The audio element for this sound
|
|
225
225
|
* @memberof Audio */
|
|
226
|
-
function playAudioFile(url, volume=1, loop=
|
|
226
|
+
function playAudioFile(url, volume=1, loop=false)
|
|
227
227
|
{
|
|
228
228
|
if (!soundEnable) return;
|
|
229
229
|
|
|
@@ -237,9 +237,9 @@ function playAudioFile(url, volume=1, loop=1)
|
|
|
237
237
|
/** Speak text with passed in settings
|
|
238
238
|
* @param {String} text - The text to speak
|
|
239
239
|
* @param {String} [language] - The language/accent to use (examples: en, it, ru, ja, zh)
|
|
240
|
-
* @param {Number} [volume
|
|
241
|
-
* @param {Number} [rate
|
|
242
|
-
* @param {Number} [pitch
|
|
240
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
241
|
+
* @param {Number} [rate] - How quickly to speak
|
|
242
|
+
* @param {Number} [pitch] - How much to change the pitch by
|
|
243
243
|
* @return {SpeechSynthesisUtterance} - The utterance that was spoken
|
|
244
244
|
* @memberof Audio */
|
|
245
245
|
function speak(text, language='', volume=1, rate=1, pitch=1)
|
|
@@ -266,7 +266,7 @@ function speakStop() {speechSynthesis && speechSynthesis.cancel();}
|
|
|
266
266
|
|
|
267
267
|
/** Get frequency of a note on a musical scale
|
|
268
268
|
* @param {Number} semitoneOffset - How many semitones away from the root note
|
|
269
|
-
* @param {Number} [
|
|
269
|
+
* @param {Number} [rootFrequency=220] - Frequency at semitone offset 0
|
|
270
270
|
* @return {Number} - The frequency of the note
|
|
271
271
|
* @memberof Audio */
|
|
272
272
|
function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
@@ -280,14 +280,14 @@ let audioContext;
|
|
|
280
280
|
|
|
281
281
|
/** Play cached audio samples with given settings
|
|
282
282
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
283
|
-
* @param {Number} [volume
|
|
284
|
-
* @param {Number} [rate
|
|
285
|
-
* @param {Number} [pan
|
|
286
|
-
* @param {Boolean} [loop
|
|
283
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
284
|
+
* @param {Number} [rate] - The playback rate to use
|
|
285
|
+
* @param {Number} [pan] - How much to apply stereo panning
|
|
286
|
+
* @param {Boolean} [loop] - True if the sound should loop when it reaches the end
|
|
287
287
|
* @param {Number} [sampleRate=44100] - Sample rate for the sound
|
|
288
288
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
289
289
|
* @memberof Audio */
|
|
290
|
-
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=
|
|
290
|
+
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=zzfxR)
|
|
291
291
|
{
|
|
292
292
|
if (!soundEnable) return;
|
|
293
293
|
|
|
@@ -327,7 +327,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate
|
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
///////////////////////////////////////////////////////////////////////////////
|
|
330
|
-
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.
|
|
330
|
+
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.1 by Frank Force
|
|
331
331
|
|
|
332
332
|
/** Generate and play a ZzFX sound
|
|
333
333
|
*
|
|
@@ -343,27 +343,27 @@ function zzfx(...zzfxSound) { return playSamples([zzfxG(...zzfxSound)]); }
|
|
|
343
343
|
const zzfxR = 44100;
|
|
344
344
|
|
|
345
345
|
/** Generate samples for a ZzFX sound
|
|
346
|
-
* @param {Number} [volume
|
|
347
|
-
* @param {Number} [randomness
|
|
348
|
-
* @param {Number} [frequency
|
|
349
|
-
* @param {Number} [attack
|
|
350
|
-
* @param {Number} [sustain
|
|
351
|
-
* @param {Number} [release
|
|
352
|
-
* @param {Number} [shape
|
|
353
|
-
* @param {Number} [shapeCurve
|
|
354
|
-
* @param {Number} [slide
|
|
355
|
-
* @param {Number} [deltaSlide
|
|
356
|
-
* @param {Number} [pitchJump
|
|
357
|
-
* @param {Number} [pitchJumpTime
|
|
358
|
-
* @param {Number} [repeatTime
|
|
359
|
-
* @param {Number} [noise
|
|
360
|
-
* @param {Number} [modulation
|
|
361
|
-
* @param {Number} [bitCrush
|
|
362
|
-
* @param {Number} [delay
|
|
363
|
-
* @param {Number} [sustainVolume
|
|
364
|
-
* @param {Number} [decay
|
|
365
|
-
* @param {Number} [tremolo
|
|
366
|
-
* @param {Number} [filter
|
|
346
|
+
* @param {Number} [volume] - Volume scale (percent)
|
|
347
|
+
* @param {Number} [randomness] - How much to randomize frequency (percent Hz)
|
|
348
|
+
* @param {Number} [frequency] - Frequency of sound (Hz)
|
|
349
|
+
* @param {Number} [attack] - Attack time, how fast sound starts (seconds)
|
|
350
|
+
* @param {Number} [sustain] - Sustain time, how long sound holds (seconds)
|
|
351
|
+
* @param {Number} [release] - Release time, how fast sound fades out (seconds)
|
|
352
|
+
* @param {Number} [shape] - Shape of the sound wave
|
|
353
|
+
* @param {Number} [shapeCurve] - Squarenes of wave (0=square, 1=normal, 2=pointy)
|
|
354
|
+
* @param {Number} [slide] - How much to slide frequency (kHz/s)
|
|
355
|
+
* @param {Number} [deltaSlide] - How much to change slide (kHz/s/s)
|
|
356
|
+
* @param {Number} [pitchJump] - Frequency of pitch jump (Hz)
|
|
357
|
+
* @param {Number} [pitchJumpTime] - Time of pitch jump (seconds)
|
|
358
|
+
* @param {Number} [repeatTime] - Resets some parameters periodically (seconds)
|
|
359
|
+
* @param {Number} [noise] - How much random noise to add (percent)
|
|
360
|
+
* @param {Number} [modulation] - Frequency of modulation wave, negative flips phase (Hz)
|
|
361
|
+
* @param {Number} [bitCrush] - Resamples at a lower frequency in (samples*100)
|
|
362
|
+
* @param {Number} [delay] - Overlap sound with itself for reverb and flanger effects (seconds)
|
|
363
|
+
* @param {Number} [sustainVolume] - Volume level for sustain (percent)
|
|
364
|
+
* @param {Number} [decay] - Decay time, how long to reach sustain after attack (seconds)
|
|
365
|
+
* @param {Number} [tremolo] - Trembling effect, rate controlled by repeat time (precent)
|
|
366
|
+
* @param {Number} [filter] - Filter cutoff frequency, positive for HPF, negative for LPF (Hz)
|
|
367
367
|
* @return {Array} - Array of audio samples
|
|
368
368
|
* @memberof Audio
|
|
369
369
|
*/
|
|
@@ -411,7 +411,7 @@ function zzfxG
|
|
|
411
411
|
if (!(++c%(bitCrush*100|0))) // bit crush
|
|
412
412
|
{
|
|
413
413
|
s = shape? shape>1? shape>2? shape>3? // wave shape
|
|
414
|
-
Math.sin(t
|
|
414
|
+
Math.sin(t**3) : // 4 noise
|
|
415
415
|
clamp(Math.tan(t),1,-1): // 3 tan
|
|
416
416
|
1-(2*t/PI2%2+2)%2: // 2 saw
|
|
417
417
|
1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
|
|
@@ -468,7 +468,7 @@ function zzfxG
|
|
|
468
468
|
* @param {Array} instruments - Array of ZzFX sound paramaters
|
|
469
469
|
* @param {Array} patterns - Array of pattern data
|
|
470
470
|
* @param {Array} sequence - Array of pattern indexes
|
|
471
|
-
* @param {Number} [BPM
|
|
471
|
+
* @param {Number} [BPM] - Playback speed of the song in BPM
|
|
472
472
|
* @return {Array} - Left and right channel sample data
|
|
473
473
|
* @memberof Audio */
|
|
474
474
|
function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
@@ -507,10 +507,10 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
507
507
|
patternChannel = patterns[patternIndex][channelIndex] || [0, 0, 0];
|
|
508
508
|
|
|
509
509
|
// check if there are more channels
|
|
510
|
-
hasMore
|
|
510
|
+
hasMore |= patterns[patternIndex][channelIndex]&&1;
|
|
511
511
|
|
|
512
512
|
// get next offset, use the length of first channel
|
|
513
|
-
nextSampleOffset = outSampleOffset + (patterns[patternIndex][0].length - 2 -
|
|
513
|
+
nextSampleOffset = outSampleOffset + (patterns[patternIndex][0].length - 2 - (notFirstBeat?0:1)) * beatLength;
|
|
514
514
|
// for each beat in pattern, plus one extra if end of sequence
|
|
515
515
|
isSequenceEnd = sequenceIndex == sequence.length - 1;
|
|
516
516
|
for (i = 2, k = outSampleOffset; i < patternChannel.length + isSequenceEnd; notFirstBeat = ++i) {
|
|
@@ -526,7 +526,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
526
526
|
for (j = 0; j < beatLength && notFirstBeat;
|
|
527
527
|
|
|
528
528
|
// fade off attenuation at end of beat if stopping note, prevents clicking
|
|
529
|
-
j++ > beatLength - 99 && stop
|
|
529
|
+
j++ > beatLength - 99 && stop && attenuation < 1? attenuation += 1 / 99 : 0
|
|
530
530
|
) {
|
|
531
531
|
// copy sample to stereo buffers with panning
|
|
532
532
|
sample = (1 - attenuation) * sampleBuffer[sampleOffset++] / 2 || 0;
|