Music
Music is often a huge part of the module experience, and physical size tends to represent the lion’s share of a module’s disk space. Music does not occupy memory though, because OpebOR streams music tracks live from the module’s data content.
Format
OpenBOR supports the following formats for music playback.
BOR
A proprietary ADPCM music format that requires a conversion process from .wav files. This is the fastest and most portable format.
Conversion
- Locate the wav2bor folder. It is part of the OpenBOR Development Kit available here and contains the tools you will need to convert .wav to .bor format.
- Gather the .wav files for conversion, and ensure they are compatible.
- 16bit PCM.
- Stereo or Mono.
- 22KHz – Other sampling rates may work, but they are not officially supported and may produce unexpected results.
- Place all the finished .wav files in the wav2bor folder.
- Open conmusic.bat with a text editor such as Notepad, then find
Wav2Bor mymusic.wav ..\data\music\mymusic.bor
and edit as follows:
mymusic.wav
is the name of the .wav file to be converted...\data\music\mumusic.bor
is the path and name of the converted output file.
Copy/paste and edit additional lines for each of your .wav files. Save and execute the batch (double click in Windows). The batch you just made will run wave2bor.exe for all of the target files, producing .bor music ready to use in your module.
Ogg Vorbis
An open source compression format very similar to .mp3 in performance and purpose. Ogg Vorbis is well documented and OpenBOR can play virtually any .ogg file, making it a good choice for beginners and advanced authors who want to optimize their music compression. The primary drawback is that some platforms, the PSP in particular, may experience some slowdown during playback of .ogg files.
Loop
OpenBOR allows you to loop to specific point in music tracks with the offset property. When a music offset is defined, the music track will loop to offset upon ending. Offsets are measured in bytes. For instance, with a music file of 128KB, setting offset to 64000 will cause the track to loop back to its halfway point.
Sound Effects
OpenBOR supports .wav files for sound effects. Unlike music, sound effect files are loaded to memory for playback. Default sounds (menu beeps, etc.) load on startup. Sounds played with the native “sound” command in model text files load with the model’s other assets.
You will need to load files manually for scripted playback (see below).
Channels
Sound files are mono only. This is nowhere near limiting as it sounds. OpenBOR supports playback of 256 simultaneous sound effects with direct control of left and right volume for each, enabling stereo mixing on the fly. In this example video, scripted stereo control is used to pan character voices and sound left or right based on their screen location:
Bit Depth
- 8 – Recommended for general purpose sound effects as it has the smaller memory footprint without quality loss.
- 16 – Recommended if you intend to perform stereo mixing with script. Mixing with 8bit may introduce an annoying “pop” into the sound effect.
Sample Rate
11Khz to 44Khz. 22khz is recommended as it generally offers the best compromise of sound quality and size.
Playback
Native
Predefined
OpenBOR includes several hard coded sound references. To change these sounds, replace the file. If you don’t want a hard coded sound to play, replace it with a blank file.
- data/sounds/beat1.wav
- Played when an attack hits an entity’s bbox.
- Normally, this sound will be played slower depending on how much damage the attack deals. If this is a problem, you can disable this with the ‘noslowfx’ command.
- data/sounds/fall.wav
- Played when an entity hits the floor after being knocked down.
- data/sounds/get.wav
- Played when a player picks up an item.
- data/sounds/money.wav
- Played when a player grabs a score item.
- data/sounds/jump.wav
- Played when someone jumps.
- data/sounds/indirect.wav
- Played when an entity hits other entities while being thrown or blasted.
- data/sounds/punch.wav
- Played when a player uses an attack in their attack chain (Pressing attack from a standing position). Normally only heard if the attack misses.
- data/sounds/1up.wav
- Played when the player gets a 1-up.
- data/sounds/go.wav
- Plays three times in a row when the player has beaten all enemies at a wait and can now move forward again.
- data/sounds/timeover.wav
- Played if the timer hits zero. Also played if all credits are lost.
- data/sounds/beep.wav
- Played in menus (not in game) when you move up or down.
- data/sounds/beep2.wav
- Played in menus (not in game) when you select an option.
- data/sounds/bike.wav
- Required if you have bikers. Plays for bikers, of course.
- data/sounds/block.wav
- Optional. Plays when an entity blocks an attack.
- data/sounds/pause.wav
- Optional. Played when pausing. If the file does not exist beep2.wav will play instead.
Model Playback
Die Sound
diesound <path>
#default
diesound none
Path points to a .wav file that plays if the entity is defeated by damage, including special damage types (pits, lifespan, etc.).
Block Effects
blockfx <path>
#default
blockfx none
If during this animation entity blocks an attack, this sound effect will be played. Normally used in BLOCK animation but it works in any animation if entity is in blocking status (set by script).
Sound
sound <path>
#default
sound none
Place immediately predeceasing a frame in any animation to play a sound effect.
- {path} points to a sound effect. The sound will be played as soon as the next frame is reached.
- One sound per animation frame supported. If you want to play more sounds in a frame, you can do so with script.
Other
There are other native means to play sounds. One example is defining specific hit sounds for an attack. These are detailed in articles about the relevant functionality.
Script
In order to play a sound, you must load the sound file into memory and/or get its sample ID. OpenBOR pre-loads the files for global sound effects on module start up, and loads the files for model sound commands when the model is loaded. For script playback, use the loadsample()
function. This will prepare a sound for playback by loading the sound file from the module pack into memory, assigning a sample ID, and returning the ID for use. You can then play the sound with playsample()
loadsample()
char path = "<path to sound file>";
int log = 0;
int sample_id = loadsample(path, log);
- char <path>: Full path to the sound file.
- int <log>: Optional. If true, will send a record of any failed load attempts to the log.
Load a sound file into memory and returns its sample ID. If the sound is already loaded, loadsample()
returns the existing ID instead (it does not load another copy or replace the existing file in memory). If the sound file cannot be loaded, loadsample()
returns -1. Valid sound IDs will always be 0+, so you can use this to reliably test for existence of a sound file. Although not a requirement, it is generally a good idea to pre-load sounds outside of active gameplay. If the sound file is not already in memory, there may be a small delay in the action while it is loaded.
playsample()
char path = "data/some_folder/some_sound.wav";
int log = 0;
int sample_id = loadsample(path, log);
int priority = 0;
int volume_left = 64;
int volume_right = 64;
int speed = 100;
int loop = 0;
int channel = playsample(sample_id, priority, volume_left, volume_right, speed, loop);
Find the first available sound channel and use it to play a sound sample. Returns the channel used, or -1 if playback fails.
- char <sample id>: ID of the sound to play. Obtain this with
loadsample()
. - int <priority>: Sets a priority for the play attempt. If all channels are occupied, the first channel with a lower priority is overridden. If no channel with a lower priority is found, the play attempt fails.
- int <volume left>: Left volume. 0 = Mute. You can set any value you like, but there is a hard code limit of 64 applied at playback for backward compatibility. Note: This is true for ALL sound effect playabck, despite any menu settings.
- int <volume right>: Right volume. Same rules as volume left.
- int <speed>: Playback speed. Default playback speed is 100. Slightly increasing or decreasing speed can give sounds higher or lower pitch. OpenBOR uses this with native hit sound playback.
- int <loop> 0 = No loop. 1 = Loop playback until stopped.
isactivesample()
int channel = 0;
int active = isactivesample(channel);
Returns 1 if channel is active (sound in play), else it returns 0.
sampleid()
int channel = 0;
int sample_id = sampleid(channel);
Returns sample id in channel if sample is active, it returns -1 otherwise.
querychannel()
int sample_id = 0;
int channel = querychannel(sample_id);
Accepts a sample id and returns first channel playing the sound, or -1 if none.
unloadsample()
int sample_id = 0;
unloadsample(sample_id);
Accepts a sample id and unloads the sample from memory.