Clavier virtuel, barre d'aide des boutons et sons de navigation du thème Orbe (générés, tools/gen-sounds.mjs)
Some checks are pending
CI / windows (push) Waiting to run
Some checks are pending
CI / windows (push) Waiting to run
This commit is contained in:
parent
e7478d3c64
commit
b8b1afc626
11 changed files with 228 additions and 19 deletions
49
tools/gen-sounds.mjs
Normal file
49
tools/gen-sounds.mjs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Génère les sons de navigation du thème Orbe (WAV 16 bits mono, 44,1 kHz) : sobres, courts, sans dépendance.
|
||||
// Usage : node tools/gen-sounds.mjs
|
||||
import { mkdirSync, writeFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const RATE = 44100
|
||||
const out = join(import.meta.dirname, '..', 'themes', 'orbe', 'sounds')
|
||||
|
||||
/* voix : fréquence qui glisse de f0 à f1, enveloppe attaque/déclin, timbre sinus + un peu d'harmonique */
|
||||
function tone(dur, f0, f1, { gain = 0.5, attack = 0.004, harm = 0.15, delay = 0 } = {}) {
|
||||
const n = Math.round((dur + delay) * RATE), s = new Float32Array(n)
|
||||
let phase = 0
|
||||
for (let i = Math.round(delay * RATE); i < n; i++) {
|
||||
const t = i / RATE - delay, p = t / dur
|
||||
const f = f0 * Math.pow(f1 / f0, p)
|
||||
phase += (2 * Math.PI * f) / RATE
|
||||
const env = Math.min(1, t / attack) * Math.pow(1 - p, 2.2)
|
||||
s[i] = gain * env * (Math.sin(phase) + harm * Math.sin(2 * phase))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const mix = (...parts) => {
|
||||
const n = Math.max(...parts.map((p) => p.length)), s = new Float32Array(n)
|
||||
for (const p of parts) for (let i = 0; i < p.length; i++) s[i] += p[i]
|
||||
return s
|
||||
}
|
||||
|
||||
function wav(samples) {
|
||||
const b = Buffer.alloc(44 + samples.length * 2)
|
||||
b.write('RIFF', 0); b.writeUInt32LE(36 + samples.length * 2, 4); b.write('WAVE', 8)
|
||||
b.write('fmt ', 12); b.writeUInt32LE(16, 16); b.writeUInt16LE(1, 20); b.writeUInt16LE(1, 22)
|
||||
b.writeUInt32LE(RATE, 24); b.writeUInt32LE(RATE * 2, 28); b.writeUInt16LE(2, 32); b.writeUInt16LE(16, 34)
|
||||
b.write('data', 36); b.writeUInt32LE(samples.length * 2, 40)
|
||||
samples.forEach((v, i) => b.writeInt16LE(Math.round(Math.max(-1, Math.min(1, v)) * 32767), 44 + i * 2))
|
||||
return b
|
||||
}
|
||||
|
||||
const sounds = {
|
||||
move: tone(0.035, 2400, 2200, { gain: 0.18, harm: 0 }), // petit tic
|
||||
select: mix(tone(0.07, 660, 680, { gain: 0.32 }), tone(0.09, 990, 1000, { gain: 0.28, delay: 0.045 })), // deux notes qui montent
|
||||
back: mix(tone(0.07, 740, 720, { gain: 0.28 }), tone(0.09, 494, 480, { gain: 0.26, delay: 0.045 })), // deux notes qui descendent
|
||||
error: mix(tone(0.08, 180, 170, { gain: 0.35, harm: 0.4 }), tone(0.08, 180, 170, { gain: 0.35, harm: 0.4, delay: 0.11 })),
|
||||
launch: mix(tone(0.45, 330, 1320, { gain: 0.3, attack: 0.02 }), tone(0.5, 495, 1980, { gain: 0.12, attack: 0.05, delay: 0.06 }))
|
||||
}
|
||||
|
||||
mkdirSync(out, { recursive: true })
|
||||
for (const [name, s] of Object.entries(sounds)) writeFileSync(join(out, name + '.wav'), wav(s))
|
||||
console.log('sons écrits dans', out)
|
||||
Loading…
Add table
Add a link
Reference in a new issue