mirror of
https://github.com/lisk77/comet.git
synced 2025-12-12 09:08:49 +00:00
feat(sound): added a simple sound player to the engine with api in the App struct and a component to store metadata
This commit is contained in:
parent
dfdffed745
commit
dab38c1e32
8 changed files with 203 additions and 4 deletions
|
|
@ -11,6 +11,7 @@ comet_colors = { path = "../comet_colors" }
|
||||||
comet_log = { path = "../comet_log" }
|
comet_log = { path = "../comet_log" }
|
||||||
comet_input = { path = "../comet_input" }
|
comet_input = { path = "../comet_input" }
|
||||||
comet_structs = { path = "../comet_structs" }
|
comet_structs = { path = "../comet_structs" }
|
||||||
|
comet_sound = { path = "../comet_sound" }
|
||||||
|
|
||||||
winit = { version = "0.29", features = ["rwh_05"] }
|
winit = { version = "0.29", features = ["rwh_05"] }
|
||||||
pollster = "0.3"
|
pollster = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use comet_ecs::{Camera2D, Component, Entity, Render2D, Scene, Text, Transform2D,
|
||||||
use comet_input::keyboard::Key;
|
use comet_input::keyboard::Key;
|
||||||
use comet_log::*;
|
use comet_log::*;
|
||||||
use comet_renderer::renderer::Renderer;
|
use comet_renderer::renderer::Renderer;
|
||||||
|
use comet_sound::*;
|
||||||
use std::any::{type_name, Any, TypeId};
|
use std::any::{type_name, Any, TypeId};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::LogicalSize;
|
||||||
|
|
@ -30,6 +31,7 @@ pub struct App {
|
||||||
delta_time: f32,
|
delta_time: f32,
|
||||||
update_timer: f32,
|
update_timer: f32,
|
||||||
game_state: Option<Box<dyn Any>>,
|
game_state: Option<Box<dyn Any>>,
|
||||||
|
audio: Box<dyn Audio>,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
should_quit: bool,
|
should_quit: bool,
|
||||||
|
|
@ -47,6 +49,7 @@ impl App {
|
||||||
delta_time: 0.0,
|
delta_time: 0.0,
|
||||||
update_timer: 0.0166667,
|
update_timer: 0.0166667,
|
||||||
game_state: None,
|
game_state: None,
|
||||||
|
audio: Box::new(KiraAudio::new()),
|
||||||
scene: Scene::new(),
|
scene: Scene::new(),
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
|
|
@ -246,6 +249,38 @@ impl App {
|
||||||
self.scene.has_prefab(name)
|
self.scene.has_prefab(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_audio(&mut self, name: &str, path: &str) {
|
||||||
|
self.audio.load(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_audio(&mut self, name: &str, looped: bool) {
|
||||||
|
self.audio.play(name, looped);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pause_audio(&mut self, name: &str) {
|
||||||
|
self.audio.pause(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_audio(&mut self, name: &str) {
|
||||||
|
self.audio.stop(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_all_audio(&mut self) {
|
||||||
|
self.audio.stop_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_audio(&mut self, dt: f32) {
|
||||||
|
self.audio.update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_playing(&self, name: &str) -> bool {
|
||||||
|
self.audio.is_playing(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_volume(&mut self, name: &str, volume: f32) {
|
||||||
|
self.audio.set_volume(name, volume);
|
||||||
|
}
|
||||||
|
|
||||||
/// Stops the event loop and with that quits the `App`.
|
/// Stops the event loop and with that quits the `App`.
|
||||||
pub fn quit(&mut self) {
|
pub fn quit(&mut self) {
|
||||||
self.should_quit = true;
|
self.should_quit = true;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// You can use these components as is or as a reference to create your own components
|
// You can use these components as is or as a reference to create your own components
|
||||||
// Also just as a nomenclature: bundles are a component made up of multiple components,
|
// Also just as a nomenclature: bundles are a component made up of multiple components,
|
||||||
// so it's a collection of components bundled together (like Transform2D)
|
// so it's a collection of components bundled together (like Transform2D)
|
||||||
|
// They are intended to work with the base suite of systems provided by the engine.
|
||||||
use crate::math::{v2, v3};
|
use crate::math::{v2, v3};
|
||||||
use crate::{Entity, Scene};
|
use crate::{Entity, Scene};
|
||||||
use comet_colors::Color as ColorTrait;
|
use comet_colors::Color as ColorTrait;
|
||||||
|
|
@ -78,6 +79,15 @@ pub struct Timer {
|
||||||
done: bool,
|
done: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct AudioSource {
|
||||||
|
name: &'static str,
|
||||||
|
path: Option<&'static str>,
|
||||||
|
looped: bool,
|
||||||
|
volume: f32,
|
||||||
|
pitch: f32,
|
||||||
|
}
|
||||||
|
|
||||||
// ##################################################
|
// ##################################################
|
||||||
// # BUNDLES #
|
// # BUNDLES #
|
||||||
// ##################################################
|
// ##################################################
|
||||||
|
|
@ -271,6 +281,14 @@ impl Render2D {
|
||||||
scale: v2::new(1.0, 1.0),
|
scale: v2::new(1.0, 1.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self) -> v2 {
|
||||||
|
self.scale
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scale(&mut self, scale: v2) {
|
||||||
|
self.scale = scale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Render2D {
|
impl Render for Render2D {
|
||||||
|
|
@ -548,3 +566,47 @@ impl Timer {
|
||||||
self.done = false;
|
self.done = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AudioSource {
|
||||||
|
pub fn new(name: &'static str, path: Option<&'static str>) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
path,
|
||||||
|
looped: false,
|
||||||
|
volume: 1.0,
|
||||||
|
pitch: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> Option<&str> {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn looped(&self) -> bool {
|
||||||
|
self.looped
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn volume(&self) -> f32 {
|
||||||
|
self.volume
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pitch(&self) -> f32 {
|
||||||
|
self.pitch
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_looped(&mut self, looped: bool) {
|
||||||
|
self.looped = looped;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_volume(&mut self, volume: f32) {
|
||||||
|
self.volume = volume.clamp(0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pitch(&mut self, pitch: f32) {
|
||||||
|
self.pitch = pitch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rodio = "0.12.0"
|
kira = "0.10.8"
|
||||||
|
|
|
||||||
13
crates/comet_sound/src/audio.rs
Normal file
13
crates/comet_sound/src/audio.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
pub trait Audio {
|
||||||
|
fn new() -> Self
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
fn load(&mut self, name: &str, path: &str);
|
||||||
|
fn play(&mut self, name: &str, looped: bool);
|
||||||
|
fn pause(&mut self, name: &str);
|
||||||
|
fn stop(&mut self, name: &str);
|
||||||
|
fn stop_all(&mut self);
|
||||||
|
fn update(&mut self, dt: f32);
|
||||||
|
fn is_playing(&self, name: &str) -> bool;
|
||||||
|
fn set_volume(&mut self, name: &str, volume: f32);
|
||||||
|
}
|
||||||
86
crates/comet_sound/src/kira.rs
Normal file
86
crates/comet_sound/src/kira.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
use crate::audio::Audio;
|
||||||
|
use kira::{
|
||||||
|
sound::static_sound::{StaticSoundData, StaticSoundHandle, StaticSoundSettings},
|
||||||
|
AudioManager, AudioManagerSettings, Decibels, Tween,
|
||||||
|
};
|
||||||
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
|
pub struct KiraAudio {
|
||||||
|
manager: AudioManager,
|
||||||
|
sounds: HashMap<String, StaticSoundData>,
|
||||||
|
handles: HashMap<String, StaticSoundHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KiraAudio {
|
||||||
|
fn load_sound(path: &Path) -> Option<StaticSoundData> {
|
||||||
|
StaticSoundData::from_file(path).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Audio for KiraAudio {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
manager: AudioManager::new(AudioManagerSettings::default()).unwrap(),
|
||||||
|
sounds: HashMap::new(),
|
||||||
|
handles: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&mut self, name: &str, path: &str) {
|
||||||
|
if let Some(sound) = Self::load_sound(Path::new(path)) {
|
||||||
|
self.sounds.insert(name.to_string(), sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play(&mut self, name: &str, looped: bool) {
|
||||||
|
if let Some(sound) = self.sounds.get(name) {
|
||||||
|
let mut settings = StaticSoundSettings::default();
|
||||||
|
|
||||||
|
if looped {
|
||||||
|
settings = settings.loop_region(..);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(handle) = self.manager.play(sound.clone().with_settings(settings)) {
|
||||||
|
self.handles.insert(name.to_string(), handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pause(&mut self, name: &str) {
|
||||||
|
if let Some(handle) = self.handles.get_mut(name) {
|
||||||
|
handle.pause(Tween::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&mut self, name: &str) {
|
||||||
|
if let Some(handle) = self.handles.get_mut(name) {
|
||||||
|
handle.stop(Tween::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_all(&mut self) {
|
||||||
|
for handle in self.handles.values_mut() {
|
||||||
|
handle.stop(Tween::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// KiraAudio needs no updating function, it just exists to make the trait happy
|
||||||
|
fn update(&mut self, _dt: f32) {}
|
||||||
|
|
||||||
|
fn is_playing(&self, name: &str) -> bool {
|
||||||
|
self.handles.contains_key(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_volume(&mut self, name: &str, volume: f32) {
|
||||||
|
let vol = volume.clamp(0.0, 1.0);
|
||||||
|
let db = if vol == 0.0 {
|
||||||
|
Decibels::from(-80.0) // effectively silent
|
||||||
|
} else {
|
||||||
|
Decibels::from(20.0 * vol.log10())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(handle) = self.handles.get_mut(name) {
|
||||||
|
handle.set_volume(db, Tween::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
crates/comet_sound/src/lib.rs
Normal file
5
crates/comet_sound/src/lib.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod audio;
|
||||||
|
mod kira;
|
||||||
|
|
||||||
|
pub use audio::Audio;
|
||||||
|
pub use kira::KiraAudio;
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue