moon_rodio is a native-only MoonBit audio playback library.
It provides in-memory playback composition through Mixer, Sink, Player, and
Source, plus built-in decoders for common audio formats.
- Preferred target:
native - Output and input are built on
Milky2018/moon_cpal - The main package is
Milky2018/moon_rodio - The lower-level decoder package is
Milky2018/moon_rodio/decoder
- Add
"Milky2018/moon_rodio": "0.3.0"todepsinmoon.mod.json - Set
"preferred-target": "native"inmoon.mod.json
Use this package for the normal playback API:
OutputStreamBuilderMixerSinkPlayerDecoderandDecoder::builder()- source helpers such as gain, speed, delay, fades, filters, spatial helpers, and WAV output helpers
Use this package when you want lower-level byte-to-sample decoding helpers directly:
decode_wav_bytesdecode_mp3_bytesdecode_flac_bytesdecode_vorbis_bytesdecode_mp4a_bytes
- WAV
- MP3
- FLAC
- Ogg Vorbis
- MP4A / AAC
Backend notes:
- WAV: native parser
- MP3: vendored
minimp3 - FLAC: vendored
dr_flac - Vorbis: vendored
stb_vorbis - MP4A / AAC:
- macOS: AudioToolbox
- Linux / Windows: FFmpeg
MP4A on Linux and Windows depends on FFmpeg development libraries being available to native builds.
build.js will try to discover them automatically. If auto-detection does not fit
your environment, set these variables explicitly before building or testing:
MOON_RODIO_FFMPEG_CFLAGSMOON_RODIO_FFMPEG_LIBSMOON_RODIO_ENABLE_FFMPEG=1
Create an in-memory playback chain:
///|
test "readme: in-memory playback chain" {
let (tx, rx) = mixer(1, 44_100)
let sink = Sink::connect_new(tx)
let source = SamplesBuffer::new(1, 44_100, [0.0, 0.25, 0.0, -0.25])
sink.append(source)
assert_eq(rx.next(), Some(0.0))
}Decode audio bytes with the high-level decoder API:
///|
test "readme: decoder builder" {
let decoder = Decoder::builder()
.with_data(@decoder.mp3_ill2_mono_bytes())
.with_hint("mp3")
.with_seekable(true)
.build()
assert_eq(decoder.channels(), 1)
assert_eq(decoder.sample_rate(), 48_000)
}Play embedded bytes through a mixer:
///|
test "readme: play bytes through mixer" {
let (tx, _rx) = mixer(1, 44_100)
let player = play_bytes(tx, @decoder.flac_pop_bytes())
player.pause()
player.play()
}For files on disk, use play_file(...), Reader::from_file(...), or
Decoder::try_from_file(...).