littlejsengine 1.8.8 → 1.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/littlejs.d.ts +9 -9
- package/build/littlejs.esm.js +107 -90
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +107 -90
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +107 -90
- package/examples/logo.png +0 -0
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/starter/game.js +1 -1
- package/examples/starter/tiles.png +0 -0
- package/package.json +1 -1
- package/src/engine.js +28 -25
- package/src/engineAudio.js +72 -58
- package/src/engineParticles.js +7 -7
|
@@ -2819,7 +2819,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate
|
|
|
2819
2819
|
}
|
|
2820
2820
|
|
|
2821
2821
|
///////////////////////////////////////////////////////////////////////////////
|
|
2822
|
-
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.
|
|
2822
|
+
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force
|
|
2823
2823
|
|
|
2824
2824
|
/** Generate and play a ZzFX sound
|
|
2825
2825
|
*
|
|
@@ -2855,6 +2855,7 @@ const zzfxR = 44100;
|
|
|
2855
2855
|
* @param {Number} [sustainVolume=1] - Volume level for sustain (percent)
|
|
2856
2856
|
* @param {Number} [decay=0] - Decay time, how long to reach sustain after attack (seconds)
|
|
2857
2857
|
* @param {Number} [tremolo=0] - Trembling effect, rate controlled by repeat time (precent)
|
|
2858
|
+
* @param {Number} [filter=0] - Filter cutoff frequency, positive for HPF, negative for LPF (Hz)
|
|
2858
2859
|
* @return {Array} - Array of audio samples
|
|
2859
2860
|
* @memberof Audio
|
|
2860
2861
|
*/
|
|
@@ -2864,78 +2865,91 @@ function zzfxG
|
|
|
2864
2865
|
volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
|
|
2865
2866
|
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
|
|
2866
2867
|
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
|
|
2867
|
-
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
|
|
2868
|
+
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
|
|
2868
2869
|
)
|
|
2869
2870
|
{
|
|
2870
|
-
//
|
|
2871
|
-
let PI2 = PI*2,
|
|
2872
|
-
|
|
2873
|
-
|
|
2871
|
+
// init parameters
|
|
2872
|
+
let PI2 = PI*2, sampleRate = zzfxR,
|
|
2873
|
+
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
|
|
2874
|
+
startFrequency = frequency *=
|
|
2875
|
+
rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
|
|
2876
|
+
b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
|
|
2877
|
+
|
|
2878
|
+
// biquad LP/HP filter
|
|
2879
|
+
quality = 2, w = PI2 * abs(filter) * 2 / sampleRate,
|
|
2880
|
+
cos = Math.cos(w), alpha = Math.sin(w) / 2 / quality,
|
|
2881
|
+
a0 = 1 + alpha, a1 = -2*cos / a0, a2 = (1 - alpha) / a0,
|
|
2882
|
+
b0 = (1 + sign(filter) * cos) / 2 / a0,
|
|
2883
|
+
b1 = -(sign(filter) + cos) / a0, b2 = b0,
|
|
2884
|
+
x2 = 0, x1 = 0, y2 = 0, y1 = 0;
|
|
2874
2885
|
|
|
2875
2886
|
// scale by sample rate
|
|
2876
|
-
attack = attack *
|
|
2877
|
-
decay *=
|
|
2878
|
-
sustain *=
|
|
2879
|
-
release *=
|
|
2880
|
-
delay *=
|
|
2881
|
-
deltaSlide *= 500 * PI2 /
|
|
2882
|
-
modulation *= PI2 /
|
|
2883
|
-
pitchJump *= PI2 /
|
|
2884
|
-
pitchJumpTime *=
|
|
2885
|
-
repeatTime = repeatTime *
|
|
2887
|
+
attack = attack * sampleRate + 9; // minimum attack to prevent pop
|
|
2888
|
+
decay *= sampleRate;
|
|
2889
|
+
sustain *= sampleRate;
|
|
2890
|
+
release *= sampleRate;
|
|
2891
|
+
delay *= sampleRate;
|
|
2892
|
+
deltaSlide *= 500 * PI2 / sampleRate**3;
|
|
2893
|
+
modulation *= PI2 / sampleRate;
|
|
2894
|
+
pitchJump *= PI2 / sampleRate;
|
|
2895
|
+
pitchJumpTime *= sampleRate;
|
|
2896
|
+
repeatTime = repeatTime * sampleRate | 0;
|
|
2897
|
+
volume *= soundVolume;
|
|
2886
2898
|
|
|
2887
2899
|
// generate waveform
|
|
2888
|
-
for
|
|
2889
|
-
i < length; b[i++] = s)
|
|
2900
|
+
for(length = attack + decay + sustain + release + delay | 0;
|
|
2901
|
+
i < length; b[i++] = s * volume) // sample
|
|
2890
2902
|
{
|
|
2891
|
-
if (!(++c%(bitCrush*100|0)))
|
|
2903
|
+
if (!(++c%(bitCrush*100|0))) // bit crush
|
|
2892
2904
|
{
|
|
2893
|
-
s = shape? shape>1? shape>2? shape>3?
|
|
2894
|
-
Math.sin(
|
|
2895
|
-
|
|
2896
|
-
1-(2*t/PI2%2+2)%2:
|
|
2897
|
-
1-4*abs(Math.round(t/PI2)-t/PI2):
|
|
2898
|
-
Math.sin(t);
|
|
2899
|
-
|
|
2905
|
+
s = shape? shape>1? shape>2? shape>3? // wave shape
|
|
2906
|
+
Math.sin(t*t) : // 4 noise
|
|
2907
|
+
clamp(Math.tan(t),1,-1): // 3 tan
|
|
2908
|
+
1-(2*t/PI2%2+2)%2: // 2 saw
|
|
2909
|
+
1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
|
|
2910
|
+
Math.sin(t); // 0 sin
|
|
2911
|
+
|
|
2900
2912
|
s = (repeatTime ?
|
|
2901
2913
|
1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
|
|
2902
2914
|
: 1) *
|
|
2903
|
-
sign(s)*(abs(s)**shapeCurve) *
|
|
2904
|
-
|
|
2905
|
-
i < attack
|
|
2906
|
-
i
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
f = (frequency += slide += deltaSlide) * // frequency
|
|
2921
|
-
Math.cos(modulation*tm++); // modulation
|
|
2922
|
-
t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
|
|
2923
|
-
|
|
2924
|
-
if (j && ++j > pitchJumpTime) // pitch jump
|
|
2925
|
-
{
|
|
2926
|
-
frequency += pitchJump; // apply pitch jump
|
|
2927
|
-
startFrequency += pitchJump; // also apply to start
|
|
2928
|
-
j = 0; // reset pitch jump time
|
|
2915
|
+
sign(s)*(abs(s)**shapeCurve) * // curve
|
|
2916
|
+
(i < attack ? i/attack : // attack
|
|
2917
|
+
i < attack + decay ? // decay
|
|
2918
|
+
1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
|
|
2919
|
+
i < attack + decay + sustain ? // sustain
|
|
2920
|
+
sustainVolume : // sustain volume
|
|
2921
|
+
i < length - delay ? // release
|
|
2922
|
+
(length - i - delay)/release * // release falloff
|
|
2923
|
+
sustainVolume : // release volume
|
|
2924
|
+
0); // post release
|
|
2925
|
+
|
|
2926
|
+
s = delay ? s/2 + (delay > i ? 0 : // delay
|
|
2927
|
+
(i<length-delay? 1 : (length-i)/delay) * // release delay
|
|
2928
|
+
b[i-delay|0]/2/volume) : s; // sample delay
|
|
2929
|
+
|
|
2930
|
+
if (filter) // apply filter
|
|
2931
|
+
s = y1 = b2*x2 + b1*(x2=x1) + b0*(x1=s) - a2*y2 - a1*(y2=y1);
|
|
2929
2932
|
}
|
|
2930
2933
|
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2934
|
+
f = (frequency += slide += deltaSlide) *// frequency
|
|
2935
|
+
Math.cos(modulation*tm++); // modulation
|
|
2936
|
+
t += f + f*noise*Math.sin(i**5); // noise
|
|
2937
|
+
|
|
2938
|
+
if (j && ++j > pitchJumpTime) // pitch jump
|
|
2939
|
+
{
|
|
2940
|
+
frequency += pitchJump; // apply pitch jump
|
|
2941
|
+
startFrequency += pitchJump; // also apply to start
|
|
2942
|
+
j = 0; // stop pitch jump time
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
if (repeatTime && !(++r % repeatTime)) // repeat
|
|
2946
|
+
{
|
|
2947
|
+
frequency = startFrequency; // reset frequency
|
|
2948
|
+
slide = startSlide; // reset slide
|
|
2949
|
+
j = j || 1; // reset pitch jump time
|
|
2936
2950
|
}
|
|
2937
2951
|
}
|
|
2938
|
-
|
|
2952
|
+
|
|
2939
2953
|
return b;
|
|
2940
2954
|
}
|
|
2941
2955
|
|
|
@@ -3431,13 +3445,13 @@ constructor(pos, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderO
|
|
|
3431
3445
|
class ParticleEmitter extends EngineObject
|
|
3432
3446
|
{
|
|
3433
3447
|
/** Create a particle system with the given settings
|
|
3434
|
-
* @param {Vector2} position
|
|
3435
|
-
* @param {Number} [angle=0]
|
|
3436
|
-
* @param {Number} [emitSize=0]
|
|
3437
|
-
* @param {Number} [emitTime=0]
|
|
3438
|
-
* @param {Number} [emitRate=100]
|
|
3448
|
+
* @param {Vector2} position - World space position of the emitter
|
|
3449
|
+
* @param {Number} [angle=0] - Angle to emit the particles
|
|
3450
|
+
* @param {Number|Vector2} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
|
|
3451
|
+
* @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
|
|
3452
|
+
* @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
|
|
3439
3453
|
* @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
|
|
3440
|
-
* @param {TileInfo} [tileInfo]
|
|
3454
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3441
3455
|
* @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
|
|
3442
3456
|
* @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
|
|
3443
3457
|
* @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
|
|
@@ -3493,7 +3507,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3493
3507
|
super(pos, vec2(), tileInfo, angle, undefined, renderOrder);
|
|
3494
3508
|
|
|
3495
3509
|
// emitter settings
|
|
3496
|
-
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
3510
|
+
/** @property {Number|Vector2} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
3497
3511
|
this.emitSize = emitSize
|
|
3498
3512
|
/** @property {Number} - How long to stay alive (0 is forever) */
|
|
3499
3513
|
this.emitTime = emitTime;
|
|
@@ -4456,7 +4470,7 @@ const engineName = 'LittleJS';
|
|
|
4456
4470
|
* @type {String}
|
|
4457
4471
|
* @default
|
|
4458
4472
|
* @memberof Engine */
|
|
4459
|
-
const engineVersion = '1.8.
|
|
4473
|
+
const engineVersion = '1.8.9';
|
|
4460
4474
|
|
|
4461
4475
|
/** Frames per second to update objects
|
|
4462
4476
|
* @type {Number}
|
|
@@ -4778,21 +4792,23 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
4778
4792
|
|
|
4779
4793
|
function drawEngineSplashScreen(t)
|
|
4780
4794
|
{
|
|
4781
|
-
// background
|
|
4782
|
-
const grayscale = 0;
|
|
4783
4795
|
const x = mainContext;
|
|
4784
4796
|
const w = mainCanvas.width = innerWidth;
|
|
4785
4797
|
const h = mainCanvas.height = innerHeight;
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4798
|
+
{
|
|
4799
|
+
// background
|
|
4800
|
+
const p3 = percent(t, 1, .8);
|
|
4801
|
+
const p4 = percent(t, 0, .5);
|
|
4802
|
+
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,Math.hypot(w,h)*.7);
|
|
4803
|
+
g.addColorStop(0,hsl(0,0,lerp(p4,0,p3/2),p3));
|
|
4804
|
+
g.addColorStop(1,hsl(0,0,0,p3));
|
|
4805
|
+
x.save();
|
|
4806
|
+
x.fillStyle = g;
|
|
4807
|
+
x.fillRect(0,0,w,h);
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4810
|
+
// draw LittleJS logo...
|
|
4811
|
+
|
|
4796
4812
|
const rect = (X, Y, W, H, C)=>
|
|
4797
4813
|
{
|
|
4798
4814
|
x.beginPath();
|
|
@@ -4817,7 +4833,7 @@ function drawEngineSplashScreen(t)
|
|
|
4817
4833
|
C ? x.fill() : x.stroke();
|
|
4818
4834
|
};
|
|
4819
4835
|
const color = (c=0, l=0) =>
|
|
4820
|
-
hsl([.98,.3,.57,.14][c%4]-10
|
|
4836
|
+
hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]);
|
|
4821
4837
|
const alpha = wave(1,1,t);
|
|
4822
4838
|
const p = percent(alpha, .1, .5);
|
|
4823
4839
|
|
|
@@ -4860,9 +4876,9 @@ function drawEngineSplashScreen(t)
|
|
|
4860
4876
|
rect(50,20,6,-10,color(0,2));
|
|
4861
4877
|
rect(50,20,3,-10,color(0,3));
|
|
4862
4878
|
rect(50,10,10,10);
|
|
4863
|
-
circle(55,2,11,.5,PI-.5,color(3,3));
|
|
4864
|
-
circle(55,2,11,.5,PI/2,color(3,2),1);
|
|
4865
|
-
circle(55,2,11,.5,PI-.5);
|
|
4879
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
4880
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
4881
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
4866
4882
|
rect(45,7,20,-7,color(0,2));
|
|
4867
4883
|
rect(45,0,20,3,color(0,3));
|
|
4868
4884
|
rect(45,0,20,7);
|
|
@@ -4900,8 +4916,9 @@ function drawEngineSplashScreen(t)
|
|
|
4900
4916
|
}
|
|
4901
4917
|
|
|
4902
4918
|
// wheels
|
|
4903
|
-
rect(
|
|
4904
|
-
rect(
|
|
4919
|
+
rect(6,40,5,5);
|
|
4920
|
+
rect(6,40,5,5,color());
|
|
4921
|
+
rect(15,54,38,-14,color());
|
|
4905
4922
|
for (let i=3; i--;)
|
|
4906
4923
|
for (let j=2; j--;)
|
|
4907
4924
|
{
|
|
@@ -4910,26 +4927,26 @@ function drawEngineSplashScreen(t)
|
|
|
4910
4927
|
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
4911
4928
|
x.stroke();
|
|
4912
4929
|
}
|
|
4913
|
-
line(6,40,68,40) // center
|
|
4914
|
-
line(77,54,4,54) // bottom
|
|
4930
|
+
line(6,40,68,40); // center
|
|
4931
|
+
line(77,54,4,54); // bottom
|
|
4915
4932
|
|
|
4916
|
-
//
|
|
4933
|
+
// draw engine name
|
|
4917
4934
|
const s = engineName;
|
|
4918
4935
|
x.font = '900 16px arial';
|
|
4919
4936
|
x.textAlign = 'center';
|
|
4920
4937
|
x.textBaseline = 'top';
|
|
4921
|
-
x.lineWidth = 1+p*3
|
|
4938
|
+
x.lineWidth = 1+p*3;
|
|
4922
4939
|
let w2 = 0;
|
|
4923
4940
|
for (let i=0; i<s.length; ++i)
|
|
4924
4941
|
w2 += x.measureText(s[i]).width;
|
|
4925
4942
|
for (let j=2; j--;)
|
|
4926
4943
|
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
4927
4944
|
{
|
|
4928
|
-
x.fillStyle = color(i,
|
|
4945
|
+
x.fillStyle = color(i,2);
|
|
4929
4946
|
const w = x.measureText(s[i]).width;
|
|
4930
4947
|
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
4931
4948
|
X += w;
|
|
4932
4949
|
}
|
|
4933
|
-
|
|
4950
|
+
|
|
4934
4951
|
x.restore();
|
|
4935
4952
|
}
|
package/examples/logo.png
CHANGED
|
Binary file
|
|
@@ -18,7 +18,7 @@ const sound_destroyObject =new Sound([.5,,1e3,.02,,.2,1,3,.1,,,,,1,-30,.5,,.5]);
|
|
|
18
18
|
const sound_die = new Sound([.5,.4,126,.05,,.2,1,2.09,,-4,,,1,1,1,.4,.03]);
|
|
19
19
|
const sound_jump = new Sound([.4,.2,250,.04,,.04,,,1,,,,,3]);
|
|
20
20
|
const sound_dodge = new Sound([.4,.2,150,.05,,.05,,,-1,,,,,4,,,,,.02]);
|
|
21
|
-
const sound_walk = new Sound([.3,.1,
|
|
21
|
+
const sound_walk = new Sound([.3,.1,200,,,.01,4,,,,-9,.1,,,,,,.5]);
|
|
22
22
|
const sound_explosion = new Sound([2,.2,72,.01,.01,.2,4,,,,,,,1,,.5,.1,.5,.02]);
|
|
23
23
|
const sound_grenade = new Sound([.5,.01,300,,,.02,3,.22,,,-9,.2,,,,,,.5]);
|
|
24
24
|
const sound_killEnemy = new Sound([,,783,,.03,.02,1,2,,,940,.03,,,,,.2,.6,,.06]);
|
package/examples/starter/game.js
CHANGED
|
@@ -111,7 +111,7 @@ function gameRender()
|
|
|
111
111
|
drawRect(vec2(16,8), vec2(20,14), hsl(0,0,.6), 0, 0);
|
|
112
112
|
|
|
113
113
|
// draw the logo as a tile
|
|
114
|
-
drawTile(vec2(21,5), vec2(4.5), tile(
|
|
114
|
+
drawTile(vec2(21,5), vec2(4.5), tile(3,128));
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
///////////////////////////////////////////////////////////////////////////////
|
|
Binary file
|
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.8.
|
|
33
|
+
const engineVersion = '1.8.9';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update objects
|
|
36
36
|
* @type {Number}
|
|
@@ -352,21 +352,23 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
352
352
|
|
|
353
353
|
function drawEngineSplashScreen(t)
|
|
354
354
|
{
|
|
355
|
-
// background
|
|
356
|
-
const grayscale = 0;
|
|
357
355
|
const x = mainContext;
|
|
358
356
|
const w = mainCanvas.width = innerWidth;
|
|
359
357
|
const h = mainCanvas.height = innerHeight;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
358
|
+
{
|
|
359
|
+
// background
|
|
360
|
+
const p3 = percent(t, 1, .8);
|
|
361
|
+
const p4 = percent(t, 0, .5);
|
|
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));
|
|
365
|
+
x.save();
|
|
366
|
+
x.fillStyle = g;
|
|
367
|
+
x.fillRect(0,0,w,h);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// draw LittleJS logo...
|
|
371
|
+
|
|
370
372
|
const rect = (X, Y, W, H, C)=>
|
|
371
373
|
{
|
|
372
374
|
x.beginPath();
|
|
@@ -391,7 +393,7 @@ function drawEngineSplashScreen(t)
|
|
|
391
393
|
C ? x.fill() : x.stroke();
|
|
392
394
|
};
|
|
393
395
|
const color = (c=0, l=0) =>
|
|
394
|
-
hsl([.98,.3,.57,.14][c%4]-10
|
|
396
|
+
hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]);
|
|
395
397
|
const alpha = wave(1,1,t);
|
|
396
398
|
const p = percent(alpha, .1, .5);
|
|
397
399
|
|
|
@@ -434,9 +436,9 @@ function drawEngineSplashScreen(t)
|
|
|
434
436
|
rect(50,20,6,-10,color(0,2));
|
|
435
437
|
rect(50,20,3,-10,color(0,3));
|
|
436
438
|
rect(50,10,10,10);
|
|
437
|
-
circle(55,2,11,.5,PI-.5,color(3,3));
|
|
438
|
-
circle(55,2,11,.5,PI/2,color(3,2),1);
|
|
439
|
-
circle(55,2,11,.5,PI-.5);
|
|
439
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
440
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
441
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
440
442
|
rect(45,7,20,-7,color(0,2));
|
|
441
443
|
rect(45,0,20,3,color(0,3));
|
|
442
444
|
rect(45,0,20,7);
|
|
@@ -474,8 +476,9 @@ function drawEngineSplashScreen(t)
|
|
|
474
476
|
}
|
|
475
477
|
|
|
476
478
|
// wheels
|
|
477
|
-
rect(
|
|
478
|
-
rect(
|
|
479
|
+
rect(6,40,5,5);
|
|
480
|
+
rect(6,40,5,5,color());
|
|
481
|
+
rect(15,54,38,-14,color());
|
|
479
482
|
for (let i=3; i--;)
|
|
480
483
|
for (let j=2; j--;)
|
|
481
484
|
{
|
|
@@ -484,26 +487,26 @@ function drawEngineSplashScreen(t)
|
|
|
484
487
|
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
485
488
|
x.stroke();
|
|
486
489
|
}
|
|
487
|
-
line(6,40,68,40) // center
|
|
488
|
-
line(77,54,4,54) // bottom
|
|
490
|
+
line(6,40,68,40); // center
|
|
491
|
+
line(77,54,4,54); // bottom
|
|
489
492
|
|
|
490
|
-
//
|
|
493
|
+
// draw engine name
|
|
491
494
|
const s = engineName;
|
|
492
495
|
x.font = '900 16px arial';
|
|
493
496
|
x.textAlign = 'center';
|
|
494
497
|
x.textBaseline = 'top';
|
|
495
|
-
x.lineWidth = 1+p*3
|
|
498
|
+
x.lineWidth = 1+p*3;
|
|
496
499
|
let w2 = 0;
|
|
497
500
|
for (let i=0; i<s.length; ++i)
|
|
498
501
|
w2 += x.measureText(s[i]).width;
|
|
499
502
|
for (let j=2; j--;)
|
|
500
503
|
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
501
504
|
{
|
|
502
|
-
x.fillStyle = color(i,
|
|
505
|
+
x.fillStyle = color(i,2);
|
|
503
506
|
const w = x.measureText(s[i]).width;
|
|
504
507
|
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
505
508
|
X += w;
|
|
506
509
|
}
|
|
507
|
-
|
|
510
|
+
|
|
508
511
|
x.restore();
|
|
509
512
|
}
|
package/src/engineAudio.js
CHANGED
|
@@ -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.
|
|
330
|
+
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.3.0 by Frank Force
|
|
331
331
|
|
|
332
332
|
/** Generate and play a ZzFX sound
|
|
333
333
|
*
|
|
@@ -363,6 +363,7 @@ const zzfxR = 44100;
|
|
|
363
363
|
* @param {Number} [sustainVolume=1] - Volume level for sustain (percent)
|
|
364
364
|
* @param {Number} [decay=0] - Decay time, how long to reach sustain after attack (seconds)
|
|
365
365
|
* @param {Number} [tremolo=0] - Trembling effect, rate controlled by repeat time (precent)
|
|
366
|
+
* @param {Number} [filter=0] - Filter cutoff frequency, positive for HPF, negative for LPF (Hz)
|
|
366
367
|
* @return {Array} - Array of audio samples
|
|
367
368
|
* @memberof Audio
|
|
368
369
|
*/
|
|
@@ -372,78 +373,91 @@ function zzfxG
|
|
|
372
373
|
volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
|
|
373
374
|
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
|
|
374
375
|
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
|
|
375
|
-
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
|
|
376
|
+
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
|
|
376
377
|
)
|
|
377
378
|
{
|
|
378
|
-
//
|
|
379
|
-
let PI2 = PI*2,
|
|
380
|
-
|
|
381
|
-
|
|
379
|
+
// init parameters
|
|
380
|
+
let PI2 = PI*2, sampleRate = zzfxR,
|
|
381
|
+
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
|
|
382
|
+
startFrequency = frequency *=
|
|
383
|
+
rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
|
|
384
|
+
b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
|
|
385
|
+
|
|
386
|
+
// biquad LP/HP filter
|
|
387
|
+
quality = 2, w = PI2 * abs(filter) * 2 / sampleRate,
|
|
388
|
+
cos = Math.cos(w), alpha = Math.sin(w) / 2 / quality,
|
|
389
|
+
a0 = 1 + alpha, a1 = -2*cos / a0, a2 = (1 - alpha) / a0,
|
|
390
|
+
b0 = (1 + sign(filter) * cos) / 2 / a0,
|
|
391
|
+
b1 = -(sign(filter) + cos) / a0, b2 = b0,
|
|
392
|
+
x2 = 0, x1 = 0, y2 = 0, y1 = 0;
|
|
382
393
|
|
|
383
394
|
// scale by sample rate
|
|
384
|
-
attack = attack *
|
|
385
|
-
decay *=
|
|
386
|
-
sustain *=
|
|
387
|
-
release *=
|
|
388
|
-
delay *=
|
|
389
|
-
deltaSlide *= 500 * PI2 /
|
|
390
|
-
modulation *= PI2 /
|
|
391
|
-
pitchJump *= PI2 /
|
|
392
|
-
pitchJumpTime *=
|
|
393
|
-
repeatTime = repeatTime *
|
|
395
|
+
attack = attack * sampleRate + 9; // minimum attack to prevent pop
|
|
396
|
+
decay *= sampleRate;
|
|
397
|
+
sustain *= sampleRate;
|
|
398
|
+
release *= sampleRate;
|
|
399
|
+
delay *= sampleRate;
|
|
400
|
+
deltaSlide *= 500 * PI2 / sampleRate**3;
|
|
401
|
+
modulation *= PI2 / sampleRate;
|
|
402
|
+
pitchJump *= PI2 / sampleRate;
|
|
403
|
+
pitchJumpTime *= sampleRate;
|
|
404
|
+
repeatTime = repeatTime * sampleRate | 0;
|
|
405
|
+
volume *= soundVolume;
|
|
394
406
|
|
|
395
407
|
// generate waveform
|
|
396
|
-
for
|
|
397
|
-
i < length; b[i++] = s)
|
|
408
|
+
for(length = attack + decay + sustain + release + delay | 0;
|
|
409
|
+
i < length; b[i++] = s * volume) // sample
|
|
398
410
|
{
|
|
399
|
-
if (!(++c%(bitCrush*100|0)))
|
|
411
|
+
if (!(++c%(bitCrush*100|0))) // bit crush
|
|
400
412
|
{
|
|
401
|
-
s = shape? shape>1? shape>2? shape>3?
|
|
402
|
-
Math.sin(
|
|
403
|
-
|
|
404
|
-
1-(2*t/PI2%2+2)%2:
|
|
405
|
-
1-4*abs(Math.round(t/PI2)-t/PI2):
|
|
406
|
-
Math.sin(t);
|
|
407
|
-
|
|
413
|
+
s = shape? shape>1? shape>2? shape>3? // wave shape
|
|
414
|
+
Math.sin(t*t) : // 4 noise
|
|
415
|
+
clamp(Math.tan(t),1,-1): // 3 tan
|
|
416
|
+
1-(2*t/PI2%2+2)%2: // 2 saw
|
|
417
|
+
1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
|
|
418
|
+
Math.sin(t); // 0 sin
|
|
419
|
+
|
|
408
420
|
s = (repeatTime ?
|
|
409
421
|
1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
|
|
410
422
|
: 1) *
|
|
411
|
-
sign(s)*(abs(s)**shapeCurve) *
|
|
412
|
-
|
|
413
|
-
i < attack
|
|
414
|
-
i
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
423
|
+
sign(s)*(abs(s)**shapeCurve) * // curve
|
|
424
|
+
(i < attack ? i/attack : // attack
|
|
425
|
+
i < attack + decay ? // decay
|
|
426
|
+
1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
|
|
427
|
+
i < attack + decay + sustain ? // sustain
|
|
428
|
+
sustainVolume : // sustain volume
|
|
429
|
+
i < length - delay ? // release
|
|
430
|
+
(length - i - delay)/release * // release falloff
|
|
431
|
+
sustainVolume : // release volume
|
|
432
|
+
0); // post release
|
|
433
|
+
|
|
434
|
+
s = delay ? s/2 + (delay > i ? 0 : // delay
|
|
435
|
+
(i<length-delay? 1 : (length-i)/delay) * // release delay
|
|
436
|
+
b[i-delay|0]/2/volume) : s; // sample delay
|
|
437
|
+
|
|
438
|
+
if (filter) // apply filter
|
|
439
|
+
s = y1 = b2*x2 + b1*(x2=x1) + b0*(x1=s) - a2*y2 - a1*(y2=y1);
|
|
426
440
|
}
|
|
427
441
|
|
|
428
|
-
f = (frequency += slide += deltaSlide)
|
|
429
|
-
Math.cos(modulation*tm++);
|
|
430
|
-
t += f
|
|
431
|
-
|
|
432
|
-
if (j && ++j > pitchJumpTime)
|
|
433
|
-
{
|
|
434
|
-
frequency += pitchJump;
|
|
435
|
-
startFrequency += pitchJump;
|
|
436
|
-
j = 0;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (repeatTime && !(++r % repeatTime))
|
|
440
|
-
{
|
|
441
|
-
frequency = startFrequency;
|
|
442
|
-
slide = startSlide;
|
|
443
|
-
j
|
|
442
|
+
f = (frequency += slide += deltaSlide) *// frequency
|
|
443
|
+
Math.cos(modulation*tm++); // modulation
|
|
444
|
+
t += f + f*noise*Math.sin(i**5); // noise
|
|
445
|
+
|
|
446
|
+
if (j && ++j > pitchJumpTime) // pitch jump
|
|
447
|
+
{
|
|
448
|
+
frequency += pitchJump; // apply pitch jump
|
|
449
|
+
startFrequency += pitchJump; // also apply to start
|
|
450
|
+
j = 0; // stop pitch jump time
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (repeatTime && !(++r % repeatTime)) // repeat
|
|
454
|
+
{
|
|
455
|
+
frequency = startFrequency; // reset frequency
|
|
456
|
+
slide = startSlide; // reset slide
|
|
457
|
+
j = j || 1; // reset pitch jump time
|
|
444
458
|
}
|
|
445
459
|
}
|
|
446
|
-
|
|
460
|
+
|
|
447
461
|
return b;
|
|
448
462
|
}
|
|
449
463
|
|