hello_ymfm_wasm

VGM

What is VGM?

VGM stands for Video Game Music.

In practice, a VGM file is usually not a recording like mp3 or wav. Instead, it is closer to a log of chip operations.

For example, a VGM file can contain information such as:

So a VGM file is often closer to:

than to:

Mental model

A simple mental model is:

  1. A composer or tool creates chip music data.
  2. The VGM file stores chip writes and wait commands.
  3. A player reads the VGM commands in order.
  4. The player sends register writes to the YM2612 emulator.
  5. The emulator generates audio samples.

VGM is not the same as WAV

It is useful to separate these ideas:

A wav file says:

A vgm file says:

Why this matters for YM2612

The YM2612 is controlled by register writes.

This matches VGM very well, because VGM also describes playback as a sequence of chip commands.

That means:

FM and PCM are different

It is useful to separate these two ideas early:

For FM, we usually think in terms of:

For PCM / DAC, the mental model is different.

We do not select “instrument 3” or “sample 5” inside the YM2612. Instead, we send 8-bit sample values to the chip over time.

That is why PCM playback is closer to:

than to:

YM2612 registers for PCM / DAC

Two YM2612 registers are especially important here:

The rough idea is:

  1. Enable DAC playback with 0x2B.
  2. Write 8-bit sample values to 0x2A.
  3. Keep writing data at the correct timing.

So for PCM, the “sound source” is not a built-in preset. The sound source is the byte stream that we feed into 0x2A.

What we will need later

To support VGM playback, we will eventually need to understand:

Short summary

VGM is a music data format that stores sound chip commands and timing.

For this repository, VGM matters because it could let us:

VGM Header / Command

This note is intentionally YM2612-first.

The full VGM specification is large, but for an initial YM2612 player, we do not need all of it.

At first, we only need to understand:

First fields to care about

If the goal is “play YM2612 VGM through ymfm”, start with these fields:

Everything else can wait until later.

VGM Header

A VGM file begins with a header.

The header stores metadata such as:

For modern VGM files, the header is usually treated as a 0x100 byte area.

Some important fields are:

Important ideas

To replay YM2612 correctly, we will especially care about:

The YM2612 clock is important because it tells us what chip clock the music expects.

For a first implementation, this is already enough.

VGM Commands

After the header comes a stream of commands.

The player reads the commands one by one. Each command usually means one of these things:

For YM2612 playback, the most important commands are:

For YM2612 DAC / PCM playback, these are also important:

First commands to care about

For a first YM2612-only implementation, these commands are enough:

That means the first player only needs to support:

Why 0x52 and 0x53 matter

These commands map very naturally to the YM2612 interface we already have.

This is one of the main reasons VGM fits well with YM2612 emulation.

How PCM is described in VGM

For PCM, VGM usually does not mean:

Instead, it usually means something closer to:

That is why commands such as 0x67, 0x80-0x8F, 0x90-0x95, and 0xE0 matter.

0x67 and 0x68 are different

These two commands are easy to mix up.

So the rough distinction is:

For YM2612 DAC playback, the most common mental model is still:

  1. enable DAC with register 0x2B
  2. send bytes to register 0x2A
  3. wait between writes

That is why some YM2612 VGM files can still play even if 0x68 is not implemented.

Mental model for YM2612 PCM in VGM

A simple mental model is:

  1. A VGM data block stores PCM bytes.
  2. The player remembers that byte array.
  3. A DAC-related command selects where to read from.
  4. The player writes bytes to YM2612 register 0x2A.
  5. Wait timing controls the playback speed.

So the PCM “instrument” is really:

Practical mapping

This is the important connection:

In other words:

Small example

The playback idea is roughly:

  1. Write 0x2B to enable DAC.
  2. Load or point to PCM sample data.
  3. Send one byte to 0x2A.
  4. Wait a little.
  5. Send the next byte to 0x2A.
  6. Repeat until the sample ends.

That is the basic PCM / DAC model for YM2612.

Wait commands

VGM does not only store register writes. It also stores timing.

That timing is critical.

For example:

Without the wait commands, the music would not have the correct rhythm or note lengths.

Minimal player mental model

A minimal YM2612 VGM player would do this:

  1. Read the header.
  2. Find the command stream start.
  3. Parse commands in order.
  4. For 0x52 and 0x53, write to YM2612.
  5. For wait commands, generate that many audio samples.
  6. Stop at 0x66, or jump to the loop point if looping is enabled.

Notes

Practical scope

If we keep the scope small, the first YM2612 VGM player can be:

  1. Read the header.
  2. Find the data start.
  3. Handle 0x52 and 0x53.
  4. Handle 0x61, 0x62, and 0x63.
  5. Stop at 0x66.
  6. Optionally handle looping with the loop offset.

This is a good first target.

What this repository supports now

At the current stage of this repository:

More specifically:

So PCM / DAC playback is not “fully done”, but it is also no longer “all skipped”.

References