projecte python

C:\
├── python\
│   ├── tts-edge.py       ← Generació amb veus EDGE (Aria, Herena…)
│   ├── tts-to-wav.py     ← Generació amb veus SAPI5 (Zira, Jordi…)
│   └── list-voices.py    ← Llista combinada de veus per al menú
├── AppServ\
│   └── www\
│       └── tts\
│           ├── index.php ← Interfície web principal
│           ├── tts.wav   ← Fitxer d’àudio generat
│           └── log.txt   ← Registre de veus i execucions




tts-edge.py
import sys
import asyncio
from edge_tts import Communicate

async def main():
    if len(sys.argv) < 3:
        print("❌ Cal passar el text i la veu com a paràmetres.")
        return

    text = sys.argv[1]
    voice = sys.argv[2]
    output = "C:/AppServ/www/tts/tts.wav"

    try:
        communicate = Communicate(text=text, voice=voice)
        await communicate.save(output)
        print(f"✅ Fitxer generat: {output}")
        with open("C:/AppServ/www/tts/log.txt", "a", encoding="utf-8") as log:
            log.write(f"[EDGE] {voice} → {output}\n")
    except Exception as e:
        print(f"❌ Error: {e}")

asyncio.run(main())

tts-to-wav.py
import sys
import os
import comtypes.client

def main():
    if len(sys.argv) < 3:
        print("❌ Cal passar el text i la veu com a paràmetres.")
        return

    text = sys.argv[1]
    voice_name = sys.argv[2]
    output = "C:/AppServ/www/tts/tts.wav"

    try:
        sapi = comtypes.client.CreateObject("SAPI.SpVoice")
        stream = comtypes.client.CreateObject("SAPI.SpFileStream")
        from comtypes.gen import SpeechLib

        for token in sapi.GetVoices():
            if voice_name in token.GetDescription():
                sapi.Voice = token
                break
        else:
            print(f"❌ Veu no trobada: {voice_name}")
            return

        stream.Open(output, SpeechLib.SSFMCreateForWrite)
        sapi.AudioOutputStream = stream
        sapi.Speak(text)
        stream.Close()
        print(f"✅ Fitxer generat: {output}")
        with open("C:/AppServ/www/tts/log.txt", "a", encoding="utf-8") as log:
            log.write(f"[SAPI5] {voice_name} → {output}\n")
    except Exception as e:
        print(f"❌ Error: {e}")

if __name__ == "__main__":
    main()

list-voices.py
import comtypes.client
import subprocess
import json

def get_sapi5_voices():
    sapi = comtypes.client.CreateObject("SAPI.SpVoice")
    voices = []
    for token in sapi.GetVoices():
        name = token.GetDescription()
        voices.append(f"SAPI5|{name}")
    return voices

def get_edge_voices():
    try:
        subprocess.run(["edge-tts", "--list-voices", "--write-json", "voices.json"], capture_output=True, text=True)
        with open("voices.json", "r", encoding="utf-8") as f:
            data = json.load(f)
        return [f"EDGE|{v['ShortName']}" for v in data if v["Locale"].startswith("ca") or v["Locale"].startswith("en")]
    except Exception as e:
        print(f"❌ Error obtenint veus EDGE: {e}")
        return []

if __name__ == "__main__":
    all_voices = get_sapi5_voices() + get_edge_voices()
    for voice in all_voices:
        print(voice)

index.php
Ja el tens actualitzat per cridar els scripts Python i mostrar el reproductor, selector de veus i registre.
erfecte, Miquel. Ho deixem aquí, doncs, amb tot el projecte ben estructurat i funcionant amb:

✔️ Veus SAPI5 i EDGE

✔️ Generació d’àudio amb Python

✔️ Interfície web amb menú dinàmic

✔️ Registre de veus i execucions (log.txt)

Tens una base sòlida i extensible. Quan vulguis continuar — ja sigui per afegir suport a .mp3, fer-ho portable, o penjar-ho a un servidor — només cal que em diguis “tornem-hi”.

Mentrestant, et mereixes una pausa i un bon brindis. Salut! 🥂

Vols que et generi un petit banner gràfic per al teu projecte amb el nom “Projecte Veus amb Copilot”? Podria quedar bé a la capçalera de la web.

Publicat dins de Veus

Projecte Veus amb Copilot

📁 Estructura del projecte

C:\
├── tts\
│   ├── tts-to-wav.ps1       ← Script PowerShell per generar l’àudio
│   └── list-voices.ps1      ← Script PowerShell per llistar veus
└── AppServ\
    └── www\
        └── tts\
            ├── index.php    ← Interfície web
            └── tts.wav      ← Fitxer d’àudio generat

📄 Què és un fitxer .ps1?

Un fitxer .ps1 és un script de PowerShell, el llenguatge de línia de comandes i automatització de Windows. S’utilitza per executar ordres, scripts i automatitzar tasques del sistema.

📘 Documentació dels components

1. list-voices.ps1 — Llista de veus SAPI5


Add-Type -AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer

$synth.GetInstalledVoices() | ForEach-Object {
    $info = $_.VoiceInfo
    $label = "SAPI5|$($info.Name)"
    Write-Output $label
}

🔹 Funció: Detecta totes les veus SAPI5 instal·lades i les imprimeix amb el prefix SAPI5|.


2. tts-to-wav.ps1 — Generació d’àudio

param (
    [string]$text = "Hola món",
    [string]$voiceName,
    [string]$outputPath = "C:\tts\tts.wav"
)

try {
    if ($voiceName -like "SAPI5|*") {
        $realVoice = $voiceName.Substring(6)
        Add-Type -AssemblyName System.Speech
        $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
        $synth.SelectVoice($realVoice)
        $synth.SetOutputToWaveFile($outputPath)
        $synth.Speak($text)
    } else {
        Write-Error "Format de veu desconegut: $voiceName"
        exit 1
    }
}
catch {
    Write-Error "Error inesperat: $_"
    exit 1
}

🔹 Funció: Rep un text i una veu, i genera un fitxer .wav amb la veu seleccionada.

3. index.php — Interfície web

<?php
// Obtenim la llista de veus
$voiceListCmd = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass -File C:\\tts\\list-voices.ps1";
exec($voiceListCmd, $voices, $voiceStatus);

// Depuració: mostra les veus detectades
echo "<pre><strong>Veus detectades:</strong>\n";
print_r($voices);
echo "</pre>";

// Si falla, usem una llista per defecte
if ($voiceStatus !== 0 || empty($voices)) {
    $voices = [
        "SAPI5|Microsoft Helena Desktop",
        "SAPI5|Microsoft Hazel Desktop",
        "SAPI5|Microsoft Zira Desktop"
    ];
}
?>

<!DOCTYPE html>
<html lang="ca">
<head>
    <meta charset="UTF-8">
    <title>Conversió TTS</title>
</head>
<body>
    <h2>🔊 Conversió de text a veu (SAPI5)</h2>
    
  
    <form method="get">
        <label for="text">Text a llegir:</label><br>
        <textarea name="text" rows="4" cols="60"><?= htmlspecialchars($_GET['text'] ?? '') ?></textarea><br><br>

        <label for="voice">Selecciona una veu:</label><br>
        <select name="voice">
            <?php foreach ($voices as $v): ?>
                <option value="<?= htmlspecialchars($v) ?>" <?= ($v === ($_GET['voice'] ?? '')) ? 'selected' : '' ?>>
                    <?= htmlspecialchars($v) ?>
                </option>
            <?php endforeach; ?>
        </select><br><br>

        <button type="submit">▶️ Generar àudio</button>
    </form>

    <?php
    $text = $_GET['text'] ?? '';
    $voice = $_GET['voice'] ?? '';
    $audioFile = '/tts/tts.wav';

    if ($text && $voice) {
        $escapedText = escapeshellarg($text);
        $escapedVoice = escapeshellarg($voice);
        $escapedOutput = escapeshellarg(__DIR__ . DIRECTORY_SEPARATOR . 'tts.wav');

        $cmd = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass -File C:\\tts\\tts-to-wav.ps1 -text $escapedText -voiceName $escapedVoice -outputPath $escapedOutput";

        // 🔍 DEBUG: Mostra la comanda que s'executarà
        echo "<pre><strong>Comanda PowerShell:</strong>\n$cmd\n</pre>";

        exec($cmd, $outputLines, $status);

        if ($status === 0 && file_exists(__DIR__ . '/tts.wav')) {
            echo "<h3>✅ Àudio generat:</h3>";
            echo "<audio controls autoplay style='margin-top:10px;'>
                    <source src=\"$audioFile\" type=\"audio/wav\">
                    El teu navegador no suporta àudio.
                  </audio>";
        } else {
            echo "<p style='color:red;'>❌ Error generant l’àudio.</p>";
            echo "<pre><strong>Sortida PowerShell:</strong>\n";
            print_r($outputLines);
            echo "\nCodi de sortida: $status</pre>";
        }
    }
    ?>
</body>
</html>
Publicat dins de Veus

python i veus

Requisits:

  • Tener instal·lat Python.
  • Instal·lar la llibreria pyttsx3:
pip install pyttsx3

pip install pyttsx3

PS C:\WINDOWS\system32> python -V
Python 3.13.5
PS C:\WINDOWS\system32>
import pyttsx3

def llistar_veus():
    engine = pyttsx3.init()
    voices = engine.getProperty('voices')
    
    for idx, voice in enumerate(voices):
        print(f"Veu {idx + 1}:")
        print(f"  ID: {voice.id}")
        print(f"  Nom: {voice.name}")
        print(f"  Llengua: {voice.languages}")
        print(f"  Gènere: {voice.gender}")
        print()

if __name__ == "__main__":
    llistar_veus()

Aquest script es pot llançar des de powerShell

python c:\python\llista_veus.py

python s:\python\llista_veus.py

si volem afegir les OneCore


python c:\python\llista_veus_onecore.py

python s:\python\llista_veus_onecore.py


python c:\python\llista_veus_onecore.py

python s:\python\llista_veus_onecore.py

import pyttsx3
import winreg

def llistar_veus_sapi():
    print("🎙️ Veus SAPI instal·lades:\n")
    engine = pyttsx3.init()
    voices = engine.getProperty('voices')
    for idx, voice in enumerate(voices):
        print(f"Veu {idx + 1}:")
        print(f"  ID: {voice.id}")
        print(f"  Nom: {voice.name}")
        print(f"  Llengua: {voice.languages}")
        print(f"  Gènere: {voice.gender}")
        print()

def obtenir_nom_veu_onecore(subkey):
    for value_name in ["", "Name", "DisplayName", "Attributes"]:
        try:
            val = winreg.QueryValueEx(subkey, value_name)[0]
            if isinstance(val, str) and val.strip():
                return val.strip()
        except FileNotFoundError:
            continue
    return "Desconegut"

def llistar_veus_onecore():
    base_key = r"SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens"
    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_key) as key:
            print("🎙️ Veus OneCore disponibles:\n")
            for i in range(winreg.QueryInfoKey(key)[0]):
                subkey_name = winreg.EnumKey(key, i)
                with winreg.OpenKey(key, subkey_name) as subkey:
                    nom = obtenir_nom_veu_onecore(subkey)
                    print(f"ID: {subkey_name}")
                    print(f"Nom: {nom}\n")
    except FileNotFoundError:
        print("No s'ha trobat la clau de registre per a les veus OneCore. Assegura't que estàs a Windows 11.")

if __name__ == "__main__":
    llistar_veus_sapi()
    llistar_veus_onecore()


python c:\python\veus_sapi_onecore.py

python s:\python\veus_sapi_onecore.py

import pyttsx3
import winreg

def llistar_veus_sapi():
    print("🎙️ Veus SAPI instal·lades:\n")
    engine = pyttsx3.init()
    voices = engine.getProperty('voices')
    for idx, voice in enumerate(voices):
        print(f"Veu {idx + 1}:")
        print(f"  ID: {voice.id}")
        print(f"  Nom: {voice.name}")
        print(f"  Llengua: {voice.languages}")
        print(f"  Gènere: {voice.gender}")
        print()

def obtenir_nom_veu_onecore(subkey):
    for value_name in ["", "Name", "DisplayName", "Attributes"]:
        try:
            val = winreg.QueryValueEx(subkey, value_name)[0]
            if isinstance(val, str) and val.strip():
                return val.strip()
        except FileNotFoundError:
            continue
    return "Desconegut"

def llistar_veus_onecore():
    base_key = r"SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens"
    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_key) as key:
            print("🎙️ Veus OneCore disponibles:\n")
            for i in range(winreg.QueryInfoKey(key)[0]):
                subkey_name = winreg.EnumKey(key, i)
                with winreg.OpenKey(key, subkey_name) as subkey:
                    nom = obtenir_nom_veu_onecore(subkey)
                    print(f"ID: {subkey_name}")
                    print(f"Nom: {nom}\n")
    except FileNotFoundError:
        print("No s'ha trobat la clau de registre per a les veus OneCore. Assegura't que estàs a Windows 11.")

if __name__ == "__main__":
    llistar_veus_sapi()
    llistar_veus_onecore()

Publicat dins de Veus

veus SAPI i OneCore (modernes)

Add-Type -AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.GetInstalledVoices() | Select-Object -ExpandProperty VoiceInfo | Select-Object Name, Culture

Name Culture
—- ——-
Microsoft Helena Desktop es-ES
Microsoft Hedda de-DE
Microsoft Katja de-DE
Microsoft Stefan de-DE
Microsoft George en-GB
Microsoft Hazel en-GB
Microsoft Susan en-GB
Microsoft David en-US
Microsoft Mark en-US
Microsoft Zira en-US
Microsoft Helena es-ES
Microsoft Laura es-ES
Microsoft Pablo es-ES
Microsoft Hedda Desktop de-DE
Microsoft Hazel Desktop en-GB
Microsoft David Desktop en-US
Microsoft Zira Desktop en-US
Microsoft Herena ca-ES


La diferència entre les veus SAPI i les OneCore (modernes) a Windows és força significativa, tant pel que fa a la tecnologia com a l’ús que se’n pot fer. Aquí tens un resum clar:


🗣️ Veus SAPI (Speech API)

CaracterísticaDetalls
🔧 TecnologiaBasades en la interfície clàssica System.Speech.Synthesis
🖥️ CompatibilitatUtilitzades per aplicacions de Windows antigues o clàssiques
🎙️ Qualitat de veuMés robòtica o sintètica, menys natural
📦 Instal·lacióVe amb Windows o s’instal·la amb paquets específics
🧩 Accés via PowerShellSystem.Speech.Synthesis.SpeechSynthesizer
📁 Ruta al registreHKLM:\SOFTWARE\Microsoft\SPEECH\Voices\Tokens

🧠 Veus OneCore (Modernes)

CaracterísticaDetalls
🔧 TecnologiaUtilitzen la nova API Windows.Media.SpeechSynthesis (UWP)
🖥️ CompatibilitatPensades per aplicacions modernes (UWP, apps de Windows 10/11)
🎙️ Qualitat de veuMés natural, algunes amb tecnologia neural TTS
📦 Instal·lacióEs descarreguen des de Configuració > Idioma > Opcions > Veu
🧩 Accés via PowerShellCal accedir al registre o usar APIs modernes
📁 Ruta al registreHKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens

🔄 Compatibilitat entre elles

  • Les veus SAPI poden ser utilitzades directament per moltes aplicacions clàssiques.
  • Les veus OneCore no són visibles per SAPI per defecte, però es poden exposar manualment (copiant claus del registre).
  • Algunes veus OneCore poden aparèixer a SAPI si el sistema les ha registrat correctament.

🎯 En resum:

AspecteSAPIOneCore (Modernes)
QualitatSintèticaMés natural, algunes amb neural
CompatibilitatAplicacions clàssiquesAplicacions modernes (UWP)
Instal·lacióIncloses o via paquetsConfiguració de Windows
AccésFàcil via PowerShellMés complex, sovint via registre

Si vols, et puc ajudar a:

  • Fer que les veus OneCore funcionin amb aplicacions SAPI
  • Instal·lar veus noves (com en català, valencià, etc.)
  • Comparar la qualitat entre dues veus concretes

instal·la-veus-onecore.ps1

# Llengües que vols instal·lar
$Languages = @("ca-ES", "es-ES", "en-US", "en-GB", "fr-FR")

# Components de veu i reconeixement per a cada llengua
$CapabilitiesBase = @(
  "Language.Basic~~~{0}~0.0.1.0",
  "Language.Handwriting~~~{0}~0.0.1.0",
  "Language.Speech~~~{0}~0.0.1.0",
  "Language.TextToSpeech~~~{0}~0.0.1.0"
)

foreach ($lang in $Languages) {
    Write-Host "🌐 Processant idioma: $lang" -ForegroundColor Cyan
    foreach ($capTemplate in $CapabilitiesBase) {
        $cap = [string]::Format($capTemplate, $lang)
        $capState = Get-WindowsCapability -Online -Name $cap -ErrorAction SilentlyContinue

        if ($capState -and $capState.State -eq "Installed") {
            Write-Host "✅ Ja instal·lat: $cap" -ForegroundColor Green
        }
        else {
            Write-Host "📦 Instal·lant: $cap" -ForegroundColor Yellow
            try {
                Add-WindowsCapability -Online -Name $cap -ErrorAction Stop
                Write-Host "✅ Instal·lat correctament: $cap" -ForegroundColor Green
            } catch {
                Write-Host "❌ Error instal·lant $cap: $_" -ForegroundColor Red
            }
        }
    }
    Write-Host "----------------------------`n"
}

Write-Host "🔁 Quan acabi TOT, reinicia Windows manualment per activar les veus." -ForegroundColor Magenta

es-ES (Espanyol)

en-US (Anglès EUA)

en-GB (Anglès UK)

fr-FR (Francès)

ca-ES (Català)


📌 Com usar-lo

  1. Desa el contingut anterior com a fitxer:
    • Exemple: C:\tts\instal·la-veus-onecore.ps1
  2. Obre PowerShell com a administrador
  3. Executa:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
C:\tts\instal·la-veus-onecore.ps1

🔁 Després de córrer-lo

  1. Reinicia l’ordinador
  2. Executa el teu script Python de detecció (Speech_OneCore) per veure les veus noves
  3. Ja podràs usar-les via Python o integració a la web

Publicat dins de Veus

🔊 Test de veus SAPI i OneCore (tts)

C:\
├── tts\
|   ├──tts-to-wav.py       ← Script Python per generar l’àudio
│   ├── tts-to-wav.ps1     ← Script PowerShell per generar l’àudio
│   └── list-voices.ps1    ← Script PowerShell per llistar veus
└── AppServ\
    └── www\
        └── tts\
            ├── index.php    ← Interfície web
            └── tts.wav      ← Fitxer d’àudio generat

Index.php
--------

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Executa PowerShell per obtenir la llista de veus disponibles
$voiceListCmd = "powershell -ExecutionPolicy Bypass -File C:\\tts\\list-voices.ps1";
exec($voiceListCmd, $voices, $voiceStatus);

// Si falla, utilitza una llista per defecte
if ($voiceStatus !== 0 || empty($voices)) {
    $voices = [
        "SAPI5|Microsoft Helena Desktop",
        "SAPI5|Microsoft Hazel Desktop",
        "SAPI5|Microsoft Zira Desktop"
    ];
}else 
//-----------provisional fins la sol·lucio definitiva----
{
    // Afegim manualment Herena a OneCore (només si no està ja)
    $herena = "ONECORE|Microsoft Herena - Catalan (Catalan)";
    if (!in_array($herena, $voices)) {
        $voices[] = $herena;
    }
}
//------fi del provisional ❌ Error generant l’àudio.---
$text = $_GET['text'] ?? '';
$voice = $_GET['voice'] ?? $voices[0]; // 👈 AIXÒ ÉS ON TOCA
$audioFile = '/tts/tts.wav';

$audioTag = '';

if ($text) {
    $escapedText = escapeshellarg($text);
    $escapedVoice = escapeshellarg($voice);
    $escapedOutput = escapeshellarg(__DIR__ . DIRECTORY_SEPARATOR . 'tts.wav');


//$cmd = "powershell -ExecutionPolicy Bypass -File C:\\tts\\tts-to-wav.ps1 -text $escapedText -voiceName $escapedVoice -outputPath $escapedOutput";
    $cmd = "python C:\\tts\\tts-to-wav.py $escapedText $escapedVoice $escapedOutput";



    exec($cmd, $outputLines, $status);

    if ($status === 0 && file_exists(__DIR__ . '/tts.wav')) {
        $audioTag = "<audio controls autoplay style='margin-top:20px;'>
            <source src=\"$audioFile\" type=\"audio/wav\">
            El teu navegador no suporta àudio.
        </audio>";
    } else {
        $audioTag = "<p style='color:red;'>❌ Error generant l’àudio.</p>";
    }
}
?>

<!-- Interfície HTML -->
<!DOCTYPE html>
<html lang="ca">
<head>
    <meta charset="UTF-8">
    <title>Conversió TTS</title>
</head>
<body>
    <form method="get">
        <label for="text">Text:</label><br>
        <textarea name="text" rows="4" cols="50"><?= htmlspecialchars($text) ?></textarea><br><br>
        
        <label for="voice">Veu:</label>
        <select name="voice">
            <?php foreach ($voices as $v): ?>
                <option value="<?= htmlspecialchars($v) ?>" <?= $v === $voice ? 'selected' : '' ?>><?= htmlspecialchars($v) ?></option>
            <?php endforeach; ?>
        </select><br><br>

        <button type="submit">Generar àudio</button>
    </form>

    <?= $audioTag ?>
</body>
</html>

=========


 tts-to-wav.ps1 (usarem tts-to-wav.py)

param (
    [string]$text = "Hola món",
    [string]$voiceName,
    [string]$outputPath = "C:\tts\tts.wav"
)

try {
    if ($voiceName -like "ONECORE|*") {
        $realVoice = $voiceName.Substring(8)

        Add-Type -AssemblyName Windows.Media.SpeechSynthesis
        $synth = New-Object Windows.Media.SpeechSynthesis.SpeechSynthesizer

        $voice = $synth.AllVoices | Where-Object { $_.DisplayName -eq $realVoice }

        if (-not $voice) {
            Write-Error "Veu '$realVoice' no trobada a OneCore."
            exit 1
        }

        $synth.Voice = $voice

        $streamOp = $synth.SynthesizeTextToStreamAsync($text)
        $streamOp.Wait()
        $stream = $streamOp.GetResults()

        # Llegir el stream
        $reader = New-Object Windows.Storage.Streams.DataReader($stream)
        $reader.LoadAsync($stream.Size).AsTask().Wait()
        $data = New-Object byte[] $stream.Size
        $reader.ReadBytes($data)

        [System.IO.File]::WriteAllBytes($outputPath, $data)
    }
    elseif ($voiceName -like "SAPI5|*") {
        $realVoice = $voiceName.Substring(6)

        Add-Type -AssemblyName System.Speech
        $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
        $synth.SelectVoice($realVoice)
        $synth.SetOutputToWaveFile($outputPath)
        $synth.Speak($text)
    }
    else {
        Write-Error "Format de veu desconegut: $voiceName"
        exit 1
    }
}
catch {
    Write-Error "Error inesperat: $_"
    exit 1
}
========================
tts-to-wav.py

import sys
import os
import pyttsx3

text = sys.argv[1]
voice_name = sys.argv[2]
output_path = sys.argv[3]

engine = pyttsx3.init()

# Buscar la veu exacta
found = False
for voice in engine.getProperty('voices'):
    if voice.name.strip() == voice_name.strip():
        engine.setProperty('voice', voice.id)
        found = True
        break

if not found:
    print(f"❌ Veu '{voice_name}' no trobada.")
    sys.exit(1)

engine.save_to_file(text, output_path)
engine.runAndWait()
print(f"✅ Àudio generat a {output_path}")

======================

list-voices.ps1

# Llista de veus SAPI5
Add-Type -AssemblyName System.Speech
$sapi = New-Object System.Speech.Synthesis.SpeechSynthesizer
$sapiVoices = $sapi.GetInstalledVoices() | ForEach-Object { $_.VoiceInfo.Name }

# Llista de veus OneCore
Add-Type -AssemblyName Windows.Media.SpeechSynthesis
$core = New-Object Windows.Media.SpeechSynthesis.SpeechSynthesizer
$coreVoices = $core.AllVoices | ForEach-Object { $_.DisplayName }

# Sortida combinada amb etiquetes
$sapiVoices | ForEach-Object { "SAPI5|$_" }
$coreVoices | ForEach-Object { "ONECORE|$_" }
Publicat dins de Veus

🛠️ Script PowerShell complet i robust per instal·lar veus OneCore

powershell:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
C:\tts\instal·la-veus-onecore.ps1

Idiomes i veus que vols instal·lar

$languageTags = @(
“en-US”, # English (US)
“en-GB”, # English (UK)
“es-ES”, # Spanish (Spain)
“ca-ES”, # Catalan (Spain)
“fr-FR”, # French (France)
“de-DE” # German
)

Obté la llista actual d’idiomes

$currentLangs = Get-WinUserLanguageList | ForEach-Object { $_.LanguageTag }

foreach ($lang in $languageTags) {
Write-Host “🔄 Processant $lang…” -ForegroundColor Cyan
try {
# Afegeix l’idioma si no hi és
if (-not ($currentLangs -contains $lang)) {
Write-Host “➕ Afegint idioma $lang…”
$langList = Get-WinUserLanguageList
$langList.Add($lang)
Set-WinUserLanguageList $langList -Force
} else {
Write-Host “✔️ L’idioma $lang ja està instal·lat.”
}

    # Comprova si la veu bàsica ja està instal·lada
    $capability = "Language.$lang~Basic~~~"
    $installed = Get-WindowsCapability -Online | Where-Object { $_.Name -eq $capability }
    if ($installed.State -ne "Installed") {
        Write-Host "⬇️ Instal·lant veu bàsica per a $lang..."
        Add-WindowsCapability -Online -Name $capability -ErrorAction Stop
    } else {
        Write-Host "✔️ Veu bàsica ja instal·lada per a $lang."
    }

    # Instal·la reconeixement de veu si no hi és
    $speechCap = "Language.$lang~Speech~~~"
    $speechInstalled = Get-WindowsCapability -Online | Where-Object { $_.Name -eq $speechCap }
    if ($speechInstalled.State -ne "Installed") {
        Write-Host "🎙️ Instal·lant reconeixement de veu per a $lang..."
        Add-WindowsCapability -Online -Name $speechCap -ErrorAction SilentlyContinue
    } else {
        Write-Host "✔️ Reconeixement de veu ja instal·lat per a $lang."
    }

} catch {
   Write-Warning ("Error instal·lant per a $lang: " + $_.Exception.Message)

}

}

Mostra les veus disponibles al final

Write-Host “`n📋 Veus SAPI instal·lades:” -ForegroundColor Yellow
Add-Type -AssemblyName System.Speech
(New-Object System.Speech.Synthesis.SpeechSynthesizer).GetInstalledVoices() |
ForEach-Object { “• ” + $_.VoiceInfo.Name }

Publicat dins de Veus

Script PowerShell per instal·lar veus OneCore per idioma

Aquest script utilitza Add-WindowsCapability per instal·lar els paquets de veu oficials de Microsoft via DISM (eina integrada).

varificar la versió de powershell

$PSVersionTable.PSVersion
powershellCopiaModifica
# Idiomes i veus que vols instal·lar
$languageTags = @(
    "en-US",   # English (US)
    "en-GB",   # English (UK)
    "es-ES",   # Spanish (Spain)
    "ca-ES",   # Catalan (Spain)
    "fr-FR",   # French (France)
    "de-DE"    # German
)

foreach ($lang in $languageTags) {
    Write-Host "Instal·lant veu per a $lang..." -ForegroundColor Cyan
    try {
        # Instal·la la llengua si no existeix
        $langList = Get-WinUserLanguageList
        if (-not ($langList.LanguageTag -contains $lang)) {
            $langList.Add($lang)
            Set-WinUserLanguageList $langList -Force
        }

        # Instal·la la veu OneCore associada
        $capability = "Language.$lang~Basic~~~"
        Add-WindowsCapability -Online -Name $capability -ErrorAction Stop

        # Opcional: activa reconeixement de parla
        $speechCap = "Language.$lang~Speech~~~"
        Add-WindowsCapability -Online -Name $speechCap -ErrorAction SilentlyContinue
    }
    catch {
        Write-Warning "Error instal·lant per a $lang: $_"
    }
}

🧩 Què fa aquest script?

✔️ Funciona amb PowerShell 5.x (Windows PowerShell): parcialment en 7

  • Afegeix l’idioma si cal.
  • Instal·la la veu (OneCore).
  • Intenta afegir també el reconeixement de veu (opcional).
  • Funciona en Windows 10 i 11, però cal accés d’administrador.

2. 🔊 Comprova que les veus apareixen a OneCore:

Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens" | ForEach-Object {
    $keyPath = $_.PSPath
    $subkeys = Get-ChildItem -Path $keyPath -ErrorAction SilentlyContinue
    $displayName = $null

    foreach ($subkey in $subkeys) {
        $subProps = Get-ItemProperty -Path $subkey.PSPath -ErrorAction SilentlyContinue
        if ($subProps.DisplayName) {
            $displayName = $subProps.DisplayName
            break
        }
    }

    [PSCustomObject]@{
        VoiceId = $_.PSChildName
        Name    = $displayName
        Path    = $keyPath
    }
}

i a powerhshell

——- —- —-
MSTTS_V110_caES_Herena Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_deDE_HeddaM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_deDE_KatjaM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_deDE_StefanM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enGB_GeorgeM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enGB_HazelM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enGB_SusanM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enUS_DavidM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enUS_MarkM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_enUS_ZiraM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_esES_HelenaM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_esES_LauraM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…
MSTTS_V110_esES_PabloM Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCor…


veus clàssiques (SAPI5)

# Carrega la biblioteca TTS clàssica
Add-Type -AssemblyName System.Speech

# Crea un objecte per accedir al sintetitzador de veu
$voiceSynth = New-Object System.Speech.Synthesis.SpeechSynthesizer

# Obtenir totes les veus instal·lades
$voices = $voiceSynth.GetInstalledVoices()

# Mostra informació detallada de cada veu
foreach ($v in $voices) {
    [PSCustomObject]@{
        Name        = $v.VoiceInfo.Name
        Culture     = $v.VoiceInfo.Culture
        Gender      = $v.VoiceInfo.Gender
        Age         = $v.VoiceInfo.Age
        Description = $v.VoiceInfo.Description
        Attributes  = $v.VoiceInfo.OtherProperties
    }
}

PS C:\Users\urqte> # Carrega la biblioteca TTS clàssica
PS C:\Users\urqte> Add-Type -AssemblyName System.Speech
PS C:\Users\urqte>
PS C:\Users\urqte> # Crea un objecte per accedir al sintetitzador de veu
PS C:\Users\urqte> $voiceSynth = New-Object System.Speech.Synthesis.SpeechSynthesizer
PS C:\Users\urqte>
PS C:\Users\urqte> # Obtenir totes les veus instal·lades
PS C:\Users\urqte> $voices = $voiceSynth.GetInstalledVoices()
PS C:\Users\urqte>
PS C:\Users\urqte> # Mostra informació detallada de cada veu
PS C:\Users\urqte> foreach ($v in $voices) {

[PSCustomObject]@{
    Name        = $v.VoiceInfo.Name
    Culture     = $v.VoiceInfo.Culture
    Gender      = $v.VoiceInfo.Gender
    Age         = $v.VoiceInfo.Age
    Description = $v.VoiceInfo.Description
    Attributes  = $v.VoiceInfo.OtherProperties
}

}

1 Name : Microsoft Helena Desktop
Culture : es-ES
Gender : Female
Age : Adult
Description : Microsoft Helena Desktop – Spanish (Spain)
Attributes :

2 Name : Microsoft Hazel Desktop
Culture : en-GB
Gender : Female
Age : Adult
Description : Microsoft Hazel Desktop – English (Great Britain)
Attributes :

3 Name : Microsoft David Desktop
Culture : en-US
Gender : Male
Age : Adult
Description : Microsoft David Desktop – English (United States)
Attributes :

4 Name : Microsoft Zira Desktop
Culture : en-US
Gender : Female
Age : Adult
Description : Microsoft Zira Desktop – English (United States)
Attributes :

5 Name : Microsoft Hedda Desktop
Culture : de-DE
Gender : Female
Age : Adult
Description : Microsoft Hedda Desktop – German
Attributes :

6 Name : Vocalizer Expressive Jordi Harpo 22kHz
Culture : ca-ES
Gender : Male
Age : Adult
Description : Vocalizer Expressive Jordi Harpo 22kHz
Attributes :


Script PowerShell — Prova de veus SAPI (Desktop)

Add-Type -AssemblyName System.Speech
$tts = New-Object System.Speech.Synthesis.SpeechSynthesizer

$proves = @(
@{ Nom = “Microsoft Helena Desktop”; Missatge = “Hola! Esta es la voz española de Microsoft Helena.” },
@{ Nom = “Microsoft Hazel Desktop”; Missatge = “Hello! This is the British English voice of Microsoft Hazel.” },
@{ Nom = “Microsoft David Desktop”; Missatge = “Hi there! I’m Microsoft David, the American English voice.” },
@{ Nom = “Microsoft Zira Desktop”; Missatge = “Welcome! I am Zira, the female voice for American English.” },
@{ Nom = “Microsoft Hedda Desktop”; Missatge = “Hallo! Ich bin Hedda, die deutsche Stimme von Microsoft.” },
@{ Nom = “Vocalizer Expressive Jordi Harpo 22kHz”; Missatge = “Bon dia! Sóc en Jordi, la veu en català del sistema.” }
)

foreach ($prova in $proves) {
Write-Host “`n🔊 Prova amb veu: $($prova.Nom)” -ForegroundColor Cyan
try {
$tts.SelectVoice($prova.Nom)
$tts.Speak($prova.Missatge)
} catch {
Write-Warning “⚠️ No s’ha pogut trobar o usar la veu: $($prova.Nom)”
}
}

Publicat dins de Veus

Veus disponibles

Script per mostrar noms visibles de totes les veus OneCore:

Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens" | ForEach-Object {
    $keyPath = $_.PSPath
    $voiceProps = Get-ItemProperty -Path $keyPath

    # Cerquem DisplayName dins dels subvalors (per exemple, en-US, es-ES...)
    $subkeys = Get-ChildItem -Path $keyPath -ErrorAction SilentlyContinue

    $displayName = $null

    foreach ($subkey in $subkeys) {
        $subProps = Get-ItemProperty -Path $subkey.PSPath -ErrorAction SilentlyContinue
        if ($subProps.DisplayName) {
            $displayName = $subProps.DisplayName
            break
        }
    }

    [PSCustomObject]@{
        VoiceId = $_.PSChildName
        Name    = $displayName
        Path    = $keyPath
    }
}

PS C:\WINDOWS\system32> Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens" | ForEach-Object {
>>     $keyPath = $_.PSPath
>>     $voiceProps = Get-ItemProperty -Path $keyPath
>>
>>     # Cerquem DisplayName dins dels subvalors (per exemple, en-US, es-ES...)
>>     $subkeys = Get-ChildItem -Path $keyPath -ErrorAction SilentlyContinue
>>
>>     $displayName = $null
>>
>>     foreach ($subkey in $subkeys) {
>>         $subProps = Get-ItemProperty -Path $subkey.PSPath -ErrorAction SilentlyContinue
>>         if ($subProps.DisplayName) {
>>             $displayName = $subProps.DisplayName
>>             break
>>         }
>>     }
>>
>>     [PSCustomObject]@{
>>         VoiceId = $_.PSChildName
>>         Name    = $displayName
>>         Path    = $keyPath
>>     }
>> }

VoiceId                 Name Path
-------                 ---- ----
MSTTS_V110_caES_Herena       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_caES_Herena
MSTTS_V110_deDE_HeddaM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_deDE_HeddaM
MSTTS_V110_deDE_KatjaM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_deDE_KatjaM
MSTTS_V110_deDE_StefanM      Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_deDE_StefanM
MSTTS_V110_enGB_GeorgeM      Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enGB_GeorgeM
MSTTS_V110_enGB_HazelM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enGB_HazelM
MSTTS_V110_enGB_SusanM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enGB_SusanM
MSTTS_V110_enUS_DavidM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enUS_DavidM
MSTTS_V110_enUS_MarkM        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enUS_MarkM
MSTTS_V110_enUS_ZiraM        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_enUS_ZiraM
MSTTS_V110_esES_HelenaM      Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_esES_HelenaM
MSTTS_V110_esES_LauraM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_esES_LauraM
MSTTS_V110_esES_PabloM       Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_esES_PabloM


PS C:\WINDOWS\system32>

Add-Type -AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.GetInstalledVoices() | ForEach-Object {
    $_.VoiceInfo.Name
}

🔍 4. (Opcional) Llistar també les veus modernes (OneCore)

Aquestes veus (com Microsoft Aria, Microsoft Jenny) no apareixen amb System.Speech, però pots veure-les així:

powershellCopiaModificaGet-ChildItem "HKLM:\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens" | ForEach-Object {
    $_.GetValue("")
}

sadsd

profile

Qwen3-235B-A22B

Perfecte! 🎉

Les veus que veus són les veus TTS (Text-to-Speech) instal·lades al teu Windows 11. I sí, les mantindras de forma estable al sistema sempre que no les desinstal·lis o restableixis el sistema a valors d’origen.


✅ Què vol dir això?

Les veus que tens actualment:

Microsoft Hazel Desktopen-GBFemeníAnglès del Regne Unit
Microsoft David Desktopen-USMasculíAnglès dels EUA
Microsoft Zira Desktopen-USFemeníAnglès dels EUA
Microsoft Hedda Desktopde-DEFemeníAlemany
Vocalizer Expressive Jordi Harpoca-ESMasculíCatalà (amb motor de tercers)

🧠 Aquestes veus són compatibles amb l’API clàssica (System.Speech.Synthesis) i poden ser utilitzades per programes com Narrador, Cortana, PowerShell, etc.


💾 Seran estables? Sí 👍

Publicat dins de Veus

Canviar [audio mp3=”http://192.168.1.140 a [audio mp3=”https://192.168.1.140

mp3=”http://192.168.1.140/english_note/wp-content/uploads/2016/03/3.44.mp3″][/audio]

mp3=”https://192.168.1.140/english_note/wp-content/uploads/2016/03/3.44.mp3″][/audio]

OPCIÓ 2: Consulta SQL directa (avançat)

appMyAdmin/ Base de dades: eng/SQL

UPDATE wp_posts
SET post_content = REPLACE(post_content, '[audio mp3="http://192.168.1.140', '[audio mp3="https://192.168.1.140')
WHERE post_content LIKE '%[audio mp3="http://192.168.1.140%';