proton_microphone

    Microphone capture device and session helpers.

    moonbit
    native
    microphone
    audio
    Download zip
    Version
    0.2.10
    License
    Apache-2.0
    Last updated
    2 hours ago
    Downloads
    6K

    #moonbit-community/proton_microphone

    Native-only microphone device discovery helpers for MoonBit.

    ///|
    fn main {
    let devices = @proton_microphone.MicrophoneDevice::list()
    for device in devices {
    println(device.session_label())
    }
    }

    ///|
    fn example_label {
    let device = @proton_microphone.MicrophoneDevice::{
    id: "mic-1",
    name: "Built-in Mic",
    state: Idle,
    default_config: @proton_microphone.CaptureConfig(
    echo_cancellation=true,
    noise_suppression=true,
    ),
    monitor_supported: true,
    }
    println(device.session_label())
    }

    CaptureConfig

    pub(all) struct CaptureConfig {
    channels : Int
    sample_rate_hz : Int
    sample_format : SampleFormat
    echo_cancellation : Bool
    noise_suppression : Bool
    } derive(Eq,
    Debug
    )

    Capture settings used when opening or describing a microphone stream.

    channels and sample_rate_hz are normalized by CaptureConfig::normalized before chunk sizing is computed. echo_cancellation and noise_suppression are advisory voice-processing flags; support depends on the actual host audio stack, but keeping them in the config makes intent explicit at API boundaries.

    CaptureConfig::CaptureConfig

    fn CaptureConfig::CaptureConfig(channels? : Int, sample_rate_hz? : Int, sample_format? : SampleFormat, echo_cancellation? : Bool, noise_suppression? : Bool) -> CaptureConfig

    Create a capture configuration.

    Every argument has a conservative default: mono, 48 kHz, floating-point audio with voice-processing flags disabled. Callers can override only the fields they care about, then call normalized before sizing buffers or opening a native capture stream. This keeps common code short while still making platform-sensitive options explicit at the call site.

    Example

    test "CaptureConfig applies conservative defaults" {
    let config = CaptureConfig::CaptureConfig(sample_rate_hz=44_100)
    assert_eq(config.channels, 1)
    assert_eq(config.sample_rate_hz, 44_100)
    }

    CaptureConfig::equal

    CaptureConfig::normalized

    fn CaptureConfig::normalized(self : CaptureConfig) -> CaptureConfig

    Normalize a capture configuration into safe runtime bounds.

    A configuration with fewer than one channel is clamped to mono, and a sample rate below 8 kHz is clamped to 8 kHz. The sample format and voice-processing flags are preserved so callers do not lose intent when normalizing user-provided settings.

    Example

    test "normalized clamps channels and sample rate to safe bounds" {
    let config = CaptureConfig::CaptureConfig(channels=0, sample_rate_hz=4_000).normalized()
    assert_eq(config.channels, 1)
    assert_eq(config.sample_rate_hz, 8_000)
    }

    CaptureConfig::not_equal

    fn CaptureConfig::not_equal(x : CaptureConfig, y : CaptureConfig) -> Bool

    CaptureConfig::output

    fn CaptureConfig::output(self : CaptureConfig, logger : &Logger) -> Unit

    CaptureConfig::recommended_chunk_frames

    fn CaptureConfig::recommended_chunk_frames(self : CaptureConfig) -> Int

    Return the preferred frame count for one responsive capture chunk.

    The recommendation is ten milliseconds of audio after normalization. For example, 48 kHz audio yields 480 frames, while an invalid 4 kHz input first normalizes to 8 kHz and then yields 80 frames.

    Example

    test "recommended_chunk_frames is ten milliseconds of audio" {
    assert_eq(
    CaptureConfig::CaptureConfig(sample_rate_hz=48_000).recommended_chunk_frames(),
    480,
    )
    }

    CaptureConfig::to_string

    fn CaptureConfig::to_string(self : CaptureConfig) -> String

    CaptureConfig::uses_voice_processing

    fn CaptureConfig::uses_voice_processing(self : CaptureConfig) -> Bool

    Whether a config requests voice-processing behavior.

    This helper only checks caller intent. It does not promise that the current operating system or selected device can actually provide echo cancellation or noise suppression.

    Example

    test "uses_voice_processing reflects requested flags" {
    assert_false(CaptureConfig::CaptureConfig().uses_voice_processing())
    assert_true(
    CaptureConfig::CaptureConfig(noise_suppression=true).uses_voice_processing(),
    )
    }

    CaptureState

    pub(all) enum CaptureState {
    Idle
    Armed
    Recording
    Muted
    } derive(Eq,
    Debug
    )

    Runtime state for a microphone capture session.

    Idle means the device is known but not prepared, Armed means the application is ready to begin capture, Recording means audio frames are actively being collected, and Muted means capture is intentionally suppressed while the device remains selected.

    CaptureState::equal

    CaptureState::label

    fn CaptureState::label(self : CaptureState) -> String

    Return a stable lowercase label for a capture state.

    The labels are designed for logs, telemetry, and user settings where a compact string is easier to persist than a debug representation. They are intentionally independent of the derived Show output so future internal formatting changes do not affect persisted labels.

    Example

    test "label returns a stable lowercase string" {
    assert_eq(CaptureState::Recording.label(), "recording")
    }

    CaptureState::not_equal

    fn CaptureState::not_equal(x : CaptureState, y : CaptureState) -> Bool

    CaptureState::output

    fn CaptureState::output(self : CaptureState, logger : &Logger) -> Unit

    CaptureState::to_string

    fn CaptureState::to_string(self : CaptureState) -> String

    MicrophoneDevice

    pub(all) struct MicrophoneDevice {
    id : String
    name : String
    state : CaptureState
    default_config : CaptureConfig
    monitor_supported : Bool
    } derive(Eq,
    Debug
    )

    Microphone device descriptor returned by native discovery.

    id is a stable identifier for the parsed listing within one discovery result, name is the human-facing device name, state starts at Idle, default_config is safe for low-latency voice capture, and monitor_supported reports whether this package recognized the entry as a monitor/source-loopback device.

    MicrophoneDevice::equal

    MicrophoneDevice::is_live

    fn MicrophoneDevice::is_live(self : MicrophoneDevice) -> Bool

    Whether the microphone is currently armed or actively capturing.

    Armed and Recording are live states because either state means the application has reserved the selected device for immediate capture. Idle and Muted are not live states, so this helper is suitable for UI badges, telemetry, and guard checks before reading capture buffers.

    MicrophoneDevice::list

    List microphone-like capture devices visible to the current platform.

    Discovery is best-effort and uses the host audio API directly: Windows uses Core Audio capture endpoints, Linux uses ALSA device hints when available, and macOS uses Core Audio device properties. If the platform API is unavailable, blocked, or returns no capture devices, the function returns an empty array instead of raising.

    Example

    for device in @proton_microphone.MicrophoneDevice::list() {
    println(device.session_label())
    }

    MicrophoneDevice::not_equal

    fn MicrophoneDevice::not_equal(x : MicrophoneDevice, y : MicrophoneDevice) -> Bool

    MicrophoneDevice::output

    fn MicrophoneDevice::output(self : MicrophoneDevice, logger : &Logger) -> Unit

    MicrophoneDevice::parse_listing

    fn MicrophoneDevice::parse_listing(output : String) -> Array[MicrophoneDevice]

    Parse a native microphone listing into device descriptors.

    The parser expects one device name per line after the private FFI layer has decoded the native string encoding. Empty lines are ignored, Linux monitor/source-loopback names are filtered out, and parsed ids are assigned densely as mic-0, mic-1, and so on. Each parsed device receives CaptureConfig() defaults and starts in Idle, which keeps tests deterministic even when the host platform reports devices in a different order.

    Example

    test "parse_listing assigns dense ids and drops monitors" {
    let devices = MicrophoneDevice::parse_listing(
    "Built-in Mic\nMonitor of Output\nUSB Mic\n",
    )
    assert_eq(devices.length(), 2)
    assert_eq(devices[0].id, "mic-0")
    assert_eq(devices[1].name, "USB Mic")
    }

    MicrophoneDevice::session_label

    fn MicrophoneDevice::session_label(self : MicrophoneDevice) -> String

    Produce a concise session label for settings or telemetry.

    The label combines the parsed device id, stable state label, and device name. It is deterministic for a single discovery result and convenient for logs such as mic-0:idle:Built-in Microphone.

    MicrophoneDevice::to_string

    fn MicrophoneDevice::to_string(self : MicrophoneDevice) -> String

    SampleFormat

    pub(all) enum SampleFormat {
    I16
    U16
    F32
    } derive(Eq,
    Debug
    )

    Sample representation requested from a microphone capture session.

    I16 and U16 are 16-bit integer formats that are common in lower-level APIs. F32 is the preferred normalized floating-point representation for processing pipelines because each sample is four bytes and typically maps to the [-1.0, 1.0] audio range.

    SampleFormat::bytes_per_sample

    fn SampleFormat::bytes_per_sample(self : SampleFormat) -> Int

    Return the number of bytes occupied by one sample.

    This is useful when translating frame counts into byte sizes for native buffers. I16 and U16 occupy two bytes per channel, while F32 occupies four bytes per channel.

    Example

    test "bytes_per_sample reflects the format width" {
    assert_eq(SampleFormat::I16.bytes_per_sample(), 2)
    assert_eq(SampleFormat::F32.bytes_per_sample(), 4)
    }

    SampleFormat::equal

    SampleFormat::not_equal

    fn SampleFormat::not_equal(x : SampleFormat, y : SampleFormat) -> Bool

    SampleFormat::output

    fn SampleFormat::output(self : SampleFormat, logger : &Logger) -> Unit

    SampleFormat::to_string

    fn SampleFormat::to_string(self : SampleFormat) -> String

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io