From c3fcbcd91f1e466acad762f1bd888e188bb77a17 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Fri, 21 Feb 2020 15:28:48 +0900 Subject: [PATCH 01/16] enabled optional logging * added description about the env variables to README.md [ci-build] --- Cargo.lock | 20 ++++++++++---------- README.md | 5 +++++ src/main.rs | 8 +++++--- src/sound.rs | 1 - 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf92a10..f8e6ac9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,9 +327,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.66" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" [[package]] name = "libloading" @@ -352,9 +352,9 @@ dependencies = [ [[package]] name = "mach" -version = "0.2.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ "libc", ] @@ -382,9 +382,9 @@ dependencies = [ [[package]] name = "minimp3" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9943faa16a9729ff85d28857d9e4a4e8ac4f47f82a738184cd28d32a50c2bc38" +checksum = "dce0cff6a0bfd3f8b6b2350819bbddd63bc65cc45e53888bdd0ff49dde16d2d5" dependencies = [ "minimp3-sys", "slice-deque", @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "minimp3-sys" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c109ae05c00ad6e3a53fab101e2f234545bdd010f0fffd399355efaf70817817" +checksum = "e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90" dependencies = [ "cc", ] @@ -599,9 +599,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "slice-deque" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffddf594f5f597f63533d897427a570dbaa9feabaaa06595b74b71b7014507d7" +checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" dependencies = [ "libc", "mach", diff --git a/README.md b/README.md index a9d6b8d..a651911 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ This pattern will make soundsense-rs ignore any cancallations related to water. The regex pattern uses the [regex crate](https://docs.rs/regex/) syntax. +## Logging +You can set the following environment variables to set the logging parameters. (Disabled on Windows releases) +* __SOUNDSENSE_RS_LOG__: set the level of logging. _(trace, debug, info, warn, error; default: warn)_ +* __SOUNDSENSE_RS_LOG_STYLE__: st the level of the log style. _(always, never; default: always)_ + ## Dependencies Linux: libasound2, libgtk-3, libwebkit2gtk-4.0 diff --git a/src/main.rs b/src/main.rs index c6a7500..9d35a91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,15 +5,17 @@ use std::env; use std::sync::mpsc::channel; use std::path::PathBuf; use regex::Regex; -#[macro_use] -extern crate log; +#[macro_use] extern crate log; mod sound; mod ui; mod message; fn main() { - env_logger::init(); + let env = env_logger::Env::default() + .filter_or("SOUNDSENSE_RS_LOG", "warn") + .write_style_or("SOUNDSENSE_RS_LOG_STYLE", "always"); + env_logger::init_from_env(env); info!("Starting SoundSense-RS"); let args: Vec = env::args().collect(); let mut opts = getopts::Options::new(); diff --git a/src/sound.rs b/src/sound.rs index 6c61821..ff27e04 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -80,7 +80,6 @@ pub struct SoundEntry { } pub fn run(sound_rx: Receiver, ui_tx: Sender) { - loop { info!("(Re)Starting sound thread."); let mut manager : Option = None; From 548e6cabf82d3610c6dd56290333999ca954acf9 Mon Sep 17 00:00:00 2001 From: prixt <34859963+prixt@users.noreply.github.com> Date: Fri, 21 Feb 2020 21:40:33 +0900 Subject: [PATCH 02/16] Updated linux dependencies on README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a651911..9b125f9 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ You can set the following environment variables to set the logging parameters. ( * __SOUNDSENSE_RS_LOG_STYLE__: st the level of the log style. _(always, never; default: always)_ ## Dependencies -Linux: libasound2, libgtk-3, libwebkit2gtk-4.0 +__Linux__: libasound2, libgtk-3, libgdk-3, libwebkit2gtk-4.0, libjavascriptcregtk-4.0 ## [MIT License](./LICENSE) From 1c1782bdd5dfc812f69ba86ae7361904b39c896e Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Fri, 21 Feb 2020 22:08:42 +0900 Subject: [PATCH 03/16] removed examples of 'bloat' since, what can be called bloat? --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b125f9..bbe2451 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ My attempt at recreating [SoundSense](http://df.zweistein.cz/soundsense/), a sou ## Why? 1. To see if I could do it. -2. Attempt to create a standalone application that doesn't require bloat (Java VM, C# VM, gtk, etc...). +2. Attempt to create a standalone application that doesn't require bloat. * Ultimately, you should only need one executable, the soundpack folder, and DF. * Recommended soundpack fork: https://github.com/jecowa/soundsensepack From 3a6322f6d9b1477a708e77d023ead17f4a966683 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 03:01:44 +0900 Subject: [PATCH 04/16] make x[[:digit:]]+ pattern repeat previous pattern --- src/sound/sound_manager.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 305d9ed..1216224 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -3,6 +3,7 @@ use super::*; pub struct SoundManager { sounds: Vec, recent: HashSet, + previous_log: String, ignore_list: Vec, device: Device, channels: BTreeMap, SoundChannel>, @@ -251,6 +252,7 @@ impl SoundManager { let mut manager = Self { sounds, recent: HashSet::new(), + previous_log: String::with_capacity(50), ignore_list: Vec::new(), device, channels, @@ -306,6 +308,19 @@ impl SoundManager { #[allow(clippy::cognitive_complexity)] // You flag this functions, but not `SoundManager::new`?! pub fn process_log(&mut self, log: &str) -> Result<()> { trace!("log: {}", log); + let mut log = log; + lazy_static!{ + static ref REPEAT_PATTERN: Regex = Regex::new( + r"x[[:digit:]]+" + ).unwrap(); + } + if REPEAT_PATTERN.is_match(&log) { + log = self.previous_log.as_str(); + trace!(" swapped: {}", log); + } + else { + self.previous_log = log.to_string(); + } for pattern in self.ignore_list.iter() { if pattern.is_match(log) { @@ -319,7 +334,7 @@ impl SoundManager { for (i, sound) in sounds.iter_mut().enumerate() { if sound.pattern.is_match(log) { - trace!("-pattern: {}", sound.pattern.as_str()); + trace!(" pattern: {}", sound.pattern.as_str()); recent.insert(i); sound.recent_call += 1; From 74e0008ef52644abf31c08d6cc663b27d0bd3756 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 08:13:20 +0900 Subject: [PATCH 05/16] tweaked some logging messages --- src/main.rs | 6 +++++- src/sound/sound_channel.rs | 4 ++-- src/sound/sound_channel/loop_player.rs | 8 ++++---- src/sound/sound_manager.rs | 14 +++++++------- src/ui.rs | 6 +++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9d35a91..79186f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,8 +15,12 @@ fn main() { let env = env_logger::Env::default() .filter_or("SOUNDSENSE_RS_LOG", "warn") .write_style_or("SOUNDSENSE_RS_LOG_STYLE", "always"); - env_logger::init_from_env(env); + env_logger::Builder::from_env(env) + .format_module_path(false) + .format_timestamp_millis() + .init(); info!("Starting SoundSense-RS"); + let args: Vec = env::args().collect(); let mut opts = getopts::Options::new(); opts.optopt("l", "gamelog", diff --git a/src/sound/sound_channel.rs b/src/sound/sound_channel.rs index cf617a7..2bf4bed 100644 --- a/src/sound/sound_channel.rs +++ b/src/sound/sound_channel.rs @@ -137,8 +137,8 @@ fn get_source(path: &Path) -> Option> { Some(source) }, Err(e) => { - error!("Error while asserting {}: {}", path.display(), e); - error!("Will ignore this source."); + warn!("Failed to assert {}: {}", path.display(), e); + warn!("Will ignore this source."); None } } diff --git a/src/sound/sound_channel/loop_player.rs b/src/sound/sound_channel/loop_player.rs index 2d1bdae..9149deb 100644 --- a/src/sound/sound_channel/loop_player.rs +++ b/src/sound/sound_channel/loop_player.rs @@ -109,8 +109,8 @@ impl LoopPlayer { let f = match fs::File::open(path) { Ok(f) => f, Err(e) => { - error!("Failed to open file {}\nError: {}", path.display(), e); - error!("Will ignore this file."); + warn!("Failed to open file {}: {}", path.display(), e); + warn!("Will ignore this file."); continue } }; @@ -120,8 +120,8 @@ impl LoopPlayer { self.append_source(source, volume, balance) } Err(e) => { - error!("Error while asserting {}: {}", path.display(), e); - error!("Will ignore this source."); + warn!("Error while asserting {}: {}", path.display(), e); + warn!("Will ignore this source."); } } } diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 1216224..7d5a64e 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -37,8 +37,8 @@ impl SoundManager { } } Err(e) => { - error!("Error while visiting {}: {}", dir.display(), e); - error!("Will ignore this directory."); + warn!("Error while visiting {}: {}", dir.display(), e); + warn!("Will ignore this directory."); } } Ok(()) @@ -116,11 +116,11 @@ impl SoundManager { b"ansiFormat" => (), b"ansiPattern" => (), _ => { - error!( + warn!( "Unknown sound value: {}", unsafe {std::str::from_utf8_unchecked(attr.key)} ); - error!("Will ignore this value."); + warn!("Will ignore this value."); } } } @@ -181,11 +181,11 @@ impl SoundManager { is_playlist = true; } _ => { - error!( + warn!( "Unknown sound value: {}", unsafe {std::str::from_utf8_unchecked(attr.key)} ); - error!("Will ignore this value."); + warn!("Will ignore this value."); } } } @@ -311,7 +311,7 @@ impl SoundManager { let mut log = log; lazy_static!{ static ref REPEAT_PATTERN: Regex = Regex::new( - r"x[[:digit:]]+" + r"^x[0-9]+$" ).unwrap(); } if REPEAT_PATTERN.is_match(&log) { diff --git a/src/ui.rs b/src/ui.rs index 90d29a4..b3d902e 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -83,21 +83,21 @@ A sound-engine utility for Dwarf Fortress, written in Rust } "link_original" => { if let Err(e) = webbrowser::open("http://df.zweistein.cz/soundsense/") { - error!("webbrowser error: {}", e); + warn!("Failed to open link with system's default browser: {}", e); add_error(webview, "Webbrowser Error", "Failed to open link with the system's default browser."); } } "link_fork" => { if let Err(e) = webbrowser::open("https://github.com/jecowa/soundsensepack") { - error!("webbrowser error: {}", e); + warn!("Failed to open link with system's default browser: {}", e); add_error(webview, "Webbrowser Error", "Failed to open link with the system's default browser."); } } "link_source" => { if let Err(e) = webbrowser::open("https://github.com/prixt/soundsense-rs") { - error!("webbrowser error: {}", e); + warn!("Failed to open link with system's default browser: {}", e); add_error(webview, "Webbrowser Error", "Failed to open link with the system's default browser."); } From 6d01fa7baa597f9f0665e2da5dbd12ca9357cf58 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 08:40:30 +0900 Subject: [PATCH 06/16] a few edits & probability fixes --- src/main.rs | 20 ++++++++++---------- src/sound/sound_manager.rs | 11 ++++++----- src/ui.rs | 4 ++-- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index 79186f5..6014e7f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ fn main() { } }; - let conf = if !matches.opt_present("no-config") { + let config = if !matches.opt_present("no-config") { dirs::config_dir() .and_then(|mut p| { p.push("soundsense-rs/default-paths.ini"); @@ -56,10 +56,10 @@ fn main() { if path.is_file() {Some(path)} else {None} }) .or_else(|| - conf.as_ref() - .and_then(|conf_txt| + config.as_ref() + .and_then(|config_txt| Regex::new("gamelog=(.+)").unwrap() - .captures(&conf_txt) + .captures(&config_txt) .and_then(|c| c.get(1)) .map(|m| PathBuf::from(m.as_str())) .filter(|p| p.is_file()) @@ -78,10 +78,10 @@ fn main() { if path.is_dir() {Some(path)} else {None} }) .or_else(|| - conf.as_ref() - .and_then(|conf_txt| + config.as_ref() + .and_then(|config_txt| Regex::new("soundpack=(.+)").unwrap() - .captures(&conf_txt) + .captures(&config_txt) .and_then(|c| c.get(1)) .map(|m| PathBuf::from(m.as_str())) .filter(|p| p.is_dir()) @@ -100,10 +100,10 @@ fn main() { if path.is_file() {Some(path)} else {None} }) .or_else(|| - conf.as_ref() - .and_then(|conf_txt| + config.as_ref() + .and_then(|config_txt| Regex::new("ignore=(.+)").unwrap() - .captures(&conf_txt) + .captures(&config_txt) .and_then(|c| c.get(1)) .map(|m| PathBuf::from(m.as_str())) .filter(|p| p.is_file()) diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 7d5a64e..06c38cc 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -125,10 +125,12 @@ impl SoundManager { } } - trace!(" Sound {{"); + trace!(" Sound"); + let pattern = pattern.expect("SoundEntry must include a regex pattern!"); + trace!("-Pattern:{}", pattern); current_sound = Some( SoundEntry{ - pattern: pattern.unwrap(), + pattern, channel, loop_attr, concurency, @@ -189,7 +191,7 @@ impl SoundManager { } } } - trace!(" SoundFile: {:?}", path); + trace!(" -SoundFile: {:?}", path); let r#type = if is_playlist { let path_vec = parse_playlist(&path)?; SoundFileType::IsPlaylist(path_vec) @@ -216,7 +218,6 @@ impl SoundManager { sounds.push( current_sound.take() .ok_or("Tried to finish a Sound, even though there is no Sound!")? ); - trace!(" }}"); } }, @@ -341,7 +342,7 @@ impl SoundManager { let mut can_play = sound.current_timeout == 0; if can_play { if let Some(probability) = sound.probability { - can_play &= probability >= rng.next_u32() as usize; + can_play &= probability >= rng.gen_range(0usize, 100usize); if !can_play { trace!(" can't play: failed probability roll"); } diff --git a/src/ui.rs b/src/ui.rs index b3d902e..e9689da 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -223,13 +223,13 @@ A sound-engine utility for Dwarf Fortress, written in Rust fn add_slider(webview: &mut WebView<()>, name: &str) { webview.eval( - &format!(r#"addSlider("{channel_name}")"#, channel_name=&name) + &format!(r#"addSlider("{channel_name}")"#, channel_name=name) ).unwrap(); } fn set_slider_value(webview: &mut WebView<()>, name: Box, value: f32) { webview.eval(&format!( r#"setSliderValue("{channel_name}", {value})"#, - channel_name=&name, + channel_name=name, value=value as u32 )).unwrap(); } From 61d171913a60bf1dbbbea50010b08c23e4db5cde Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 08:45:26 +0900 Subject: [PATCH 07/16] improved trace logging message --- src/sound/sound_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 06c38cc..148507c 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -127,7 +127,7 @@ impl SoundManager { trace!(" Sound"); let pattern = pattern.expect("SoundEntry must include a regex pattern!"); - trace!("-Pattern:{}", pattern); + trace!(" -Pattern: {}", pattern); current_sound = Some( SoundEntry{ pattern, @@ -191,7 +191,7 @@ impl SoundManager { } } } - trace!(" -SoundFile: {:?}", path); + trace!(" --SoundFile: {:?}", path); let r#type = if is_playlist { let path_vec = parse_playlist(&path)?; SoundFileType::IsPlaylist(path_vec) From 5d836ea45793e08e26312ab3ae2fa3f94b38707f Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 13:18:22 +0900 Subject: [PATCH 08/16] some changes * html_minifier="=1.1.14", because 1.1.15 panics. * added more error handling in sound_manager * minor tweaks to html and js --- Cargo.lock | 8 ++++---- Cargo.toml | 7 +++++-- build.rs | 10 ++++------ src/sound/sound_manager.rs | 10 +++++++--- web/index.html | 12 +++++++----- web/script.js | 2 +- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42c8060..5578935 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,9 +367,9 @@ checksum = "0e72f7deb758fea9ea7d290aebfa788763d0bffae12caa6406a25baaf8fa68a8" [[package]] name = "memchr" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "minifier" @@ -641,9 +641,9 @@ checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" [[package]] name = "syn" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +checksum = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 959ec12..c149245 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ env_logger = "0.7.1" [build-dependencies] winres = "0.1" -html-minifier = "1.1.14" +html-minifier = "=1.1.14" [profile.dev.package.rodio] debug-assertions = false @@ -39,4 +39,7 @@ incremental = false panic = "abort" [profile.release.build-override] -opt-level = 0 \ No newline at end of file +opt-level = 0 + +[package.metadata.winres] +LegalCopyright = "© 2019-2020 prixt" \ No newline at end of file diff --git a/build.rs b/build.rs index fc79023..3a77902 100644 --- a/build.rs +++ b/build.rs @@ -24,14 +24,12 @@ fn main() -> Result<(), Box> { let index_html = html_minifier::minify(index_html)?; File::create(dest_dir)? - .write_all( index_html.as_bytes() )?; + .write_all(index_html.as_bytes())?; #[cfg(target_os="windows")] - { - let mut res = winres::WindowsResource::new(); - res.set_icon("icons/icon.ico"); - res.compile().unwrap(); - } + winres::WindowsResource::new() + .set_icon("icons/icon.ico") + .compile()?; Ok(()) } \ No newline at end of file diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 148507c..262e752 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -125,8 +125,10 @@ impl SoundManager { } } - trace!(" Sound"); - let pattern = pattern.expect("SoundEntry must include a regex pattern!"); + trace!(" SoundEntry"); + let pattern = pattern.ok_or_else(|| + format!("A SoundEntry in {:?} doesn't have a pattern!", file_path) + )?; trace!(" -Pattern: {}", pattern); current_sound = Some( SoundEntry{ @@ -149,7 +151,9 @@ impl SoundManager { } else if local_name == b"soundFile" { - assert!(current_sound.is_some(), "SoundFile must be declared inside a Sound!"); + current_sound.as_ref().ok_or_else(|| + format!("A SoundFile in {:?} was declared outside of Sound!", file_path) + )?; let mut path = PathBuf::from(file_path); let mut is_playlist = false; let mut weight: f32 = 100.0; diff --git a/web/index.html b/web/index.html index e364a2c..41a5b81 100644 --- a/web/index.html +++ b/web/index.html @@ -1,10 +1,12 @@ - + + +
diff --git a/web/script.js b/web/script.js index aa00d43..7b59196 100644 --- a/web/script.js +++ b/web/script.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; let is_windows = null; let channels = null; From cdb1d9dccae46a5ca40f0567539d6b9558b1914e Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 14:58:29 +0900 Subject: [PATCH 09/16] fixed probability --- src/sound/sound_manager.rs | 2 +- src/ui.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 262e752..1b3cfa7 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -346,7 +346,7 @@ impl SoundManager { let mut can_play = sound.current_timeout == 0; if can_play { if let Some(probability) = sound.probability { - can_play &= probability >= rng.gen_range(0usize, 100usize); + can_play &= probability > rng.gen_range(0usize, 100usize); if !can_play { trace!(" can't play: failed probability roll"); } diff --git a/src/ui.rs b/src/ui.rs index e9689da..7a672c8 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -71,8 +71,7 @@ pub fn run( .info( "About SoundSense-RS", &format!( -r" -A sound-engine utility for Dwarf Fortress, written in Rust +r"A sound-engine utility for Dwarf Fortress, written in Rust Version {} Created by prixt Original SoundSense created by zwei: @@ -141,7 +140,8 @@ A sound-engine utility for Dwarf Fortress, written in Rust add_alert(webview, "set_default_volumes", "green", "💾 Default volumes set."); } "remove_default_paths" => { - let mut conf_path = dirs::config_dir().unwrap(); + let mut conf_path = dirs::config_dir() + .expect("Failed to get configuration directory."); conf_path.push("soundsense-rs"); if conf_path.is_dir() { conf_path.push("default-paths.ini"); @@ -175,6 +175,9 @@ A sound-engine utility for Dwarf Fortress, written in Rust SoundMessage::VolumeChange(channel_name, channel_volume) ).unwrap(); } + else if parts[0] == "test_message" { + trace!("UI test message: {}", parts[1]); + } else { unimplemented!("Unimplemented webview argument: {}", other); } From ecab518f098ce1a33dfc7bda6b80960346de4e04 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 15:58:18 +0900 Subject: [PATCH 10/16] added some documentation --- Cargo.toml | 1 + src/message.rs | 16 ++++++++++++++-- src/sound.rs | 10 +++++++++- src/sound/sound_manager.rs | 38 ++++++++++++++++++++++++-------------- src/ui.rs | 8 ++++++++ 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c149245..2c099df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ build = "build.rs" authors = ["prixt "] edition = "2018" description = "A Rusty SoundSense alternative" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/message.rs b/src/message.rs index 4cbef3d..6b94bdc 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,19 +1,31 @@ +/// Messages sent from the UI thread to the Sound thread. #[non_exhaustive] pub enum SoundMessage { + /// Reload the gamelog with this path. ChangeGamelog(std::path::PathBuf), + /// Reload the soundpack with this path. ChangeSoundpack(std::path::PathBuf), + /// Reload the ignore list with this path. ChangeIgnoreList(std::path::PathBuf), + /// Change the volume of a channel. + /// "all" is total volume, other values are specific channels. VolumeChange(Box, f32), - // SetCurrentPathsAsDefault, + /// Store the current channels volumes to a config file. SetCurrentVolumesAsDefault(std::fs::File), } -#[allow(dead_code)] +/// Message sent from the Sound thread to the UI thread. #[non_exhaustive] pub enum UIMessage { + /// The gamelog finished loading. LoadedGamelog, + /// The soundpack finished loading. + /// Contains the names of the loaded channels. LoadedSoundpack(Vec>), + /// The ignore list finished loading. LoadedIgnoreList, + /// Loaded the default volumes from config. LoadedVolumeSettings(Vec<(Box,f32)>), + /// There was an error in the Sound thread. SoundThreadPanicked(String,String), } \ No newline at end of file diff --git a/src/sound.rs b/src/sound.rs index ff27e04..3eb9ac8 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -32,12 +32,16 @@ lazy_static! { ).unwrap(); } +/// Show if the SoundFile is a single sound, or a playlist of multiple sounds. #[derive(Clone)] pub enum SoundFileType { + /// Contains a single file path. IsPath(PathBuf), + /// Contains multiple file paths. IsPlaylist(Vec) } +/// A struct containing all the information about a SoundFile. #[derive(Clone)] pub struct SoundFile { pub r#type: SoundFileType, // path to audio file with sound. OR list of paths @@ -48,6 +52,8 @@ pub struct SoundFile { pub balance: f32, // adjusts stereo channel, can range for -1 (full left) to 1 (full right). } +/// A thread-safe wrapper around a volume(f32) volume. +/// Intended to be used by LoopPlayers and OneshotPlayers. #[derive(Clone)] pub struct VolumeLock(Arc>); impl VolumeLock { @@ -62,6 +68,7 @@ impl VolumeLock { } } +/// A struct containing all the information about a Sound, such as regex patterns, channel, loopability, etc. pub struct SoundEntry { pub pattern: regex::Regex, // regular expression matching log line pub channel: Option>, // channel on which sound is played. sounds played on channel can be looped/stopped prematurely @@ -79,6 +86,7 @@ pub struct SoundEntry { pub recent_call: usize, } +/// The sound thread function. pub fn run(sound_rx: Receiver, ui_tx: Sender) { loop { info!("(Re)Starting sound thread."); @@ -151,7 +159,7 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { error_message, ) ).unwrap(); - error!("SoundThreadError: {:?}", error); + error!("SoundThreadError:\n{:?}", error); } } } \ No newline at end of file diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 1b3cfa7..53ebc9e 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -1,18 +1,23 @@ use super::*; +/// The struct that parses the log entries. +/// Plays appropriate sounds on appropriate channels; checks for concurrency, delays, and probability; +/// Sends messages to the UI after loading soundpack and ignore list. pub struct SoundManager { - sounds: Vec, - recent: HashSet, - previous_log: String, - ignore_list: Vec, - device: Device, - channels: BTreeMap, SoundChannel>, - total_volume: VolumeLock, - ui_sender: Sender, - rng: ThreadRng, + sounds: Vec, // All the Sounds loaded from the soundpack. + recent: HashSet, // The indices of the recently played Sounds. + previous_log: String, // The previous log message. Replaces `x[0-9]+` messages. + ignore_list: Vec, // The patterns that SoundManager shouldn't process. + device: Device, // The sound device of the system. + channels: BTreeMap, SoundChannel>, // All the channels, sorted alphabetically. + total_volume: VolumeLock, // The total volume. + ui_sender: Sender, // Sender for UIMessage sent to the UI. + rng: ThreadRng, // RNG for probability and randomly choosing a soundfile from many. } impl SoundManager { + /// Create a new manager. + /// A new manager is created every time the user reloads a soundpack. pub fn new(sound_dir: &Path, ui_sender: Sender) -> Result { let total_volume = VolumeLock::new(); let mut sounds = Vec::new(); @@ -24,6 +29,7 @@ impl SoundManager { SoundChannel::new(&device, "misc", total_volume.clone()) ); + // Traverse the soundpack in DFS. Parses XML files. fn visit_dir(dir: &Path, func: &mut dyn FnMut(&Path)->Result<()>) -> Result<()> { trace!("Directory: {:?}", dir); match fs::read_dir(dir) { @@ -44,16 +50,16 @@ impl SoundManager { Ok(()) } + // Parse an XML file. let mut func = |file_path: &Path| -> Result<()> { use quick_xml::{Reader, events::Event}; trace!(" XML: {:?}", file_path); let mut reader = Reader::from_file(file_path)?; - let mut current_sound : Option = None; - let buf = &mut Vec::new(); loop { match reader.read_event(buf) { + // // Ok(Event::Start(ref data)) | Ok(Event::Empty(ref data)) => { let local_name = data.local_name(); if local_name == b"sound" { @@ -217,6 +223,7 @@ impl SoundManager { } }, + // Ok(Event::End(data)) => { if current_sound.is_some() && data.local_name() == b"sound" { sounds.push( current_sound.take() @@ -239,8 +246,9 @@ impl SoundManager { } }; - visit_dir(sound_dir, &mut func)?; + visit_dir(sound_dir, &mut func)?; // Run the DFS! + // Add the default channels "all" and "music" let mut channel_names: Vec> = vec![ "all".into(), "music".into(), @@ -250,6 +258,7 @@ impl SoundManager { channel_names.push(channel_name.clone()); } } + // Add the "misc" channel last, so it comes last in the UI. channel_names.push("misc".into()); ui_sender.send(UIMessage::LoadedSoundpack(channel_names))?; @@ -257,7 +266,7 @@ impl SoundManager { let mut manager = Self { sounds, recent: HashSet::new(), - previous_log: String::with_capacity(50), + previous_log: String::new(), ignore_list: Vec::new(), device, channels, @@ -268,7 +277,7 @@ impl SoundManager { let mut conf_path = dirs::config_dir().ok_or("No configuration directory found!")?; conf_path.push("soundsense-rs/default-volumes.ini"); - if conf_path.is_file() { + if conf_path.is_file() { // Check if there are default volumes. let file = fs::File::open(conf_path)?; manager.get_default_volume(file)?; } @@ -276,6 +285,7 @@ impl SoundManager { Ok(manager) } + /// Tick down timers on recently called SoundEntries. Maintain the channels. pub fn maintain(&mut self, dt: usize) -> Result<()> { { let sounds = &mut self.sounds; diff --git a/src/ui.rs b/src/ui.rs index 7a672c8..6441958 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -5,6 +5,7 @@ use std::io::Write; use web_view::*; use crate::message::{SoundMessage, UIMessage}; +/// The UI thread function. pub fn run( sound_tx: Sender, ui_rx: Receiver, gamelog_path: Option, @@ -190,6 +191,7 @@ r"A sound-engine utility for Dwarf Fortress, written in Rust webview.step().unwrap().unwrap(); + // Keep activating the webview event loop. while let Some(result) = webview.step() { result.unwrap(); for ui_message in ui_rx.try_iter() { @@ -224,11 +226,13 @@ r"A sound-engine utility for Dwarf Fortress, written in Rust } } +/// add a slider for a channel with the give name fn add_slider(webview: &mut WebView<()>, name: &str) { webview.eval( &format!(r#"addSlider("{channel_name}")"#, channel_name=name) ).unwrap(); } +/// set the slider value for the named channel fn set_slider_value(webview: &mut WebView<()>, name: Box, value: f32) { webview.eval(&format!( r#"setSliderValue("{channel_name}", {value})"#, @@ -236,21 +240,25 @@ fn set_slider_value(webview: &mut WebView<()>, name: Box, value: f32) { value=value as u32 )).unwrap(); } +/// remove all sliders fn clear_sliders(webview: &mut WebView<()>) { webview.eval("clearSliders()").unwrap(); } +/// display a notice for the user. fn add_alert(webview: &mut WebView<()>, name: &str, color: &str, text: &str) { webview.eval(&format!( r#"addAlert("{}", "{}", "{}")"#, name, color, text )).unwrap(); } +/// remove a notice if it exists. fn remove_alert(webview: &mut WebView<()>, name: &str) { webview.eval(&format!( r#"removeAlert("{}")"#, name )).unwrap(); } +/// display an error message for the user. fn add_error(webview: &mut WebView<()>, name: &str, text: &str) { webview.eval(&format!( r#"addError("{}", "{}")"#, From 59b72ae47a3f5ae4a033d405a413e484ad273a2d Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 20:41:04 +0900 Subject: [PATCH 11/16] * Added annotations/comments * Set html-minifier to 1.1.9 due to stability concerns. * Changed LoopPlayer so it adds sources to its queue only when there are no sources in the queue. --- Cargo.lock | 8 +-- Cargo.toml | 2 +- src/main.rs | 31 ++++++++++- src/sound.rs | 13 ++++- src/sound/sound_channel.rs | 16 +++++- src/sound/sound_channel/loop_player.rs | 35 ++++++++++-- src/sound/sound_channel/oneshot_player.rs | 14 +++++ src/sound/sound_manager.rs | 66 +++++++++++++++++------ 8 files changed, 157 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5578935..ea993b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,9 +292,9 @@ checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" [[package]] name = "html-minifier" -version = "1.1.14" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4adb165cd7620beaa92a890a16c4e6ae9e790c629e46c80bbfe54c049a7b491f" +checksum = "36b7f88b907af882d529ac5f1d2191e3e78869db20ddace679f4deaac9ca698a" dependencies = [ "minifier", ] @@ -373,9 +373,9 @@ checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "minifier" -version = "0.0.33" +version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70bf0db2475f5e627787da77ca52fe33c294063f49f4134b8bc662eedb5e7332" +checksum = "e981853febba4b086c4464067ac78815231e52c2b6249d28a5c814334a111b0c" dependencies = [ "macro-utils", ] diff --git a/Cargo.toml b/Cargo.toml index 2c099df..b4121cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ env_logger = "0.7.1" [build-dependencies] winres = "0.1" -html-minifier = "=1.1.14" +html-minifier = "=1.1.9" [profile.dev.package.rodio] debug-assertions = false diff --git a/src/main.rs b/src/main.rs index 6014e7f..1469af4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,18 @@ mod sound; mod ui; mod message; +/// How SoundSense-RS works: +/// 1. Dwarf Fortress(&DFHack) writes into gamelog.txt +/// 2. In the Sound thread, every loop, the SoundManager reads the newly written lines. +/// 3. The SoundManager iterates through the SoundEntries, and checks if any of their patterns match. +/// 4. If a pattern matches, play the SoundEntry's SoundFiles on the appropriate SoundChannel. +/// +/// All the while the UI thread handles user input and send SoundMessage to the SoundThread +/// through a Sender, while the Sound thread send UIMessages to the UI through +/// a Sender. + fn main() { + // Setup and initialize the env_logger. let env = env_logger::Env::default() .filter_or("SOUNDSENSE_RS_LOG", "warn") .write_style_or("SOUNDSENSE_RS_LOG_STYLE", "always"); @@ -21,6 +32,7 @@ fn main() { .init(); info!("Starting SoundSense-RS"); + // Setup getopts style argument handling. let args: Vec = env::args().collect(); let mut opts = getopts::Options::new(); opts.optopt("l", "gamelog", @@ -32,15 +44,18 @@ fn main() { .optflag("", "no-config", "Don't read config files on start. Will use the given paths, or soundsense-rs defaults."); + // If there are errors in the arguments, print the usage of SoundSense-RS and quit. let matches = match opts.parse(&args[1..]) { Ok(matches) => matches, Err(e) => { error!("{}", e); - println!("{}", opts.usage("SoundSense-rs")); + println!("{}", opts.usage("SoundSense-RS")); return } }; + // Check if there are config files available. + // If so, read `soundsense-rs/default-paths.ini`. let config = if !matches.opt_present("no-config") { dirs::config_dir() .and_then(|mut p| { @@ -51,10 +66,12 @@ fn main() { let gamelog_path = matches .opt_str("l") + // If a path is given, and is a file, use that as the gamelog. .and_then(|path| { let path = PathBuf::from(path); if path.is_file() {Some(path)} else {None} }) + // Else if config file contains path to the gamelog, use that as the gamelog. .or_else(|| config.as_ref() .and_then(|config_txt| @@ -65,6 +82,8 @@ fn main() { .filter(|p| p.is_file()) ) ) + // Else try to find `gamelog.txt` in the current working directory. + // Otherwise, just return None. .or_else(|| { let mut path = env::current_dir() .expect("Error finding current working directory."); @@ -73,10 +92,12 @@ fn main() { }); let soundpack_path = matches .opt_str("p") + // If a path is given, and is a directory, use that as the soundpack. .and_then(|path| { let path = PathBuf::from(path); if path.is_dir() {Some(path)} else {None} }) + // Else if config file contains path to the soundpack, use that as the soundpack. .or_else(|| config.as_ref() .and_then(|config_txt| @@ -87,6 +108,8 @@ fn main() { .filter(|p| p.is_dir()) ) ) + // Else try to find `soundpack` directory in the current working directory. + // Otherwise, just return None. .or_else(|| { let mut path = env::current_dir() .expect("Error finding current working directory."); @@ -95,10 +118,12 @@ fn main() { }); let ignore_path = matches .opt_str("i") + // If a path is given, and is a file, use that as the ignore list. .and_then(|path| { let path = PathBuf::from(path); if path.is_file() {Some(path)} else {None} }) + // Else if config file contains path to the ignore list, use that as the ignore list. .or_else(|| config.as_ref() .and_then(|config_txt| @@ -109,6 +134,8 @@ fn main() { .filter(|p| p.is_file()) ) ) + // Else try to find `ignore.txt` in the current working directory. + // Otherwise, just return None. .or_else(|| { let mut path = env::current_dir() .expect("Error finding current working directory."); @@ -119,8 +146,10 @@ fn main() { let (sound_tx, sound_rx) = channel(); let (ui_tx, ui_rx) = channel(); + // Build and spawn the Sound thread. std::thread::Builder::new() .name("sound_thread".to_string()) .spawn(move || sound::run(sound_rx, ui_tx)).unwrap(); + // Start the UI thread. ui::run(sound_tx, ui_rx, gamelog_path, soundpack_path, ignore_path); } \ No newline at end of file diff --git a/src/sound.rs b/src/sound.rs index 3eb9ac8..76a5743 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -88,13 +88,21 @@ pub struct SoundEntry { /// The sound thread function. pub fn run(sound_rx: Receiver, ui_tx: Sender) { + // Outer loop. Restarts the inner loop if an error occured, but didn't panic. loop { info!("(Re)Starting sound thread."); + // SoundManager let mut manager : Option = None; + // BufReader for the gamelog. let mut buf_reader : Option> = None; + // Current time for delta time calculation. let mut prev = Instant::now(); + + // Arguably the most front-heavy if statement I ever wrote. if let Err(error) = || -> Result<()> { + // Inner loop. Will return an Error if something wrong happens. loop { + // Read SoundMessages sent from the UI. for message in sound_rx.try_iter() { use SoundMessage::*; match message { @@ -109,6 +117,7 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { manager = Some(SoundManager::new(&path, ui_tx.clone())?); } + // These types of messages require a manager. message => if let Some(manager) = manager.as_mut() { match message { ChangeIgnoreList(path) => { @@ -150,7 +159,9 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { } prev = current; } - }(){ // Arguably the most front-heavy if statement I ever wrote. + }(){// LOOK, A BUTTERFLY! + // If an error occurred and was caugth, send the error message to the UI. + // Return to the outer loop, which will then restart the inner loop. let mut error_message = "The soundthread restarted due to this error:\n".to_string(); error_message.push_str(&error.to_string()); ui_tx.send( diff --git a/src/sound/sound_channel.rs b/src/sound/sound_channel.rs index 2bf4bed..857ead2 100644 --- a/src/sound/sound_channel.rs +++ b/src/sound/sound_channel.rs @@ -1,6 +1,4 @@ use super::*; - -#[allow(unused_imports)] use source::Spatial; mod loop_player; @@ -9,6 +7,8 @@ mod oneshot_player; use loop_player::LoopPlayer; use oneshot_player::OneshotPlayer; +/// Struct responsible for containing currently playing sounds. +/// "music" and "weather" channels can play only one sound at a time. pub struct SoundChannel { looping: LoopPlayer, one_shots: OneshotPlayer, @@ -18,6 +18,7 @@ pub struct SoundChannel { } impl SoundChannel { + /// Create a new SoundChannel. #[inline] pub fn new(device: &Device, name: &str, total_volume: VolumeLock) -> Self { let local_volume = VolumeLock::new(); @@ -30,6 +31,8 @@ impl SoundChannel { } } + /// Maintain this channel. + /// Maintain looping player, tick down delay, cleanup oneshots. pub fn maintain(&mut self, rng: &mut ThreadRng, dt: usize) { let delay = self.delay.saturating_sub(dt); self.delay = delay; @@ -48,6 +51,8 @@ impl SoundChannel { self.looping.maintain(rng); } + /// Change the loop. + /// If "music" or "weather", stop all oneshots. pub fn change_loop(&mut self, device: &Device, files: &[SoundFile], delay: usize, rng: &mut ThreadRng) { self.looping.change_loop(device, files, rng); self.delay = delay; @@ -62,6 +67,9 @@ impl SoundChannel { self.delay = delay; } + /// Play a oneshot. + /// Will make other oneshots 25% quieter. + /// If "music" or "weather", pauses loop and stops other oneshots. pub fn add_oneshot(&mut self, device: &Device, file: &SoundFile, delay: usize, rng: &mut ThreadRng) { if self.only_one_sound { self.looping.pause(); @@ -104,6 +112,8 @@ impl SoundChannel { } } +/// Get a Vector of (source, volume, balance) from a SoundFile. +/// Note that non-playlist files will just return a 1-length Vector. fn get_soundfiles(soundfile: &SoundFile, rng: &mut ThreadRng) -> Vec<(rodio::decoder::Decoder, f32, f32)> { @@ -129,6 +139,8 @@ fn get_soundfiles(soundfile: &SoundFile, rng: &mut ThreadRng) vec![] } +/// Check if the file at the give path is a valid sound source. +/// Otherwise, return a None. fn get_source(path: &Path) -> Option> { let f = fs::File::open(path).expect("Invalid sound source path!"); let source = Decoder::new(f); diff --git a/src/sound/sound_channel/loop_player.rs b/src/sound/sound_channel/loop_player.rs index 9149deb..98b6e96 100644 --- a/src/sound/sound_channel/loop_player.rs +++ b/src/sound/sound_channel/loop_player.rs @@ -1,14 +1,30 @@ use super::*; use std::collections::VecDeque; +/// Struct responsible of playing looping sounds. pub struct LoopPlayer { + /// Atomic reference cell to the SourceQueueInput. + /// Sources are input here to be played. queue_tx: Arc>, + /// Count of how many sources are in the SourceQueue. + queue_count: usize, + /// Whether the loop is stopped. + /// Playing will cause a new source to be played. stopped: Arc, + /// Whether the loop is paused. + /// Playing will resume the source. paused: Arc, + /// LoopPlayer's volume. + /// This is different from local_volume. This is for dynamic volume changes. volume: VolumeLock, + /// Channel's volume. local_volume: VolumeLock, + /// Total volume (SoundManager's volume). total_volume: VolumeLock, + /// Option for Receiver that checks if the current source has finished playing. sleep_until_end: Option>, + /// SoundFile deque. + /// Whenever a source finishes playing, the first file will play, then the deque rotates. files: VecDeque, } impl LoopPlayer { @@ -22,6 +38,7 @@ impl LoopPlayer { play_raw(device, queue_rx); Self { queue_tx, + queue_count: 0, local_volume, total_volume, stopped: Arc::new(AtomicBool::new(false)), @@ -69,11 +86,14 @@ impl LoopPlayer { self.volume.get() } + /// Number of sources currently playing. Will always be 0 or 1. #[inline] pub fn len(&self) -> usize { - (!self.is_paused() && !self.is_stopped() && !self.files.is_empty()) as usize + !(self.is_paused() || self.is_stopped() || self.files.is_empty()) as usize } + /// Change the loop. + /// Replaces the current set of files with another one. pub fn change_loop( &mut self, device: &Device, @@ -93,6 +113,7 @@ impl LoopPlayer { self.append_file(rng); } + /// Gets sound source(s) from the first file path, and append to the SourceQueue. fn append_file(&mut self, rng: &mut ThreadRng) { let file = self.files.front_mut().unwrap(); let files = match &file.r#type { @@ -120,13 +141,14 @@ impl LoopPlayer { self.append_source(source, volume, balance) } Err(e) => { - warn!("Error while asserting {}: {}", path.display(), e); + warn!("Error while decoding {}: {}", path.display(), e); warn!("Will ignore this source."); } } } } + /// Wraps the source with the appropriate control wrappers, then adds it to the queue. fn append_source(&mut self, source: S, source_volume: f32, balance: f32) where S: Source + Send + 'static, @@ -160,9 +182,11 @@ impl LoopPlayer { } } ).convert_samples::(); + // If balance is equal, just append it to queue. if balance == 0.0 { self.sleep_until_end = Some(self.queue_tx.append_with_signal(source)); } + // If not, add a Spatial wrapper around the source, then append it to queue. else { let source = source.buffered(); let source = Spatial::new( @@ -173,8 +197,10 @@ impl LoopPlayer { ); self.sleep_until_end = Some(self.queue_tx.append_with_signal(source)); } + self.queue_count+=1; } + /// Maintain the loop. pub fn maintain(&mut self, rng: &mut ThreadRng) { use std::sync::mpsc::TryRecvError; if self.stopped.load(Ordering::Relaxed) {return} @@ -188,8 +214,11 @@ impl LoopPlayer { } } + /// Triggerd when the current source ends. + /// If there are no more sources in queue, rotated the files deque, and appends the first file. fn on_source_end(&mut self, rng: &mut ThreadRng) { - if !self.files.is_empty() && !self.stopped.load(Ordering::Relaxed) + self.queue_count-=1; + if self.queue_count == 0 && !self.files.is_empty() && !self.stopped.load(Ordering::Relaxed) { self.files.rotate_left(1); self.append_file(rng); diff --git a/src/sound/sound_channel/oneshot_player.rs b/src/sound/sound_channel/oneshot_player.rs index 2925595..0b81242 100644 --- a/src/sound/sound_channel/oneshot_player.rs +++ b/src/sound/sound_channel/oneshot_player.rs @@ -2,16 +2,25 @@ use super::*; +/// Struct responsible for one playing oneshot source. struct Control { + /// This volume is independent from Channel's local_volume and SoundManager's total_volume. volume: VolumeLock, + /// Whether the source is stopped. stopped: AtomicBool, + /// Marker to check whether the sound has stopped playing. count: Arc, } +/// Struct responsible of playing oneshot sounds. pub struct OneshotPlayer { + /// Whether the oneshot player is paused. paused: Arc, + /// Vector of controls, each responsible for a different source. controls: Vec>, + /// Channel's local_volume. local_volume: VolumeLock, + /// SoundManager's total_volume. total_volume: VolumeLock, } @@ -41,6 +50,7 @@ impl OneshotPlayer { self.paused.load(Ordering::Relaxed); } + /// Make all playing sources stop. #[inline] pub fn stop(&self) { for control in self.controls.iter() { @@ -68,6 +78,9 @@ impl OneshotPlayer { self.controls[idx].volume.set(volume); } + /// Add a oneshot source. + /// Generate a control for the source. + /// Wraps the source in appropriate control wraps plays it. pub fn add_source( &mut self, device: &Device, @@ -132,6 +145,7 @@ impl OneshotPlayer { self.controls.push(control); } + /// Remove all controls if stopped, or if the source has finished playing. pub fn maintain(&mut self) { self.controls.retain(|c| !c.stopped.load(Ordering::Relaxed) diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 53ebc9e..12238ab 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -1,18 +1,28 @@ use super::*; /// The struct that parses the log entries. -/// Plays appropriate sounds on appropriate channels; checks for concurrency, delays, and probability; +/// Plays appropriate sounds on appropriate channels; +/// checks for concurrency, delays, and probability; /// Sends messages to the UI after loading soundpack and ignore list. pub struct SoundManager { - sounds: Vec, // All the Sounds loaded from the soundpack. - recent: HashSet, // The indices of the recently played Sounds. - previous_log: String, // The previous log message. Replaces `x[0-9]+` messages. - ignore_list: Vec, // The patterns that SoundManager shouldn't process. - device: Device, // The sound device of the system. - channels: BTreeMap, SoundChannel>, // All the channels, sorted alphabetically. - total_volume: VolumeLock, // The total volume. - ui_sender: Sender, // Sender for UIMessage sent to the UI. - rng: ThreadRng, // RNG for probability and randomly choosing a soundfile from many. + /// All the Sounds loaded from the soundpack. + sounds: Vec, + /// The indices of the recently played Sounds. + recent: HashSet, + /// The previous log message. Replaces `x[0-9]+` messages. + previous_log: String, + /// The patterns that SoundManager shouldn't process. + ignore_list: Vec, + /// The sound device of the system. + device: Device, + /// All the channels, sorted alphabetically. + channels: BTreeMap, SoundChannel>, + /// The total volume. + total_volume: VolumeLock, + /// Sender for UIMessage sent to the UI. + ui_sender: Sender, + /// RNG for probability and randomly choosing a soundfile from many. + rng: ThreadRng, } impl SoundManager { @@ -29,7 +39,7 @@ impl SoundManager { SoundChannel::new(&device, "misc", total_volume.clone()) ); - // Traverse the soundpack in DFS. Parses XML files. + /// Traverse the soundpack in DFS. Parses XML files. fn visit_dir(dir: &Path, func: &mut dyn FnMut(&Path)->Result<()>) -> Result<()> { trace!("Directory: {:?}", dir); match fs::read_dir(dir) { @@ -59,9 +69,10 @@ impl SoundManager { let buf = &mut Vec::new(); loop { match reader.read_event(buf) { - // // + // <...> or <.../> Ok(Event::Start(ref data)) | Ok(Event::Empty(ref data)) => { let local_name = data.local_name(); + // or if local_name == b"sound" { let mut pattern: Option = None; @@ -80,6 +91,7 @@ impl SoundManager { for attr in data.attributes().with_checks(false) { let attr = attr?; + // This value came from an XML file, so it must be utf8. let attr_value = unsafe {std::str::from_utf8_unchecked(&attr.value)}; match attr.key { b"logPattern" => { @@ -155,7 +167,8 @@ impl SoundManager { } ); } - + + // or else if local_name == b"soundFile" { current_sound.as_ref().ok_or_else(|| format!("A SoundFile in {:?} was declared outside of Sound!", file_path) @@ -241,7 +254,7 @@ impl SoundManager { ) }, - _ => () + _ => () // Other Reader::Events aren't used, just ignore them. } } }; @@ -289,7 +302,9 @@ impl SoundManager { pub fn maintain(&mut self, dt: usize) -> Result<()> { { let sounds = &mut self.sounds; - let recent = &mut self.recent; + let recent = &mut self.recent; + // Tick down timeout and recent_call. + // If the timeout == 0, remove from recent list. recent.retain(|&i| { let timeout = sounds[i].current_timeout.saturating_sub(dt); let recent_call = sounds[i].recent_call.saturating_sub(1); @@ -304,6 +319,7 @@ impl SoundManager { Ok(()) } + /// Set the volume of all, or specific channels. pub fn set_volume(&mut self, channel_name: &str, volume: f32) -> Result<()> { if channel_name == "all" { self.total_volume.set(volume); @@ -314,6 +330,7 @@ impl SoundManager { Ok(()) } + /// Reload the ignore list. pub fn set_ignore_list(&mut self, ignore_list: Vec) -> Result<()> { self.ignore_list = ignore_list; self.ui_sender.send(UIMessage::LoadedIgnoreList)?; @@ -321,6 +338,7 @@ impl SoundManager { } #[allow(clippy::cognitive_complexity)] // You flag this functions, but not `SoundManager::new`?! + /// Process one line of log message, and make channels play/pause/stop sounds appropriately. pub fn process_log(&mut self, log: &str) -> Result<()> { trace!("log: {}", log); let mut log = log; @@ -348,6 +366,7 @@ impl SoundManager { let recent = &mut self.recent; for (i, sound) in sounds.iter_mut().enumerate() { + // Activate the Sound if the log matches its pattern. if sound.pattern.is_match(log) { trace!(" pattern: {}", sound.pattern.as_str()); recent.insert(i); @@ -367,6 +386,10 @@ impl SoundManager { if can_play { let files = &sound.files; + // Choose index. + // If there are more than one soundfiles, + // and the sound doesn't loop, choose based on weighted distribution. + // Else, 0. let idx : usize = if files.len() > 1 && !sound.loop_attr.unwrap_or(false) { match WeightedIndex::new(&sound.weights) { Ok(weight) => weight.sample(rng), @@ -379,6 +402,7 @@ impl SoundManager { 0 }; + // Play on a given channel. if let Some(chn) = &sound.channel { trace!(" channel: {}", chn); let channel = if let Some(channel) = self.channels.get_mut(chn) { @@ -388,17 +412,21 @@ impl SoundManager { continue; }; let chn_len = channel.len(); + // Check if there are too many sounds playing on this channel (concurrency). if chn_len < sound.concurency.unwrap_or(std::usize::MAX) { + // Set current_timeout if the sound has a timeout value. if let Some(timeout) = sound.timeout { sound.current_timeout = timeout; } let device = &self.device; + // Check if the sound starts a loop if let Some(is_loop_start) = sound.loop_attr { if is_loop_start { trace!(" loop=start"); channel.change_loop(device, sound.files.as_slice(), sound.delay.unwrap_or(0), rng); } else { + // If loop=stop, add the sound to the oneshot player. trace!(" loop=stop"); channel.stop_loop(sound.delay.unwrap_or(0)); if !sound.files.is_empty() { @@ -406,6 +434,7 @@ impl SoundManager { } } } + // Otherwise, add to oneshot player. else if !sound.files.is_empty() && channel.len() <= sound.concurency.unwrap_or(std::usize::MAX) { channel.add_oneshot(device, &files[idx], sound.delay.unwrap_or(0), rng); } @@ -440,6 +469,7 @@ impl SoundManager { Ok(()) } + /// Write the current slider values into the soundsense-rs/default-volumes.ini file. pub fn set_current_volumes_as_default(&self, mut file: File) -> Result<()> { use std::io::Write; writeln!(&mut file, "all={}", (self.total_volume.get()*100.0) as u32)?; @@ -449,6 +479,7 @@ impl SoundManager { Ok(()) } + /// Get the volume from the soundsense-rs/default-volumes.ini file. fn get_default_volume(&mut self, mut file: File) -> Result<()> { lazy_static! { static ref INI_ENTRY: Regex = Regex::new("([[:word:]]+)=(.+)").unwrap(); @@ -474,18 +505,22 @@ impl SoundManager { entries.push((name.to_string().into_boxed_str(), volume)); } } + // Tell the UI to change the slider values. self.ui_sender .send(UIMessage::LoadedVolumeSettings(entries))?; Ok(()) } } +/// Convert a playlist into a list or file paths. fn parse_playlist(path: &Path) -> Result> { let parent_path = path.parent().unwrap(); let mut path_vec = Vec::new(); let f = File::open(path)?; let f = BufReader::new(f); + // Check if the path contains the m3u or pls extension. + // Else, error out. let extension = path.extension() .filter(|ext| *ext=="m3u" || *ext=="pls") .ok_or_else(|| format!( @@ -493,7 +528,6 @@ fn parse_playlist(path: &Path) -> Result> { path ))?; if extension == "m3u" { - // f.read_to_string(buf)?; for line in f.lines() .filter_map(|l| l.ok()) { From 1ba24c41e0e3069939fd92a7e9b4dd121a00c034 Mon Sep 17 00:00:00 2001 From: prixt <34859963+prixt@users.noreply.github.com> Date: Sat, 22 Feb 2020 21:05:15 +0900 Subject: [PATCH 12/16] Update sound.rs Added more annotations. --- src/sound.rs | 57 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/sound.rs b/src/sound.rs index 76a5743..4070f56 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -44,12 +44,18 @@ pub enum SoundFileType { /// A struct containing all the information about a SoundFile. #[derive(Clone)] pub struct SoundFile { - pub r#type: SoundFileType, // path to audio file with sound. OR list of paths - pub weight: f32, // controls likelihood of sound to be chosen. Default is 100. - pub volume: f32, // adjusts volume of sample. Can range from -40 to +6 decibles, default 0. - pub random_balance: bool, // if set to true will randomply distribute sound between stereo channels. - pub delay: usize, // number, delay before sound is played. In miliseconds, default 0. - pub balance: f32, // adjusts stereo channel, can range for -1 (full left) to 1 (full right). + /// Path to audio file with sound. OR list of paths + pub r#type: SoundFileType, + /// Controls likelihood of sound to be chosen. Default is 100. + pub weight: f32, + /// Adjusts volume of sample. Can range from -40 to +6 decibles, default 0. + pub volume: f32, + /// If set to true will randomply distribute sound between stereo channels. + pub random_balance: bool, + /// number, delay before sound is played. In miliseconds, default 0. + pub delay: usize, + /// Adjusts stereo channel, can range for -1 (full left) to 1 (full right). + pub balance: f32, } /// A thread-safe wrapper around a volume(f32) volume. @@ -70,19 +76,36 @@ impl VolumeLock { /// A struct containing all the information about a Sound, such as regex patterns, channel, loopability, etc. pub struct SoundEntry { - pub pattern: regex::Regex, // regular expression matching log line - pub channel: Option>, // channel on which sound is played. sounds played on channel can be looped/stopped prematurely - pub loop_attr: Option, // "start" - sound start loop on channel until different sound is played on channel (if it is non-looped sound, loop will resume when it is done playing) or sound with "stop" is triggered. - pub concurency: Option, // number of councured sounds allowed to be played besides this sound. If currenty playing more than that, sound is ignored. In miliseconds, default unlimited. - pub timeout: Option, // number, timeout during which is sound going to be prevented from playing again. In miliseconds default 0. - pub probability: Option, // percentage, Propablity that sound will be played. Default is always played. - pub delay: Option, // number, delay before sound is played. In miliseconds, default 0. - pub halt_on_match: bool, // boolean, if set to true, sound sense will stop processing long line after it was matched to this sound. Default false - pub random_balance: bool, // boolean, if set to true will randomply distribute sound betweem stereo channels. + /// regular expression matching log line + pub pattern: regex::Regex, + /// channel on which sound is played. sounds played on channel can be looped/stopped prematurely + pub channel: Option>, + /// "start" - sound start loop on channel until different sound is played on channel + /// (if it is non-looped sound, loop will resume when it is done playing) or sound with "stop" is triggered. + pub loop_attr: Option, + /// number of councured sounds allowed to be played besides this sound. + /// If currenty playing more than that, sound is ignored. In miliseconds, default unlimited. + pub concurency: Option, + /// number, timeout during which is sound going to be prevented from playing again. In miliseconds default 0. + pub timeout: Option, + /// percentage, Propablity that sound will be played. Default is always played. + pub probability: Option, + /// number, delay before sound is played. In miliseconds, default 0. + pub delay: Option, + /// boolean, if set to true, sound sense will stop processing long line after it was matched to this sound. + /// Default false + pub halt_on_match: bool, + /// boolean, if set to true will randomply distribute sound betweem stereo channels. + pub random_balance: bool, + /// number, threashold used when filtering sound depending on level (currently not used) pub playback_threshold: u8, + /// Collection of SoundFiles pub files: Vec, + /// Collection of each SoundFile's weight. pub weights: Vec, + /// Timeout. While timeout, can't be played. pub current_timeout: usize, + /// Number of times this SoundEntry has been called. pub recent_call: usize, } @@ -160,7 +183,7 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { prev = current; } }(){// LOOK, A BUTTERFLY! - // If an error occurred and was caugth, send the error message to the UI. + // If an error occurred and was caught, send the error message to the UI. // Return to the outer loop, which will then restart the inner loop. let mut error_message = "The soundthread restarted due to this error:\n".to_string(); error_message.push_str(&error.to_string()); @@ -173,4 +196,4 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { error!("SoundThreadError:\n{:?}", error); } } -} \ No newline at end of file +} From 4a24f0f8e272b21d1b432071b3f59dc7f6798ecb Mon Sep 17 00:00:00 2001 From: prixt <34859963+prixt@users.noreply.github.com> Date: Sat, 22 Feb 2020 21:06:09 +0900 Subject: [PATCH 13/16] Update main.rs fixed typo --- src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1469af4..c93d415 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,8 +17,8 @@ mod message; /// 3. The SoundManager iterates through the SoundEntries, and checks if any of their patterns match. /// 4. If a pattern matches, play the SoundEntry's SoundFiles on the appropriate SoundChannel. /// -/// All the while the UI thread handles user input and send SoundMessage to the SoundThread -/// through a Sender, while the Sound thread send UIMessages to the UI through +/// All the while the UI thread handles user input and sends SoundMessage to the SoundThread +/// through a Sender, while the Sound thread sends UIMessages to the UI through /// a Sender. fn main() { @@ -152,4 +152,4 @@ fn main() { .spawn(move || sound::run(sound_rx, ui_tx)).unwrap(); // Start the UI thread. ui::run(sound_tx, ui_rx, gamelog_path, soundpack_path, ignore_path); -} \ No newline at end of file +} From 88328d0f0a57b0a2dc79be28c22f35027776d467 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 21:30:11 +0900 Subject: [PATCH 14/16] turns out, that was queue_cout was unnecessary! [ci-build] --- src/sound/sound_channel/loop_player.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/sound/sound_channel/loop_player.rs b/src/sound/sound_channel/loop_player.rs index 98b6e96..d142699 100644 --- a/src/sound/sound_channel/loop_player.rs +++ b/src/sound/sound_channel/loop_player.rs @@ -6,8 +6,6 @@ pub struct LoopPlayer { /// Atomic reference cell to the SourceQueueInput. /// Sources are input here to be played. queue_tx: Arc>, - /// Count of how many sources are in the SourceQueue. - queue_count: usize, /// Whether the loop is stopped. /// Playing will cause a new source to be played. stopped: Arc, @@ -38,7 +36,6 @@ impl LoopPlayer { play_raw(device, queue_rx); Self { queue_tx, - queue_count: 0, local_volume, total_volume, stopped: Arc::new(AtomicBool::new(false)), @@ -197,7 +194,6 @@ impl LoopPlayer { ); self.sleep_until_end = Some(self.queue_tx.append_with_signal(source)); } - self.queue_count+=1; } /// Maintain the loop. @@ -217,8 +213,7 @@ impl LoopPlayer { /// Triggerd when the current source ends. /// If there are no more sources in queue, rotated the files deque, and appends the first file. fn on_source_end(&mut self, rng: &mut ThreadRng) { - self.queue_count-=1; - if self.queue_count == 0 && !self.files.is_empty() && !self.stopped.load(Ordering::Relaxed) + if !self.files.is_empty() && !self.stopped.load(Ordering::Relaxed) { self.files.rotate_left(1); self.append_file(rng); From 7f0490d3e9a3b1b141e799a217743e5fab36aa33 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Sat, 22 Feb 2020 21:31:38 +0900 Subject: [PATCH 15/16] ticked version in manifest [ci-build] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b4121cc..a3010b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "soundsense-rs" -version = "1.4.5" +version = "1.4.6" build = "build.rs" authors = ["prixt "] edition = "2018" From aaa2f8c5956c85de3403d59489ceaa5f5f26790b Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Thu, 27 Feb 2020 15:41:37 +0900 Subject: [PATCH 16/16] sleep the sound thread for 10ms every loop [ci-build] --- Cargo.lock | 40 +++++++++++++++++----------------------- Cargo.toml | 2 +- src/sound.rs | 1 + 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea993b4..e3cab3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +checksum = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" dependencies = [ "memchr", ] @@ -42,12 +42,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - [[package]] name = "autocfg" version = "1.0.0" @@ -205,11 +199,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 0.1.7", + "autocfg", "cfg-if", "lazy_static", ] @@ -277,9 +271,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hermit-abi" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67" +checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" dependencies = [ "libc", ] @@ -292,9 +286,9 @@ checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" [[package]] name = "html-minifier" -version = "1.1.9" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b7f88b907af882d529ac5f1d2191e3e78869db20ddace679f4deaac9ca698a" +checksum = "8629f665999d91b6192a3fc085b6966db540c844fb73483bcd43b2313368aac2" dependencies = [ "minifier", ] @@ -373,9 +367,9 @@ checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "minifier" -version = "0.0.31" +version = "0.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e981853febba4b086c4464067ac78815231e52c2b6249d28a5c814334a111b0c" +checksum = "1152a0a768a747fd88f25b1d47d28b9450e11df8ebdcaadea4cc55d9c0e79673" dependencies = [ "macro-utils", ] @@ -415,7 +409,7 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" dependencies = [ - "autocfg 1.0.0", + "autocfg", ] [[package]] @@ -447,9 +441,9 @@ checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" dependencies = [ "unicode-xid", ] @@ -616,7 +610,7 @@ checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" [[package]] name = "soundsense-rs" -version = "1.4.5" +version = "1.4.6" dependencies = [ "dirs", "env_logger", @@ -641,9 +635,9 @@ checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" [[package]] name = "syn" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" +checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index a3010b9..69a2a61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ env_logger = "0.7.1" [build-dependencies] winres = "0.1" -html-minifier = "=1.1.9" +html-minifier = "1.1.16" [profile.dev.package.rodio] debug-assertions = false diff --git a/src/sound.rs b/src/sound.rs index 4070f56..53e56e7 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -181,6 +181,7 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { } } prev = current; + std::thread::sleep(std::time::Duration::from_millis(10)); } }(){// LOOK, A BUTTERFLY! // If an error occurred and was caught, send the error message to the UI.