### Integrate Oddio with cpal Source: https://context7.com/ralith/oddio/llms.txt A complete example demonstrating how to set up a cpal output stream and use an Oddio mixer to play sine waves and buffered audio data. ```rust use std::{thread, time::Duration}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use oddio::{Mixer, SpatialScene, FramesSignal, Frames, Gain, MonoToStereo, Sine, Signal}; fn main() { // Setup cpal audio output let host = cpal::default_host(); let device = host.default_output_device().expect("no output device"); let sample_rate = device.default_output_config().unwrap().sample_rate(); let config = cpal::StreamConfig { channels: 2, sample_rate, buffer_size: cpal::BufferSize::Default, }; // Create the mixer (control handle + signal) let (mut mixer_handle, mut mixer) = Mixer::new(); // Build the output stream let stream = device .build_output_stream( &config, move |out_flat: &mut [f32], _: &cpal::OutputCallbackInfo| { let out_stereo = oddio::frame_stereo(out_flat); oddio::run(&mut mixer, sample_rate.0, out_stereo); }, |err| eprintln!("Audio error: {}", err), None, ) .unwrap(); stream.play().unwrap(); // Play a sine wave mixer_handle.play(MonoToStereo::new(Sine::new(0.0, 440.0))); // Load and play a sound effect with gain control let sound_data: Vec = vec![0.0; 44100]; // Your audio data here let frames = Frames::from_slice(sample_rate.0, &sound_data); let (mut gain_ctrl, signal) = Gain::new(FramesSignal::from(frames)); mixer_handle.play(MonoToStereo::new(signal)); // Adjust volume gain_ctrl.set_gain(-6.0); thread::sleep(Duration::from_secs(3)); } ``` -------------------------------- ### Create and Use FramesSignal for Audio Playback in Rust Source: https://context7.com/ralith/oddio/llms.txt Demonstrates creating audio frames from a sine wave and playing them back using FramesSignal. Supports custom start times and playback control. ```rust use std::sync::Arc; use oddio::{Frames, FramesSignal, Signal}; // Create frames from a slice of mono audio samples let sample_rate = 44100; let samples: Vec = (0..sample_rate) .map(|i| { let t = i as f32 / sample_rate as f32; (t * 440.0 * 2.0 * std::f32::consts::PI).sin() }) .collect(); let frames: Arc> = Frames::from_slice(sample_rate as u32, &samples); // Check frame properties println!("Sample rate: {} Hz", frames.rate()); println!("Duration: {:.2} seconds", frames.runtime()); // Create a signal that plays from the beginning let signal: FramesSignal = FramesSignal::from(frames.clone()); // Or create with a control handle and custom start time (negative = delay before start) let (control, signal) = FramesSignal::new(frames, -0.5); // Start 0.5 seconds before audio begins // Use control to check playback position from another thread println!("Current position: {} seconds", control.playback_position()); println!("Is finished: {}", control.is_finished()); ``` -------------------------------- ### Initialize and Use Oddio Spatial Scene Source: https://github.com/ralith/oddio/blob/main/README.md Demonstrates initializing a `SpatialScene` and handling audio output and game logic updates. Ensure `data` is correctly formatted for `frame_stereo` and `output_sample_rate` is set. ```rust let (mut scene_handle, mut scene) = oddio::SpatialScene::new(); // In audio callback: let out_frames = oddio::frame_stereo(data); oddio::run(&mut scene, output_sample_rate, out_frames); // In game logic: let frames = oddio::FramesSignal::from(oddio::Frames::from_slice(sample_rate, &frames)); let mut handle = scene_handle .play(frames, oddio::SpatialOptions { position, velocity, ..Default::default() }); // When position/velocity changes: handle.set_motion(position, velocity, false); ``` -------------------------------- ### Run Signal in Audio Callback Source: https://context7.com/ralith/oddio/llms.txt Populates an output buffer from any signal at a specific sample rate. ```rust use oddio::{run, Mixer, Signal, MonoToStereo, Sine}; let (mut control, mut mixer) = Mixer::<[f32; 2]>::new(); control.play(MonoToStereo::new(Sine::new(0.0, 440.0))); let sample_rate = 44100u32; // In your audio callback: let mut output_buffer = [[0.0f32; 2]; 512]; run(&mut mixer, sample_rate, &mut output_buffer); ``` -------------------------------- ### Dynamic and Static Gain Control Source: https://context7.com/ralith/oddio/llms.txt Gain provides thread-safe dynamic volume control, while FixedGain is used for static amplification. ```rust use oddio::{Gain, FixedGain, Sine, Signal}; // Dynamic gain with thread-safe control let (mut gain_control, mut gain_signal) = Gain::new(Sine::new(0.0, 440.0)); // Set gain in decibels (0 dB = unity, negative = quieter) gain_control.set_gain(-12.0); // Reduce by 12 dB // Or set amplitude ratio directly (1.0 = unity, 0.5 = half amplitude) gain_control.set_amplitude_ratio(0.5); // Read current gain println!("Current gain: {} dB", gain_control.gain()); println!("Amplitude ratio: {}", gain_control.amplitude_ratio()); // Sample the signal let mut output = [0.0f32; 256]; gain_signal.sample(1.0 / 44100.0, &mut output); // FixedGain for static amplification (preserves Seek trait) let fixed = FixedGain::new(Sine::new(0.0, 440.0), -6.0); // -6 dB ``` -------------------------------- ### Manage Concurrent Audio Signals with Mixer in Rust Source: https://context7.com/ralith/oddio/llms.txt Shows how to use Oddio's Mixer to play multiple audio signals concurrently, including sound effects and continuous tones. Handles automatic cleanup of finished signals. ```rust use oddio::{Mixer, FramesSignal, Frames, Signal, MonoToStereo, Sine}; use std::sync::Arc; // Create a stereo mixer let (mut mixer_control, mut mixer) = Mixer::<[f32; 2]>::new(); // Load a sound effect let sample_rate = 44100u32; let explosion_samples: Vec = vec![0.0; sample_rate as usize]; // placeholder let explosion = Frames::from_slice(sample_rate, &explosion_samples); // Play a sound effect - returns a handle to control playback let mut handle = mixer_control.play(MonoToStereo::new(FramesSignal::from(explosion))); // Check if still playing if !handle.is_stopped() { println!("Sound is still playing"); } // Stop the sound immediately handle.stop(); // Play a continuous sine wave mixer_control.play(MonoToStereo::new(Sine::new(0.0, 440.0))); // In your audio callback, generate output: let mut output = [[0.0f32; 2]; 1024]; mixer.sample(1.0 / 44100.0, &mut output); ``` -------------------------------- ### Stream Live Audio Source: https://context7.com/ralith/oddio/llms.txt Handles dynamic audio from external sources with buffering. Drop the control to signal the end of the stream. ```rust use oddio::{Stream, Signal}; let sample_rate = 44100u32; let buffer_size = 8192; // Frames of buffer let (mut stream_control, mut stream) = Stream::::new(sample_rate, buffer_size); // Producer thread: write samples as they become available let samples_to_write: Vec = vec![0.0; 1024]; let written = stream_control.write(&samples_to_write); println!("Wrote {} samples, {} free", written, stream_control.free()); // Consumer (audio callback): read from the stream let mut output = [0.0f32; 256]; stream.sample(1.0 / sample_rate as f32, &mut output); // When done, drop the control to signal end of stream drop(stream_control); // stream.is_finished() will return true once buffer drains ``` -------------------------------- ### Implement Custom Square Wave Signal in Rust Source: https://context7.com/ralith/oddio/llms.txt Defines a custom signal that produces a square wave. This implementation runs indefinitely and can be used as a basic audio source. ```rust use oddio::{Signal, Sample}; // Define a custom signal that produces a square wave struct SquareWave { phase: f32, frequency: f32, } impl SquareWave { fn new(frequency_hz: f32) -> Self { Self { phase: 0.0, frequency: frequency_hz, } } } impl Signal for SquareWave { type Frame = Sample; fn sample(&mut self, interval: f32, out: &mut [Sample]) { for (i, x) in out.iter_mut().enumerate() { let t = self.phase + interval * i as f32; // Square wave: 1.0 for first half of period, -1.0 for second half *x = if (t * self.frequency).fract() < 0.5 { 1.0 } else { -1.0 }; } self.phase += interval * out.len() as f32; } fn is_finished(&self) -> bool { false // Runs forever } } ``` -------------------------------- ### Convert Interleaved Stereo to Frames Source: https://context7.com/ralith/oddio/llms.txt Converts flat interleaved stereo buffers into frame arrays for compatibility with Oddio. ```rust use oddio::{frame_stereo, run, Mixer, Signal}; // Typical cpal callback provides flat interleaved buffer let mut flat_buffer: Vec = vec![0.0; 1024]; // 512 stereo frames // Convert to frame array for oddio let stereo_frames: &mut [[f32; 2]] = frame_stereo(&mut flat_buffer); assert_eq!(stereo_frames.len(), 512); // Now use with run() let (_, mut mixer) = Mixer::<[f32; 2]>::new(); run(&mut mixer, 44100, stereo_frames); ``` -------------------------------- ### Loop Audio with Cycle Source: https://context7.com/ralith/oddio/llms.txt Loops a Frames signal endlessly. Useful for background music or ambient sounds. ```rust use oddio::{Cycle, Frames, Signal, Seek}; use std::sync::Arc; let sample_rate = 44100u32; let loop_samples: Vec = (0..sample_rate * 2) // 2 second loop .map(|i| (i as f32 / sample_rate as f32 * 440.0 * std::f32::consts::TAU).sin()) .collect(); let frames = Frames::from_slice(sample_rate, &loop_samples); let mut looped = Cycle::new(frames); // Will loop forever let mut output = [0.0f32; 44100 * 5]; // 5 seconds looped.sample(1.0 / sample_rate as f32, &mut output); // Seek within the loop looped.seek(0.5); // Jump 0.5 seconds into the loop ``` -------------------------------- ### SpatialScene 3D Audio Spatialization Source: https://context7.com/ralith/oddio/llms.txt Configures a 3D audio scene with listener orientation, source positioning, and velocity-based doppler effects. ```rust use oddio::{SpatialScene, SpatialOptions, FramesSignal, Frames, Seek, Signal}; use std::sync::Arc; // Create a spatial scene let (mut scene_control, mut scene) = SpatialScene::new(); // Load mono audio (spatial signals must be mono) let sample_rate = 44100u32; let gunshot: Arc> = Frames::from_slice(sample_rate, &[0.0f32; 4410]); // Play a spatialized sound with initial position and velocity let signal = FramesSignal::from(gunshot); let mut spatial_handle = scene_control.play( signal, SpatialOptions { position: [10.0, 0.0, -5.0].into(), // 10m right, 5m in front velocity: [-2.0, 0.0, 0.0].into(), // Moving left at 2 m/s radius: 0.1, // Minimum attenuation distance }, ); // Update position/velocity as the sound source moves spatial_handle.set_motion( [8.0, 0.0, -5.0].into(), // New position [-2.0, 0.0, 0.0].into(), // Velocity false, // Set true if teleporting to avoid doppler artifacts ); // Rotate the listener (quaternion: facing +X instead of -Z) scene_control.set_listener_rotation(mint::Quaternion { s: 0.707, v: [0.0, 0.707, 0.0].into(), }); // Check if sound has finished (including propagation delay) if spatial_handle.is_finished() { println!("Sound has finished"); } // Sample the scene for stereo output let mut stereo_output = [[0.0f32; 2]; 512]; scene.sample(1.0 / 44100.0, &mut stereo_output); ``` -------------------------------- ### Generate a Sine Wave Source: https://context7.com/ralith/oddio/llms.txt Creates a continuous sine wave at a specified frequency. Sine implements the Seek trait for jumping to specific points in the signal. ```rust use oddio::{Sine, Signal, Seek}; // Create a 440 Hz sine wave (A4 note) let mut sine = Sine::new(0.0, 440.0); // phase, frequency_hz // Sample the signal let sample_rate = 44100u32; let mut output = [0.0f32; 1024]; sine.sample(1.0 / sample_rate as f32, &mut output); // Sine implements Seek, so you can jump ahead sine.seek(0.5); // Jump forward 0.5 seconds ``` -------------------------------- ### Apply Soft Limiting Filters Source: https://context7.com/ralith/oddio/llms.txt Uses Reinhard or Tanh filters to compress signals into the (-1, 1) range to prevent clipping. ```rust use oddio::{Reinhard, Tanh, Mixer, Signal, MonoToStereo, Sine}; let (mut control, mixer) = Mixer::<[f32; 2]>::new(); // Add many loud signals that might clip for i in 0..20 { control.play(MonoToStereo::new(Sine::new(0.0, 440.0 + i as f32 * 50.0))); } // Apply Reinhard limiting: x / (1 + |x|) // Distorts quiet sounds less than loud sounds let mut limited = Reinhard::new(mixer); // Or use Tanh: tanh(x) // Distorts quiet sounds less, loud sounds more than Reinhard // let mut limited = Tanh::new(mixer); let mut output = [[0.0f32; 2]; 256]; limited.sample(1.0 / 44100.0, &mut output); ``` -------------------------------- ### Convert Mono to Stereo Source: https://context7.com/ralith/oddio/llms.txt Duplicates a mono signal into two channels for stereo output. ```rust use oddio::{MonoToStereo, Sine, Signal}; let mono_sine = Sine::new(0.0, 440.0); let mut stereo_sine = MonoToStereo::new(mono_sine); // Now outputs [f32; 2] frames let mut output = [[0.0f32; 2]; 256]; stereo_sine.sample(1.0 / 44100.0, &mut output); ``` -------------------------------- ### Downmix Multi-channel to Mono Source: https://context7.com/ralith/oddio/llms.txt Sums all channels of a multi-channel signal into a single mono channel. ```rust use oddio::{Downmix, Constant, Signal}; // Create a stereo signal let stereo = Constant::new([0.5f32, 0.3f32]); let mut mono = Downmix::new(stereo); // Outputs mono (sum of channels) let mut output = [0.0f32; 256]; mono.sample(1.0 / 44100.0, &mut output); // Each sample will be 0.8 (0.5 + 0.3) ``` -------------------------------- ### SpatialScene Buffered Playback Source: https://context7.com/ralith/oddio/llms.txt Use play_buffered for signals that do not implement the Seek trait, such as those with dynamic filters. ```rust use oddio::{SpatialScene, SpatialOptions, Gain, Sine, Signal}; let (mut scene_control, mut scene) = SpatialScene::new(); // Create a signal with dynamic gain control (cannot implement Seek) let (mut gain_control, gain_signal) = Gain::new(Sine::new(0.0, 440.0)); // Use play_buffered for non-seekable signals let sample_rate = 44100u32; let mut spatial = scene_control.play_buffered( gain_signal, SpatialOptions { position: [0.0, 0.0, -100.0].into(), // 100m away velocity: [0.0, 0.0, 0.0].into(), radius: 0.1, }, 200.0, // max_distance: buffer for up to 200m propagation delay sample_rate, 0.1, // buffer_duration: seconds of extra buffer ); // Dynamically adjust gain during playback gain_control.set_gain(-6.0); // Reduce by 6 dB ``` -------------------------------- ### Signal Crossfading with Fader Source: https://context7.com/ralith/oddio/llms.txt Performs constant-power crossfades between audio signals. ```rust use oddio::{Fader, FaderControl, Sine, Constant, Signal}; // Start with a sine wave let (mut fader_control, mut fader) = Fader::new(Sine::new(0.0, 440.0)); // Crossfade to a different frequency over 2 seconds fader_control.fade_to(Sine::new(0.0, 880.0), 2.0); // Sample during the fade let mut output = [0.0f32; 1024]; fader.sample(1.0 / 44100.0, &mut output); // Queue another fade (will start after current fade completes) fader_control.fade_to(Sine::new(0.0, 220.0), 1.0); ``` -------------------------------- ### Playback Speed Adjustment Source: https://context7.com/ralith/oddio/llms.txt Adjusts the playback rate of a signal, which directly impacts the pitch. ```rust use oddio::{Speed, FramesSignal, Frames, Signal}; use std::sync::Arc; let sample_rate = 44100u32; let audio = Frames::from_slice(sample_rate, &[0.0f32; 44100]); let (mut speed_control, mut speed_signal) = Speed::new(FramesSignal::from(audio)); // Double speed (one octave higher) speed_control.set_speed(2.0); // Half speed (one octave lower) speed_control.set_speed(0.5); // Read current speed println!("Current speed: {}x", speed_control.speed()); let mut output = [0.0f32; 256]; speed_signal.sample(1.0 / 44100.0, &mut output); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.