Skip to content

Conversation

@leecbaker
Copy link

This adds the ability to get the current voice in AVFoundation. This is either the most recent voice passed to set_voice(), or the system default voice.

Here's an example of this feature in use:

#[cfg(target_os = "macos")]
use cocoa_foundation::base::id;
#[cfg(target_os = "macos")]
use cocoa_foundation::foundation::NSRunLoop;
#[cfg(target_os = "macos")]
use objc::{msg_send, sel, sel_impl};

use tts::*;

fn main() -> Result<(), Error> {
    env_logger::init();
    let mut tts = Tts::default()?;

    // Check to ensure we can use this feature
    if !tts.supported_features().get_voice {
        return Err(Error::UnsupportedFeature);
    }

    // First, lets see what the default voice is. We'll print the name, and
    // say something in it (to ensure we can speak with it)
    let voice_on_start = tts.voice().unwrap();
    println!(
        "Voice on start: {}",
        voice_on_start
            .as_ref()
            .map_or("None".to_owned(), |voice: &Voice| voice.name())
    );

    if let Some(voice) = voice_on_start {
        tts.speak(format!("The default voice is {}", voice.name()), false)?;
    } else {
        tts.speak("No default voice", false)?;
    }

    // Pick a different voice
    let voices = tts.voices().unwrap();
    let chosen_voice = &voices[5];

    println!("Setting voice: {}", chosen_voice.name());
    tts.set_voice(chosen_voice).unwrap();

    // Say something with the new voice to ensure that it actually changed
    tts.speak(format!("The new voice is {}", chosen_voice.name()), false)?;

    let voice_now = &tts.voice().unwrap();
    println!(
        "Voice is now: {}",
        voice_now
            .as_ref()
            .map_or("None".to_owned(), |voice: &Voice| voice.name())
    );

    assert_eq!(
        voice_now.as_ref().map(|voice: &Voice| voice.name()),
        tts.voice()?.map(|voice| voice.name())
    );

    // The below is only needed to make the example run on MacOS because there is no NSRunLoop in this context.
    // It shouldn't be needed in an app or game that almost certainly has one already.
    #[cfg(target_os = "macos")]
    {
        let run_loop: id = unsafe { NSRunLoop::currentRunLoop() };
        unsafe {
            let _: () = msg_send![run_loop, run];
        }
    }

    Ok(())
}

@madsmtm madsmtm mentioned this pull request Jan 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant