SEGA SOUND / INTRODUCTION

Sega Mega CD RF5C164 Introduction with JavaScript

Put a waveform in memory, then change its read speed and stereo levels. Explore PCM basics with working code.

How to use this page

Run starts each example; Stop ends it. Change one code value and Run again to compare. Playback never starts automatically. Stop the other example before comparing.

These short performances release their sound chip at the end. They do not reproduce the tone of physical speakers or amplifiers.

Read a waveform instead of synthesizing one

The Sega Mega CD RF5C164 is a PCM chip that reads waveform RAM and plays up to eight channels. They share 64 KiB of RAM, with separate start address, loop address, playback speed, volume, and stereo output settings.

This is separate from CD-DA music track playback. Rather than using external ROMs or sounds extracted from games, this page writes an original sine wave to RAM.

1. Load a waveform and loop it

Generate one sine-wave cycle with 256 points. loadMemory() transfers chip-format bytes, and keyOn() starts playback. Change stepForHz(440) to 220 to read the same data more slowly and play about an octave lower.

loadMemory() takes an array of chip-format bytes, not WAV file bytes. For WAV / FLAC, use loadSample() instead.

Edit this code in a separate Playground tab ↗

2. Change pitch and stereo output with the same waveform

Play for one second with a target of 440 Hz on the left and 660 Hz on the right, then lower only the left to about 220 Hz. With this waveform and core, measured frequencies are about 440 Hz left and 651 Hz right. Listen for different pitches on each side and check that pitch changes do not require retransferring RAM.

pan has left / right levels from 0 to 15. Zero sends nothing to that side; 15 is maximum. Headphones help compare the sides.

Edit this code in a separate Playground tab ↗

Waveform format and playback speed

SettingMeaning
startStart RAM address, aligned to a 256-byte boundary.
loopStartRAM address to return to after reading an 0xff marker.
step16-bit address increment with 11 fractional bits. At 2048, each internal update advances one byte.
volumeChannel volume, 0–255.
panSeparate left and right output levels, 0–15.

In each waveform byte, bit 7 is the sign (1 means positive); the lower seven bits encode amplitude. 0xff is the loop marker, not the maximum positive sample. This example limits amplitude to 100.

The internal update rate is clock / 384: about 32.55 kHz with this runtime's default 12.5 MHz clock. This differs from a PCM output rate such as 48 kHz. Fast playback can skip RAM addresses, so the example places eight marker bytes at the end to ensure loop detection in the 220–660 Hz comparison.

stepForHz() is an approximation for a waveform containing one cycle in 256 points. For arbitrary recordings, choose playback speed based on the sample's original pitch and length.setPitch() takes a raw step value, not a MIDI number or Hz.

await waits for the browser audio backend to receive uploads or settings. sleep() sets note duration in JavaScript. The example releases the chip at the end with dispose().