GitHunt
KN

knight-ryu12/libymfm.wasm

This repository is an experimental WebAssembly build of the [ymfm](https://github.com/aaronsgiles/ymfm) Yamaha FM sound cores library.

libymfm.wasm

This repository is an experimental WebAssembly build of the ymfm Yamaha FM sound cores library.

aaronsgiles / ymfm

BSD-licensed Yamaha FM sound cores (OPM, OPN, OPL, and others)

Supported Sound Chips

chip from note
YM2149 ymfm
YM2151 ymfm
YM2203 ymfm
YM2413 ymfm
YM2608 ymfm
YM2610/YM2610B ymfm
YM2612 ymfm
YM3526 ymfm
Y8950 ymfm
YM3812 ymfm
YMF262 ymfm
YMF278B ymfm
SN76489 mame Rust ports
SEGAPCM mame Rust ports
PWM mame Rust ports
OKIM6285 mame Rust ports

Web Browser Interface

WebAssembly VGM Player

Firefox or Chromium is recommended. Currently, Safari does not support SharedArrayBuffer because it is not available.

  • Web Worker/Worklet architecture
  • WASI build on browser

Source code:

https://github.com/h1romas4/libymfm.wasm/tree/main/examples/web

Python Example

Source code:

https://github.com/h1romas4/libymfm.wasm/tree/main/examples/python

WASI Commnad Line Interface

Options

$ wasmer run libymfm-cli.wasm -- -h
libymfm-cli 0.9.0
Hiromasa Tanaka <h1romas4@gmail.com>
libymfm CLI

USAGE:
    libymfm-cli.wasm [OPTIONS] <filename>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
        --loop <loop>                 Loop count
    -o, --output <output filepath>    Output file path
    -r, --rate <rate>                 Output sampling rate

ARGS:
    <filename>    Play .vgm/.vzg/.xgm/.xgz file path

Example 1 - Specify output file name

$ wasmer run libymfm-cli.wasm --mapdir /:./docs/vgm -- /ym2612.vgm -o ym2612.pcm
$ ffplay -f f32le -ar 44100 -ac 2 ./docs/vgm/ym2612.pcm

Example 2 - Direct play

$ wasmer run libymfm-cli.wasm --mapdir /:./docs/vgm -- /ym2612.vgm | ffplay -f f32le -ar 44100 -ac 2 -i -

Example 3 - Specify samplig rate

$ wasmer run libymfm-cli.wasm --mapdir /:./docs/vgm -- /ym2612.vgm -r 96000 | ffplay -f f32le -ar 96000 -ac 2 -i -

Source code:

https://github.com/h1romas4/libymfm.wasm/tree/main/examples/libymfm-cli

Build

Build require Rust 2021 edition and +nightly.

rustup install nightly

Cargo.toml

[package]
edition = "2021"
rust-version = "1.56"

Setup wasi-sdk-14

.bashrc

export WASI_SDK_PATH=/home/hiromasa/devel/toolchain/wasi-sdk-14.0
export CARGO_TARGET_WASM32_WASI_LINKER=${WASI_SDK_PATH}/bin/lld
export CARGO_TARGET_WASM32_WASI_RUSTFLAGS="-L ${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi"
$ echo ${WASI_SDK_PATH}
/home/hiromasa/devel/toolchain/wasi-sdk-14.0
$ ls -alF ${WASI_SDK_PATH}
drwxr-xr-x 2 hiromasa hiromasa 4096 12月  3  2020 bin/
drwxr-xr-x 3 hiromasa hiromasa 4096 12月  3  2020 lib/
drwxr-xr-x 6 hiromasa hiromasa 4096 12月  3  2020 share/
$ ${WASI_SDK_PATH}/bin/clang -v
clang version 13.0.0 (https://github.com/llvm/llvm-project fd1d8c2f04dde23bee0fb3a7d069a9b1046da979)
Target: wasm32-unknown-wasi
Thread model: posix
InstalledDir: /home/hiromasa/devel/toolchain/wasi-sdk-14.0/bin

cmake / make

git clone --recursive https://github.com/h1romas4/libymfm.wasm
cd libymfm.wasm
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/wasi.cmake  ..
make -j4

Web Browser Interface (examples/web)

Install wasm-bindgen

cargo install wasm-bindgen-cli --version 0.2.78

Rust build and wasm-bindgen

Always add the +nightly flag.

rustup target add wasm32-wasi
cargo +nightly build --release --target wasm32-wasi --features bindgen
wasm-bindgen target/wasm32-wasi/release/libymfm.wasm --out-dir ./examples/web/src/wasm/

npm

cd examples/web
npm install
npm run start

WASI Commnad Line Interface (examples/libymfm-cli)

@see libymfm command line interface

Python Binding Test (examples/python)

Rust build and copy .wasm to Python project

Always add the +nightly flag.

rustup target add wasm32-wasi
cargo +nightly build --release --target wasm32-wasi
cp -p target/wasm32-wasi/release/libymfm.wasm ./examples/python/src/wasm/

Run Python

cd examples/python
# Install require
pip3 install -r requirements.txt
# Simple VGM Player
python src/sample_vgmplay.py
# Pyxel impliments example
python src/sample_pyxel.py
# Sound chip direct access example
python src/sample_direct.py

Native Debug & Test

Since Rust currently does not allow create-type switching, the following modification to the source code is required for native debugging.

Cargo --crate-type CLI Argument

It is also required if you want to use this library as a simple native library.

These are the codes needed to make the library the "WASI Library".

Pacth Cargo.toml

[lib]
# https://github.com/rust-lang/rust/pull/79997
# https://github.com/bazelbuild/rules_rust/issues/771
# crate-type = ["bin"] # disable this line
crate-type = ["cdylib", "rlib"] # enable this line
path = "src/rust/lib.rs"

Pacth src/rust/lib.rs

// #![no_main] // disable this line

Buile or test on native

cargo build --release
cargo test ym2612_1 -- --nocapture

Build Note

WASI Library

Essentially, wasm-bindgen is incompatible with wasm32-wasi.

improve panic message when compiling to wasi #2554

panicked at 'unknown instruction LocalTee

To link Rust 1.55 with C/C++ using wasm32-wasi, you need LLD for LLVM 12.

WASI: Cannot open paths with nightly >= 2021-03-11 when linked with LLD 11.1 #85840

failed to find a pre-opened file descriptor

wasm-bindgen outputs a TextEncoder TextDecoder function that cannot be used in a Worklet.

Unblock AudioWorklets: Find an alternative to TextEncoder / TextDecoder #2367

License

BSD 3-Clause License

Thanks

TODO / Known Issues

  • VGM driver
    • YM2141 clock worng?
    • Is there a problem with the file parser? The beginning of the song may be wrong.
    • Support all data stream (now only support YM2612 and OKIM6285)
  • Non-vgm driver support
    • XGM
      • There is still a bug with multi-channel PCM.
  • Multilingual Interface
    • CLI
    • Web/JavaScript
    • Python wasmer-python
    • Add an interface that does not depend on wasm-bindgen
  • ymfm
    • Add direct ymfm intarfece
    • Support yfmf's all sound chips
  • Refactoring
    • Better upsampling
    • Separate the sound stream from the sound driver.
    • Support for arbitrary input tick rate and output sampling rate.
    • Support data stream.
  • Add support sound chip
    • Fix SEGAPCM
    • OKIM6285
    • Next to be determined
  • Examples source
    • Web Frontend: Safari now supports SharedArrayBuffer, but it does not work well.
    • Web Frontend: Support YM2608 ADPCM ROM (wasmer-js WASI fopen)
    • Web Frontend: AudioWorklet
    • Web Frontend: Web Worker AudioWorklet and SharedArrayBuffer (The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers cannot be set in github pages, so they cannot be deployed)
    • Web Frontend: Add buffering mode
    • CLI: Support loop
  • To BSD license
    • SN76489
    • PWM
knight-ryu12/libymfm.wasm | GitHunt