From ad1b8869eeabfd63ad69082500036f130652dd74 Mon Sep 17 00:00:00 2001 From: "paraxite@naver.com" Date: Thu, 5 Mar 2020 22:26:47 +0900 Subject: [PATCH] * implemented threshold filtering --- README.md | 2 +- src/message.rs | 5 ++- src/sound.rs | 11 +++++++ src/sound/sound_channel.rs | 11 +++++++ src/sound/sound_manager.rs | 67 ++++++++++++++++++++++++++++---------- src/ui.rs | 9 ++++- web/script.js | 16 ++++++++- web/w3.css | 6 +++- 8 files changed, 104 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e55137b..6570ea4 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Example: ``` (.+) cancels (.+): (.*)(Water|water)(.*)\. ``` -This pattern will make soundsense-rs ignore any cancallations related to water. +This pattern will make soundsense-rs ignore any cancellations related to water. The regex pattern uses the [regex crate](https://docs.rs/regex/) syntax. diff --git a/src/message.rs b/src/message.rs index 749c815..040c475 100644 --- a/src/message.rs +++ b/src/message.rs @@ -8,8 +8,11 @@ pub enum SoundMessage { /// 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. + /// "total" is total volume, other values are specific channels. VolumeChange(Box, f32), + /// Change the threshold of a channel. + /// "total" is total threshold, other values are specific channels. + ThresholdChange(Box, u8), /// Skip sound currently played by loop_player SkipCurrentSound(Box), /// Play/Pause channel diff --git a/src/sound.rs b/src/sound.rs index 31c5958..e786f88 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -66,12 +66,15 @@ pub struct SoundFile { #[derive(Clone)] pub struct VolumeLock(Arc>); impl VolumeLock { + #[inline] pub fn new() -> Self { Self(Arc::new(ShardedLock::new(1.0))) } + #[inline] pub fn get(&self) -> f32 { *self.0.read().unwrap() } + #[inline] pub fn set(&self, volume: f32) { *self.0.write().unwrap() = volume; } @@ -80,14 +83,17 @@ impl VolumeLock { #[derive(Clone)] pub struct IsPausedLock(Arc); impl IsPausedLock { + #[inline] pub fn new() -> Self { Self(Arc::new(AtomicBool::new(false))) } + #[inline] pub fn get(&self) -> bool { self.0.load(Ordering::Relaxed) } + #[inline] pub fn flip(&self) -> bool { self.0.fetch_nand(true, Ordering::SeqCst) } @@ -195,6 +201,11 @@ pub fn run(sound_rx: Receiver, ui_tx: Sender) { manager.set_volume(&channel, volume * 0.01)?; } + ThresholdChange(channel,threshold) => { + trace!("Set channel {} threshold to {}", channel, threshold); + manager.set_threshold(&channel, threshold)?; + } + SkipCurrentSound(channel) => { trace!("Skip Current Sound in {}", channel); manager.skip(&channel)?; diff --git a/src/sound/sound_channel.rs b/src/sound/sound_channel.rs index a60bbfc..eab8ff2 100644 --- a/src/sound/sound_channel.rs +++ b/src/sound/sound_channel.rs @@ -15,6 +15,7 @@ pub struct SoundChannel { local_volume: VolumeLock, delay: usize, local_is_paused: IsPausedLock, + threshold: u8, pub play_type: ChannelPlayType, } @@ -49,6 +50,7 @@ impl SoundChannel { } }, local_is_paused, + threshold: 4, } } @@ -152,6 +154,15 @@ impl SoundChannel { self.local_volume.get() } + #[inline] + pub fn set_threshold(&mut self, threshold: u8) { + self.threshold = threshold; + } + #[inline] + pub fn get_threshold(&mut self) -> u8 { + self.threshold + } + #[inline] pub fn len(&self) -> usize { self.one_shots.len() + self.looping.len() diff --git a/src/sound/sound_manager.rs b/src/sound/sound_manager.rs index 5a59387..38bd5d0 100644 --- a/src/sound/sound_manager.rs +++ b/src/sound/sound_manager.rs @@ -22,6 +22,8 @@ pub struct SoundManager { total_volume: VolumeLock, /// Total is_paused. total_is_paused: IsPausedLock, + /// Total playback_treshold + total_threshold: u8, /// Sender for UIMessage sent to the UI. ui_sender: Sender, /// RNG for probability and randomly choosing a soundfile from many. @@ -96,7 +98,7 @@ impl SoundManager { let mut halt_on_match: bool = false; let mut random_balance: bool = false; #[allow(unused_mut)] - let mut playback_threshold: u8 = 5; + let mut playback_threshold: u8 = 4; let files = Vec::new(); let weights = Vec::new(); @@ -288,7 +290,7 @@ impl SoundManager { match attr_value { "singleEager" => play_type = ChannelPlayType::SingleEager, "singleLazy" => play_type = ChannelPlayType::SingleLazy, - "all" => (), + "total" => (), other => { warn!("Unknown Channel PlayType: {}", other); warn!("Will ignore this value."); @@ -338,9 +340,9 @@ impl SoundManager { visit_dir(sound_dir, &mut func)?; // Run the DFS! - // Add the default channels "all" and "music" + // Add the default channels "total" and "music" let mut channel_names: Vec> = vec![ - "all".into(), + "total".into(), "music".into(), ]; for channel_name in channels.keys() { @@ -362,6 +364,7 @@ impl SoundManager { channels, total_volume, total_is_paused, + total_threshold: 4, ui_sender, rng: thread_rng(), }; @@ -413,7 +416,7 @@ impl SoundManager { /// Set the volume of all, or specific channels. pub fn set_volume(&mut self, channel_name: &str, volume: f32) -> Result<()> { - if channel_name == "all" { + if channel_name == "total" { self.total_volume.set(volume); } else if let Some(channel) = self.channels.get_mut(channel_name) { @@ -422,8 +425,18 @@ impl SoundManager { Ok(()) } + pub fn set_threshold(&mut self, channel_name: &str, threshold: u8) -> Result<()> { + if channel_name == "total" { + self.total_threshold = threshold; + } + else if let Some(channel) = self.channels.get_mut(channel_name) { + channel.set_threshold(threshold); + } + Ok(()) + } + pub fn skip(&mut self, channel_name: &str) -> Result<()> { - if channel_name == "all" { + if channel_name == "total" { for (_, channel) in self.channels.iter_mut() { channel.skip(); } @@ -435,7 +448,7 @@ impl SoundManager { } pub fn play_pause(&mut self, channel_name: &str) -> Result<()> { - if channel_name == "all" { + if channel_name == "total" { let is_paused = !self.total_is_paused.flip(); self.ui_sender.send( UIMessage::ChannelWasPlayPaused( @@ -512,6 +525,13 @@ impl SoundManager { trace!(" can't play: failed probability roll"); } } + can_play &= self.total_threshold > sound.playback_threshold; + if !can_play { + trace!( + " can't play: at threshold limit - sound.playback_threshold: {}, total_threshold: {}", + sound.playback_threshold, self.total_threshold + ); + } } else { trace!(" can't play: current_timeout: {}", sound.current_timeout); } @@ -544,8 +564,18 @@ impl SoundManager { continue; }; let chn_len = channel.len(); + let chn_threshold = channel.get_threshold(); // Check if there are too many sounds playing on this channel (concurrency). - if chn_len < sound.concurency.unwrap_or(std::usize::MAX) { + if chn_len >= sound.concurency.unwrap_or(std::usize::MAX) { + trace!(" can't play: at concurency limit: limit {}, channel {}", + sound.concurency.unwrap(), chn_len); + } + // Check if the playback_threshold is higher than the channel threshold. + else if chn_threshold <= sound.playback_threshold { + trace!(" can't play: at threshold limit - sound.playback_threshold: {}, channel_threshold: {}", + sound.playback_threshold, chn_threshold); + } + else { // Set current_timeout if the sound has a timeout value. if let Some(timeout) = sound.timeout { sound.current_timeout = timeout; @@ -571,25 +601,26 @@ impl SoundManager { channel.add_oneshot(device, &files[idx], sound.delay.unwrap_or(0), rng); } } - else { - trace!(" can't play: at concurency limit: limit {}, channel {}", - sound.concurency.unwrap(), chn_len); - } } else if !sound.files.is_empty() { trace!(" channel: misc"); let channel = self.channels.get_mut("misc").unwrap(); let chn_len = channel.len(); - if channel.len() < sound.concurency.unwrap_or(std::usize::MAX) { + let chn_threshold = channel.get_threshold(); + if chn_len >= sound.concurency.unwrap_or(std::usize::MAX) { + trace!(" can't play: at concurency limit - limit {}, channel {}", + sound.concurency.unwrap(), chn_len); + } + else if chn_threshold <= sound.playback_threshold { + trace!(" can't play: at threshold limit - sound.playback_threshold: {}, channel_threshold: {}", + sound.playback_threshold, chn_threshold); + } + else { if let Some(timeout) = sound.timeout { sound.current_timeout = timeout; } channel.add_oneshot(&self.device, &files[idx], sound.delay.unwrap_or(0), rng); } - else { - trace!(" can't play: at concurency limit: limit {}, channel {}", - sound.concurency.unwrap(), chn_len); - } } } @@ -628,7 +659,7 @@ impl SoundManager { .ok_or("Failed to parse .ini file.")? .as_str() .parse()?; - if name == "all" { + if name == "total" { self.total_volume.set(volume / 100.0); } else if let Some(chn) = self.channels.get_mut(name) { diff --git a/src/ui.rs b/src/ui.rs index 4ba74f5..62b7e34 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -178,6 +178,13 @@ r"A sound-engine utility for Dwarf Fortress, written in Rust SoundMessage::VolumeChange(channel_name, channel_volume) ).unwrap(); } + "change_threshold" => { + let channel_name: Box = parts[1].into(); + let channel_threshold: u8 = parts[2].parse().unwrap(); + sound_tx.send( + SoundMessage::ThresholdChange(channel_name, channel_threshold) + ).unwrap(); + } "skip_current_sound" => { let channel_name: Box = parts[1].into(); sound_tx.send( @@ -191,7 +198,7 @@ r"A sound-engine utility for Dwarf Fortress, written in Rust ).unwrap(); } "test_message" => { - trace!("UI test message: {}", parts[1]); + info!("UI test message: {}", parts[1]); } _ => { add_error( diff --git a/web/script.js b/web/script.js index 3e335a5..1d1acae 100644 --- a/web/script.js +++ b/web/script.js @@ -31,8 +31,18 @@ function createSlider(channel_name) { slider.className="w3-cell-row w3-border-bottom"; slider.insertAdjacentHTML( 'afterbegin', - "
"+ + "
"+ + "Threshold
"+ + ""+ + "
"+ "

"+channel_name+"

"+ "
"+ "
"+ @@ -140,6 +150,10 @@ function createError(name, text) { return error; } +function thresholdSelect(channel_name, value) { + external.invoke("change_threshold:"+channel_name+":"+value); +} + function main() { channels = document.getElementById('channels'); is_windows = /MSIE|Trident|Edge/.test(window.navigator.userAgent); diff --git a/web/w3.css b/web/w3.css index 3bb496b..cca17cc 100644 --- a/web/w3.css +++ b/web/w3.css @@ -232,4 +232,8 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0} .w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important} .w3-closebtn{margin-left:15px;color:white;font-weight:bold;float:right;font-size:22px;line-height:20px;cursor:pointer;} -.w3-closebtn:hover{color:black;} \ No newline at end of file +.w3-closebtn:hover{color:black;} + +.overlay-container{position:relative;} +.overlay-content{position:absolute;left:0;top:0;display:none;min-width:100%} +.overlay-container:hover .overlay-content{display:inline-block;} \ No newline at end of file