Skip to content

Commit

Permalink
* added skip function
Browse files Browse the repository at this point in the history
* changed channel implementation to crossbeam
  • Loading branch information
prixt committed Mar 5, 2020
1 parent 7b7fc77 commit bbb9649
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 112 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ jobs:
if: runner.os == 'Windows'
uses: actions/upload-artifact@v1
with:
name: soundsense-rs-${{runner.os}}.exe
name: soundsense-rs-${{runner.os}}
path: target/release/soundsense-rs.exe
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.vscode
/target
**/*.rs.bk
/soundpack
Expand Down
108 changes: 107 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "soundsense-rs"
version = "1.4.7"
version = "1.5.0"
build = "build.rs"
authors = ["prixt <[email protected]>"]
edition = "2018"
Expand All @@ -18,6 +18,7 @@ rodio = {git="https://github.com/RustAudio/rodio", rev="2c7d1716707876aad450949f
quick-xml = "0.17"
rand = "0.7"
lazy_static = "1.4"
crossbeam = "0.7.3"
web-view = "0.6"
getopts = "0.2"
webbrowser = "0.5.2"
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
#![cfg_attr(debug_assertions, windows_subsystem = "console")]

use std::env;
use std::sync::mpsc::channel;
use std::path::PathBuf;
use regex::Regex;
#[macro_use] extern crate log;
use crossbeam::channel::unbounded as channel;

mod sound;
mod ui;
Expand Down
2 changes: 2 additions & 0 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub enum SoundMessage {
/// Change the volume of a channel.
/// "all" is total volume, other values are specific channels.
VolumeChange(Box<str>, f32),
/// Skip sound currently played by loop_player
SkipCurrentSound(Box<str>),
/// Store the current channels volumes to a config file.
SetCurrentVolumesAsDefault(std::fs::File),
}
Expand Down
15 changes: 11 additions & 4 deletions src/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ use std::io::{Read, Seek, SeekFrom, BufReader, BufRead};
use std::path::{Path, PathBuf};
use std::collections::{BTreeMap, HashSet};
use std::sync::{
Arc, RwLock,
mpsc::{Sender, Receiver},
Arc,
atomic::{AtomicBool, AtomicUsize, Ordering}
};
use std::error::Error;

use crate::message::*;
use crossbeam::{
sync::ShardedLock,
channel::{Sender, Receiver}
};
use rodio::*;
use rand::prelude::*;
use rand::distributions::weighted::WeightedIndex;
Expand Down Expand Up @@ -61,10 +64,10 @@ pub struct SoundFile {
/// A thread-safe wrapper around a volume(f32) volume.
/// Intended to be used by LoopPlayers and OneshotPlayers.
#[derive(Clone)]
pub struct VolumeLock(Arc<RwLock<f32>>);
pub struct VolumeLock(Arc<ShardedLock<f32>>);
impl VolumeLock {
pub fn new() -> Self {
Self(Arc::new(RwLock::new(1.0)))
Self(Arc::new(ShardedLock::new(1.0)))
}
pub fn get(&self) -> f32 {
*self.0.read().unwrap()
Expand Down Expand Up @@ -159,6 +162,10 @@ pub fn run(sound_rx: Receiver<SoundMessage>, ui_tx: Sender<UIMessage>) {
manager.set_volume(&channel, volume * 0.01)?;
}

SkipCurrentSound(channel) => {
manager.skip(&channel)?;
}

SetCurrentVolumesAsDefault(file) => {
manager.set_current_volumes_as_default(file)?;
}
Expand Down
39 changes: 34 additions & 5 deletions src/sound/sound_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,23 @@ mod oneshot_player;
use loop_player::LoopPlayer;
use oneshot_player::OneshotPlayer;

#[allow(dead_code)]
#[non_exhaustive]
#[derive(PartialEq)]
enum ChannelPlayType {
All,
SingleEager,
SingleLazy,
}

/// 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,
local_volume: VolumeLock,
delay: usize,
only_one_sound: bool,
play_type: ChannelPlayType,
}

impl SoundChannel {
Expand All @@ -27,7 +36,14 @@ impl SoundChannel {
one_shots : OneshotPlayer::new(local_volume.clone(), total_volume),
local_volume,
delay : 0,
only_one_sound: name == "weather" || name == "music",
play_type: {
if name == "weather" || name == "music" {
ChannelPlayType::SingleEager
}
else {
ChannelPlayType::All
}
}
}
}

Expand Down Expand Up @@ -57,7 +73,7 @@ impl SoundChannel {
self.looping.change_loop(device, files, rng);
self.delay = delay;
self.maintain(rng, 0);
if self.only_one_sound {
if self.play_type == ChannelPlayType::SingleEager {
self.one_shots.stop();
}
}
Expand All @@ -67,11 +83,17 @@ impl SoundChannel {
self.delay = delay;
}

pub fn skip(&mut self) {
if self.looping.len() != 0 {
self.looping.skip();
}
}

/// 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 {
if self.play_type == ChannelPlayType::SingleEager {
self.looping.pause();
self.one_shots.stop();
}
Expand Down Expand Up @@ -142,7 +164,14 @@ fn get_soundfiles(soundfile: &SoundFile, rng: &mut ThreadRng)
/// Check if the file at the give path is a valid sound source.
/// Otherwise, return a None.
fn get_source(path: &Path) -> Option<rodio::decoder::Decoder<std::fs::File>> {
let f = fs::File::open(path).expect("Invalid sound source path!");
let f = match fs::File::open(path) {
Ok(f) => f,
Err(e) => {
warn!("Path {} is invalid: {}", path.display(), e);
warn!("Will ignore this source.");
return None
}
};
let source = Decoder::new(f);
match source {
Ok(source) => {
Expand Down
15 changes: 13 additions & 2 deletions src/sound/sound_channel/loop_player.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use std::sync::mpsc::Receiver;
use std::collections::VecDeque;

/// Struct responsible of playing looping sounds.
Expand All @@ -12,6 +13,8 @@ pub struct LoopPlayer {
/// Whether the loop is paused.
/// Playing will resume the source.
paused: Arc<AtomicBool>,
/// Whether current playing sound should be skipped.
skipped: Arc<AtomicBool>,
/// LoopPlayer's volume.
/// This is different from local_volume. This is for dynamic volume changes.
volume: VolumeLock,
Expand Down Expand Up @@ -40,6 +43,7 @@ impl LoopPlayer {
total_volume,
stopped: Arc::new(AtomicBool::new(false)),
paused: Arc::new(AtomicBool::new(false)),
skipped: Arc::new(AtomicBool::new(false)),
volume: VolumeLock::new(),
sleep_until_end: None,
files: VecDeque::new(),
Expand Down Expand Up @@ -72,6 +76,11 @@ impl LoopPlayer {
self.stopped.load(Ordering::Relaxed)
}

#[inline]
pub fn skip(&self) {
self.skipped.store(true, Ordering::SeqCst);
}

#[inline]
pub fn set_volume(&self, volume: f32) {
self.volume.set(volume);
Expand Down Expand Up @@ -155,6 +164,7 @@ impl LoopPlayer {
{
let stopped = self.stopped.clone();
let paused = self.paused.clone();
let skipped = self.skipped.clone();
let volume = self.volume.clone();
let local_volume = self.local_volume.clone();
let total_volume = self.total_volume.clone();
Expand All @@ -164,7 +174,8 @@ impl LoopPlayer {
.stoppable()
.periodic_access(Duration::from_millis(5),
move |src| {
if stopped.load(Ordering::SeqCst) {
if stopped.load(Ordering::Relaxed)
|| skipped.swap(false, Ordering::Relaxed) {
src.stop();
}
else {
Expand All @@ -177,7 +188,7 @@ impl LoopPlayer {
);
src.inner_mut()
.inner_mut()
.set_paused(paused.load(Ordering::SeqCst));
.set_paused(paused.load(Ordering::Relaxed));
}
}
).convert_samples::<f32>();
Expand Down
Loading

0 comments on commit bbb9649

Please sign in to comment.