Skip to content

Audio files

The VN connoisseur edited this page Oct 10, 2026 · 11 revisions

Main characteristics

Version 1

Specifications Hardcoded Notes
Container OGG Vorbis ✅ -
Bits per sample 16 ✅ -
Sample rate 44.1 KHz ✅ It is possible that some games might use a different sample rate.
Number of channels 1 ✅ -
Encoder aoTuV Beta5.7 - -
Decoder Main game executable function - -

Version 2

Specifications Hardcoded Notes
Container OGG Vorbis ❌ The DLL used also supports WAV files, and MP3.
Bits per sample 16 ✅ -
Sample rate 44.1 KHz ❌ -
Number of channels 1-2 ❌ The WAVEFORMATEX structure does not support more than 2 channels.
Encoder aoTuV Beta5.7 - -
Decoder Ayame 6.0.0 - Also used by SPLUSH WAVE. Check the history of this library to know where it came from.

Decoding process

Version 1

Once finished the process of obtaining the file inside the ODN file, the same function will contain a function to decode the OGG file itself. To do that, it will create a WAVEFORMATEX structure to create the PCM stream:

PlayVoice_SNDDataXX

waveFormat[0] = 0x10001;                      // this and what comes below is for WAVEFORMATEX, wFormatTag=1 (PCM) in low word, nChannels=1 (mono) in high word
blockAlignAndBitDepth = 0x100002;             // nBlockAlign=2 (16-bit mono) in low word, wBitsPerSample=16 in high word
v26 = 0;
v28 = 0;
v29 = 0;
v30 = 0;
v31 = 0;
pWaveFormat = waveFormat;
waveFormat[1] = 44100;                        // nSamplesPerSec
avgBytesPerSec = 88200;                       // nAvgBytesPerSec = 44100 * 2
cbSize = 18;
bufferDesc[0] = 36;                           // dwSize = sizeof(DSBUFFERDESC). this and what comes below is basically for building DSBUFFERDESC on the stack
bufferDesc[1] = 98760;                        // dwFlags (DSBCAPS flags)
dsbufferSize = pcmByteLength + 16;            // dwBufferBytes = decoded PCM size + header slack for DirectSound

After finishing the decoding process, if the user has activated the function to wait for the previous voice line to end in order to play the next, the game will calculate the duration of the audio file by using the PCM length. To do that, it will perform the following operation:

PCM length (bytes) * 16 (bits/sample) / 441000 (samples/second)

This will compute the amount of seconds the audio track does play for.

Version 2

For this engine, the game uses an open source DLL called Ayame. Since the program is open source, everything can be seen without any kind of obfuscation. Like with version 1, it makes use of the WAVEFORMATEX structure to create a PCM stream:

COggFileReader::CreateInstance

const	vorbis_info*	info = ov_info(&vf, -1);
const	int				sampleBits = 16;	//デコードする量子化ビット数は16で固定
const	int				blockAlign = info->channels * (sampleBits / 8);	//1ブロックのバイト数
pReader->m_WaveFormat.wFormatTag      = WAVE_FORMAT_PCM;
pReader->m_WaveFormat.nChannels       = (unsigned short)info->channels;
pReader->m_WaveFormat.nSamplesPerSec  = info->rate;
pReader->m_WaveFormat.nAvgBytesPerSec = info->rate * blockAlign;
pReader->m_WaveFormat.nBlockAlign     = (unsigned short)blockAlign;
pReader->m_WaveFormat.wBitsPerSample  = sampleBits;

pReader->m_totalSamples = (unsigned long)ov_pcm_total(&vf, -1);
pReader->m_terminated   = false;

From the resulting struct, only the bits per sample rate gets hardcoded, the rest is inferred from the sound file (it is still constrained to the limits imposed by the WAVEFORMATEX structure).

To close of this, in order to load the DLL it has to store it somewhere. First, it will try to load it in the game's directory root. If that fails, it will copy it from the game's executable resources (you can obtain the DLL through any tool like Resource Hacker) and try to save it temporarily in the %TEMP% folder (which is what happens) or if that path is locked, inside game's root path.

History of the Ayame library

As expected, the library they used for audio decoding is open source, and it is called Ayame. According to the author, called Haniwa, designed a library for DirectX for making the programming of Windows programs more approachable called Luna, and Ayame is the part that handles audio processing.

Sadly, according to this post from 2005, the link for the original version of that tool is long gone, alongside all of the tools made for it. The only thing that remains is the source code for the engine that succeeded Luna, called Selene, which does include some header files for Ayame.

After 2011, he decided to leave the programming scene for good, and subsequently, took down his website around that same date (or maybe let his domain expire).


In 2010, an user called mirichi decided to port and maintain until 2016 a wrapper for the Luna library for the game engine called DXRuby. This time nothing was backed up from this wrapper, and it's lost completely to time.

According to this blog, in 2014, a user called Sazanta decided to release an updated version of the Ayame library, that'd being version 6.0.0. It's not super clear if he was already maintaining it by his own given the README included in the tool, but a theory is that the Luna engine is what offers version 1.0.0 of the Ayame dll, and Sazanta decided to update that library by himself.

Clone this wiki locally