{"id":51,"date":"2021-07-21T08:43:58","date_gmt":"2021-07-21T13:43:58","guid":{"rendered":"https:\/\/chronocrash.com\/obor\/wiki\/?p=51"},"modified":"2023-12-28T08:41:46","modified_gmt":"2023-12-28T13:41:46","slug":"audio-overview","status":"publish","type":"post","link":"https:\/\/chronocrash.com\/obor\/wiki\/audio-overview\/","title":{"rendered":"Audio Overview"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Music<\/h1>\n\n\n\n<p>Music is often a huge part of the module experience, and physical size tends to represent the lion&#8217;s share of a module&#8217;s disk space. Music does not occupy memory though, because OpebOR streams music tracks live from the module&#8217;s data content.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Format<\/h2>\n\n\n\n<p>OpenBOR supports the following formats for music playback.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">BOR<\/h3>\n\n\n\n<p>A proprietary ADPCM music format that requires a conversion process from .wav files. This is the fastest and most portable format.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Conversion<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Locate the <em>wav2bor<\/em> folder. It is part of the OpenBOR Development Kit available <a href=\"https:\/\/www.chronocrash.com\/forum\/index.php?resources\/neo-edit-pack.2\/\">here<\/a> and contains the tools you will need to convert .wav to .bor format.<\/li>\n\n\n\n<li>Gather the .wav files for conversion, and ensure they are compatible.\n<ul class=\"wp-block-list\">\n<li>16bit PCM.<\/li>\n\n\n\n<li>Stereo or Mono.<\/li>\n\n\n\n<li>22KHz &#8211; Other sampling rates may work, but they are not officially supported and may produce unexpected results.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Place all the finished .wav files in the wav2bor folder.<\/li>\n\n\n\n<li>Open conmusic.bat with a text editor such as Notepad, then find <code>Wav2Bor mymusic.wav ..\\data\\music\\mymusic.bor<\/code> and edit as follows:<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>mymusic.wav<\/code> is the name of the .wav file to be converted.<\/li>\n\n\n\n<li><code>..\\data\\music\\mumusic.bor<\/code> is the path and name of the converted output file.<\/li>\n<\/ul>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ogg Vorbis<\/h3>\n\n\n\n<p>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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Loop<\/h2>\n\n\n\n<p>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.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Sound Effects<\/h1>\n\n\n\n<p>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 &#8220;sound&#8221; command in model text files  load with the model&#8217;s other assets.<br><br>You will need to load files manually for scripted playback (see below).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Channels<\/h2>\n\n\n\n<p>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:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Galford Progress Demo\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/kXriBQFgxh0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Bit Depth<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>8 &#8211; Recommended for general purpose sound effects as it has the smaller memory footprint without quality loss.<\/li>\n\n\n\n<li>16 &#8211; Recommended if you intend to perform stereo mixing with script. Mixing with 8bit may introduce an annoying &#8220;pop&#8221; into the sound effect.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Sample Rate<\/h2>\n\n\n\n<p>11Khz to 44Khz. 22khz is recommended as it generally offers the best compromise of sound quality and size.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Playback<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Native<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Predefined<\/h4>\n\n\n\n<p>OpenBOR includes several hard coded sound references. To change these sounds, replace the file. If you don&#8217;t want a hard coded sound to play, replace it with a blank file.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>data\/sounds\/beat1.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when an attack hits an entity\u2019s bbox.<\/li>\n\n\n\n<li>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 \u2018noslowfx\u2019 command.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/fall.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when an entity hits the floor after being knocked down.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/get.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when a player picks up an item.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/money.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when a player grabs a score item.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/jump.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when someone jumps.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/indirect.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when an entity hits other entities while being thrown or blasted.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/punch.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when a player uses an attack in their attack chain (Pressing attack from a standing position). Normally only heard if the attack misses.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/1up.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played when the player gets a 1-up.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/go.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Plays three times in a row when the player has beaten all enemies at a wait and can now move forward again.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/timeover.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played if the timer hits zero. Also played if all credits are lost.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/beep.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played in menus (not in game) when you move up or down.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/beep2.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Played in menus (not in game) when you select an option.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/bike.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Required if you have bikers. Plays for bikers, of course.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/block.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Optional. Plays when an entity blocks an attack.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>data\/sounds\/pause.wav<\/strong>\n<ul class=\"wp-block-list\">\n<li>Optional. Played when pausing. If the file does not exist beep2.wav will play instead.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Model Playback\u200b<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Die Sound\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ndiesound &amp;lt;path&gt;\n\n#default\ndiesound none\n<\/pre><\/div>\n\n\n<p>Path points to a .wav file that plays if the entity is defeated by damage, including special damage types (pits, lifespan, etc.).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Block Effects\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nblockfx &amp;lt;path&gt;\n\n#default\nblockfx none\n<\/pre><\/div>\n\n\n<p>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).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Sound\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nsound &amp;lt;path&gt;\n\n#default\nsound none\n<\/pre><\/div>\n\n\n<p>Place immediately predeceasing a frame in any animation to play a sound effect.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>{path} points to a sound effect. The sound will be played as soon as the next frame is reached.<\/li>\n\n\n\n<li>One sound per animation frame supported. If you want to play more sounds in a frame, you can do so with script.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Other\u200b<\/h4>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Script<\/h3>\n\n\n\n<p>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 <code>loadsample()<\/code> 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 <code>playsample()<\/code><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">loadsample()<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nchar path = &quot;&lt;path to sound file&gt;&quot;;\nint log = 0;\n\nint sample_id = loadsample(path, log);\n<\/pre><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>char &lt;path&gt;: Full path to the sound file.<\/li>\n\n\n\n<li>int &lt;log&gt;: Optional. If true, will send a record of any failed load attempts to the log.<\/li>\n<\/ul>\n\n\n\n<p>Load a sound file into memory and returns its sample ID. If the sound is already loaded, <code>loadsample()<\/code> 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, <code>loadsample()<\/code> 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.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">playsample()<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nchar path = &quot;data\/some_folder\/some_sound.wav&quot;;\nint log = 0;\nint sample_id = loadsample(path, log);\n\nint priority = 0;\nint volume_left = 64;\nint volume_right = 64;\nint speed = 100;\nint loop = 0;\n\nint channel = playsample(sample_id, priority, volume_left, volume_right, speed, loop);\n\n<\/pre><\/div>\n\n\n<p>Find the first available sound channel and use it to play a sound sample. Returns the channel used, or -1 if playback fails.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>char &lt;sample id&gt;: ID of the sound to play. Obtain this with <code>loadsample()<\/code>.<\/li>\n\n\n\n<li>int &lt;priority&gt;: 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.<\/li>\n\n\n\n<li>int &lt;volume left&gt;: 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.<\/li>\n\n\n\n<li>int &lt;volume right&gt;: Right volume. Same rules as volume left.<\/li>\n\n\n\n<li>int &lt;speed&gt;: 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.<\/li>\n\n\n\n<li>int &lt;loop&gt; 0 = No loop. 1 = Loop playback until stopped.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">isactivesample()\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nint channel = 0;\n\nint active = isactivesample(channel);\n<\/pre><\/div>\n\n\n<p>Returns 1 if channel is active (sound in play), else it returns 0.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">sampleid()\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nint channel = 0;\n\nint sample_id = sampleid(channel);\n<\/pre><\/div>\n\n\n<p>Returns sample id in channel if sample is active, it returns -1 otherwise.<br><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">querychannel()\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nint sample_id = 0;\n\nint channel = querychannel(sample_id);\n<\/pre><\/div>\n\n\n<p>Accepts a sample id and returns first channel playing the sound, or -1 if none.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">unloadsample()\u200b<\/h4>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\nint sample_id = 0;\n\nunloadsample(sample_id);\n<\/pre><\/div>\n\n\n<p>Accepts a sample id and unloads the sample from memory.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Working with music and sound effects.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[36,328,2],"tags":[34,82,81,476,474,475,478,477,479,5,83,35],"class_list":["post-51","post","type-post","status-publish","format-standard","hentry","category-audio","category-openbor","category-script","tag-audio","tag-blockfx","tag-diesound","tag-obor_func_isactivesample-2","tag-obor_func_loadsample-2","tag-obor_func_playsample-2","tag-obor_func_querychannel-2","tag-obo_func_sampleid","tag-obor_func_unloadsample-2","tag-manual","tag-sound","tag-sounds"],"revision_note":"","jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/posts\/51","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/comments?post=51"}],"version-history":[{"count":4,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/posts\/51\/revisions"}],"predecessor-version":[{"id":1257,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/posts\/51\/revisions\/1257"}],"wp:attachment":[{"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/media?parent=51"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/categories?post=51"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chronocrash.com\/obor\/wiki\/wp-json\/wp\/v2\/tags?post=51"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}