Comments (8)
Hi! You locking mutex for 5 seconds and mixer thread just does not have enough time to mix everything and send data to sound device. Here is your loop:
loop {
println!("Looping");
let mut context = context.lock().unwrap();
let source = context.source_mut(source_handle);
source.play();
// This introduces audio artifacts after a while.
// Use `from_secs(5)` and these go away for me.
thread::sleep(Duration::from_millis(5000));
}
and here is correct version:
loop {
println!("Looping");
// This scope ensures that mutex will be released before calling thread::sleep.
// Alternatively you can std::mem::drop(context) after source.play(); which will
// also release the lock.
{
let mut context = context.lock().unwrap();
let source = context.source_mut(source_handle);
source.play();
}
// This introduces audio artifacts after a while.
// Use `from_secs(5)` and these go away for me.
thread::sleep(Duration::from_millis(5000));
}
So, general rule is to lock mutex as short time as possible, otherwise mixer thread will just wait and sound will be incorrect.
from fyrox.
Oh, duh. Sorry for the silly mistake.
Now, with this code, I'm able to trigger the odd delays. I would expect this footstep sound to play rhythmically. But, on my system, it doesn't. There are odd delays every few footsteps, and the pattern doesn't repeat. To be clear, I don't expect it to cleanly loop. I just expect it to sound rhythmic, but instead it is more staggered.
Not sure if play
is meant to restart the source, which is why I'm stopping it.
Am I doing something wrong here as well? Thanks.
use std::{thread, time::Duration};
use rg3d_sound::{
buffer::{DataSource, SoundBuffer},
context::Context,
pool::Handle,
source::{generic::GenericSourceBuilder, SoundSource},
};
fn main() {
// Initialize new sound context with default output device.
let context = Context::new().unwrap();
// Load sound buffer.
let footstep_buffer =
SoundBuffer::new_generic(DataSource::from_file("footstep.wav").unwrap()).unwrap();
// Create generic source (without spatial effects) using that buffer.
let source = GenericSourceBuilder::new(footstep_buffer)
.with_looping(false)
.build_source()
.unwrap();
// Each sound sound must be added to context, context takes ownership on source
// and returns pool handle to it by which it can be accessed later on if needed.
let source_handle: Handle<SoundSource> = context.lock().unwrap().add_source(source);
// This plays the sound way more than once every 5 seconds.
loop {
{
let mut context = context.lock().unwrap();
let source = context.source_mut(source_handle);
source.stop().unwrap();
source.play();
}
thread::sleep(Duration::from_millis(500));
}
}
from fyrox.
Here is the picture that should clarify what is going on under the hood:
So there are two threads - one is user thread, and second is mixer thread. Mixer thread mix samples into audio buffer and sends data to output device, the time that send procedure could take is undefined, it depends on the driver, OS, and other stuff. So perfect looping could be achived only by setting .with_looping(true)
on a sound source. By doing this, looping happens in mixer thread and it is able to do perfect loop. Please note that backend implemented using ring buffer and by phrase "mixing another portion" on the picture I mean that we mixing a portion of samples for the next iteration, not the current one.
from fyrox.
from fyrox.
Oh, sorry. What I'm doing in my shooter is that I'm creating new source per footstep. Also the engine can automatically handle lifetime of a source for such temporary sound sources. So you need to create a source with .with_play_once(true)
and just play it and forget about it - it will die automatically when it ends. Creating a source is cheap, however you should ensure that amount of simultaneously playing sources is relatively low (soft cap here is about 64 sources), otherwise mixer probably will take large amount of time and sound will stutter.
Other way of implementing this is to use multiple sources with different buffers - each buffer should have slightly different version of footstep to sound more naturally. In this case you should stop currently playing source, and then play a random one.
I'm not a sound designer and don't know all the tricks that will result in natural sound, just relying on what I hear.
from fyrox.
Got it, so seems this is working as designed. Any chance you might eventually support more responsive stopping/restarting of sources? Or should this be closed?
Having to create new sources vs. controlling an existing one would seem to make some types of problems more difficult. It's also a bit more verbose, since instead of just reusing this footstep source, I'd have to create a new one each time.
Thanks for your help.
from fyrox.
I can't imagine a situation in game where such precision is needed, in case of footsteps small variation is good actually, in other cases such small delay is ok too for me 🤔 .
from fyrox.
from fyrox.
Related Issues (20)
- The "Run" Button Does Not Work on the Editor
- Is it possible to run VR on all devices with Rust? Are we heading towards the era of wearable VR PCs? HOT 2
- Can't start "Quick Start" from Fyrox Game Engine Book, I get error: stream did not contain valid UTF-8 HOT 3
- Black Screen HOT 4
- Move interaction modes panel to the toolbar
- Add icons for widgets in World Viewer
- Add an ability to rotate the editor camera using scene gizmo HOT 2
- Calculate frame luminance using histogram for HDR HOT 3
- Add an `ImageDecorator` widget
- Add an ability to unassign textures in material editor
- Add ability to perform convex shape casting in physics
- Support for shader editor
- More hotkeys
- Editor crash when saving terrain HOT 1
- Mixamo mesh import issue HOT 2
- Fyrox-Sound glitchy sounds on Android HOT 2
- Bug found - Clicking in asset browser deleted some files and duplicated the data folder 180+ times until I Ctrl+C the editor process. HOT 2
- thread 'main' panicked HOT 25
- No Texture field in the Inspector HOT 5
- Unsound implementation of `transmute_vec_as_bytes` in `fyrox-core` HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fyrox.