arikwex/infernal-sigil

How do you come up with your audio formulas

eguneys opened this issue · 2 comments

I love your audio synthesis code. I had an interesting chatGPT conversation about this I would like to share here:
https://chat.openai.com/share/957a3f2c-2d05-4ed2-885c-3c8af7c7caf9

So, can you please share your insights about how your audio formulas work and how can I learn and apply similar techniques, thank you.

I can try 😂

// N is chosen by the duration of the audio snippet (sampleRate * duration).
// The function "fn" is evaluated for each audio sample.
// Audio is always faded from max volume to 0 volume over the duration (1 - i/N).

for (let i = 0; i < N; i++) {
  buffer[i] = fn(i * 44100 / sampleRate) * (1 - i/N);
}

There are 4 base sounds that can be composed to make all sorts of content:

  • sin is a smooth ooooo
  • saw is an electric zzzzz
  • sqr is a digital brbrbr
  • random is a noisy shshsh

Tuning the balance, timing, and frequency of these functions lets you make all sort of audio! There's some amount of intuition you can build by experimenting for a while. I highly recommend plotting some of these functions to help build that intuition 🎵

🦴 Collecting a bone in the game should be imagined as a "points gained" sound. It's a short little "zzz".

boneCollectSound = await generate(0.06, (i) => {
  return 0.03 * saw(i/4);
});

🚪 Activating a switch has no sounds on its own, but rather the sound of a door opening for 1.5 seconds. That sound in my mind is a mechanical ratcheting system that is roughly "zi zi zi zi". The low frequency square wave turns the sound on and off to simulate the intermittent sound of mechanical gear teeth making new contact. Multiplying this by fixed frequency saw wave makes the sound be "zz" when on and nothing when off.

switchSound = await generate(1.5, (i) => {
  return 0.1 * (sqr(i/800) * 0.5 + 0.5) * saw(i/(110));
});

🕸️ Hitting the spider webs with basic attacks should effectively make a cute "boing" sound. A boing sound is all about frequency oscillating around a base frequency. Since a web can be viewed like a guitar string, I use a sin function as the base waveform, then modulate its frequency with another sin inside!

boingSound = await generate(0.6, (i) => {
  return 0.06 * sin(i/(20+sin(i/900)+i/1300));
});

🔥 The fireball attack is a fun composition of flame sound + doppler shift (the sound cars make while whiffing by). A burning flame is a crackling sound simply modeled with the random function. As for the doppler shift, take any repeating waveform (I chose square wave here), then make its base frequency decrease over time. Old game audio has convinced us this sound is pronounced pewwwww.

fireballSound = await generate(0.4, (i) => {
  return 0.03 * (sqr(i/(20 + i / 100) + Math.random()));
});

Hopefully that helps get you started!

Interesting stuff, I will experiment for a while, thanks for your detailed explanation.