Skip to main content

SoundEngine

Struct SoundEngine 

Source
pub struct SoundEngine(/* private fields */);
Expand description

Sound engine manages contexts, feeds output device with data. Sound engine instance can be cloned, however this is always a “shallow” clone, because actual sound engine data is wrapped in Arc.

Implementations§

Source§

impl SoundEngine

Source

pub fn new() -> Result<Self, Box<dyn Error>>

Creates new instance of the sound engine. It is possible to have multiple engines running at the same time, but you shouldn’t do this because you can create multiple contexts which should cover 99% of use cases.

Examples found in repository?
examples/raw_streaming.rs (line 76)
74fn main() {
75    // Initialize sound engine with default output device.
76    let engine = SoundEngine::new().unwrap();
77
78    // Initialize new sound context.
79    let context = SoundContext::new();
80
81    engine.state().add_context(context.clone());
82
83    // Create sine wave generator
84    let sine_wave = DataSource::RawStreaming(Box::new(SamplesGenerator::new()));
85
86    let sine_wave_buffer = SoundBufferResource::new_streaming(sine_wave).unwrap();
87
88    // Create generic source (without spatial effects) using that buffer.
89    let source = SoundSourceBuilder::new()
90        .with_buffer(sine_wave_buffer)
91        .with_status(Status::Playing)
92        .build()
93        .unwrap();
94
95    context.state().add_source(source);
96
97    // Play sound for some time.
98    thread::sleep(Duration::from_secs(10));
99}
More examples
Hide additional examples
examples/streaming.rs (line 35)
33fn main() {
34    // Initialize sound engine with default output device.
35    let engine = SoundEngine::new().unwrap();
36
37    // Initialize new sound context.
38    let context = SoundContext::new();
39
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let waterfall_buffer = SoundBufferResource::new_streaming(
44        block_on(DataSource::from_file(
45            "examples/data/waterfall.ogg",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create flat source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(waterfall_buffer)
56        .with_status(Status::Playing)
57        .with_looping(true)
58        .build()
59        .unwrap();
60
61    // Each sound sound must be added to context, context takes ownership on source
62    // and returns pool handle to it by which it can be accessed later on if needed.
63    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
64
65    thread::sleep(Duration::from_secs(30))
66}
examples/raw_samples.rs (line 32)
30fn main() {
31    // Initialize sound engine with default output device.
32    let engine = SoundEngine::new().unwrap();
33
34    // Initialize new sound context.
35    let context = SoundContext::new();
36
37    engine.state().add_context(context.clone());
38
39    // Create sine wave.
40    let sample_rate = 44100;
41    let sine_wave = DataSource::Raw {
42        sample_rate,
43        channel_count: 1,
44        samples: {
45            let frequency = 440.0;
46            let amplitude = 0.75;
47            (0..44100)
48                .map(|i| {
49                    amplitude
50                        * ((2.0 * std::f32::consts::PI * i as f32 * frequency) / sample_rate as f32)
51                            .sin()
52                })
53                .collect()
54        },
55    };
56
57    let sine_wave_buffer = SoundBufferResource::new_generic(sine_wave).unwrap();
58
59    // Create generic source (without spatial effects) using that buffer.
60    let source = SoundSourceBuilder::new()
61        .with_buffer(sine_wave_buffer)
62        .with_status(Status::Playing)
63        .with_looping(true)
64        .build()
65        .unwrap();
66
67    context.state().add_source(source);
68
69    // Play sound for some time.
70    thread::sleep(Duration::from_secs(10));
71}
examples/play_sound.rs (line 34)
32fn main() {
33    // Initialize sound engine with default output device.
34    let engine = SoundEngine::new().unwrap();
35
36    // Create new context.
37    let context = SoundContext::new();
38
39    // Register context in the engine.
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let door_open_buffer = SoundBufferResource::new_generic(
44        fyrox_sound::futures::executor::block_on(DataSource::from_file(
45            "examples/data/door_open.wav",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create generic source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(door_open_buffer)
56        .with_status(Status::Playing)
57        // Ensure that no spatial effects will be applied.
58        .with_spatial_blend_factor(0.0)
59        .build()
60        .unwrap();
61
62    // Each sound sound must be added to context, context takes ownership on source
63    // and returns pool handle to it by which it can be accessed later on if needed.
64    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
65
66    // Wait until sound will play completely.
67    thread::sleep(Duration::from_secs(3));
68}
examples/play_spatial_sound.rs (line 39)
37fn main() {
38    // Initialize sound engine with default output device.
39    let engine = SoundEngine::new().unwrap();
40
41    // Initialize new sound context.
42    let context = SoundContext::new();
43
44    engine.state().add_context(context.clone());
45
46    // Load sound buffer.
47    let drop_buffer = SoundBufferResource::new_generic(
48        block_on(DataSource::from_file(
49            "examples/data/drop.wav",
50            // Load from the default resource io (File system)
51            &FsResourceIo,
52        ))
53        .unwrap(),
54    )
55    .unwrap();
56
57    // Create spatial source - spatial sources can be positioned in space.
58    let source = SoundSourceBuilder::new()
59        .with_buffer(drop_buffer)
60        .with_looping(true)
61        .with_status(Status::Playing)
62        .build()
63        .unwrap();
64
65    // Each sound sound must be added to context, context takes ownership on source
66    // and returns pool handle to it by which it can be accessed later on if needed.
67    let source_handle: Handle<SoundSource> = context.state().add_source(source);
68
69    // Move sound around listener for some time.
70    let start_time = time::Instant::now();
71    let mut angle = 0.0f32;
72    while (time::Instant::now() - start_time).as_secs() < 11 {
73        let axis = Vector3::y_axis();
74        let rotation_matrix =
75            UnitQuaternion::from_axis_angle(&axis, angle.to_radians()).to_homogeneous();
76        context.state().source_mut(source_handle).set_position(
77            rotation_matrix
78                .transform_point(&Point3::new(0.0, 0.0, 3.0))
79                .coords,
80        );
81
82        angle += 3.6;
83
84        // Limit rate of updates.
85        thread::sleep(Duration::from_millis(100));
86    }
87}
examples/listener.rs (line 39)
37fn main() {
38    // Initialize sound engine with default output device.
39    let engine = SoundEngine::new().unwrap();
40
41    // Initialize new sound context.
42    let context = SoundContext::new();
43
44    engine.state().add_context(context.clone());
45
46    // Load sound buffer.
47    let drop_buffer = SoundBufferResource::new_generic(
48        block_on(DataSource::from_file(
49            "examples/data/drop.wav", // Load from the default resource io (File system)
50            &FsResourceIo,
51        ))
52        .unwrap(),
53    )
54    .unwrap();
55
56    // Create spatial source - spatial sources can be positioned in space.
57    let source = SoundSourceBuilder::new()
58        .with_buffer(drop_buffer)
59        .with_looping(true)
60        .with_status(Status::Playing)
61        .build()
62        .unwrap();
63
64    // Each sound sound must be added to context, context takes ownership on source
65    // and returns pool handle to it by which it can be accessed later on if needed.
66    context.state().add_source(source);
67
68    // Rotate listener for some time.
69    let start_time = time::Instant::now();
70    let mut angle = 0.0f32;
71    while (time::Instant::now() - start_time).as_secs() < 20 {
72        // Separate scope for update to make sure that mutex lock will be released before
73        // thread::sleep will be called so context can actually work in background thread.
74        {
75            let mut context = context.state();
76
77            let listener = context.listener_mut();
78
79            // Define up-axis of listener.
80            let up = Vector3::y_axis();
81
82            // And rotate look axis.
83            let rotation_matrix =
84                UnitQuaternion::from_axis_angle(&up, angle.to_radians()).to_homogeneous();
85            let look = rotation_matrix
86                .transform_point(&Point3::new(0.0, 0.0, 1.0))
87                .coords;
88
89            // Finally combine axes. _lh suffix here means that we using left-handed coordinate system.
90            // there is also _rh (right handed) version. Also basis can be set directly by using `set_basis`
91            listener.set_orientation_lh(look, *up);
92
93            // Move listener a bit back from sound source.
94            listener.set_position(Vector3::new(0.0, 0.0, -2.0));
95
96            // Continue rotation.
97            angle += 2.0;
98        }
99
100        // Limit rate of updates.
101        thread::sleep(Duration::from_millis(100));
102    }
103}
Source

pub fn without_device() -> Self

Creates new instance of a sound engine without OS audio output device (so called headless mode). The user should periodically run State::render if they want to implement their own sample sending method to an output device (or a file, etc.).

Examples found in repository?
examples/write_wav.rs (line 34)
32fn main() {
33    // Initialize sound engine without output device.
34    let engine = SoundEngine::without_device();
35
36    // Create new context.
37    let context = SoundContext::new();
38
39    // Register context in the engine.
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let door_open_buffer = SoundBufferResource::new_generic(
44        fyrox_sound::futures::executor::block_on(DataSource::from_file(
45            "examples/data/door_open.wav",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create generic source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(door_open_buffer)
56        .with_status(Status::Playing)
57        .build()
58        .unwrap();
59
60    // Each sound sound must be added to context, context takes ownership on source
61    // and returns pool handle to it by which it can be accessed later on if needed.
62    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
63
64    // Create output wav file. The sample rate is currently fixed.
65    let wav_spec = hound::WavSpec {
66        channels: 2,
67        sample_rate: fyrox_sound::context::SAMPLE_RATE,
68        bits_per_sample: 32,
69        sample_format: hound::SampleFormat::Float,
70    };
71    let mut wav_writer = hound::WavWriter::create("output.wav", wav_spec).unwrap();
72
73    // Create an output buffer.
74    let buf_len = State::render_buffer_len();
75    let mut buf = vec![(0.0f32, 0.0f32); buf_len];
76    let mut samples_written = 0;
77
78    // Wait until sound will play completely.
79    while samples_written < 3 * fyrox_sound::context::SAMPLE_RATE {
80        engine.state().render(&mut buf);
81        for &(l, r) in buf.iter() {
82            wav_writer.write_sample(l).unwrap();
83            wav_writer.write_sample(r).unwrap();
84        }
85        samples_written += buf_len as u32;
86    }
87
88    wav_writer.finalize().unwrap();
89}
Source

pub fn initialize_audio_output_device(&self) -> Result<(), Box<dyn Error>>

Tries to initialize default audio output device.

Source

pub fn destroy_audio_output_device(&self)

Destroys current audio output device (if any).

Source

pub fn state(&self) -> MutexGuard<'_, State>

Provides direct access to actual engine data.

Examples found in repository?
examples/raw_streaming.rs (line 81)
74fn main() {
75    // Initialize sound engine with default output device.
76    let engine = SoundEngine::new().unwrap();
77
78    // Initialize new sound context.
79    let context = SoundContext::new();
80
81    engine.state().add_context(context.clone());
82
83    // Create sine wave generator
84    let sine_wave = DataSource::RawStreaming(Box::new(SamplesGenerator::new()));
85
86    let sine_wave_buffer = SoundBufferResource::new_streaming(sine_wave).unwrap();
87
88    // Create generic source (without spatial effects) using that buffer.
89    let source = SoundSourceBuilder::new()
90        .with_buffer(sine_wave_buffer)
91        .with_status(Status::Playing)
92        .build()
93        .unwrap();
94
95    context.state().add_source(source);
96
97    // Play sound for some time.
98    thread::sleep(Duration::from_secs(10));
99}
More examples
Hide additional examples
examples/streaming.rs (line 40)
33fn main() {
34    // Initialize sound engine with default output device.
35    let engine = SoundEngine::new().unwrap();
36
37    // Initialize new sound context.
38    let context = SoundContext::new();
39
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let waterfall_buffer = SoundBufferResource::new_streaming(
44        block_on(DataSource::from_file(
45            "examples/data/waterfall.ogg",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create flat source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(waterfall_buffer)
56        .with_status(Status::Playing)
57        .with_looping(true)
58        .build()
59        .unwrap();
60
61    // Each sound sound must be added to context, context takes ownership on source
62    // and returns pool handle to it by which it can be accessed later on if needed.
63    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
64
65    thread::sleep(Duration::from_secs(30))
66}
examples/raw_samples.rs (line 37)
30fn main() {
31    // Initialize sound engine with default output device.
32    let engine = SoundEngine::new().unwrap();
33
34    // Initialize new sound context.
35    let context = SoundContext::new();
36
37    engine.state().add_context(context.clone());
38
39    // Create sine wave.
40    let sample_rate = 44100;
41    let sine_wave = DataSource::Raw {
42        sample_rate,
43        channel_count: 1,
44        samples: {
45            let frequency = 440.0;
46            let amplitude = 0.75;
47            (0..44100)
48                .map(|i| {
49                    amplitude
50                        * ((2.0 * std::f32::consts::PI * i as f32 * frequency) / sample_rate as f32)
51                            .sin()
52                })
53                .collect()
54        },
55    };
56
57    let sine_wave_buffer = SoundBufferResource::new_generic(sine_wave).unwrap();
58
59    // Create generic source (without spatial effects) using that buffer.
60    let source = SoundSourceBuilder::new()
61        .with_buffer(sine_wave_buffer)
62        .with_status(Status::Playing)
63        .with_looping(true)
64        .build()
65        .unwrap();
66
67    context.state().add_source(source);
68
69    // Play sound for some time.
70    thread::sleep(Duration::from_secs(10));
71}
examples/play_sound.rs (line 40)
32fn main() {
33    // Initialize sound engine with default output device.
34    let engine = SoundEngine::new().unwrap();
35
36    // Create new context.
37    let context = SoundContext::new();
38
39    // Register context in the engine.
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let door_open_buffer = SoundBufferResource::new_generic(
44        fyrox_sound::futures::executor::block_on(DataSource::from_file(
45            "examples/data/door_open.wav",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create generic source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(door_open_buffer)
56        .with_status(Status::Playing)
57        // Ensure that no spatial effects will be applied.
58        .with_spatial_blend_factor(0.0)
59        .build()
60        .unwrap();
61
62    // Each sound sound must be added to context, context takes ownership on source
63    // and returns pool handle to it by which it can be accessed later on if needed.
64    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
65
66    // Wait until sound will play completely.
67    thread::sleep(Duration::from_secs(3));
68}
examples/play_spatial_sound.rs (line 44)
37fn main() {
38    // Initialize sound engine with default output device.
39    let engine = SoundEngine::new().unwrap();
40
41    // Initialize new sound context.
42    let context = SoundContext::new();
43
44    engine.state().add_context(context.clone());
45
46    // Load sound buffer.
47    let drop_buffer = SoundBufferResource::new_generic(
48        block_on(DataSource::from_file(
49            "examples/data/drop.wav",
50            // Load from the default resource io (File system)
51            &FsResourceIo,
52        ))
53        .unwrap(),
54    )
55    .unwrap();
56
57    // Create spatial source - spatial sources can be positioned in space.
58    let source = SoundSourceBuilder::new()
59        .with_buffer(drop_buffer)
60        .with_looping(true)
61        .with_status(Status::Playing)
62        .build()
63        .unwrap();
64
65    // Each sound sound must be added to context, context takes ownership on source
66    // and returns pool handle to it by which it can be accessed later on if needed.
67    let source_handle: Handle<SoundSource> = context.state().add_source(source);
68
69    // Move sound around listener for some time.
70    let start_time = time::Instant::now();
71    let mut angle = 0.0f32;
72    while (time::Instant::now() - start_time).as_secs() < 11 {
73        let axis = Vector3::y_axis();
74        let rotation_matrix =
75            UnitQuaternion::from_axis_angle(&axis, angle.to_radians()).to_homogeneous();
76        context.state().source_mut(source_handle).set_position(
77            rotation_matrix
78                .transform_point(&Point3::new(0.0, 0.0, 3.0))
79                .coords,
80        );
81
82        angle += 3.6;
83
84        // Limit rate of updates.
85        thread::sleep(Duration::from_millis(100));
86    }
87}
examples/write_wav.rs (line 40)
32fn main() {
33    // Initialize sound engine without output device.
34    let engine = SoundEngine::without_device();
35
36    // Create new context.
37    let context = SoundContext::new();
38
39    // Register context in the engine.
40    engine.state().add_context(context.clone());
41
42    // Load sound buffer.
43    let door_open_buffer = SoundBufferResource::new_generic(
44        fyrox_sound::futures::executor::block_on(DataSource::from_file(
45            "examples/data/door_open.wav",
46            // Load from the default resource io (File system)
47            &FsResourceIo,
48        ))
49        .unwrap(),
50    )
51    .unwrap();
52
53    // Create generic source (without spatial effects) using that buffer.
54    let source = SoundSourceBuilder::new()
55        .with_buffer(door_open_buffer)
56        .with_status(Status::Playing)
57        .build()
58        .unwrap();
59
60    // Each sound sound must be added to context, context takes ownership on source
61    // and returns pool handle to it by which it can be accessed later on if needed.
62    let _source_handle: Handle<SoundSource> = context.state().add_source(source);
63
64    // Create output wav file. The sample rate is currently fixed.
65    let wav_spec = hound::WavSpec {
66        channels: 2,
67        sample_rate: fyrox_sound::context::SAMPLE_RATE,
68        bits_per_sample: 32,
69        sample_format: hound::SampleFormat::Float,
70    };
71    let mut wav_writer = hound::WavWriter::create("output.wav", wav_spec).unwrap();
72
73    // Create an output buffer.
74    let buf_len = State::render_buffer_len();
75    let mut buf = vec![(0.0f32, 0.0f32); buf_len];
76    let mut samples_written = 0;
77
78    // Wait until sound will play completely.
79    while samples_written < 3 * fyrox_sound::context::SAMPLE_RATE {
80        engine.state().render(&mut buf);
81        for &(l, r) in buf.iter() {
82            wav_writer.write_sample(l).unwrap();
83            wav_writer.write_sample(r).unwrap();
84        }
85        samples_written += buf_len as u32;
86    }
87
88    wav_writer.finalize().unwrap();
89}

Trait Implementations§

Source§

impl Clone for SoundEngine

Source§

fn clone(&self) -> SoundEngine

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for SoundEngine

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AsyncTaskResult for T
where T: Any + Send + 'static,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T, U> ObjectOrVariant<T> for U

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V