欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++ Windows SAPI實現(xiàn)文字轉語音功能

 更新時間:2025年02月05日 15:39:30   作者:T0uken  
本文通過封裝Windows SAPI(Speech Application Programming Interface),提供了一個現(xiàn)代化的C++接口實現(xiàn)文字轉語音功能,這篇文章重點給大家介紹C/C++ Windows SAPI自實現(xiàn)文字轉語音功能,感興趣的朋友一起看看吧

本文通過封裝Windows SAPI(Speech Application Programming Interface),提供了一個現(xiàn)代化的C++接口實現(xiàn)文字轉語音功能。主要特性包括支持同步/異步語音合成、可調節(jié)語速(-10到10)和音量控制(0-100%),同時支持將合成語音保存為WAV文件,并自動處理特殊字符轉義,設計上也確保了線程安全。該接口依賴于Windows系統(tǒng)(需.NET Framework支持)、PowerShell 5.1及以上版本,以及C++11或更高版本。完整代碼在文字末尾提供。

快速開始

基礎使用示例

#include "tts.hpp"
int main() {
    TTS::TextToSpeech tts;
    // 設置語音參數(shù)
    tts.set_rate(5);    // 加快語速
    tts.set_volume(80); // 80%音量
    // 同步朗讀
    tts.speak_sync("Hello, welcome to the text-to-speech system.");
    // 異步朗讀
    auto future = tts.speak_async("This is an async operation.");
    future.wait(); // 等待完成
    // 保存到文件
    std::string filename = tts.save_to_wav("Audio saved to file.");
    return 0;
}

核心功能詳解

語音參數(shù)設置

語速控制 (set_rate())

void set_rate(int rate);  // 范圍:-10 ~ 10
  • 正值加快語速
  • 負值減慢語速
  • 自動鉗制在有效范圍內

音量控制 (set_volume())

void set_volume(int volume);  // 范圍:0 ~ 100
  • 0表示靜音
  • 100表示最大音量
  • 支持百分比精確控制

同步朗讀 (speak_sync())

bool speak_sync(const std::string& text);
  • 阻塞當前線程直到朗讀完成
  • 返回執(zhí)行狀態(tài)(true表示成功)
  • 適合需要順序執(zhí)行的場景

示例:

if (!tts.speak_sync("Critical system alert!")) {
    // 錯誤處理
}

異步朗讀 (speak_async())

std::future<bool> speak_async(const std::string& text);
  • 立即返回std::future對象
  • 支持多種等待方式:
auto future = tts.speak_async("Processing completed");
// 方式1:阻塞等待
future.wait();
// 方式2:輪詢檢查
while (future.wait_for(100ms) != std::future_status::ready) {
    // 執(zhí)行其他任務
}
// 獲取結果
bool success = future.get();

保存音頻文件 (save_to_wav())

std::string save_to_wav(const std::string& text, 
                       const std::string& filename = "");
  • 自動生成臨時文件(當filename為空時)
  • 返回最終文件路徑
  • 文件保存位置規(guī)則:
    • 指定filename:使用完整路徑
    • 未指定:生成隨機文件名(系統(tǒng)臨時目錄)

示例:

// 自動生成臨時文件
auto auto_file = tts.save_to_wav("Automatic filename");
// 自定義路徑
std::string custom_path = R"(C:\audio\alert.wav)";
auto custom_file = tts.save_to_wav("Custom path", custom_path);

高級用法

批量語音生成

std::vector<std::future<bool>> batch_process() {
    TTS::TextToSpeech tts;
    std::vector<std::future<bool>> results;
    for (int i = 0; i < 10; ++i) {
        std::string text = "Message " + std::to_string(i);
        results.push_back(tts.speak_async(text));
    }
    return results;
}

實時進度跟蹤

void monitor_async() {
    auto future = tts.speak_async("Long running operation");
    std::thread monitor([&future]{
        while (future.wait_for(1s) != std::future_status::ready) {
            std::cout << "Synthesizing..." << std::endl;
        }
        std::cout << "Completed with status: " << future.get() << std::endl;
    });
    monitor.detach();
}

注意事項與最佳實踐

字符處理

  • 自動轉義XML特殊字符:&, <, >, ", '
  • 支持多語言文本(需系統(tǒng)語音包支持)
  • 建議預處理用戶輸入:
std::string sanitize_input(const std::string& raw) {
    // 移除控制字符等
    std::string filtered;
    std::copy_if(raw.begin(), raw.end(), std::back_inserter(filtered),
        [](char c){ return std::isprint(c); });
    return filtered;
}

性能優(yōu)化

  • 復用TextToSpeech實例(避免重復初始化)
  • 異步操作時注意生命周期管理:
// 錯誤示例(對象提前銷毀):
auto future = TTS::TextToSpeech().speak_async("text");
// 正確做法:
auto tts = std::make_shared<TTS::TextToSpeech>();
auto future = tts->speak_async("text");

錯誤處理

檢查返回值:

if (!tts.speak_sync("text")) {
    std::cerr << "Speech synthesis failed" << std::endl;
}

常見錯誤原因:

  • PowerShell訪問權限不足
  • 無效的文件路徑
  • 系統(tǒng)語音引擎故障

常見問題解答

Q:支持哪些音頻格式?
A:目前僅支持WAV格式,由系統(tǒng)API決定

Q:如何處理中文字符?
A:需確保:

  • 系統(tǒng)已安裝中文語音包
  • 代碼文件使用UTF-8編碼
  • 控制臺支持Unicode(建議使用chcp 65001)

Q:為什么需要生成批處理文件?
A:為了解決:

  • PowerShell直接執(zhí)行的編碼問題
  • 長命令行參數(shù)限制
  • 錯誤代碼捕獲需求

Q:最大支持文本長度?
A:由系統(tǒng)限制決定,建議分段處理超過1MB的文本

Q:如何實現(xiàn)語音中斷?
A:當前版本未實現(xiàn),但可以通過銷毀對象終止異步操作

TTS.hpp 源代碼

#pragma once
#include <string>
#include <sstream>
#include <cstdlib>
#include <random>
#include <atomic>
#include <thread>
#include <memory>
#include <system_error>
#include <future>
#include <fstream>
#include <cstdio>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
namespace TTS {
class TextToSpeech {
public:
    static constexpr int MIN_RATE = -10;
    static constexpr int MAX_RATE = 10;
    static constexpr int MIN_VOLUME = 0;
    static constexpr int MAX_VOLUME = 100;
    explicit TextToSpeech() = default;
    // 設置語音速率(-10~10)
    void set_rate(int rate) {
        rate_ = clamp(rate, MIN_RATE, MAX_RATE);
    }
    // 設置音量(0~100)
    void set_volume(int volume) {
        volume_ = clamp(volume, MIN_VOLUME, MAX_VOLUME);
    }
    // 同步朗讀(阻塞直到完成)
    bool speak_sync(const std::string& text) {
        return execute_command(generate_ps_command(text));
    }
    // 異步朗讀(立即返回)
    std::future<bool> speak_async(const std::string& text) {
        return std::async(std::launch::async, [this, text] { return this->speak_sync(text); });
    }
    // 生成臨時WAV文件(返回文件路徑)
    std::string save_to_wav(const std::string& text, const std::string& filename = "") {
        std::string full_path;
        bool clean_up;
        std::tie(full_path, clean_up) = generate_temp_path(filename, ".wav");
        std::string command = generate_ps_command(text, full_path);
        if (!execute_command(command)) {
            if (clean_up) std::remove(full_path.c_str());
            return "";
        }
        return full_path;
    }
private:
    int rate_ = 0; // 默認語速
    int volume_ = 100; // 默認音量
    std::atomic<bool> cancel_flag_{false};
    // 生成PowerShell命令
    std::string generate_ps_command(const std::string& text, const std::string& output_file = "") const {
        std::ostringstream oss;
        oss << "powershell -Command \"";
        oss << "Add-Type -AssemblyName System.Speech; ";
        oss << "$speech = New-Object System.Speech.Synthesis.SpeechSynthesizer; ";
        oss << "$speech.Rate = " << rate_ << "; ";
        oss << "$speech.Volume = " << volume_ << "; ";
        if (!output_file.empty()) {
            oss << "$speech.SetOutputToWaveFile('" << output_file << "'); ";
        } else {
            oss << "$speech.SetOutputToDefaultAudioDevice(); ";
        }
        oss << "$speech.Speak([System.Xml.XmlConvert]::VerifyXmlChars('"
            << escape_ps_string(escape_xml(text)) << "'));\"";
        return oss.str();
    }
    // 轉義 PowerShell 字符串
    std::string escape_ps_string(const std::string& text) const {
        std::string result;
        result.reserve(text.size() * 2);
        for (char c : text) {
            result += (c == '\'') ? "''" : std::string(1, c);
        }
        return result;
    }
    // 執(zhí)行命令并返回結果
    bool execute_command(const std::string& command) const {
        // 創(chuàng)建并寫入批處理文件
        std::string bat_path;
        bool dummy;
        std::tie(bat_path, dummy) = generate_temp_path("tts_", ".bat");
        std::ofstream bat_file(bat_path);
        if (!bat_file) return false;
        bat_file << "@echo off\n"
                 << "chcp 65001 > nul\n"
                 << command << "\n"
                 << "exit /b %ERRORLEVEL%";
        bat_file.close();
        // 執(zhí)行批處理文件
        std::string cmd = "cmd /c \"" + bat_path + "\"";
        int result = std::system(cmd.c_str());
        // 清理臨時文件
        std::remove(bat_path.c_str());
        return (result == 0);
    }
    // 生成臨時文件路徑
    std::tuple<std::string, bool> generate_temp_path(const std::string& prefix = "tts_", const std::string& extension = "") const {
        static std::random_device rd;
        static std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(0, 15);
        std::string full_path;
        bool need_cleanup = false;
        if (prefix.empty()) {
            char tmp_name[L_tmpnam];
            if (std::tmpnam(tmp_name)) {
                full_path = tmp_name;
                need_cleanup = true;
            }
        } else {
            const std::string temp_dir = get_temp_directory();
            do {
                std::string unique_part;
                for (int i = 0; i < 8; ++i) {
                    unique_part += "0123456789abcdef"[dis(gen) % 16];
                }
                full_path = temp_dir + "\\" + prefix + unique_part + extension;
            } while (file_exists(full_path));
        }
        return {full_path, need_cleanup};
    }
    // XML 轉義
    static std::string escape_xml(std::string data) {
        std::string buffer;
        buffer.reserve(data.size());
        for (char c : data) {
            switch (c) {
                case '&':  buffer += "&amp;";  break;
                case '\"': buffer += "&quot;"; break;
                case '\'': buffer += "&apos;"; break;
                case '<':  buffer += "&lt;";   break;
                case '>':  buffer += "&gt;";   break;
                default:   buffer += c;        break;
            }
        }
        return buffer;
    }
    // 范圍限制函數(shù)
    template <typename T>
    static T clamp(T value, T min, T max) {
        return (value < min) ? min : (value > max) ? max : value;
    }
    // 獲取臨時目錄
    static std::string get_temp_directory() {
        const char* tmp = std::getenv("TEMP");
        if (!tmp) tmp = std::getenv("TMP");
        return tmp ? tmp : ".";
    }
    // 檢查文件是否存在
    static bool file_exists(const std::string& path) {
#ifdef _WIN32
        return ::_access(path.c_str(), 0) == 0;
#else
        return ::access(path.c_str(), F_OK) == 0;
#endif
    }
};
} // namespace TTS

到此這篇關于C/C++ Windows SAPI實現(xiàn)文字轉語音功能的文章就介紹到這了,更多相關C++ Windows SAPI文字轉語音內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • QString的常用方法(小結)

    QString的常用方法(小結)

    這篇文章主要介紹了QString的常用方法(小結),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • C++簡單又好用的基本運算符重載

    C++簡單又好用的基本運算符重載

    繼友元知識過后,就到了今天的C++運算符重載的內容了,運算符重載是C++里比較重要的內容。這篇博文不會一下子講完各種運算符重載,因為太多了了也不好吸收掌握,所以運算符重載我準備分多次記錄和分享,那么接下來進入正文
    2022-06-06
  • 基于ios中的流狀態(tài)的定義分析

    基于ios中的流狀態(tài)的定義分析

    本篇文章介紹了,基于ios中的流狀態(tài)的定義分析。需要的朋友參考下
    2013-05-05
  • stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列)

    stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列)

    這篇文章主要介紹了stl常用算法(Algorithms)介紹(stl排序算法、非變序型隊列),需要的朋友可以參考下
    2014-05-05
  • QT實現(xiàn)FTP上傳文件

    QT實現(xiàn)FTP上傳文件

    這篇文章主要為大家詳細介紹了QT實現(xiàn)FTP上傳文件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • C語言基礎之二分查找知識最全匯總

    C語言基礎之二分查找知識最全匯總

    這篇文章主要介紹了C語言基礎之二分查找知識最全匯總,文中有非常詳細的二分查找基礎知識詳解,對正在學習C語言基礎的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • C指針原理教程之垃圾回收-內存泄露

    C指針原理教程之垃圾回收-內存泄露

    C語言沒有運行時庫,無法自動壓縮使用中的內存,縮小堆棧所需內存空間。若只申請內存,沒有釋放,勢必造成系統(tǒng)內存不斷減少、丟失。長時間的運行,最終導致系統(tǒng)死機。文章闡述了C語言垃圾產生的原因,并從引用計數(shù)、標記一清除算法兩方面提出如何實現(xiàn)C語言的垃圾回收。
    2019-02-02
  • C語言設計實現(xiàn)掃描器的自動機的示例詳解

    C語言設計實現(xiàn)掃描器的自動機的示例詳解

    這篇文章主要為大家詳細介紹了如何利用C語言設計實現(xiàn)掃描器的自動機,可識別的單詞包括:關鍵字、界符、標識符和常整型數(shù),感興趣的小伙伴可以了解一下
    2022-12-12
  • Qt實現(xiàn)矩形大小任意縮放的示例代碼

    Qt實現(xiàn)矩形大小任意縮放的示例代碼

    這篇文章主要介紹了Qt如何實現(xiàn)在窗口上繪制任意大小的矩形,并且通過邊角的拖曳按鈕可改變矩形大小,感興趣的小伙伴可以跟隨小編一起學習一下
    2022-06-06
  • C語言實現(xiàn)簡單停車場管理系統(tǒng)

    C語言實現(xiàn)簡單停車場管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單停車場管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評論