core: Support start, stop, event sounds in audio backend
Event sounds on the timeline in Flash have a "sync" setting, which allows them to stop other sounds or only play if the sound is not already playing.
This commit is contained in:
parent
875f250b86
commit
af163d9183
|
@ -37,6 +37,15 @@ pub trait AudioBackend {
|
|||
/// Good ol' stopAllSounds() :-)
|
||||
fn stop_all_sounds(&mut self);
|
||||
|
||||
/// Stops all active sound instances of a particular sound.
|
||||
/// Used by SWF `StartSound` tag with `SoundEvent::Stop`.
|
||||
fn stop_sounds_with_handle(&mut self, handle: SoundHandle);
|
||||
|
||||
/// Returns wheter a sound clip is playing.
|
||||
/// Used by SWF `StartSouynd` tag with `SoundEvent:Start`,
|
||||
/// which only plays a sound if that sound is not already playing.
|
||||
fn is_sound_playing_with_handle(&mut self, handle: SoundHandle) -> bool;
|
||||
|
||||
// TODO: Eventually remove this/move it to library.
|
||||
fn is_loading_complete(&self) -> bool {
|
||||
true
|
||||
|
@ -74,8 +83,11 @@ impl AudioBackend for NullAudioBackend {
|
|||
) -> AudioStreamHandle {
|
||||
self.streams.insert(())
|
||||
}
|
||||
|
||||
fn stop_all_sounds(&mut self) {}
|
||||
fn stop_sounds_with_handle(&mut self, _handle: SoundHandle) {}
|
||||
fn is_sound_playing_with_handle(&mut self, _handle: SoundHandle) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NullAudioBackend {
|
||||
|
|
|
@ -1255,8 +1255,23 @@ impl<'gc, 'a> MovieClip<'gc> {
|
|||
) -> DecodeResult {
|
||||
let start_sound = reader.read_start_sound_1()?;
|
||||
if let Some(handle) = context.library.get_sound(start_sound.id) {
|
||||
use swf::SoundEvent;
|
||||
// The sound event type is controlled by the "Sync" setting in the Flash IDE.
|
||||
match start_sound.sound_info.event {
|
||||
// "Event" sounds always play, independent of the timeline.
|
||||
SoundEvent::Event => context.audio.start_sound(handle, &start_sound.sound_info),
|
||||
|
||||
// "Start" sounds only play if an instance of the same sound is not already playing.
|
||||
SoundEvent::Start => {
|
||||
if !context.audio.is_sound_playing_with_handle(handle) {
|
||||
context.audio.start_sound(handle, &start_sound.sound_info);
|
||||
}
|
||||
}
|
||||
|
||||
// "Stop" stops any active instances of a given sound.
|
||||
SoundEvent::Stop => context.audio.stop_sounds_with_handle(handle),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,6 +351,20 @@ impl AudioBackend for CpalAudioBackend {
|
|||
sound_instances.clear();
|
||||
}
|
||||
|
||||
fn stop_sounds_with_handle(&mut self, handle: SoundHandle) {
|
||||
let mut sound_instances = self.sound_instances.lock().unwrap();
|
||||
let handle = Some(handle);
|
||||
sound_instances.retain(|_, instance| instance.handle == handle);
|
||||
}
|
||||
|
||||
fn is_sound_playing_with_handle(&mut self, handle: SoundHandle) -> bool {
|
||||
let sound_instances = self.sound_instances.lock().unwrap();
|
||||
let handle = Some(handle);
|
||||
sound_instances
|
||||
.iter()
|
||||
.any(|(_, instance)| instance.handle == handle && instance.active)
|
||||
}
|
||||
|
||||
fn tick(&mut self) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,10 +54,12 @@ type Decoder = Box<dyn Iterator<Item = [i16; 2]>>;
|
|||
#[allow(dead_code)]
|
||||
enum AudioStream {
|
||||
Decoder {
|
||||
handle: SoundHandle,
|
||||
decoder: Decoder,
|
||||
is_stereo: bool,
|
||||
}, // closure: Option<Closure<Box<FnMut(web_sys::AudioProcessingEvent)>>> } ,
|
||||
AudioBuffer {
|
||||
handle: SoundHandle,
|
||||
node: web_sys::AudioBufferSourceNode,
|
||||
},
|
||||
}
|
||||
|
@ -125,7 +127,7 @@ impl WebAudioBackend {
|
|||
}
|
||||
}
|
||||
|
||||
let audio_stream = AudioStream::AudioBuffer { node };
|
||||
let audio_stream = AudioStream::AudioBuffer { node, handle };
|
||||
STREAMS.with(|streams| {
|
||||
let mut streams = streams.borrow_mut();
|
||||
streams.insert(audio_stream)
|
||||
|
@ -161,6 +163,7 @@ impl WebAudioBackend {
|
|||
};
|
||||
|
||||
let audio_stream = AudioStream::Decoder {
|
||||
handle,
|
||||
decoder,
|
||||
is_stereo: sound.format.is_stereo,
|
||||
//closure: None,
|
||||
|
@ -487,7 +490,7 @@ impl AudioBackend for WebAudioBackend {
|
|||
STREAMS.with(|streams| {
|
||||
let mut streams = streams.borrow_mut();
|
||||
for (_, stream) in streams.iter() {
|
||||
if let AudioStream::AudioBuffer { node } = stream {
|
||||
if let AudioStream::AudioBuffer { node, .. } = stream {
|
||||
let _ = node.stop();
|
||||
}
|
||||
// TODO: Have to handle Decoder nodes. (These may just go into a different backend.)
|
||||
|
@ -495,6 +498,32 @@ impl AudioBackend for WebAudioBackend {
|
|||
streams.clear();
|
||||
})
|
||||
}
|
||||
|
||||
fn stop_sounds_with_handle(&mut self, handle: SoundHandle) {
|
||||
STREAMS.with(|streams| {
|
||||
let mut streams = streams.borrow_mut();
|
||||
streams.retain(|_, instance| {
|
||||
let instance_handle = match instance {
|
||||
AudioStream::Decoder { handle, .. } => *handle,
|
||||
AudioStream::AudioBuffer { handle, .. } => *handle,
|
||||
};
|
||||
instance_handle == handle
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn is_sound_playing_with_handle(&mut self, handle: SoundHandle) -> bool {
|
||||
STREAMS.with(|streams| {
|
||||
let streams = streams.borrow();
|
||||
streams.iter().any(|(_, instance)| {
|
||||
let instance_handle = match instance {
|
||||
AudioStream::Decoder { handle, .. } => *handle,
|
||||
AudioStream::AudioBuffer { handle, .. } => *handle,
|
||||
};
|
||||
instance_handle == handle
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Janky resmapling code.
|
||||
|
|
Loading…
Reference in New Issue