aboutsummaryrefslogtreecommitdiffstats
path: root/mumd/src
diff options
context:
space:
mode:
Diffstat (limited to 'mumd/src')
-rw-r--r--mumd/src/audio.rs345
-rw-r--r--mumd/src/audio/noise_gate.rs335
2 files changed, 348 insertions, 332 deletions
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs
index 299a4e6..6b46a7a 100644
--- a/mumd/src/audio.rs
+++ b/mumd/src/audio.rs
@@ -1,22 +1,29 @@
pub mod input;
pub mod output;
+mod noise_gate;
-use crate::{audio::output::SaturatingAdd, state::StatePhase};
+use crate::audio::output::SaturatingAdd;
+use crate::audio::noise_gate::{from_interleaved_samples_stream, OpusEncoder, StreamingNoiseGate, StreamingSignalExt};
use crate::network::VoiceStreamType;
+use crate::state::StatePhase;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{SampleFormat, SampleRate, StreamConfig};
-use dasp_frame::Frame;
use dasp_interpolate::linear::Linear;
-use dasp_sample::{SignedSample, ToSample, Sample};
use dasp_signal::{self as signal, Signal};
-use futures_util::{StreamExt, stream::Stream};
+use futures_util::stream::Stream;
+use futures_util::StreamExt;
use log::*;
use mumble_protocol::Serverbound;
use mumble_protocol::voice::{VoicePacketPayload, VoicePacket};
use mumlib::config::SoundEffect;
-use opus::Channels;
-use std::{borrow::Cow, collections::{hash_map::Entry, HashMap, VecDeque}, convert::TryFrom, fmt::Debug, fs::File, future::Future, io::Read, pin::Pin, sync::{Arc, Mutex}, task::{Context, Poll}};
+use std::borrow::Cow;
+use std::collections::{hash_map::Entry, HashMap, VecDeque};
+use std::convert::TryFrom;
+use std::fmt::Debug;
+use std::fs::File;
+use std::io::Read;
+use std::sync::{Arc, Mutex};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use tokio::sync::watch;
@@ -395,329 +402,3 @@ fn get_default_sfx() -> Cow<'static, [u8]> {
Cow::from(include_bytes!("fallback_sfx.wav").as_ref())
}
-type FloatSample<S> = <<S as Frame>::Sample as Sample>::Float;
-
-struct StreamingNoiseGate<S: StreamingSignal> {
- open: usize,
- signal: S,
- deactivation_delay: usize,
- alltime_high: FloatSample<S::Frame>,
-}
-
-impl<S: StreamingSignal> StreamingNoiseGate<S> {
- pub fn new(
- signal: S,
- deactivation_delay: usize,
- ) -> StreamingNoiseGate<S> {
- Self {
- open: 0,
- signal,
- deactivation_delay,
- alltime_high: FloatSample::<S::Frame>::EQUILIBRIUM,
- }
- }
-}
-
-impl<S> StreamingSignal for StreamingNoiseGate<S>
- where
- S: StreamingSignal + Unpin,
- FloatSample<S::Frame>: Unpin,
- <S as StreamingSignal>::Frame: Unpin {
- type Frame = S::Frame;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
- const MUTE_PERCENTAGE: f32 = 0.1;
-
- let s = self.get_mut();
-
- let frame = match S::poll_next(Pin::new(&mut s.signal), cx) {
- Poll::Ready(v) => v,
- Poll::Pending => return Poll::Pending,
- };
-
- if let Some(highest) = frame.to_float_frame().channels().find(|e| abs(e.clone()) > s.alltime_high) {
- s.alltime_high = highest;
- }
-
- match s.open {
- 0 => {
- if frame.to_float_frame().channels().any(|e| abs(e) >= s.alltime_high.mul_amp(MUTE_PERCENTAGE.to_sample())) {
- s.open = s.deactivation_delay;
- }
- }
- _ => {
- if frame.to_float_frame().channels().any(|e| abs(e) >= s.alltime_high.mul_amp(MUTE_PERCENTAGE.to_sample())) {
- s.open = s.deactivation_delay;
- } else {
- s.open -= 1;
- }
- }
- }
-
- if s.open != 0 {
- Poll::Ready(frame)
- } else {
- Poll::Ready(<S::Frame as Frame>::EQUILIBRIUM)
- }
- }
-
- fn is_exhausted(&self) -> bool {
- self.signal.is_exhausted()
- }
-}
-
-fn abs<S: SignedSample>(sample: S) -> S {
- let zero = S::EQUILIBRIUM;
- if sample >= zero {
- sample
- } else {
- -sample
- }
-}
-
-trait StreamingSignal {
- type Frame: Frame;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame>;
-
- fn is_exhausted(&self) -> bool {
- false
- }
-}
-
-impl<S> StreamingSignal for S
- where
- S: Signal + Unpin {
- type Frame = S::Frame;
-
- fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Frame> {
- Poll::Ready(self.get_mut().next())
- }
-}
-
-trait StreamingSignalExt: StreamingSignal {
- fn next(&mut self) -> Next<'_, Self> {
- Next {
- stream: self
- }
- }
-
- fn into_interleaved_samples(self) -> IntoInterleavedSamples<Self>
- where
- Self: Sized {
- IntoInterleavedSamples { signal: self, current_frame: None }
- }
-}
-
-impl<S> StreamingSignalExt for S
- where S: StreamingSignal {}
-
-struct Next<'a, S: ?Sized> {
- stream: &'a mut S
-}
-
-impl<'a, S: StreamingSignal + Unpin> Future for Next<'a, S> {
- type Output = S::Frame;
-
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- match S::poll_next(Pin::new(self.stream), cx) {
- Poll::Ready(val) => {
- Poll::Ready(val)
- }
- Poll::Pending => Poll::Pending
- }
- }
-}
-
-struct IntoInterleavedSamples<S: StreamingSignal> {
- signal: S,
- current_frame: Option<<S::Frame as Frame>::Channels>,
-}
-
-impl<S> Stream for IntoInterleavedSamples<S>
- where
- S: StreamingSignal + Unpin,
- <<S as StreamingSignal>::Frame as Frame>::Channels: Unpin {
- type Item = <S::Frame as Frame>::Sample;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- let s = self.get_mut();
- loop {
- if s.current_frame.is_some() {
- if let Some(channel) = s.current_frame.as_mut().unwrap().next() {
- return Poll::Ready(Some(channel));
- }
- }
- match S::poll_next(Pin::new(&mut s.signal), cx) {
- Poll::Ready(val) => {
- s.current_frame = Some(val.channels());
- }
- Poll::Pending => return Poll::Pending,
- }
- }
- }
-}
-
-struct FromStream<S> {
- stream: S,
- underlying_exhausted: bool,
-}
-
-impl<S> StreamingSignal for FromStream<S>
- where
- S: Stream + Unpin,
- S::Item: Frame + Unpin {
- type Frame = S::Item;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
- let s = self.get_mut();
- if s.underlying_exhausted {
- return Poll::Ready(<Self::Frame as Frame>::EQUILIBRIUM);
- }
- match S::poll_next(Pin::new(&mut s.stream), cx) {
- Poll::Ready(Some(val)) => {
- Poll::Ready(val)
- }
- Poll::Ready(None) => {
- s.underlying_exhausted = true;
- return Poll::Ready(<Self::Frame as Frame>::EQUILIBRIUM);
- }
- Poll::Pending => Poll::Pending,
- }
- }
-
- fn is_exhausted(&self) -> bool {
- self.underlying_exhausted
- }
-}
-
-
-struct FromInterleavedSamplesStream<S, F>
- where
- F: Frame {
- stream: S,
- next_buf: Vec<F::Sample>,
- underlying_exhausted: bool,
-}
-
-fn from_interleaved_samples_stream<S, F>(stream: S) -> FromInterleavedSamplesStream<S, F>
- where
- S: Stream + Unpin,
- S::Item: Sample,
- F: Frame<Sample = S::Item> {
- FromInterleavedSamplesStream {
- stream,
- next_buf: Vec::new(),
- underlying_exhausted: false,
- }
-}
-
-impl<S, F> StreamingSignal for FromInterleavedSamplesStream<S, F>
- where
- S: Stream + Unpin,
- S::Item: Sample + Unpin,
- F: Frame<Sample = S::Item> + Unpin {
- type Frame = F;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
- let s = self.get_mut();
- if s.underlying_exhausted {
- return Poll::Ready(F::EQUILIBRIUM);
- }
- while s.next_buf.len() < F::CHANNELS {
- match S::poll_next(Pin::new(&mut s.stream), cx) {
- Poll::Ready(Some(v)) => {
- s.next_buf.push(v);
- }
- Poll::Ready(None) => {
- s.underlying_exhausted = true;
- return Poll::Ready(F::EQUILIBRIUM);
- }
- Poll::Pending => return Poll::Pending,
- }
- }
-
- let mut data = s.next_buf.iter().cloned();
- let n = F::from_samples(&mut data).unwrap();
- s.next_buf.clear();
- Poll::Ready(n)
- }
-
- fn is_exhausted(&self) -> bool {
- self.underlying_exhausted
- }
-}
-
-struct OpusEncoder<S> {
- encoder: opus::Encoder,
- frame_size: u32,
- sample_rate: u32,
- stream: S,
- input_buffer: Vec<f32>,
- exhausted: bool,
-}
-
-impl<S, I> OpusEncoder<S>
- where
- S: Stream<Item = I>,
- I: ToSample<f32> {
- fn new(frame_size: u32, sample_rate: u32, channels: usize, stream: S) -> Self {
- let encoder = opus::Encoder::new(
- sample_rate,
- match channels {
- 1 => Channels::Mono,
- 2 => Channels::Stereo,
- _ => unimplemented!(
- "Only 1 or 2 channels supported, got {})",
- channels
- ),
- },
- opus::Application::Voip,
- ).unwrap();
- Self {
- encoder,
- frame_size,
- sample_rate,
- stream,
- input_buffer: Vec::new(),
- exhausted: false,
- }
- }
-}
-
-impl<S, I> Stream for OpusEncoder<S>
- where
- S: Stream<Item = I> + Unpin,
- I: Sample + ToSample<f32> {
- type Item = Vec<u8>;
-
- fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- let s = self.get_mut();
- if s.exhausted {
- return Poll::Ready(None);
- }
- let opus_frame_size = (s.frame_size * s.sample_rate / 400) as usize;
- loop {
- while s.input_buffer.len() < opus_frame_size {
- match S::poll_next(Pin::new(&mut s.stream), cx) {
- Poll::Ready(Some(v)) => {
- s.input_buffer.push(v.to_sample::<f32>());
- }
- Poll::Ready(None) => {
- s.exhausted = true;
- return Poll::Ready(None);
- }
- Poll::Pending => return Poll::Pending,
- }
- }
- if s.input_buffer.iter().any(|&e| e != 0.0) {
- break;
- }
- s.input_buffer.clear();
- }
-
- let encoded = s.encoder.encode_vec_float(&s.input_buffer, opus_frame_size).unwrap();
- s.input_buffer.clear();
- Poll::Ready(Some(encoded))
- }
-}
diff --git a/mumd/src/audio/noise_gate.rs b/mumd/src/audio/noise_gate.rs
new file mode 100644
index 0000000..824ffe0
--- /dev/null
+++ b/mumd/src/audio/noise_gate.rs
@@ -0,0 +1,335 @@
+use dasp_frame::Frame;
+use dasp_sample::{SignedSample, ToSample, Sample};
+use dasp_signal::Signal;
+use futures_util::stream::Stream;
+use opus::Channels;
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+type FloatSample<S> = <<S as Frame>::Sample as Sample>::Float;
+
+pub struct StreamingNoiseGate<S: StreamingSignal> {
+ open: usize,
+ signal: S,
+ deactivation_delay: usize,
+ alltime_high: FloatSample<S::Frame>,
+}
+
+impl<S: StreamingSignal> StreamingNoiseGate<S> {
+ pub fn new(
+ signal: S,
+ deactivation_delay: usize,
+ ) -> StreamingNoiseGate<S> {
+ Self {
+ open: 0,
+ signal,
+ deactivation_delay,
+ alltime_high: FloatSample::<S::Frame>::EQUILIBRIUM,
+ }
+ }
+}
+
+impl<S> StreamingSignal for StreamingNoiseGate<S>
+ where
+ S: StreamingSignal + Unpin,
+ FloatSample<S::Frame>: Unpin,
+ <S as StreamingSignal>::Frame: Unpin {
+ type Frame = S::Frame;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
+ const MUTE_PERCENTAGE: f32 = 0.1;
+
+ let s = self.get_mut();
+
+ let frame = match S::poll_next(Pin::new(&mut s.signal), cx) {
+ Poll::Ready(v) => v,
+ Poll::Pending => return Poll::Pending,
+ };
+
+ if let Some(highest) = frame.to_float_frame().channels().find(|e| abs(e.clone()) > s.alltime_high) {
+ s.alltime_high = highest;
+ }
+
+ match s.open {
+ 0 => {
+ if frame.to_float_frame().channels().any(|e| abs(e) >= s.alltime_high.mul_amp(MUTE_PERCENTAGE.to_sample())) {
+ s.open = s.deactivation_delay;
+ }
+ }
+ _ => {
+ if frame.to_float_frame().channels().any(|e| abs(e) >= s.alltime_high.mul_amp(MUTE_PERCENTAGE.to_sample())) {
+ s.open = s.deactivation_delay;
+ } else {
+ s.open -= 1;
+ }
+ }
+ }
+
+ if s.open != 0 {
+ Poll::Ready(frame)
+ } else {
+ Poll::Ready(<S::Frame as Frame>::EQUILIBRIUM)
+ }
+ }
+
+ fn is_exhausted(&self) -> bool {
+ self.signal.is_exhausted()
+ }
+}
+
+fn abs<S: SignedSample>(sample: S) -> S {
+ let zero = S::EQUILIBRIUM;
+ if sample >= zero {
+ sample
+ } else {
+ -sample
+ }
+}
+
+pub trait StreamingSignal {
+ type Frame: Frame;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame>;
+
+ fn is_exhausted(&self) -> bool {
+ false
+ }
+}
+
+impl<S> StreamingSignal for S
+ where
+ S: Signal + Unpin {
+ type Frame = S::Frame;
+
+ fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Frame> {
+ Poll::Ready(self.get_mut().next())
+ }
+}
+
+pub trait StreamingSignalExt: StreamingSignal {
+ fn next(&mut self) -> Next<'_, Self> {
+ Next {
+ stream: self
+ }
+ }
+
+ fn into_interleaved_samples(self) -> IntoInterleavedSamples<Self>
+ where
+ Self: Sized {
+ IntoInterleavedSamples { signal: self, current_frame: None }
+ }
+}
+
+impl<S> StreamingSignalExt for S
+ where S: StreamingSignal {}
+
+pub struct Next<'a, S: ?Sized> {
+ stream: &'a mut S
+}
+
+impl<'a, S: StreamingSignal + Unpin> Future for Next<'a, S> {
+ type Output = S::Frame;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ match S::poll_next(Pin::new(self.stream), cx) {
+ Poll::Ready(val) => {
+ Poll::Ready(val)
+ }
+ Poll::Pending => Poll::Pending
+ }
+ }
+}
+
+pub struct IntoInterleavedSamples<S: StreamingSignal> {
+ signal: S,
+ current_frame: Option<<S::Frame as Frame>::Channels>,
+}
+
+impl<S> Stream for IntoInterleavedSamples<S>
+ where
+ S: StreamingSignal + Unpin,
+ <<S as StreamingSignal>::Frame as Frame>::Channels: Unpin {
+ type Item = <S::Frame as Frame>::Sample;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ let s = self.get_mut();
+ loop {
+ if s.current_frame.is_some() {
+ if let Some(channel) = s.current_frame.as_mut().unwrap().next() {
+ return Poll::Ready(Some(channel));
+ }
+ }
+ match S::poll_next(Pin::new(&mut s.signal), cx) {
+ Poll::Ready(val) => {
+ s.current_frame = Some(val.channels());
+ }
+ Poll::Pending => return Poll::Pending,
+ }
+ }
+ }
+}
+
+struct FromStream<S> {
+ stream: S,
+ underlying_exhausted: bool,
+}
+
+impl<S> StreamingSignal for FromStream<S>
+ where
+ S: Stream + Unpin,
+ S::Item: Frame + Unpin {
+ type Frame = S::Item;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
+ let s = self.get_mut();
+ if s.underlying_exhausted {
+ return Poll::Ready(<Self::Frame as Frame>::EQUILIBRIUM);
+ }
+ match S::poll_next(Pin::new(&mut s.stream), cx) {
+ Poll::Ready(Some(val)) => {
+ Poll::Ready(val)
+ }
+ Poll::Ready(None) => {
+ s.underlying_exhausted = true;
+ return Poll::Ready(<Self::Frame as Frame>::EQUILIBRIUM);
+ }
+ Poll::Pending => Poll::Pending,
+ }
+ }
+
+ fn is_exhausted(&self) -> bool {
+ self.underlying_exhausted
+ }
+}
+
+
+pub struct FromInterleavedSamplesStream<S, F>
+ where
+ F: Frame {
+ stream: S,
+ next_buf: Vec<F::Sample>,
+ underlying_exhausted: bool,
+}
+
+pub fn from_interleaved_samples_stream<S, F>(stream: S) -> FromInterleavedSamplesStream<S, F>
+ where
+ S: Stream + Unpin,
+ S::Item: Sample,
+ F: Frame<Sample = S::Item> {
+ FromInterleavedSamplesStream {
+ stream,
+ next_buf: Vec::new(),
+ underlying_exhausted: false,
+ }
+}
+
+impl<S, F> StreamingSignal for FromInterleavedSamplesStream<S, F>
+ where
+ S: Stream + Unpin,
+ S::Item: Sample + Unpin,
+ F: Frame<Sample = S::Item> + Unpin {
+ type Frame = F;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Frame> {
+ let s = self.get_mut();
+ if s.underlying_exhausted {
+ return Poll::Ready(F::EQUILIBRIUM);
+ }
+ while s.next_buf.len() < F::CHANNELS {
+ match S::poll_next(Pin::new(&mut s.stream), cx) {
+ Poll::Ready(Some(v)) => {
+ s.next_buf.push(v);
+ }
+ Poll::Ready(None) => {
+ s.underlying_exhausted = true;
+ return Poll::Ready(F::EQUILIBRIUM);
+ }
+ Poll::Pending => return Poll::Pending,
+ }
+ }
+
+ let mut data = s.next_buf.iter().cloned();
+ let n = F::from_samples(&mut data).unwrap();
+ s.next_buf.clear();
+ Poll::Ready(n)
+ }
+
+ fn is_exhausted(&self) -> bool {
+ self.underlying_exhausted
+ }
+}
+
+pub struct OpusEncoder<S> {
+ encoder: opus::Encoder,
+ frame_size: u32,
+ sample_rate: u32,
+ stream: S,
+ input_buffer: Vec<f32>,
+ exhausted: bool,
+}
+
+impl<S, I> OpusEncoder<S>
+ where
+ S: Stream<Item = I>,
+ I: ToSample<f32> {
+ pub fn new(frame_size: u32, sample_rate: u32, channels: usize, stream: S) -> Self {
+ let encoder = opus::Encoder::new(
+ sample_rate,
+ match channels {
+ 1 => Channels::Mono,
+ 2 => Channels::Stereo,
+ _ => unimplemented!(
+ "Only 1 or 2 channels supported, got {})",
+ channels
+ ),
+ },
+ opus::Application::Voip,
+ ).unwrap();
+ Self {
+ encoder,
+ frame_size,
+ sample_rate,
+ stream,
+ input_buffer: Vec::new(),
+ exhausted: false,
+ }
+ }
+}
+
+impl<S, I> Stream for OpusEncoder<S>
+ where
+ S: Stream<Item = I> + Unpin,
+ I: Sample + ToSample<f32> {
+ type Item = Vec<u8>;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ let s = self.get_mut();
+ if s.exhausted {
+ return Poll::Ready(None);
+ }
+ let opus_frame_size = (s.frame_size * s.sample_rate / 400) as usize;
+ loop {
+ while s.input_buffer.len() < opus_frame_size {
+ match S::poll_next(Pin::new(&mut s.stream), cx) {
+ Poll::Ready(Some(v)) => {
+ s.input_buffer.push(v.to_sample::<f32>());
+ }
+ Poll::Ready(None) => {
+ s.exhausted = true;
+ return Poll::Ready(None);
+ }
+ Poll::Pending => return Poll::Pending,
+ }
+ }
+ if s.input_buffer.iter().any(|&e| e != 0.0) {
+ break;
+ }
+ s.input_buffer.clear();
+ }
+
+ let encoded = s.encoder.encode_vec_float(&s.input_buffer, opus_frame_size).unwrap();
+ s.input_buffer.clear();
+ Poll::Ready(Some(encoded))
+ }
+}