View on GitHub

ym2151-log-play-server

ym2151-log-play-server

ym2151-log-play-server

Japanese English

YM2151(OPM)レジスタイベントログを受け取り、リアルタイム再生を行うサーバー・クライアント。Rustで書かれています。

対象プラットフォーム

開発状況

ライブラリとして、cat-play-mmlym2151-tone-editorに組み込んで使っています。

頻繁に破壊的変更があります。特にclient-serverプロトコルとserver動作モードについて。

概要

このプロジェクトは、YM2151(OPM)音源チップのレジスタイベントログを再生するプログラムです。 サーバー・クライアントモードで動作します。

主な機能

使い方

ライブラリとしての使用(プログラマティック制御)

このライブラリをプログラムから使用する場合の推奨パターン:

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // サーバーの準備を確認(必要に応じて自動的にインストールと起動)
    client::ensure_server_ready("cat-play-mml")?;
    
    // JSONデータを送信
    let json_data = r#"{"event_count": 2, "events": [...]}"#;
    client::send_json(json_data)?;
    
    // 再生制御
    client::stop_playback()?;
    
    // 終了時にシャットダウン
    client::shutdown_server()?;
    
    Ok(())
}

ensure_server_ready() 関数は以下のことを自動的に行い、シームレスな開発体験を提供します:

  1. サーバーが既に起動しているか確認
  2. PATHにサーバーアプリケーションが見つからない場合、cargo経由でインストール
  3. サーバーをバックグラウンドモードで起動
  4. サーバーがコマンドを受け付けられる状態になるまで待機

これにより、ライブラリユーザーがサーバーのライフサイクルを手動で管理する必要がなくなります。

クライアント実装ガイド

このセクションでは、2つの主要なクライアント実装パターンについて説明します。

パターン1: 非インタラクティブモード

非インタラクティブモードは、単発のJSONデータ送信に適したシンプルなモードです。 各JSON送信ごとに演奏が停止・再開されます。

基本的な使用方法

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // サーバーの準備を確認(必要に応じて自動的にインストールと起動)
    client::ensure_server_ready("your-app-name")?;
    
    // JSONデータを送信(演奏開始)
    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)?;
    
    // 必要に応じて演奏制御
    std::thread::sleep(std::time::Duration::from_secs(5));
    client::stop_playback()?;
    
    // 別のJSONを再生
    let json_data2 = r#"{"event_count": 1, "events": [
        {"time": 1000, "addr": "0x28", "data": "0x3E"}
    ]}"#;
    client::send_json(json_data2)?;
    
    // 終了時にシャットダウン
    client::shutdown_server()?;
    
    Ok(())
}

特徴

パターン2: インタラクティブモード

インタラクティブモードは、リアルタイムな音響制御に適した高度なモードです。 連続した音声ストリームを維持しながら、レジスタイベントを動的にスケジューリングできます。

基本的な使用方法

use ym2151_log_play_server::client;

fn main() -> anyhow::Result<()> {
    // サーバーの準備
    client::ensure_server_ready("your-app-name")?;
    
    // インタラクティブモード開始(連続音声ストリーム開始)
    client::start_interactive()?;
    
    // 複数のJSONを無音ギャップなしで送信
    let phrase1 = r#"{"event_count": 2, "events": [
        {"time": 0, "addr": "0x08", "data": "0x78"},
        {"time": 2797, "addr": "0x20", "data": "0xC7"}
    ]}"#;
    client::play_json_interactive(phrase1)?;
    
    // フレーズの途中で別のフレーズに切り替え(音響ギャップなし)
    client::clear_schedule()?; // 未来のイベントをキャンセル
    let phrase2 = r#"{"event_count": 1, "events": [
        {"time": 1000, "addr": "0x28", "data": "0x3E"}
    ]}"#;
    client::play_json_interactive(phrase2)?;
    
    // サーバー時刻の同期取得(Web Audioの currentTime 相当)
    let server_time = client::get_server_time()?;
    println!("現在のサーバー時刻: {:.6}秒", server_time);
    
    // インタラクティブモード終了
    client::stop_interactive()?;
    
    Ok(())
}

高度な機能

スケジュールクリア機能

// フレーズ1を開始
client::play_json_interactive(phrase1_json)?;

// フレーズ1の途中でフレーズ2に無音ギャップなしで切り替え
client::clear_schedule()?; // まだ処理されていないイベントをクリア
client::play_json_interactive(phrase2_json)?; // 新しいフレーズを即座にスケジューリング

サーバー時刻同期

// 正確なタイミング制御のためのサーバー時刻取得
let current_time = client::get_server_time()?;
// Web Audioの currentTime プロパティと同等の機能

特徴

タイミング変換

インタラクティブモードでは、ym2151logフォーマット(サンプル単位、55930 Hz)のJSONを自動的にf64秒単位に変換してサーバーに送信します:

// 入力: サンプル単位(i64、55930 Hz)
let input_json = r#"{"event_count": 1, "events": [
    {"time": 2797, "addr": "0x08", "data": "0x00"}  // 2797サンプル = 約0.05秒
]}"#;

// 内部で自動変換: f64秒単位
// {"time": 0.050027, ...} としてサーバーに送信
client::play_json_interactive(input_json)?;

サーバー・クライアントモード

サーバーの起動

サーバーとして常駐し、待機状態で起動:

# 通常モード(ログファイルのみ)
cargo run --release -- server

# verbose モード(詳細ログとWAV出力)
cargo run --release -- server --verbose

# 低品位リサンプリングモード(比較用)
cargo run --release -- server --low-quality-resampling

# verbose + 低品位リサンプリング
cargo run --release -- server --verbose --low-quality-resampling

クライアントからの操作

別のターミナルから、クライアントモードで操作:

# 新しいJSONファイルを再生(演奏を切り替え)
cargo run --release -- client output_ym2151.json

# 詳細モードで新しいJSONファイルを再生
cargo run --release -- client output_ym2151.json --verbose

# 演奏を停止(無音化)
cargo run --release -- client --stop

# サーバーをシャットダウン
cargo run --release -- client --shutdown

コマンドライン引数一覧

使用方法:
  ym2151-log-play-server server [OPTIONS]           # サーバーモード
  ym2151-log-play-server client [OPTIONS] [FILE]    # クライアントモード

サーバーモード:
  server                    サーバーとして待機状態で起動
  server --verbose          詳細ログモードで起動(WAVファイルを出力)
  server --low-quality-resampling  低品位リサンプリングを使用(線形補間、比較用)

クライアントモード:
  client <json_file>        サーバーに新しいJSONファイルの演奏を指示
  client <json_file> --verbose  詳細な状態メッセージ付きで演奏を指示
  client --stop             サーバーに演奏停止を指示
  client --stop --verbose   詳細な状態メッセージ付きで演奏を停止
  client --shutdown         サーバーにシャットダウンを指示
  client --shutdown --verbose  詳細な状態メッセージ付きでサーバーをシャットダウン

例:
  # サーバー起動
  ym2151-log-play-server server

  # サーバー起動(verbose、WAV出力あり)
  ym2151-log-play-server server --verbose

  # サーバー起動(低品位リサンプリング)
  ym2151-log-play-server server --low-quality-resampling

  # 別のターミナルから: 演奏を切り替え
  ym2151-log-play-server client output_ym2151.json

  # 別のターミナルから: 詳細モードで演奏
  ym2151-log-play-server client output_ym2151.json --verbose

  # 別のターミナルから: 演奏停止
  ym2151-log-play-server client --stop

  # 別のターミナルから: サーバー終了
  ym2151-log-play-server client --shutdown

使用例シナリオ

シナリオ1: 基本的な使用

# ターミナル1: サーバー起動
$ cargo run --release -- server

# ターミナル2: クライアントから操作
$ cargo run --release -- client output_ym2151.json

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

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

シナリオ2: 連続再生

# サーバー起動(ターミナル1)
$ cargo run --release -- server

# 次々と曲を切り替え(ターミナル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

リリースビルド

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

テストの実行

cargo test

ビルド要件

今後の展望

プロジェクトが目指すもの

プロジェクトの意図

スコープ外

開発方法

ライセンス

MIT License

利用ライブラリ