libymfm.wasm
This repository is an experimental WebAssembly build of the ymfm Yamaha FM sound cores library.
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
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
- Install Wasmer runtime
- Download libymfm-cli.wasm from pre-build release
Options
$ wasmer run libymfm-cli.wasm -- -h
libymfm-cli 0.3.1
h1romas4
libymfm CLI
USAGE:
libymfm-cli.wasm [OPTIONS]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-o, --output
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
Cargo.toml
[package]
edition = "2021"
rust-version = "1.56"
Setup wasi-sdk-12
.bashrc
export WASI_SDK_PATH=/home/hiromasa/devel/toolchain/wasi-sdk-12.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-12.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 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06)
Target: wasm32-unknown-wasi
Thread model: posix
InstalledDir: /home/hiromasa/devel/toolchain/wasi-sdk-12.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
examples/web
)
Web Browser Interface (Install wasm-bindgen
cargo install wasm-bindgen-cli
Rust build and wasm-bindgen
rustup target add wasm32-wasi
cargo 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
examples/libymfm-cli
)
WASI Commnad Line Interface (@see libymfm command line interface
examples/python
)
Python Binding Test (Rust build and copy .wasm to Python project
rustup target add wasm32-wasi
cargo 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
Build Note
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
- 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: 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 and feedout
- To BSD license
- SN76489
- PWM