win-wrap 0.3.4

用于Rust的Windows API的高级封装
Documentation
/*
 * Copyright (c) 2024. The RigelA open source project team and
 * its contributors reserve all rights.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

use std::sync::Arc;

use windows::{
    core::HSTRING, Media::SpeechSynthesis::SpeechSynthesizer, Storage::Streams::DataReader,
};

#[derive(Clone, Debug)]
pub struct Sapi5TtsSynthesizer {
    synth: Arc<SpeechSynthesizer>,
}

impl Sapi5TtsSynthesizer {
    /**

    创建一个TTS对象(语音合成,SAPI5)
    */
    pub fn new() -> Self {
        // 创建语音合成器
        let synth = SpeechSynthesizer::new().expect("Can't create the speech synthesizer.");
        Self {
            synth: synth.into(),
        }
    }

    /**

    设置语速。
    某些语音的最低语速快于 0.5,最大语速低于 6.0。
    说话率不能直接转换为每分钟单词数,因为每种语音和语言的默认语速可能不同。
    <https://learn.microsoft.com/zh-cn/uwp/api/windows.media.speechsynthesis.speechsynthesizeroptions.speakingrate?view=winrt-22621#windows-media-speechsynthesis-speechsynthesizeroptions-speakingrate>
    */
    pub fn set_speed(&self, speed: f64) {
        let options = self.synth.Options().unwrap();
        options
            .SetSpeakingRate(speed)
            .expect("Can't set the speed value.");
    }

    /// 设置语调
    pub fn set_pitch(&self, pitch: f64) {
        let options = self.synth.Options().unwrap();
        options
            .SetAudioPitch(pitch)
            .expect("Can't set the pitch value.");
    }

    /// 设置音量
    pub fn set_volume(&self, volume: f64) {
        let options = self.synth.Options().unwrap();
        options
            .SetAudioVolume(volume)
            .expect("Can't set the volume value.");
    }

    /**

    获取所有已安装的语音合成发音人。
    */
    pub fn get_voice_list(&self) -> Vec<(String, String)> {
        let mut v: Vec<(String, String)> = vec![];
        for x in SpeechSynthesizer::AllVoices().unwrap() {
            v.push((
                x.Id().unwrap().to_string(),
                x.DisplayName().unwrap().to_string(),
            ))
        }
        v
    }

    /**

    设置发音人。
    `voice` 发音人id。
    */
    pub fn set_voice(&self, voice: String) {
        for x in SpeechSynthesizer::AllVoices().unwrap() {
            if x.Id().unwrap().to_string() == voice {
                self.synth.SetVoice(&x).unwrap_or(());
                return;
            }
        }
    }

    /**

    合成语音。
    此函数是异步函数,需要使用.await。
    `text` 要朗读的文字。
    */
    pub fn synth(&self, text: &str, recv: impl Fn(Vec<u8>) -> bool) -> Option<[u8; 44]> {
        let Ok(stream) = self.synth.SynthesizeTextToStreamAsync(&HSTRING::from(text)) else {
            return None;
        };
        let Ok(stream) = stream.get() else {
            return None;
        };

        let Ok(size) = stream.Size() else {
            return None;
        };
        let Ok(reader) = DataReader::CreateDataReader(&stream) else {
            return None;
        };
        let _ = reader.LoadAsync(size as u32);

        // 跳过音频文件头的44个字节
        let mut head: [u8; 44] = [0; 44];
        reader.ReadBytes(&mut head).unwrap();
        let mut last_len = size as u32 - 44;
        let mut buffer: [u8; 3200] = [0; 3200];
        loop {
            if reader.ReadBytes(&mut buffer).is_err() {
                break;
            }
            match reader.UnconsumedBufferLength() {
                Ok(len) if last_len != len => {
                    if !recv(buffer[0..(last_len - len) as usize].to_vec()) {
                        break;
                    }
                    last_len = len;
                }
                _ => continue,
            }
        }
        Some(head)
    }
}

#[cfg(test)]
mod test_tts {
    use crate::tts::Sapi5TtsSynthesizer;

    #[test]
    fn main() {
        let synth = Sapi5TtsSynthesizer::new();
        let (tx, rx) = std::sync::mpsc::channel();
        synth.synth("你好呀,我们是一群追求梦想的人。", move |data| {
            for i in data {
                let _ = tx.send(i);
            }
            true
        }).unwrap();
        let v = rx.iter().collect::<Vec<_>>();
        dbg!(v.len());
    }
}