Jump to content

ACB Audio Injection

From HedgeDocs
Revision as of 22:07, 2 September 2025 by Kwasior (talk | contribs) (Added an image of created ACB playing in foobar2000)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

In this tutorial you will learn the basics of injecting audio (HCA, ADX) into CRIWARE's ACB files. Helps to cut down the size of mods by not shipping the entire ACB+AWB.

The tutorial will be using cri_utf_tool from KwasTools for ACB conversion to and from XML.

Additional software will be required, such as the HCA audio converter and a text editor. I will be using VGAudioCli and Notepad++.

I also recommend installing foobar2000 with vgmstream component for easy preview of audio. Will also help with pinpointing file indices in AWB archive.

For this tutorial, I will be replacing Cyber Space 1-1 music in Sonic Frontiers.

Converting the ACB to XML

Converting the ACB is as easy as drag and dropping it on the cri_utf_tool executable.

If conversion was successful, it'll create an XML file in the same directory as the ACB. For me it created bgm_cyber.acb.xml.

XML opened in a text editor
XML opened in a text editor

Creating an internal AWB file

Some ACBs do not have an internal AWB file, which is required to store audio we want to use. This is the case with bgm_cyber, it lacks one and we need to create it.

The XML structure of AWB file is the same as one from cri_awb_tool. However, I will include a minimal example for Sonic Frontiers below to keep things straightforward.

<AWB version="2" offset_size="4" id_size="2" alignment="32" subkey="0">
    <entry id="0" path="audio.hca"/>
</AWB>

Keep in mind that parameters need to match the external AWB's. Game will crash otherwise.

Inserting the internal AWB structure

Search for <record value="" name="AwbFile"/> and you should find this:

<record value="" name="AutoModulationTable"/>
<record value="" name="StreamAwbTocWorkOld"/>
<record value="" name="AwbFile"/>
<record value="&#10;ACB Format/PC Ver.1.37.0 Build:&#10;" name="VersionString"/>
<record value="" name="CueLimitWorkTable"/>

We need to replace the AwbFile record with our own AWB structure. After changes you should get something like this:

<record value="" name="AutoModulationTable"/>
<record value="" name="StreamAwbTocWorkOld"/>
<AWB version="2" offset_size="4" id_size="2" alignment="32" subkey="0">
    <entry id="0" path="my_audio.hca"/>
    <entry id="1" path="my_audio_boost.hca"/>
</AWB>
<record value="&#10;ACB Format/PC Ver.1.37.0 Build:&#10;" name="VersionString"/>
<record value="" name="CueLimitWorkTable"/>

ID starts at 0 and goes up. Paths are relative to XML's location.

Modifying Waveform data

Next, we need to change data in the Waveform table for each track we want to replace.

In short, we have to change the MemoryAwbId and Streaming values.

Explanation of parameters

MemoryAwbId is the index in the internal AWB file. In our case, index 0 is the main track and index 1 is the boost version.

Streaming is more interesting, it has three available options:

Streaming values
Value Description
0 Audio is streamed from internal AWB file, which resides in RAM
1 Audio is streamed from external AWB file
2 Short snippet of audio in internal AWB file to initialize the decoder, rest of the audio is streamed from external AWB file

What we're looking for is the value of 0 - streaming from internal AWB.

Getting AWB IDs we want to replace

Cyber Space 1-1 stage name is w6d01. Opening bgm_cyber.awb in foobar2000 reveals that first two tracks are what we're looking for. However, foobar2000 lists all item indexes starting from 1, so we need to subtract 1 from desired index.

bgm_cyber.awb playing in foobar2000, with Cyber Space 1-1 audio tracks selected.

So our IDs are 0 for main track and 1 for boost. With that we can finally proceed.

Modifying the parameters

Quick and easy way of finding a correct Waveform is searching for a string <record value="0" name="StreamAwbId"/>, where value is the external AWB track ID.

<row>
    <record value="65535" name="MemoryAwbId"/>
    <record value="2" name="EncodeType"/>
    <record value="1" name="Streaming"/>
    <record value="2" name="NumChannels"/>
    <record value="2" name="LoopFlag"/>
    <record value="48000" name="SamplingRate"/>
    <record value="4999086" name="NumSamples"/>
    <record value="8" name="ExtensionData"/>
    <record value="0" name="StreamAwbPortNo"/>
    <record value="0" name="StreamAwbId"/>
    <record value="65535" name="LipMorthIndex"/>
</row>

Waveform data for track 0. After modifications (that is, changing MemoryAwbId and Streaming value) we get the following:

<row>
    <record value="0" name="MemoryAwbId"/>
    <record value="2" name="EncodeType"/>
    <record value="0" name="Streaming"/>
    <record value="2" name="NumChannels"/>
    <record value="2" name="LoopFlag"/>
    <record value="48000" name="SamplingRate"/>
    <record value="4999086" name="NumSamples"/>
    <record value="8" name="ExtensionData"/>
    <record value="0" name="StreamAwbPortNo"/>
    <record value="0" name="StreamAwbId"/>
    <record value="65535" name="LipMorthIndex"/>
</row>

After repeating the process for the boost track, we can now finally convert back to ACB and check results ingame.

Converting the XML to ACB

Same as before, drag and drop the XML on the cri_utf_tool. It should output a big ACB file that's ready to be copied into a mod.

Created ACB is playable in foobar2000 and will only show audio files we injected into it.

Resulting ACB playing in foobar2000

Result

0x0px
Cookies help us deliver our services. By using our services, you agree to our use of cookies.