This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getStream(stream: Readable): Promise<Buffer> { | |
return new Promise((fulfill, reject) => { | |
const chunks: Buffer[] = [] | |
let totalLength = 0 | |
stream.on("data", chunk => { | |
chunks.push(chunk) | |
totalLength += chunk.length | |
}) | |
stream.once("end", () => fulfill(Buffer.concat(chunks, totalLength))) | |
stream.once("error", reject) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function createWavHeader(dataLength: number, sampleRate: number, bitDepth: number, channels: number) { | |
const headerLength = 44; // Standard size of WAV header | |
const totalLength = headerLength + dataLength; | |
const buffer = new ArrayBuffer(headerLength); | |
const view = new DataView(buffer); | |
// RIFF chunk descriptor | |
writeString(view, 0, 'RIFF'); // ChunkID | |
view.setUint32(4, totalLength - 8, true); // ChunkSize (file size - 8 bytes) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function makeAudioPlayer(audio) { | |
audio.oncanplay = () => sm.trigger("onCanPlay") | |
audio.onerror = () => sm.trigger("onError", new Error(audio.error.message || audio.error.code)) | |
audio.onended = () => sm.trigger("onEnd") | |
const sm = new StateMachine({ | |
IDLE: { | |
load(url) { | |
audio.src = url | |
return "LOADING_PAUSED" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function makeValidGetter<T extends {isValid(): boolean}>(generator: () => Promise<T>): () => Promise<T> { | |
let value: T|undefined | |
let promise: Promise<T>|undefined | |
return async function() { | |
if (value?.isValid()) return value | |
if (promise) return await promise | |
promise = generator() | |
.then(result => { | |
value = result | |
promise = undefined |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function simulate(element, eventName, options) { | |
var opt = { | |
pointerX: 0, | |
pointerY: 0, | |
button: 0, | |
ctrlKey: false, | |
altKey: false, | |
shiftKey: false, | |
metaKey: false, | |
bubbles: true, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Repeat an action | |
* @param {Object} opt - options | |
* @param {Function} opt.action - action to repeat | |
* @param {Function} opt.until - termination condition | |
* @param {Number} opt.delay - delay between actions | |
* @param {Number} opt.max - maximum number of repetitions | |
* @returns {Promise} | |
*/ | |
function repeat(opt) { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function detectUserIdle(periodOfInactivity) { | |
return rxjs.merge( | |
rxjs.timer(periodOfInactivity), | |
rxjs.merge( | |
rxjs.fromEvent(document, "mousemove"), | |
rxjs.fromEvent(document, "keydown"), | |
rxjs.fromEvent(document, "touchstart") | |
) | |
).pipe( | |
rxjs.switchMap(event => !event ? rxjs.of(true) : rxjs.concat(rxjs.of(false), rxjs.throwError(() => "reset"))), |