freaq

A GameMaker script that adds 102 sound effects without any audio files.

freaq is a single GameMaker script that adds 102 sound effects without any audio files. Just add the one script, and you will have 102 new functions that play unique sound effects. Volume control is built in, along with adjustable randomized pitch variation to keep things sounding interesting.

If you are in the prototyping stage or are participating in a game jam, freaq is a great choice. It is the fastest and easiest way to add sound effects to your projects. It's just one script!

Usage

To adjust the volume, use freaq_set_volume(volume) and freaq_get_volume(). The default volume is 0.75 (with max volume being 1).

The sound effects in freaq (with a few exceptions) are played with a randomized pitch between 0.95 and 1.05. To adjust these numbers, use freaq_set_random_pitch_values(min, max). If you don't want any randomization at all, you can do freaq_set_random_pitch_values(1, 1).

Sounds are played using individual functions starting with freaq_play_ and then the sound name. So if you need an explosion sound, you can do freaq_play_explosion(). You can use GameMaker's auto-complete to browse all of the sounds available.

Each one of these playback functions accepts two optional arguments, volume and pitch. When you provide these arguments, they override the volume and randomized pitch that you setup with the previously mentioned functions. For example, freaq_play_explosion(0.5, 2) would play the explosion sound at half volume, and double the pitch.

Caveats

Under the hood, freaq uses audio buffers to create all of the sounds. Audio buffers take up a good amount of memory and it adds up quick. To account for this, freaq only creates the audio buffers for a sound the first time you play it. For most sounds this works transparently, but some bigger sounds can cause the game to stutter the first time it is played.

To fix this, you can use the freaq_preload_sound(...sounds) function. You can pass in multiple sound names to preload them, or just one. Following the example above, if you wanted to preload the explosion sound, you would do freaq_preload_sound("explosion"). You can also pass the keyword all to preload everything, but I would avoid doing this unless you have a good reason, as loading every single sound can spike your memory usage to over a gigabyte (yikes).

Because memory usage is a concern when using it, I wouldn't recommend depending freaq for large games.

Technical details

White noise

Making sound effects using nothing but audio buffers was a challenge for sure, but the core of its functionality was mostly just figuring out the math involved. I started out by filling an audio buffer with just white noise. For an 8 bit audio buffer, this was as simple as just generating a random integer between 0 and 255 for the length of the buffer (where length is the playback rate times the number of seconds you want the sound to play for).

White noise audio buffer creation

With just white noise alone you can create many sound effects, like bumps and ticks and explosions, especially when combined with GameMaker's built in audio effects (particularly bitcrushing).

Waves

I used the experience I'd gained from making my GM Synth project to setup the basis for the rest of the sounds, which were just sine waves, square waves, and saw waves. The implementation for these varied a bit, and you can see my math in the presets section of the global freaq object. After creating helper functions to generate these waves with optional fade-ins, fade-outs, and frequency sweeps (only from one starting hertz to one ending hertz) the rest of the sounds could be made.

Some of the musical sounds (like the success and solved sounds) are one audio buffer played multiple times in a sequence (by using call_later's) and pitch multiplied approapriately to the target frequencies. If you're curious how that works, I have a youtube video on the subject.

Many sounds use audio effects, and my approach was to create a preset number of audio buses and emitters that I could apply to sounds by a key string, which made it easy to re-use them. Just like the audio buffers that are created, these buses and emitters are never cleaned up once used. The target use case for freaq is for prototypes and jam games, so I think it's fine.

Piano sounds

The piano sounds were probably the most interesting sounds for me to create. They are technically more like an "E-Piano" setting you might find on your keyboard, but I'm still happy with it. These sounds were constructed using one audio buffer and pitch multiplied using the harmonic series 8 times. Basically, a natural vibrating piano string is actually multiple tones being played at once. To emulate this, I created one sine wave (the fundamental) and multiplied it by 8 iterations (with a fundamental of 110 giving 220, 330, 440 and so on) to generate the overtones. I play all of these sounds at one time (with decreasing volume for each overtone) which generates the unique e-piano sound. I thought about adding a low white-noise strike sound to simulate a piano hammer action, but decided it wouldn't fit in with the mostly digital aesthetic of the rest of the sounds.

Index

Utility

  • freaq_set_volume(volume) - Set the current volume of the freaq system (a number between 0 and 1)
  • freaq_get_volume() - Get the current volume of the freaq system (between 0-1)
  • freaq_set_random_pitch_values(minimum, maximum) - Sets the minimum and maximum random pitch multipliers to add variation to freaq audio. Set both to 1 for no variation.
  • freaq_preload_sound(...sounds) - Preloads the sound with the given name, which makes it play instantly the first time. Pass in the names of the sounds you want to preload as individual arguments, or the all keyword to preload everything (not recommended)
  • freaq_dbg([padding]) - Creates a debug view for testing all of the sounds that come with freaq

Sounds

  • freaq_play_alert1([volume], [pitch])
  • freaq_play_alert2([volume], [pitch])
  • freaq_play_alert3([volume], [pitch])
  • freaq_play_alert4([volume], [pitch])
  • freaq_play_bang([volume], [pitch])
  • freaq_play_beep([volume], [pitch])
  • freaq_play_beep_high([volume], [pitch])
  • freaq_play_beep_low([volume], [pitch])
  • freaq_play_beep_lowest([volume], [pitch])
  • freaq_play_blip([volume], [pitch])
  • freaq_play_blip_high([volume], [pitch])
  • freaq_play_blip_low([volume], [pitch])
  • freaq_play_blip_lowest([volume], [pitch])
  • freaq_play_boom([volume], [pitch])
  • freaq_play_boom_huge([volume], [pitch])
  • freaq_play_boop([volume], [pitch])
  • freaq_play_boop_high([volume], [pitch])
  • freaq_play_boop_low([volume], [pitch])
  • freaq_play_boop_lowest([volume], [pitch])
  • freaq_play_bubble_pop([volume], [pitch])
  • freaq_play_bump1([volume], [pitch])
  • freaq_play_bump2([volume], [pitch])
  • freaq_play_bump3([volume], [pitch])
  • freaq_play_bump4([volume], [pitch])
  • freaq_play_buzz([volume], [pitch])
  • freaq_play_buzz_high([volume], [pitch])
  • freaq_play_buzz_low([volume], [pitch])
  • freaq_play_buzz_lowest([volume], [pitch])
  • freaq_play_chord_happy([volume], [pitch])
  • freaq_play_chord_sad([volume], [pitch])
  • freaq_play_collect1([volume], [pitch])
  • freaq_play_collect2([volume], [pitch])
  • freaq_play_collect3([volume], [pitch])
  • freaq_play_collect4([volume], [pitch])
  • freaq_play_collect5([volume], [pitch])
  • freaq_play_creature1([volume], [pitch])
  • freaq_play_creature2([volume], [pitch])
  • freaq_play_creature3([volume], [pitch])
  • freaq_play_creature4([volume], [pitch])
  • freaq_play_creature5([volume], [pitch])
  • freaq_play_creature6([volume], [pitch])
  • freaq_play_energy_beam([volume], [pitch])
  • freaq_play_explosion([volume], [pitch])
  • freaq_play_explosion_huge([volume], [pitch])
  • freaq_play_explosion_small([volume], [pitch])
  • freaq_play_failure1([volume], [pitch])
  • freaq_play_failure2([volume], [pitch])
  • freaq_play_failure3([volume], [pitch])
  • freaq_play_failure4([volume], [pitch])
  • freaq_play_fall1([volume], [pitch])
  • freaq_play_fall2([volume], [pitch])
  • freaq_play_fall3([volume], [pitch])
  • freaq_play_gunshot([volume], [pitch])
  • freaq_play_gunshot_heavy([volume], [pitch])
  • freaq_play_jump1([volume], [pitch])
  • freaq_play_jump2([volume], [pitch])
  • freaq_play_jump3([volume], [pitch])
  • freaq_play_laser1([volume], [pitch])
  • freaq_play_laser2([volume], [pitch])
  • freaq_play_laser3([volume], [pitch])
  • freaq_play_laser4([volume], [pitch])
  • freaq_play_magic1([volume], [pitch])
  • freaq_play_magic2([volume], [pitch])
  • freaq_play_magic3([volume], [pitch])
  • freaq_play_magic4([volume], [pitch])
  • freaq_play_piano_a([volume])
  • freaq_play_piano_a_high([volume])
  • freaq_play_piano_a_sharp([volume])
  • freaq_play_piano_b([volume])
  • freaq_play_piano_c([volume])
  • freaq_play_piano_c_sharp([volume])
  • freaq_play_piano_d([volume])
  • freaq_play_piano_d_sharp([volume])
  • freaq_play_piano_e([volume])
  • freaq_play_piano_f([volume])
  • freaq_play_piano_f_sharp([volume])
  • freaq_play_piano_g([volume])
  • freaq_play_piano_g_sharp([volume])
  • freaq_play_power_down([volume], [pitch])
  • freaq_play_power_up([volume], [pitch])
  • freaq_play_push([volume], [pitch])
  • freaq_play_radar([volume], [pitch])
  • freaq_play_solved1([volume], [pitch])
  • freaq_play_solved2([volume], [pitch])
  • freaq_play_solved3([volume], [pitch])
  • freaq_play_success1([volume], [pitch])
  • freaq_play_success2([volume], [pitch])
  • freaq_play_success3([volume], [pitch])
  • freaq_play_success4([volume], [pitch])
  • freaq_play_tick1([volume], [pitch])
  • freaq_play_tick2([volume], [pitch])
  • freaq_play_tick3([volume], [pitch])
  • freaq_play_tick4([volume], [pitch])
  • freaq_play_tick5([volume], [pitch])
  • freaq_play_tick6([volume], [pitch])
  • freaq_play_tick_ascending([volume])
  • freaq_play_tick_descending([volume])
  • freaq_play_woosh1([volume], [pitch])
  • freaq_play_woosh2([volume], [pitch])
  • freaq_play_woosh3([volume], [pitch])
  • freaq_play_woosh4([volume], [pitch])
  • freaq_play_woosh5([volume], [pitch])