hello_ymfm_wasm

Beep For YM2612

This note is about ex03_beep.cpp.

The goal is not to make a rich instrument yet. The goal is to understand one simple YM2612 beep by starting from the final sound and then tracing how that sound is configured.

Start with the browser demo

Before reading the code, open this page and hear the target result:

That demo applies the same YM2612 settings as ex03_beep.cpp.

So the main question of this tutorial is:

How do we describe that beep in FM terms, and how do we send those settings to ymfm or to the real chip?

First describe the beep in FM terms

Before looking at register numbers, it helps to describe the beep like this:

This is the real idea behind the beep. The register writes are only the chip-specific way to express that idea.

Channel and operator idea

The YM2612 has 6 FM channels. Each channel has 4 operators.

An operator is a small tone generator. Operators can modulate each other, or they can directly contribute to the final output.

In ex03_beep.cpp, we use channel 1.

In FM synthesis, one channel is basically built from 4 operators. That is why ranges such as 0x30-0x3c exist: the settings are repeated for the 4 operators.

Why Algorithm 7?

In Algorithm 7, all 4 operators work as carriers. This is a simple starting point because every operator directly contributes to the output.

It is not the only way to make a sound, but it is easy to understand.

Beep target configuration

For this beep, the intended setup is roughly:

Channel

Operators

More concretely:

Pitch

Trigger

Without Key ON, the chip is configured but the note does not actually begin.

Then express that idea as YM2612 writes

Once the FM-side idea is clear, we can look at the chip-side expression.

Each register write follows this pattern:

  1. Write the register number to the address port.
  2. Write the value to the data port.

For example:

chip.write(0, 0x30);
chip.write(1, 0x01);

This means:

  1. Select register 0x30.
  2. Write value 0x01 into register 0x30.

So ex03_beep.cpp is really doing two things at once:

Registers used in ex03_beep.cpp

Quick view

1. DT / MULTI

These registers control detune and frequency multiple for each operator.

In ex03_beep.cpp, they are all set to 0x01.

What happens:

More detail:

2. Total Level

These registers control the output level of each operator.

In ex03_beep.cpp, operator 4 is louder than the others:

What happens:

More detail:

3. Attack Rate

These registers control how quickly the sound rises.

In ex03_beep.cpp, they are all set to 0x1f.

What happens:

More detail:

4. Sustain / Release area

These registers are part of the envelope settings.

In ex03_beep.cpp, they are all set to 0x0f.

What happens:

More detail:

5. Algorithm

This selects Algorithm 7 for channel 1.

What happens:

More detail:

6. Stereo output

This enables both left and right output.

What happens:

More detail:

7. Frequency

These two registers set the pitch.

What happens:

More detail:

8. Key ON

This turns on operators 1-4 for channel 1.

What happens:

More detail:

Read the code as a register dictionary

If you want to understand the YM2612 more deeply and write your own setup by yourself, it is a good idea to read ymfm source code directly.

In this repository, src/ymfm_opn.h:209 is a very useful register dictionary.

These lines are especially helpful:

For 0x28 key on/key off handling, src/ymfm_opn.cpp:176 is the place to read.

Once you can connect ex03_beep.cpp with these definitions, you are already very close to being able to build your own YM2612 beep setup.

Important idea

The beep is not made by one special “beep command”.

The sound appears because: