param( [string]$DataJson = "vocab_audio_output\vocab_days.json", [string]$OutDir = "vocab_audio_output\audio", [string]$Voice = "Microsoft Zira Desktop", [int]$Rate = -2, [int]$Volume = 100 ) $ErrorActionPreference = "Stop" Add-Type -AssemblyName System.Speech $data = Get-Content -LiteralPath $DataJson -Encoding UTF8 -Raw | ConvertFrom-Json New-Item -ItemType Directory -Force -Path $OutDir | Out-Null $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer $synth.SelectVoice($Voice) $synth.Rate = $Rate $synth.Volume = $Volume $format = New-Object System.Speech.AudioFormat.SpeechAudioFormatInfo( 16000, [System.Speech.AudioFormat.AudioBitsPerSample]::Sixteen, [System.Speech.AudioFormat.AudioChannel]::Mono ) $breakShort = [TimeSpan]::FromMilliseconds(320) $breakLong = [TimeSpan]::FromMilliseconds(640) foreach ($day in $data.days) { $dayNumber = [int]$day.day $path = Join-Path $OutDir ("Day{0:D2}.wav" -f $dayNumber) $builder = New-Object System.Speech.Synthesis.PromptBuilder( [System.Globalization.CultureInfo]::GetCultureInfo("en-US") ) foreach ($entry in $day.entries) { $term = ([string]$entry.spoken).Trim() if ([string]::IsNullOrWhiteSpace($term)) { continue } $builder.AppendText($term) $builder.AppendBreak($breakShort) $builder.AppendText($term) $builder.AppendBreak($breakLong) } $synth.SetOutputToWaveFile($path, $format) $synth.Speak($builder) $synth.SetOutputToNull() Write-Host ("Day {0:D2}: wrote {1}" -f $dayNumber, $path) } $synth.Dispose()