bevy_ym2149 β YM2149 Audio for Bevy
Bevy plugin that embeds the cycle-accurate ym2149 emulator, providing real-time YM/AKS/AY/SNDH playback, playlists, crossfades, diagnostics, audio mirroring, and optional UI widgets via bevy_ym2149_viz.
Why Use This Plugin?
- π΅ Accurate playback: YM2βYM6/YMT + AKS + AY + SNDH files rendered with the same cores as the CLI/exporter (
ym2149-ym-replayer,ym2149-arkos-replayer,ym2149-ay-replayer,ym2149-sndh-replayer) - ποΈ ECS-native control:
Ym2149Playbackcomponent (play/pause/seek/volume/stereo gain) - π§ Music systems: playlists with seamless crossfades,
.ymplaylistloader, music state graphs - β¨ Tone shaping: single-chip post FX (soft saturation, accent boost, stereo widen, ST color filter) via
ToneSettings - π Audio bridge: mirror samples into Bevy's audio graph or your own sinks
- π― Pattern triggers: declaratively flag YM channel hits and drive gameplay via
PatternTriggerSet - π Diagnostics & events: buffer fill metrics +
TrackStarted/TrackFinished/ChannelSnapshot/PlaybackFrameMarker - πͺ Gameplay hooks: audio-reactive state (avg/peak/freq per channel) and PSG one-shot SFX via
YmSfxRequest - π₯οΈ Visualization: drop in
Ym2149VizPluginfor oscilloscope, spectrum, progress HUD (kept in a separate crate so headless builds stay lean)
Getting Started
[]
= "0.17"
= "0.7"
= { = "0.7", = true } # For visualization features
use *;
use ;
Add Ym2149VizPlugin (from bevy_ym2149_viz) when you want the UI builders:
use ;
Quick presets
bevy_ym2149::presets::add_audio_stack(&mut app) wires the audio plugin with all subsystems enabled.
If you want audio + visualization in one go, bevy_ym2149_viz::add_full_stack(&mut app) adds both plugins.
Subsystem Toggles
Configure the plugin at runtime via Ym2149PluginConfig:
| Config flag | Default | Purpose |
|---|---|---|
playlists |
β | .ymplaylist loader + Ym2149PlaylistPlayer, crossfade driver |
channel_events |
β | Emits ChannelSnapshot + TrackStarted/Finished |
music_state |
β | MusicStateGraph + MusicStateRequest routing |
diagnostics |
β | Registers ym2149/frame_position metric |
bevy_audio_bridge |
β | Mirrors samples into AudioBridgeBuffers for custom DSP chains |
pattern_events |
β | Enables PatternTriggerSet + PatternTriggered gameplay events |
Disable what you donβt need to keep your app lean.
Asset Paths
Asset paths in Ym2149Playback::new() are resolved by Bevy's asset server relative to your project's assets/ folder:
// Loads from: your_project/assets/music/song.ym
commands.spawn;
// Also works with subdirectories
commands.spawn;
Supported file extensions: .ym, .aks, .ay, .sndh
For the example commands (e.g., cargo run -p bevy_ym2149_examples --example basic_example), assets are located in the workspace's examples/ folder. The examples use paths like "examples/ym/ND-Toxygene.ym".
Runtime Flow / Systems
- Asset Loading β
.ym/.aks/.ay/.sndhfiles load via Bevy's asset system asYm2149AudioSource(implementsDecodable) - Initialization (PreUpdate) β
initialize_playbackattachesAudioPlayer/PlaybackRuntimeStateto entities - State Driving (PreUpdate) β
drive_playback_statereacts toYm2149Playback.state, controllingAudioSinks and emittingTrackStarted/TrackFinished - Frame Processing (Update) β
process_playback_framesgenerates audio samples per VBL frame, drives crossfades, and emits lightweightFrameAudioDatamessages - Observability (Update) β
emit_playback_diagnostics(when enabled) convertsFrameAudioDataintoChannelSnapshots and oscilloscope buffers;publish_bridge_audiomirrors raw stereo data if the audio bridge is on - Visualization (optional) β
bevy_ym2149_vizsystems consume those diagnostics/resources to render their UI widgets
Key APIs
Ym2149Playback
Other helpers:
Ym2149Playback::from_asset(handle)and::from_bytes(bytes)for asset-server or embedded sources (auto-detects YM vs AKS)set_source_path / asset / bytesto retarget an entity mid-game (supports.ym/.aks)
Tone shaping (soft saturation / accent / stereo widen)
Each Ym2149Playback exposes tone_settings / set_tone_settings to dial in subtle post-processing without adding extra chips:
use ;
Settings are applied inside the decoder at audio-thread speed, so tweaks take effect immediately (see the advanced example for key bindings).
Pattern-triggered gameplay events
Attach PatternTriggerSet to a playback entity and listen for PatternTriggered:
use *;
use ;
Patterns are checked once per YM frame (β50β―Hz) using average channel amplitude, so theyβre perfect for driving gameplay beats, VFX pulses, or scripted events.
Some practical ideas and mini-snippets:
- Beat-synced lighting β channel A threshold-only trigger toggles emissive sprites:
- Solo detection β add a frequency constraint (e.g., 440β―Hz Β±10β―Hz) to gate prompts:
commands.spawn;
- Call-and-response β fire PSG SFX when a hit lands:
set_stereo_gain(left, right)for manual stereo/pan controlPlaybackFrameMarkerevent stream for 50Hz markers (frame, elapsed_seconds, looped)AudioReactiveStateresource for smoothed channel avg/peak/frequency per playback entityYmSfxRequestto trigger short PSG tones mixed into playback (channel/freq/volume/duration)
Playlists & Crossfades
// assets/music/demo.ymplaylist
(
mode: "loop",
tracks: [
{ type: "asset", path: "music/Ashtray.ym" },
{ type: "asset", path: "music/Credits.ym" },
],
)
commands.spawn;
drive_crossfade_playlists automatically preloads the next deck, and PlaylistAdvanceRequest lets you manually jump to indices.
Music State Graph
Audio Bridge
Diagnostics
FRAME_POSITION_PATHtracks the furthest frame processed across playbacks- Use Bevy's standard
DiagnosticsStoreto access metrics
Visualization (bevy_ym2149_viz)
Builders such as create_status_display, create_detailed_channel_display, and create_channel_visualization spawn flexbox-based UIs. Component types (bevy_ym2149_viz::SongInfoDisplay, SpectrumBar, OscilloscopePoint, etc.) are public so you can author your own layouts. See the advanced_example and demoscene demos for reference.
Examples
The bevy_ym2149_examples crate contains:
| Example | Focus |
|---|---|
basic_example |
Minimal playback + keyboard control |
crossfade_example |
Playlist crossfades with decks |
advanced_example |
Full tracker-style UI + drag-and-drop + audio bridge knobs |
feature_showcase |
Multiple playbacks, music state graph, diagnostics |
demoscene |
Shader-heavy scene synchronized to YM playback |
Run e.g. cargo run --example advanced_example -p bevy_ym2149_examples.
Troubleshooting Tips
- No audio: ensure the YM path is valid,
Ym2149Pluginis added with.add_audio_source::<Ym2149AudioSource>(), and your OS has a working audio device - Crackling / underruns: Bevy's audio system handles buffering automatically; check for heavy work blocking the audio callback thread
- Playback too fast/slow: confirm
Timeresource is advancing; visualization uses frame position tracking - Bridge audio silent: make sure the entity was added to
AudioBridgeTargets(viaAudioBridgeRequest) and that its mix isn't muted - Player not started: ensure
PlaybackController::play()is called on the player instance inYm2149AudioSource::new()
License
MIT License β see LICENSE.