update interface button styles

This commit is contained in:
2023-07-28 02:15:00 +02:00
parent aff5e643ac
commit 12c07c83b3
2901 changed files with 1369600 additions and 41 deletions

21
node_modules/zzfx/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Frank Force
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

127
node_modules/zzfx/README.md generated vendored Normal file
View File

@ -0,0 +1,127 @@
# ZzFX - Zuper Zmall Zound Zynth
# [ZzFX Sound Designer](https://killedbyapixel.github.io/ZzFX) - [Soundboard Demo](https://codepen.io/KilledByAPixel/full/BaowKzv)
## ZzFX Features
- Tiny sound generator with 20 controllable parameters
- Play audio via code, no need for sound asset files
- Compatible with nearly all web browsers
- Small code footprint, the micro version is under 1 kilobyte uncompressed
- Can produce a large variety of sound effect types
- Sounds can be played with a short function call
- No additional libraries or dependencies are required
- Open source with MIT license, you can use this for anything!
# Why Use ZzFX?
- You can quickly add or change sound effects with just one line of code
- Without sound asset files your game is smaller and faster for users to download
- While prototyping you can use ZzFX for placeholder sound effects
- For size limited game jams like [JS13K](https://js13kgames.com/), ZzFX uses very minimal overhead
- ZzFX is not just for games, you can use it to easily add sounds to any website
# How to Use
* Download from github or use `npm install zzfx`
* Import ZZFX as a module with using `import {ZZFX, zzfx} from './ZzFX.js'`
* Or paste the code from [ZzFXMicro.min.js](https://github.com/KilledByAPixel/ZzFX/blob/master/ZzFXMicro.min.js)
* To play a sound just call zzfx(), something like `zzfx(...[,,,,.1,,,,9])`
* Use [the ZzFX sound designer web app](https://killedbyapixel.github.io/ZzFX) to create new sounds
Here are a few more examples examples...
```javascript
zzfx(...[,,925,.04,.3,.6,1,.3,,6.27,-184,.09,.17]); // Game Over
zzfx(...[,,537,.02,.02,.22,1,1.59,-6.98,4.97]); // Heart
zzfx(...[1.5,.8,270,,.1,,1,1.5,,,,,,,,.1,.01]); // Piano
zzfx(...[,,129,.01,,.15,,,,,,,,5]); // Drum
```
![ZzFX Image](/screenshot.png)
## [ZzFX Music](https://keithclark.github.io/ZzFXM/)
- [ZzFX now supports music via ZzFXM by Keith Clark!](https://keithclark.github.io/ZzFXM/)
- Both the player and songs are super tiny and compress well
- [NoteCraft](https://killedbyapixel.github.io/NoteCraft/) can also export to ZzFXM
# ZzFX Micro Code
Here's all the code you need to play ZzFX sounds with JavaScript!
```javascript
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force ~ 880 bytes
zzfxV=.3 // volume
zzfx= // play sound
(p=1,k=.05,b=220,e=0,r=0,t=.1,q=0,D=1,u=0,y=0,v=0,z=0,l=0,E=0,A=0,F=0,c=0,w=1,m=
0,B=0,M=Math,R=44100,d=2*M.PI,G=u*=500*d/R/R,C=b*=(1-k+2*k*M.random(k=[]))*d/R,g
=0,H=0,a=0,n=1,I=0,J=0,f=0,x,h)=>{e=R*e+9;m*=R;r*=R;t*=R;c*=R;y*=500*d/R**3;A*=d
/R;v*=d/R;z*=R;l=R*l|0;for(h=e+m+r+t+c|0;a<h;k[a++]=f)++J%(100*F|0)||(f=q?1<q?2<
q?3<q?M.sin((g%d)**3):M.max(M.min(M.tan(g),1),-1):1-(2*g/d%2+2)%2:1-4*M.abs(M.
round(g/d)-g/d):M.sin(g),f=(l?1-B+B*M.sin(d*a/l):1)*(0<f?1:-1)*M.abs(f)**D*zzfxV
*p*(a<e?a/e:a<e+m?1-(a-e)/m*(1-w):a<e+m+r?w:a<h-c?(h-a-c)/t*w:0),f=c?f/2+(c>a?0:
(a<h-c?1:(h-a)/c)*k[a-c|0]/2):f),x=(b+=u+=y)*M.cos(A*H++),g+=x-x*E*(1-1E9*(M.sin
(a)+1)%2),n&&++n>z&&(b+=v,C+=v,n=0),!l||++I%l||(b=C,u=G,n||=1);p=zzfxX.
createBuffer(1,h,R);p.getChannelData(0).set(k);b=zzfxX.createBufferSource();b.
buffer=p;b.connect(zzfxX.destination);b.start();return b};zzfxX=new AudioContext;
```
## ZzFX UI Features
- Generates random sounds from presets
- Sound list is automatically saved
- Each parameter can be modified with constraints
- Lock and mutate buttons for each parameter
- Sounds can be renamed
- Shortens code for zzfx sound calls
- Displays image of sound wave when played
- Sounds can be marked as favorites to prevent removal
- Sounds can be loaded by pasting zzfx code for easy sharing
- List of sounds can be exported and imported
- Supports drag-and-drop of exported files into sound list
- Supports saving sounds as wav files for offline playback
## Games Using ZzFX
- [Space Huggers](https://js13kgames.com/entries/space-huggers)
- [Packabunchas](https://js13kgames.com/entries/packabunchas)
- [Galaxy Rider](https://js13kgames.com/entries/galaxy-rider)
- [The Adventures of Captain Callisto](https://js13kgames.com/entries/the-adventures-of-captain-callisto)
- [Welcome to Space](https://js13kgames.com/entries/welcome-to-space)
- [Bogus Roads](https://www.newgrounds.com/portal/view/747570)
- [NoteCraft](https://js13kgames.com/entries/notecraft)
- [The Wandering Wraith](https://js13kgames.com/entries/the-wandering-wraith)
- [Bounce Back](https://www.newgrounds.com/portal/view/755171)
- [Hue Jumper](https://killedbyapixel.itch.io/hue-jumper)
- [Bubba's Back Room](https://js13kgames.com/entries/bubbas-back-room)
- [Backstabber Hero](https://js13kgames.com/entries/backstabber-hero)
- [Spendotron: 2019](https://killedbyapixel.itch.io/currency-wars)
- [Dioretsa](https://js13kgames.com/entries/20461-dioretsa)
- [Back 2 Back](https://js13kgames.com/entries/back-2-back)
- [Quick Wins](https://js13kgames.com/entries/quick-wins)
- [Back Relax](http://js13kgames.com/entries/back-relax)
- [Back To The Island](https://js13kgames.com/entries/back-to-the-island)
- [Backspace It](http://js13kgames.com/entries/backspace-it)
- [Back To The Stars](https://js13kgames.com/entries/back-to-the-stars)
- [Can't Get Back](https://js13kgames.com/entries/cant-get-back)
- [Letchworth Village](https://js13kgames.com/entries/letchworth-village)
- [Noegnud](https://js13kgames.com/entries/noegnud)
- [Sausage Redemption](https://gogoprog.itch.io/sausage-redemption)
- [Marshmallow Sky](https://github.com/baturinsky/marshmallow-sky)
- [Big Champ](https://js13kgames.com/entries/big-champ)
- [I want to google the game](https://js13kgames.com/entries/i-want-to-google-the-game)
- [Edge Not Found](https://js13kgames.com/entries/edge-not-found)
- [Stolen Sword](https://js13kgames.com/entries/stolen-sword)
- [Highway 404](https://js13kgames.com/entries/highway-404)
- [The Last Spartan](https://js13kgames.com/entries/the-last-spartan)
- [OS13k](https://github.com/KilledByAPixel/OS13k)
- [Crab Story](https://www.crabstory.io/)
- [Cooking for Skully](https://github.com/gheja/js13k2022)
- [Egg Time Rewind](https://js13kgames.com/entries/egg-time-rewind)
- [Charon Jr.](https://js13kgames.com/entries/charon-jr)
- [13](https://js13kgames.com/entries/13)
- [Soul Surf](https://js13kgames.com/entries/soul-surf)
- [Dead Again](https://js13kgames.com/entries/dead-again)
![ZzFX Image](/favicon.png)

188
node_modules/zzfx/ZzFX.js generated vendored Normal file
View File

@ -0,0 +1,188 @@
/*
ZzFX - Zuper Zmall Zound Zynth v1.2.0 by Frank Force
https://github.com/KilledByAPixel/ZzFX
ZzFX Features
- Tiny synth engine with 20 controllable parameters.
- Play sounds via code, no need for sound assed files!
- Compatible with most modern web browsers.
- Small code footprint, the micro version is under 1 kilobyte.
- Can produce a huge variety of sound effect types.
- Sounds can be played with a short call. zzfx(...[,,,,.1,,,,9])
- A small bit of randomness appied to sounds when played.
- Use ZZFX.GetNote to get frequencies on a standard diatonic scale.
- Sounds can be saved out as wav files for offline playback.
- No additional libraries or dependencies are required.
*/
/*
ZzFX MIT License
Copyright (c) 2019 - Frank Force
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
'use strict';
// play a zzfx sound
export function zzfx(...parameters) { return ZZFX.play(...parameters) }
// zzfx object with some extra functionalty
export const ZZFX =
{
// master volume scale
volume: .3,
// sample rate for audio
sampleRate: 44100,
// create shared audio context
x: new AudioContext,
// play a sound from zzfx paramerters
play: function(...parameters)
{
// build samples and start sound
return this.playSamples(this.buildSamples(...parameters));
},
// play an array of samples
playSamples: function(...samples)
{
// create buffer and source
const buffer = this.x.createBuffer(samples.length, samples[0].length, this.sampleRate),
source = this.x.createBufferSource();
samples.map((d,i)=> buffer.getChannelData(i).set(d));
source.buffer = buffer;
source.connect(this.x.destination);
source.start();
return source;
},
// build an array of samples
buildSamples: function
(
volume = 1,
randomness = .05,
frequency = 220,
attack = 0,
sustain = 0,
release = .1,
shape = 0,
shapeCurve = 1,
slide = 0,
deltaSlide = 0,
pitchJump = 0,
pitchJumpTime = 0,
repeatTime = 0,
noise = 0,
modulation = 0,
bitCrush = 0,
delay = 0,
sustainVolume = 1,
decay = 0,
tremolo = 0
)
{
// init parameters
let PI2 = Math.PI*2, sampleRate = this.sampleRate, sign = v => v>0?1:-1,
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
startFrequency = frequency *= (1 + randomness*2*Math.random() - randomness) * PI2 / sampleRate,
b=[], t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
// scale by sample rate
attack = attack * sampleRate + 9; // minimum attack to prevent pop
decay *= sampleRate;
sustain *= sampleRate;
release *= sampleRate;
delay *= sampleRate;
deltaSlide *= 500 * PI2 / sampleRate**3;
modulation *= PI2 / sampleRate;
pitchJump *= PI2 / sampleRate;
pitchJumpTime *= sampleRate;
repeatTime = repeatTime * sampleRate | 0;
// generate waveform
for(length = attack + decay + sustain + release + delay | 0;
i < length; b[i++] = s)
{
if (!(++c%(bitCrush*100|0))) // bit crush
{
s = shape? shape>1? shape>2? shape>3? // wave shape
Math.sin((t%PI2)**3) : // 4 noise
Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
1-(2*t/PI2%2+2)%2: // 2 saw
1-4*Math.abs(Math.round(t/PI2)-t/PI2): // 1 triangle
Math.sin(t); // 0 sin
s = (repeatTime ?
1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
: 1) *
sign(s)*(Math.abs(s)**shapeCurve) * // curve 0=square, 2=pointy
volume * this.volume * ( // envelope
i < attack ? i/attack : // attack
i < attack + decay ? // decay
1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
i < attack + decay + sustain ? // sustain
sustainVolume : // sustain volume
i < length - delay ? // release
(length - i - delay)/release * // release falloff
sustainVolume : // release volume
0); // post release
s = delay ? s/2 + (delay > i ? 0 : // delay
(i<length-delay? 1 : (length-i)/delay) * // release delay
b[i-delay|0]/2) : s; // sample delay
}
f = (frequency += slide += deltaSlide) * // frequency
Math.cos(modulation*tm++); // modulation
t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
if (j && ++j > pitchJumpTime) // pitch jump
{
frequency += pitchJump; // apply pitch jump
startFrequency += pitchJump; // also apply to start
j = 0; // stop pitch jump time
}
if (repeatTime && !(++r % repeatTime)) // repeat
{
frequency = startFrequency; // reset frequency
slide = startSlide; // reset slide
j ||= 1; // reset pitch jump time
}
}
return b;
},
// get frequency of a musical note on a diatonic scale
getNote: function(semitoneOffset=0, rootNoteFrequency=440)
{
return rootNoteFrequency * 2**(semitoneOffset/12);
}
} // ZZFX

118
node_modules/zzfx/ZzFXMicro.js generated vendored Normal file
View File

@ -0,0 +1,118 @@
// ZzFX - Zuper Zmall Zound Zynth - Micro Edition
// MIT License - Copyright 2019 Frank Force
// https://github.com/KilledByAPixel/ZzFX
// This is a minified build of zzfx for use in size coding projects.
// You can use zzfxV to set volume.
// Feel free to minify it further for your own needs!
'use strict';
///////////////////////////////////////////////////////////////////////////////
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name ZzFXMicro.min.js
// @js_externs zzfx, zzfxG, zzfxP, zzfxV, zzfxX
// @language_out ECMASCRIPT_2019
// ==/ClosureCompiler==
const zzfx = (...z)=> zzfxP(zzfxG(...z)); // generate and play sound
const zzfxV = .3; // volume
const zzfxR = 44100; // sample rate
const zzfxX = new AudioContext; // audio context
const zzfxP = (...samples)=> // play samples
{
// create buffer and source
let buffer = zzfxX.createBuffer(samples.length, samples[0].length, zzfxR),
source = zzfxX.createBufferSource();
// copy samples to buffer and play
samples.map((d,i)=> buffer.getChannelData(i).set(d));
source.buffer = buffer;
source.connect(zzfxX.destination);
source.start();
return source;
}
const zzfxG = // generate samples
(
// parameters
volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
)=>
{
// init parameters
let PI2 = Math.PI*2, sign = v => v>0?1:-1, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR,
startFrequency = frequency *= (1 + randomness*2*Math.random() - randomness) * PI2 / zzfxR,
b=[], t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
// scale by sample rate
attack = attack * zzfxR + 9; // minimum attack to prevent pop
decay *= zzfxR;
sustain *= zzfxR;
release *= zzfxR;
delay *= zzfxR;
deltaSlide *= 500 * PI2 / zzfxR**3;
modulation *= PI2 / zzfxR;
pitchJump *= PI2 / zzfxR;
pitchJumpTime *= zzfxR;
repeatTime = repeatTime * zzfxR | 0;
// generate waveform
for(length = attack + decay + sustain + release + delay | 0;
i < length; b[i++] = s)
{
if (!(++c%(bitCrush*100|0))) // bit crush
{
s = shape? shape>1? shape>2? shape>3? // wave shape
Math.sin((t%PI2)**3) : // 4 noise
Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
1-(2*t/PI2%2+2)%2: // 2 saw
1-4*Math.abs(Math.round(t/PI2)-t/PI2): // 1 triangle
Math.sin(t); // 0 sin
s = (repeatTime ?
1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
: 1) *
sign(s)*(Math.abs(s)**shapeCurve) * // curve 0=square, 2=pointy
volume * zzfxV * ( // envelope
i < attack ? i/attack : // attack
i < attack + decay ? // decay
1-((i-attack)/decay)*(1-sustainVolume) : // decay falloff
i < attack + decay + sustain ? // sustain
sustainVolume : // sustain volume
i < length - delay ? // release
(length - i - delay)/release * // release falloff
sustainVolume : // release volume
0); // post release
s = delay ? s/2 + (delay > i ? 0 : // delay
(i<length-delay? 1 : (length-i)/delay) * // release delay
b[i-delay|0]/2) : s; // sample delay
}
f = (frequency += slide += deltaSlide) * // frequency
Math.cos(modulation*tm++); // modulation
t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
if (j && ++j > pitchJumpTime) // pitch jump
{
frequency += pitchJump; // apply pitch jump
startFrequency += pitchJump; // also apply to start
j = 0; // reset pitch jump time
}
if (repeatTime && !(++r % repeatTime)) // repeat
{
frequency = startFrequency; // reset frequency
slide = startSlide; // reset slide
j ||= 1; // reset pitch jump time
}
}
return b;
}

28
node_modules/zzfx/ZzFXMicro.min.js generated vendored Normal file
View File

@ -0,0 +1,28 @@
// ZzFX - Zuper Zmall Zound Zynth - Micro Edition
// MIT License - Copyright 2019 Frank Force
// https://github.com/KilledByAPixel/ZzFX
// This is a tiny build of zzfx with only a zzfx function to play sounds.
// You can use zzfxV to set volume.
// Feel free to minify it further for your own needs!
'use strict';let zzfx,zzfxV,zzfxX
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force ~ 880 bytes
zzfxV=.3 // volume
zzfx= // play sound
(p=1,k=.05,b=220,e=0,r=0,t=.1,q=0,D=1,u=0,y=0,v=0,z=0,l=0,E=0,A=0,F=0,c=0,w=1,m=
0,B=0,M=Math,R=44100,d=2*M.PI,G=u*=500*d/R/R,C=b*=(1-k+2*k*M.random(k=[]))*d/R,g
=0,H=0,a=0,n=1,I=0,J=0,f=0,x,h)=>{e=R*e+9;m*=R;r*=R;t*=R;c*=R;y*=500*d/R**3;A*=d
/R;v*=d/R;z*=R;l=R*l|0;for(h=e+m+r+t+c|0;a<h;k[a++]=f)++J%(100*F|0)||(f=q?1<q?2<
q?3<q?M.sin((g%d)**3):M.max(M.min(M.tan(g),1),-1):1-(2*g/d%2+2)%2:1-4*M.abs(M.
round(g/d)-g/d):M.sin(g),f=(l?1-B+B*M.sin(d*a/l):1)*(0<f?1:-1)*M.abs(f)**D*zzfxV
*p*(a<e?a/e:a<e+m?1-(a-e)/m*(1-w):a<e+m+r?w:a<h-c?(h-a-c)/t*w:0),f=c?f/2+(c>a?0:
(a<h-c?1:(h-a)/c)*k[a-c|0]/2):f),x=(b+=u+=y)*M.cos(A*H++),g+=x-x*E*(1-1E9*(M.sin
(a)+1)%2),n&&++n>z&&(b+=v,C+=v,n=0),!l||++I%l||(b=C,u=G,n||=1);p=zzfxX.
createBuffer(1,h,R);p.getChannelData(0).set(k);b=zzfxX.createBufferSource();b.
buffer=p;b.connect(zzfxX.destination);b.start();return b};zzfxX=new AudioContext;
// fix compatibility issues with old web audio (optional)
// if this is used, you must remove the zzfxX=new AudioContext line above!
//zzfxX=new(AudioContext||webkitAudioContext);zzfxX.z=zzfxX.createBufferSource;zzfxX.createBufferSource=(s=zzfxX.z())=>(s.start=s.start||s.noteOn,s)

BIN
node_modules/zzfx/favicon.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

1387
node_modules/zzfx/index.html generated vendored Normal file

File diff suppressed because it is too large Load Diff

29
node_modules/zzfx/package.json generated vendored Normal file
View File

@ -0,0 +1,29 @@
{
"name": "zzfx",
"version": "1.2.0",
"description": "A Tiny JavaScript Sound FX System",
"main": "ZzFX.js",
"scripts": {
"test": "zzfx()"
},
"repository": {
"type": "git",
"url": "git+https://github.com/KilledByAPixel/ZzFX.git"
},
"keywords": [
"sound",
"fx",
"soundfx",
"soundsynth",
"synth",
"audio",
"tinycode",
"sizecoding"
],
"author": "Frank Force",
"license": "MIT",
"bugs": {
"url": "https://github.com/KilledByAPixel/ZzFX/issues"
},
"homepage": "https://github.com/KilledByAPixel/ZzFX#readme"
}

BIN
node_modules/zzfx/screenshot.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

62
node_modules/zzfx/wav.js generated vendored Normal file
View File

@ -0,0 +1,62 @@
// wav.js by Frank Force - https://github.com/KilledByAPixel/ZzFX
export function buildWavBlob(sampleChannels, sampleRate = 44100)
{
// adapted from https://gist.github.com/asanoboy/3979747
const channelCount = sampleChannels.length;
const sampleCount = sampleChannels[0].length;
const length = channelCount * sampleCount;
const buffer = new Int16Array(length + 23);
console.assert(channelCount && sampleCount, 'No channels or samples found!');
// wave header
buffer[ 0] = 0x4952; // RI
buffer[ 1] = 0x4646; // FF
buffer[ 2] = (2*length + 15) & 0x0000ffff; // RIFF size
buffer[ 3] = ((2*length + 15) & 0xffff0000) >> 16; // RIFF size
buffer[ 4] = 0x4157; // WA
buffer[ 5] = 0x4556; // VE
buffer[ 6] = 0x6d66; // fm
buffer[ 7] = 0x2074; // t
buffer[ 8] = 0x0012; // fmt chunksize: 18
buffer[ 9] = 0x0000; //
buffer[10] = 0x0001; // format tag : 1
buffer[11] = channelCount; // channelCount
buffer[12] = sampleRate & 0x0000ffff; // sample per sec
buffer[13] = (sampleRate & 0xffff0000) >> 16; // sample per sec
buffer[14] = (2*channelCount*sampleRate) & 0x0000ffff; // byte per sec
buffer[15] = ((2*channelCount*sampleRate) & 0xffff0000) >> 16; // byte per sec
buffer[16] = 0x0004; // block align
buffer[17] = 0x0010; // bit per sample
buffer[18] = 0x0000; // cb size
buffer[19] = 0x6164; // da
buffer[20] = 0x6174; // ta
buffer[21] = (2*length) & 0x0000ffff; // data size[byte]
buffer[22] = ((2*length) & 0xffff0000) >> 16; // data size[byte]
// copy samples to buffer
for (let i = 0; i < sampleCount; i++)
for (let j = 0; j < channelCount; j++)
{
const s = sampleChannels[j][i];
buffer[i*channelCount + j + 23] = s>=1 ? (1<<15) - 1 : (s * (1<<15) | 0);
}
// build the blob
let end = 0;
let bufferNeedle = 0;
const blobData = [];
const GetBuffer = (length) =>
{
end = bufferNeedle + length >= buffer.length;
const rt = new Int16Array(end? buffer.length - bufferNeedle : length);
for(let i = 0; i < rt.length; i++)
rt[i] = buffer[i + bufferNeedle];
bufferNeedle += rt.length;
return rt.buffer;
}
while ( !end ) blobData.push(GetBuffer(1e3));
return new Blob(blobData, {type:'audio/wav'});
}