Native-only MoonBit port of Rust rodio with playback pipeline, source effects, and WAV/MP3/FLAC/Vorbis/MP4A decoding.
Dependencies
{
"deps": {
"Milky2018/moon_rodio": "0.2.0"
},
"preferred-target": "native"
}MOON_RODIO_FFMPEG_CFLAGS="-I/path/to/include" \
MOON_RODIO_FFMPEG_LIBS="-L/path/to/lib -lavformat -lavcodec -lavutil -lswresample" \
MOON_RODIO_ENABLE_FFMPEG=1 \
moon run cmd/main --target nativeimport "Milky2018/moon_rodio"
fn play_file_example(path : String) -> Unit {
let stream = try {
OutputStreamBuilder::open_default_stream()
} catch {
_ => return
} noraise {
stream => stream
}
let player = try {
play_file(stream.mixer(), path)
} catch {
_ => return
} noraise {
player => player
}
player.sleep_until_end()
}import "Milky2018/moon_rodio"
fn decode_bytes_example(bytes : Bytes) -> Unit {
let decoder = try {
Decoder::builder()
.with_data(bytes)
.with_hint("mp3")
.with_seekable(true)
.build()
} catch {
_ => return
} noraise {
decoder => decoder
}
println(decoder.channels().to_string())
println(decoder.sample_rate().to_string())
}import "Milky2018/moon_rodio"
fn play_sine_like_example() -> Unit {
let stream = try {
OutputStreamBuilder::open_default_stream()
} catch {
_ => return
} noraise {
stream => stream
}
let sink = Sink::connect_new(stream.mixer())
let source = SamplesBuffer::new(1, 44_100, [0.0, 0.2, 0.0, -0.2])
sink.append(source.repeat_infinite())
}pub(open) trait FixedSource {
next(Self) -> Double?
channels(Self) -> Int
sample_rate(Self) -> Int
total_duration(Self) -> Duration?
}pub suberror BitDepthError {
OutOfRange(Int)
}pub suberror MicrophoneError {
NoDevice
NoConfig
DefaultInputConfigError(DefaultStreamConfigError)
SupportedInputConfigsError(SupportedStreamConfigsError)
UnsupportedByDevice
BuildStreamError(BuildStreamError)
PlayStreamError(PlayStreamError)
UnsupportedSampleFormat
}impl Eq for MicrophoneListErrorimpl Show for MicrophoneListErrorpub suberror SeekError {
NotSupported
}pub suberror SpeakersError {
NoDevice
NoConfig
DefaultOutputConfigError(DefaultStreamConfigError)
SupportedOutputConfigsError(SupportedStreamConfigsError)
UnsupportedByDevice
DeviceSinkError(StreamError)
}impl Eq for SpeakersListErrorimpl Show for SpeakersListErrorpub suberror SpeakersPlayError {
WrongChannelCount(Int, Int)
WrongSampleRate(Int, Int)
BuilderError(SpeakersError)
}impl Eq for SpeakersPlayErrorimpl Show for SpeakersPlayError#alias(DeviceSinkError)
pub suberror StreamError {
PlayStreamError(PlayStreamError)
DefaultStreamConfigError(DefaultStreamConfigError)
BuildStreamError(BuildStreamError)
SupportedStreamConfigsError(SupportedStreamConfigsError)
NoDevice
UnsupportedSampleFormat
}pub suberror ToWavError {
OpenFile
Creating
Writing
Finishing
Flushing
}pub struct AutomaticGainControl {
input : DynSource
target_level : Ref[Double]
absolute_max_gain : Ref[Double]
current_gain : Ref[Double]
floor : Ref[Double]
attack_coeff : Ref[Double]
release_coeff : Ref[Double]
agc_control : Ref[Bool]
}impl Source for AutomaticGainControlfn[S : Source] AutomaticGainControl::new(source : S, settings : AutomaticGainControlSettings) -> AutomaticGainControlfn[S : Source] AutomaticGainControl::new_with_params(source : S, target_level : Double, attack_time : Duration, release_time : Duration, absolute_max_gain : Double) -> AutomaticGainControlfn AutomaticGainControlSettings::with_absolute_max_gain(self : AutomaticGainControlSettings, absolute_max_gain : Double) -> AutomaticGainControlSettingsfn AutomaticGainControlSettings::with_attack(self : AutomaticGainControlSettings, attack_time : Duration) -> AutomaticGainControlSettingsfn AutomaticGainControlSettings::with_release(self : AutomaticGainControlSettings, release_time : Duration) -> AutomaticGainControlSettingsfn AutomaticGainControlSettings::with_target_level(self : AutomaticGainControlSettings, target_level : Double) -> AutomaticGainControlSettingspub struct BitDepth {
bits : Int
}pub enum BltMode {
LowPass
HighPass
}pub struct Brownian {
sample_rate : Int
white_noise : WhiteGaussian
accumulator : Ref[Double]
leak_factor : Ref[Double]
scale : Ref[Double]
}impl Source for ChannelCountConverterpub struct Chirp {
sample_rate : Int
start_frequency : Double
end_frequency : Double
total_samples : Int
elapsed_samples : Ref[Int]
phase : Ref[Double]
}impl Source for ControlledQueueSourcepub struct Decoder {
inner : DecodedSamples
seekable : Bool
allow_backward_seek : Bool
kind : DecoderKind
}type DecoderKindfn DeviceSinkBuilder::open_sink_or_fallback(self : DeviceSinkBuilder) -> MixerDeviceSink raise StreamErrorfn DeviceSinkBuilder::with_buffer_size(self : DeviceSinkBuilder, buffer_size : BufferSize) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_channels(self : DeviceSinkBuilder, channel_count : Int) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_config(self : DeviceSinkBuilder, config : StreamConfig) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_error_callback(self : DeviceSinkBuilder, callback : (StreamError) -> Unit) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_sample_format(self : DeviceSinkBuilder, sample_format : SampleFormat) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_sample_rate(self : DeviceSinkBuilder, sample_rate : Int) -> DeviceSinkBuilderfn DeviceSinkBuilder::with_supported_config(self : DeviceSinkBuilder, config : SupportedStreamConfig) -> DeviceSinkBuilderimpl Source for Distortionpub struct Dither {
input : DynSource
noise : Ref[DitherAlgorithm]
current_channel : Ref[Int]
lsb_amplitude : Ref[Double]
rng_state : Ref[UInt64]
highpass_prev : Ref[Array[Double]]
}pub enum DitherAlgorithm {
GPDF
HighPass
RPDF
TPDF
}impl FixedSource for FixedSamplesBufferfn FixedSamplesBuffer::new(channels : Int, sample_rate : Int, samples : Array[Double]) -> FixedSamplesBufferimpl Source for FixedSourceAdapterpub struct FromFactoryIter[S] {
factory : () -> S?
current : Ref[DynSource?]
channels : Ref[Int]
sample_rate : Ref[Int]
}pub enum Function {
Sine
Triangle
Square
Sawtooth
}pub struct GeneratorFunction {
generator : (Double) -> Double
}pub struct InputConfig {
channel_count : Int
sample_rate : Int
buffer_size : BufferSize
sample_format : SampleFormat
}impl Eq for InputConfigimpl Show for InputConfigfn InputConfig::new(channel_count : Int, sample_rate : Int, buffer_size : BufferSize, sample_format : SampleFormat) -> InputConfigpub struct Limit {
input : DynSource
settings : LimitSettings
attack_coeff : Double
release_coeff : Double
integrators : Ref[Array[Double]]
peaks : Ref[Array[Double]]
position : Ref[Int]
}impl Eq for LimitSettingsimpl Show for LimitSettingsimpl Source for LinearGainRampfn[S : Source] LinearGainRamp::new(source : S, start_gain : Double, end_gain : Double, duration : Duration) -> LinearGainRampfn[S : Source] LinearGainRamp::new_with_clamp(source : S, start_gain : Double, end_gain : Double, duration : Duration, clamp_end : Bool) -> LinearGainRamppub struct LoopedDecoder {
channels : Int
sample_rate : Int
samples : Array[Double]
cursor : Ref[Int]
seekable : Bool
}impl Source for LoopedDecoderpub struct Microphone {
_stream_handle : Stream
queued_samples : Ref[Array[Double]]
read_pos : Ref[Int]
max_buffered_samples : Int
config : InputConfig
error_occurred : Ref[Bool]
}impl Source for Microphonepub struct MicrophoneBuilder {
device : Device?
supported_configs : Array[SupportedStreamConfigRange]
config : InputConfig?
error_callback : (StreamError) -> Unit
}fn MicrophoneBuilder::config(self : MicrophoneBuilder, config : InputConfig) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::default_config(self : MicrophoneBuilder) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::default_device(self : MicrophoneBuilder) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::device(self : MicrophoneBuilder, device : Input) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::prefer_buffer_sizes(self : MicrophoneBuilder, buffer_sizes : Array[Int]) -> MicrophoneBuilderfn MicrophoneBuilder::prefer_channel_counts(self : MicrophoneBuilder, channel_counts : Array[Int]) -> MicrophoneBuilderfn MicrophoneBuilder::prefer_sample_rates(self : MicrophoneBuilder, sample_rates : Array[Int]) -> MicrophoneBuilderfn MicrophoneBuilder::try_buffer_size(self : MicrophoneBuilder, buffer_size : Int) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::try_channels(self : MicrophoneBuilder, channel_count : Int) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::try_sample_rate(self : MicrophoneBuilder, sample_rate : Int) -> MicrophoneBuilder raise MicrophoneErrorfn MicrophoneBuilder::with_error_callback(self : MicrophoneBuilder, callback : (StreamError) -> Unit) -> MicrophoneBuilderpub struct OutputConfig {
channel_count : Int
sample_rate : Int
buffer_size : BufferSize
sample_format : SampleFormat
}impl Eq for OutputConfigimpl Show for OutputConfigfn OutputConfig::new(channel_count : Int, sample_rate : Int, buffer_size : BufferSize, sample_format : SampleFormat) -> OutputConfigfn OutputConfig::supported_given(self : OutputConfig, supported : SupportedStreamConfigRange) -> Boolfn OutputConfig::with_sample_format(self : OutputConfig, sample_format : SampleFormat) -> OutputConfigpub struct OutputStream {
config : OutputStreamConfig
mixer : Mixer
_stream : Stream
log_on_drop : Ref[Bool]
}fn OutputStream::open(device : Device, config : OutputStreamConfig, error_callback : (StreamError) -> Unit) -> OutputStream raise StreamErrorpub struct OutputStreamBuilder {
device : Device?
config : OutputStreamConfig
error_callback : (StreamError) -> Unit
}fn OutputStreamBuilder::open_stream_or_fallback(self : OutputStreamBuilder) -> OutputStream raise StreamErrorfn OutputStreamBuilder::with_buffer_size(self : OutputStreamBuilder, buffer_size : BufferSize) -> OutputStreamBuilderfn OutputStreamBuilder::with_channels(self : OutputStreamBuilder, channel_count : Int) -> OutputStreamBuilderfn OutputStreamBuilder::with_config(self : OutputStreamBuilder, config : StreamConfig) -> OutputStreamBuilderfn OutputStreamBuilder::with_device(self : OutputStreamBuilder, device : Device) -> OutputStreamBuilderfn OutputStreamBuilder::with_error_callback(self : OutputStreamBuilder, callback : (StreamError) -> Unit) -> OutputStreamBuilderfn OutputStreamBuilder::with_sample_format(self : OutputStreamBuilder, sample_format : SampleFormat) -> OutputStreamBuilderfn OutputStreamBuilder::with_sample_rate(self : OutputStreamBuilder, sample_rate : Int) -> OutputStreamBuilderfn OutputStreamBuilder::with_supported_config(self : OutputStreamBuilder, config : SupportedStreamConfig) -> OutputStreamBuilder#alias(DeviceSinkConfig)
pub struct OutputStreamConfig {
channel_count : Int
sample_rate : Int
buffer_size : BufferSize
sample_format : SampleFormat
}impl Eq for OutputStreamConfigimpl Show for OutputStreamConfigpub struct Pausable {
input : DynSource
paused_channels : Ref[Int?]
remaining_paused_samples : Ref[Int]
}pub struct QueueSignal {
done : Ref[Bool]
}pub struct Reader {
bytes : Bytes
}pub struct Red {
sample_rate : Int
white_noise : WhiteUniform
accumulator : Ref[Double]
leak_factor : Ref[Double]
scale : Ref[Double]
}impl Source for SampleRateConverterfn[S : Source] SampleRateConverter::new(input : S, from : Int, to : Int, num_channels : Int) -> SampleRateConverterimpl Source for SampleTypeConverterpub struct SamplesBuffer {
channels : Int
sample_rate : Int
samples : Array[Double]
cursor : Ref[Int]
}impl Source for SamplesBufferpub struct Settings {
byte_len : Int?
coarse_seek : Bool
gapless : Bool
hint : String?
mime_type : String?
is_seekable : Bool
}pub enum SignalFunction {
Sine
Square
Sawtooth
Triangle
}pub struct SignalGenerator {
channels : Int
sample_rate : Int
frequency : Double
function : SignalFunction
phase : Ref[Double]
}impl Source for SignalGeneratorfn SignalGenerator::from_function(sample_rate : Int, frequency : Double, function : Function) -> SignalGeneratorfn SignalGenerator::new(sample_rate : Int, frequency : Double, function : SignalFunction) -> SignalGeneratorfn SignalGenerator::with_function(sample_rate : Int, frequency : Double, function : Function) -> SignalGeneratorfn SignalGenerator::with_generator(sample_rate : Int, frequency : Double, function : GeneratorFunction) -> DynSourcepub struct Sink {
queue_tx : SourcesQueueInput
queue_rx : SourcesQueueOutput
controls : SinkControls
detached : Ref[Bool]
last_signal : Ref[QueueSignal?]
}pub struct SinkControls {
pause : Ref[Bool]
stopped : Ref[Bool]
to_clear : Ref[Int]
volume : Ref[Double]
speed : Ref[Double]
sound_count : Ref[Int]
position : Ref[Duration]
}pub struct SourcesQueueInput {
next_sounds : Ref[Array[QueuedSource]]
keep_alive_if_empty : Ref[Bool]
}fn[S : Source] SourcesQueueInput::append_with_signal(self : SourcesQueueInput, source : S) -> QueueSignalfn SourcesQueueInput::set_keep_alive_if_empty(self : SourcesQueueInput, keep_alive_if_empty : Bool) -> Unitpub struct SourcesQueueOutput {
current : Ref[DynSource]
current_is_fallback : Ref[Bool]
prefetched : Ref[Double?]
has_prefetched : Ref[Bool]
signal_after_end : Ref[QueueSignal?]
samples_consumed_in_span : Ref[Int]
padding_samples_remaining : Ref[Int]
input : SourcesQueueInput
}impl Source for SourcesQueueOutputfn SpatialPlayer::connect_new(mixer : Mixer, emitter_position : Array[Double], left_ear : Array[Double], right_ear : Array[Double]) -> SpatialPlayerfn SpatialSink::connect_new(mixer : Mixer, emitter_position : Array[Double], left_ear : Array[Double], right_ear : Array[Double]) -> SpatialSinkimpl Source for SpatialSourcefn[S : Source] SpatialSource::new(input : S, emitter_position : Array[Double], left_ear : Array[Double], right_ear : Array[Double]) -> SpatialSourcefn SpatialSource::set_positions(self : SpatialSource, emitter_position : Array[Double], left_ear : Array[Double], right_ear : Array[Double]) -> Unitpub struct SpeakersBuilder {
device : Device?
supported_configs : Array[SupportedStreamConfigRange]
config : OutputConfig?
error_callback : (StreamError) -> Unit
}fn SpeakersBuilder::config(self : SpeakersBuilder, config : OutputConfig) -> SpeakersBuilder raise SpeakersErrorfn SpeakersBuilder::device(self : SpeakersBuilder, output : Output) -> SpeakersBuilder raise SpeakersErrorfn[S : FixedSource] SpeakersBuilder::play(self : SpeakersBuilder, source : S) -> SinkHandle raise SpeakersPlayErrorfn SpeakersBuilder::prefer_buffer_sizes(self : SpeakersBuilder, buffer_sizes : Array[Int]) -> SpeakersBuilderfn SpeakersBuilder::prefer_channel_counts(self : SpeakersBuilder, channel_counts : Array[Int]) -> SpeakersBuilderfn SpeakersBuilder::prefer_sample_rates(self : SpeakersBuilder, sample_rates : Array[Int]) -> SpeakersBuilderfn SpeakersBuilder::try_buffer_size(self : SpeakersBuilder, buffer_size : Int) -> SpeakersBuilder raise SpeakersErrorfn SpeakersBuilder::try_channels(self : SpeakersBuilder, channel_count : Int) -> SpeakersBuilder raise SpeakersErrorfn SpeakersBuilder::try_sample_rate(self : SpeakersBuilder, sample_rate : Int) -> SpeakersBuilder raise SpeakersErrorfn SpeakersBuilder::with_error_callback(self : SpeakersBuilder, callback : (StreamError) -> Unit) -> SpeakersBuilderpub struct StaticSamplesBuffer {
channels : Int
sample_rate : Int
samples : Array[Double]
cursor : Ref[Int]
}impl Source for StaticSamplesBufferfn StaticSamplesBuffer::new(channels : Int, sample_rate : Int, samples : Array[Double]) -> StaticSamplesBufferimpl Source for UniformSourceIteratorfn[S : Source] UniformSourceIterator::new(source : S, target_channels : Int, target_sample_rate : Int) -> UniformSourceIteratorpub struct Velvet {
sample_rate : Int
rng : NoiseRngState
grid_size : Ref[Double]
grid_pos : Ref[Double]
impulse_pos : Ref[Double]
}fn[S : Source] automatic_gain_control(source : S, settings : AutomaticGainControlSettings) -> AutomaticGainControlfn[S : Source] automatic_gain_control_with_params(source : S, target_level : Double, attack_time : Duration, release_time : Duration, absolute_max_gain : Double) -> AutomaticGainControlfn[S : Source] periodic_access(source : S, every_samples : Int, callback : () -> Unit) -> PeriodicAccessfn[S : Source] periodic_access_with_source(source : S, every_samples : Int, callback : (DynSource) -> Unit) -> PeriodicAccessfn[S : Source] periodic_with_source(source : S, period : Duration, callback : (DynSource) -> Unit) -> PeriodicAccessNative-only MoonBit port of Rust rodio with playback pipeline, source effects, and WAV/MP3/FLAC/Vorbis/MP4A decoding.
Dependencies