View on GitHub

ym2151-log-play-server

ym2151-log-play-server

ym2151-log-play-server

Japanese English Ask DeepWiki

A server and client that receive YM2151 (OPM) register event logs and perform real-time playback. Written in Rust.

Supported Platforms

Development Status

It is used as a library, integrated into cat-play-mml and ym2151-tone-editor.

Frequent breaking changes occur, especially regarding the client-server protocol and server operation modes.

Overview

This project is a program that plays back register event logs from the YM2151 (OPM) sound chip. It operates in server-client mode.

Key Features

Usage

Usage as a Library (Programmatic Control)

Recommended pattern for using this library programmatically:

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // Ensure server is ready (automatically installs and starts if necessary)
    client::ensure_server_ready("cat-play-mml")?;
    
    // Send JSON data
    let json_data = r#"{"event_count": 2, "events": [...]}"#;
    client::send_json(json_data)?;
    
    // Playback control
    client::stop_playback()?;
    
    // Shutdown on exit
    client::shutdown_server()?;
    
    Ok(())
}

The ensure_server_ready() function automatically performs the following, providing a seamless development experience:

  1. Checks if the server is already running
  2. Installs the server application via cargo if not found in PATH
  3. Starts the server in background mode
  4. Waits until the server is ready to accept commands

This eliminates the need for library users to manually manage the server’s lifecycle.

Client Implementation Guide

This section describes two primary client implementation patterns.

Pattern 1: Non-Interactive Mode

Non-interactive mode is a simple mode suitable for one-shot JSON data transmission. Playback stops and restarts with each JSON transmission.

Basic Usage

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // Ensure server is ready (automatically installs and starts if necessary)
    client::ensure_server_ready("your-app-name")?;
    
    // Send JSON data (start playback)
    let json_data = r#"{"event_count": 2, "events": [
        {"time": 0, "addr": "0x08", "data": "0x00"},
        {"time": 2797, "addr": "0x20", "data": "0xC7"}
    ]}"#;
    client::send_json(json_data)?;
    
    // Control playback as needed
    std::thread::sleep(std::time::Duration::from_secs(5));
    client::stop_playback()?;
    
    // Play another JSON
    let json_data2 = r#"{"event_count": 1, "events": [
        {"time": 1000, "addr": "0x28", "data": "0x3E"}
    ]}"#;
    client::send_json(json_data2)?;
    
    // Shutdown on exit
    client::shutdown_server()?;
    
    Ok(())
}

Characteristics

Pattern 2: Interactive Mode

Interactive mode is an advanced mode suitable for real-time audio control. It allows dynamic scheduling of register events while maintaining a continuous audio stream.

Basic Usage

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // Server preparation
    client::ensure_server_ready("your-app-name")?;
    
    // Start interactive mode (begin continuous audio stream)
    client::start_interactive()?;
    
    // Send multiple JSONs without audio gaps
    let phrase1 = r#"{"event_count": 2, "events": [
        {"time": 0, "addr": "0x08", "data": "0x78"},
        {"time": 2797, "addr": "0x20", "data": "0xC7"}
    ]}"#;
    client::play_json_interactive(phrase1)?;
    
    // Switch to another phrase mid-phrase (no audio gap)
    client::clear_schedule()?; // Cancel future events
    let phrase2 = r#"{"event_count": 1, "events": [
        {"time": 1000, "addr": "0x28", "data": "0x3E"}
    ]}"#;
    client::play_json_interactive(phrase2)?;
    
    // Synchronous acquisition of server time (equivalent to Web Audio's currentTime)
    let server_time = client::get_server_time()?;
    println!("Current server time: {:.6} seconds", server_time);
    
    // End interactive mode
    client::stop_interactive()?;
    
    Ok(())
}

Advanced Features

Schedule Clear Function

// Start phrase 1
client::play_json_interactive(phrase1_json)?;

// Switch to phrase 2 mid-phrase without audio gaps
client::clear_schedule()?; // Clear events not yet processed
client::play_json_interactive(phrase2_json)?; // Immediately schedule the new phrase

Server Time Synchronization

// Get server time for precise timing control
let current_time = client::get_server_time()?;
// Functionality equivalent to Web Audio's currentTime property

Characteristics

Timing Conversion

In interactive mode, JSON in ym2151log format (sample units, 55930 Hz) is automatically converted to f64 seconds and sent to the server:

// Input: Sample units (i64, 55930 Hz)
let input_json = r#"{"event_count": 1, "events": [
    {"time": 2797, "addr": "0x08", "data": "0x00"}  // 2797 samples = approx. 0.05 seconds
]}"#;

// Automatic internal conversion: f64 seconds
// Sent to server as {"time": 0.050027, ...}
client::play_json_interactive(input_json)?;

Server-Client Mode

Starting the Server

Starts as a persistent server in a waiting state:

# Normal mode (log file only)
cargo run --release -- server

# Verbose mode (detailed logs and WAV output)
cargo run --release -- server --verbose

# Low-quality resampling mode (for comparison)
cargo run --release -- server --low-quality-resampling

# Verbose + low-quality resampling
cargo run --release -- server --verbose --low-quality-resampling

Client Operations

Operate from another terminal in client mode:

# Play a new JSON file (switch performance)
cargo run --release -- client output_ym2151.json

# Play a new JSON file in verbose mode
cargo run --release -- client output_ym2151.json --verbose

# Stop playback (mute)
cargo run --release -- client --stop

# Shut down the server
cargo run --release -- client --shutdown

Command Line Arguments

Usage:
  ym2151-log-play-server check                     # Check for updates
  ym2151-log-play-server server [OPTIONS]           # Server mode
  ym2151-log-play-server client [OPTIONS] [FILE]    # Client mode
  ym2151-log-play-server update                    # Update to latest version

Server Mode:
  server                    Start as a server in waiting state
  server --verbose          Start in verbose log mode (outputs WAV files)
  server --low-quality-resampling  Use low-quality resampling (linear interpolation, for comparison)

Client Mode:
  client <json_file>        Instruct the server to play a new JSON file
  client <json_file> --verbose  Instruct playback with detailed status messages
  client --stop             Instruct the server to stop playback
  client --stop --verbose   Stop playback with detailed status messages
  client --shutdown         Instruct the server to shut down
  client --shutdown --verbose  Shut down the server with detailed status messages

Examples:
  # Check for updates
  ym2151-log-play-server check

  # Start server
  ym2151-log-play-server server

  # Start server (verbose, with WAV output)
  ym2151-log-play-server server --verbose

  # Start server (low-quality resampling)
  ym2151-log-play-server server --low-quality-resampling

  # From another terminal: Switch playback
  ym2151-log-play-server client output_ym2151.json

  # From another terminal: Play in verbose mode
  ym2151-log-play-server client output_ym2151.json --verbose

  # From another terminal: Stop playback
  ym2151-log-play-server client --stop

  # From another terminal: Terminate server
  ym2151-log-play-server client --shutdown

  # Update to latest version
  ym2151-log-play-server update

Usage Scenarios

Scenario 1: Basic Usage

# Terminal 1: Start server
$ cargo run --release -- server

# Terminal 2: Operate from client
$ cargo run --release -- client output_ym2151.json

$ cargo run --release -- client --stop

$ cargo run --release -- client --shutdown

Scenario 2: Continuous Playback

# Start server (Terminal 1)
$ cargo run --release -- server

# Switch songs one after another (Terminal 2)
$ cargo run --release -- client music2.json
$ Start-Sleep 5
$ cargo run --release -- client music3.json
$ Start-Sleep 5
$ cargo run --release -- client music1.json

Release Build

cargo build --release
.\target\release\ym2151-log-play-server.exe server
.\target\release\ym2151-log-play-server.exe server --verbose
.\target\release\ym2151-log-play-server.exe client output_ym2151.json
.\target\release\ym2151-log-play-server.exe client --stop
.\target\release\ym2151-log-play-server.exe client --shutdown

Running Tests

cargo test

Build Requirements

Future Outlook

Project Goals

Non-Goals (Out of Scope)

Project Intent

Development Method

License

MIT License

Used Libraries