最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

快速開始

基礎(chǔ)使用示例

#include "tts.hpp"
int main() {
    TTS::TextToSpeech tts;
    // 設(shè)置語音參數(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ù)設(shè)置

語速控制 (set_rate())

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

音量控制 (set_volume())

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

同步朗讀 (speak_sync())

bool speak_sync(const std::string& text);
  • 阻塞當(dāng)前線程直到朗讀完成
  • 返回執(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í)行其他任務(wù)
}
// 獲取結(jié)果
bool success = future.get();

保存音頻文件 (save_to_wav())

std::string save_to_wav(const std::string& text, 
                       const std::string& filename = "");
  • 自動生成臨時文件(當(dāng)filename為空時)
  • 返回最終文件路徑
  • 文件保存位置規(guī)則:
    • 指定filename:使用完整路徑
    • 未指定:生成隨機(jī)文件名(系統(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;
}

實(shí)時進(jìn)度跟蹤

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();
}

注意事項(xiàng)與最佳實(shí)踐

字符處理

  • 自動轉(zhuǎn)義XML特殊字符:&, <, >, ", '
  • 支持多語言文本(需系統(tǒng)語音包支持)
  • 建議預(yù)處理用戶輸入:
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)化

  • 復(fù)用TextToSpeech實(shí)例(避免重復(fù)初始化)
  • 異步操作時注意生命周期管理:
// 錯誤示例(對象提前銷毀):
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訪問權(quán)限不足
  • 無效的文件路徑
  • 系統(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:如何實(shí)現(xiàn)語音中斷?
A:當(dāng)前版本未實(shí)現(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;
    // 設(shè)置語音速率(-10~10)
    void set_rate(int rate) {
        rate_ = clamp(rate, MIN_RATE, MAX_RATE);
    }
    // 設(shè)置音量(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; // 默認(rèn)語速
    int volume_ = 100; // 默認(rèn)音量
    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();
    }
    // 轉(zhuǎn)義 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í)行命令并返回結(jié)果
    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 轉(zhuǎn)義
    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

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

相關(guān)文章

  • C++線程間的互斥和通信場景分析

    C++線程間的互斥和通信場景分析

    很多朋友對C++線程間的互斥和通信知識掌握不是多牢靠,今天小編通過模擬車站賣票應(yīng)用場景給大家詳細(xì)解析C++線程間的互斥和通信知識,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • Qt實(shí)現(xiàn)一個簡單的word文檔編輯器

    Qt實(shí)現(xiàn)一個簡單的word文檔編輯器

    本文主要介紹了Qt實(shí)現(xiàn)一個簡單的word文檔編輯器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Qt?Creator配置opencv環(huán)境的全過程記錄

    Qt?Creator配置opencv環(huán)境的全過程記錄

    最近在PC端QT下配置opencv,想著以后應(yīng)該會用到,索性記錄下,這篇文章主要給大家介紹了關(guān)于Qt?Creator配置opencv環(huán)境的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • C++11中的可變參數(shù)模板/lambda表達(dá)式

    C++11中的可變參數(shù)模板/lambda表達(dá)式

    C++11的新特性可變參數(shù)模板能夠讓我們創(chuàng)建可以接受可變參數(shù)的函數(shù)模板和類模板,相比C++98和C++03,類模板和函數(shù)模板中只能含固定數(shù)量的模板參數(shù),可變參數(shù)模板無疑是一個巨大的改進(jìn),這篇文章主要介紹了C++11中的可變參數(shù)模板/lambda表達(dá)式,需要的朋友可以參考下
    2023-03-03
  • c語言5個常用的排序算法實(shí)例代碼

    c語言5個常用的排序算法實(shí)例代碼

    這篇文章主要介紹了c語言5個常用的排序算法實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • 插入排序的順序表實(shí)現(xiàn)代碼

    插入排序的順序表實(shí)現(xiàn)代碼

    這篇文章主要介紹了插入排序的順序表實(shí)現(xiàn)代碼,有需要的朋友可以參考一下
    2014-01-01
  • 詳解C++模擬實(shí)現(xiàn)priority_queue(仿函數(shù))

    詳解C++模擬實(shí)現(xiàn)priority_queue(仿函數(shù))

    本文主要介紹了關(guān)于C++中優(yōu)先級隊列的模擬實(shí)現(xiàn),以及仿函數(shù)的使用,優(yōu)先級隊列是一種容器適配器,其第一個元素總是最大的,仿函數(shù)本質(zhì)是一個類,重載了operator(),可改變比較邏輯,同時,文中還介紹了如何進(jìn)行類的比較,如日期類或其指針的比較,以及庫中sort函數(shù)的使用方法
    2024-10-10
  • C++模板實(shí)現(xiàn)順序棧

    C++模板實(shí)現(xiàn)順序棧

    這篇文章主要為大家詳細(xì)介紹了C++模板實(shí)現(xiàn)順序棧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C++標(biāo)準(zhǔn)模版庫(STL)之vector容器詳解

    C++標(biāo)準(zhǔn)模版庫(STL)之vector容器詳解

    vector的功能和水桶一樣,就是用來裝東西的,并且vector還提供了迭代器來很方便的訪問這些數(shù)據(jù),下面就讓我們一起看下如何使用C++的vector吧
    2023-03-03
  • C語言深入探究斐波那契數(shù)列

    C語言深入探究斐波那契數(shù)列

    斐波那契數(shù)一般指斐波那契數(shù)列。 斐波那契數(shù)列(Fibonacci sequence),又稱黃金分割數(shù)列,因數(shù)學(xué)家萊昂納多·斐波那契(Leonardo Fibonacci)以兔子繁殖為例子而引入,故又稱為兔子數(shù)列
    2022-05-05

最新評論

龙门县| 出国| 道孚县| 仙居县| 仪征市| 吉首市| 宣城市| 广西| 井研县| 兴山县| 长岛县| 太湖县| 五峰| 临猗县| 闻喜县| 宜州市| 德令哈市| 长汀县| 洮南市| 安顺市| 香格里拉县| 甘洛县| 故城县| 华宁县| 肥东县| 京山县| 六枝特区| 固阳县| 江阴市| 保定市| 白玉县| 调兵山市| 万载县| 松江区| 太和县| 法库县| 西华县| 瑞金市| 嵊州市| 当涂县| 安康市|