diff --git a/src/eyes.rs b/src/eyes.rs index a210b56..49f4e07 100644 --- a/src/eyes.rs +++ b/src/eyes.rs @@ -88,6 +88,14 @@ impl Default for Eyes { ) .unwrap(), ), + ( + EyesExpression::Wide, + RetainedImage::from_image_bytes( + "eyes_wide", + include_bytes!("assets/eyes_wide.png"), + ) + .unwrap(), + ), ]), eyes_closed_imgs: HashMap::from([ ( @@ -114,6 +122,14 @@ impl Default for Eyes { ) .unwrap(), ), + ( + EyesExpression::Wide, + RetainedImage::from_image_bytes( + "eyes_tight", + include_bytes!("assets/eyes_tight.png"), + ) + .unwrap(), + ), ]), } } @@ -191,4 +207,5 @@ pub enum EyesExpression { Normal, Sad, Angry, + Wide, } diff --git a/src/head.rs b/src/head.rs index aa9f2d7..f8b4d1a 100644 --- a/src/head.rs +++ b/src/head.rs @@ -13,11 +13,14 @@ use egui_extras::RetainedImage; const MINIMUM_FRAME_TIME: Duration = Duration::from_millis(1000 / 24); pub struct Head { + /// The threshold at which the character is considered to be half speaking, in dBFS. + half_speak_threshold_dbfs: f32, + /// The threshold at which the character is considered to be fully speaking, in dBFS. full_speak_threshold_dbfs: f32, - /// The threshold at which the character is considered to be half speaking, in dBFS. - half_speak_threshold_dbfs: f32, + /// The threshold at which the character is considered to be yelling, in dBFS. + yelling_threshold_dbfs: f32, /// Base images to use for the character's head. head_bases: HashMap<(HeadExpression, SpeakPhase), RetainedImage>, @@ -37,7 +40,9 @@ impl Head { // determine head_base to use if self.last_phase_change.elapsed() > MINIMUM_FRAME_TIME { let last_phase = self.speak_phase; - self.speak_phase = if volume > self.full_speak_threshold_dbfs { + self.speak_phase = if volume > self.yelling_threshold_dbfs { + SpeakPhase::Yell + } else if volume > self.full_speak_threshold_dbfs { SpeakPhase::FullSpeak } else if volume > self.half_speak_threshold_dbfs { SpeakPhase::HalfSpeak @@ -61,8 +66,9 @@ impl Head { impl Default for Head { fn default() -> Self { Self { - full_speak_threshold_dbfs: -20.0, half_speak_threshold_dbfs: -30.0, + full_speak_threshold_dbfs: -20.0, + yelling_threshold_dbfs: -2.0, head_bases: HashMap::from([ // happy faces @@ -116,6 +122,48 @@ impl Default for Head { ) .unwrap(), ), + ( + (HeadExpression::Frown, SpeakPhase::Yell), + RetainedImage::from_image_bytes( + "head_frown_yell", + include_bytes!("assets/head_frown_yell.png"), + ) + .unwrap(), + ), + + // wavy faces + ( + (HeadExpression::Wavy, SpeakPhase::Quiet), + RetainedImage::from_image_bytes( + "head_wavy_quiet", + include_bytes!("assets/head_wavy_quiet.png"), + ) + .unwrap(), + ), + ( + (HeadExpression::Wavy, SpeakPhase::HalfSpeak), + RetainedImage::from_image_bytes( + "head_wavy_halfspeak", + include_bytes!("assets/head_wavy_halfspeak.png"), + ) + .unwrap(), + ), + ( + (HeadExpression::Wavy, SpeakPhase::FullSpeak), + RetainedImage::from_image_bytes( + "head_wavy_speak", + include_bytes!("assets/head_wavy_speak.png"), + ) + .unwrap(), + ), + ( + (HeadExpression::Wavy, SpeakPhase::Yell), + RetainedImage::from_image_bytes( + "head_wavy_yell", + include_bytes!("assets/head_wavy_yell.png"), + ) + .unwrap(), + ), ]), // RetainedImage does not implement Clone >:c @@ -136,10 +184,12 @@ enum SpeakPhase { Quiet, HalfSpeak, FullSpeak, + Yell, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum HeadExpression { Happy, Frown, + Wavy, } diff --git a/src/main.rs b/src/main.rs index eba0e3a..7808a6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,43 +55,57 @@ impl Default for MuniTuberApp { let (audio_state, _audio_stream) = audio::start_default_stream(); let hotkey_manager = keys::ExpressionHotkeyManager { - force_blink_key: Key::Num0, + force_blink_key: Key::F12, expression_switches: HashMap::from([ ( - Key::Num1, + Key::F1, ExpressionState { eyes: eyes::EyesExpression::Normal, head: head::HeadExpression::Happy, }, ), ( - Key::Num2, + Key::F2, ExpressionState { eyes: eyes::EyesExpression::Angry, head: head::HeadExpression::Frown, }, ), ( - Key::Num3, + Key::F3, ExpressionState { eyes: eyes::EyesExpression::Sad, head: head::HeadExpression::Frown, }, ), ( - Key::Num4, + Key::F4, ExpressionState { eyes: eyes::EyesExpression::Angry, head: head::HeadExpression::Happy, }, ), ( - Key::Num5, + Key::F5, ExpressionState { eyes: eyes::EyesExpression::Sad, head: head::HeadExpression::Happy, }, ), + ( + Key::F7, + ExpressionState { + eyes: eyes::EyesExpression::Sad, + head: head::HeadExpression::Wavy, + }, + ), + ( + Key::F8, + ExpressionState { + eyes: eyes::EyesExpression::Wide, + head: head::HeadExpression::Wavy, + }, + ), ]), expression_holds: HashMap::new(), };