Batch file counter, timer mit vorleseoption?
Hallo, ich würde mir gerne ein Script erstellen, was von 0 bis 3000 (50min) zählt und alle zwei Minuten einen kurzen Satz vorließt. Ich habe nur leider keine Ahnung wie ich da vorgehe. Habe auch schon gegoogled aber leider nichts passendes gefunden. Falls sich jemand mit sowas auskennt, würde ich mich über eine Nachricht freuen :)
1 Antwort
Solch komplexe Sachen wie das akustische Ausgeben von Text gehört nicht unbedingt zur Ausstattung von Batch. (Batch hat ja schon Probleme mit der normalen Ausgabe von Text.)
Das ist auch der Grund, weshalb diesbezüglich nicht viel zu finden ist.
Erstmal ein Paar Grundlagen:
Der einfachste Weg aus dem "Handgelenk" eine Sprachausgabe zu programmieren ist ein HilfsScript in JS-VBScript (Ich ziehe diesbezüglich JavaScript vor)
Die folgende Batch ist fast überkommentiert und erklärt recht genau was im einzelnen passiert.
LaberDemo.cmd
@echo off
rem Umlaute erlauben
chcp 65001>nul
rem pfad zur Scriptdatei festlegen (Tempordner ist immer der beste Platz)
set "sayJS=%temp%\say.js"
::Begin Sprachausgabe einrichten
rem pfad zur Scriptdatei festlegen (Tempordner ist immer der beste Platz)
set "sayJS=%temp%\say.js"
rem sprachgeschwindigkeit einstellen (Werte von -10 bis 7 sind einigermaßen Sinnvoll)
set "Speed=-1"
rem lautstärke (0..100) (relativ zu den globalen Lautstärkeeinstellungen des Systems)
set "Volume=100"
rem das LaberScript in den Tempordner schreiben
echo s=new ActiveXObject('SAPI.SpVoice');s.Rate=%Speed%;s.Volume=%Volume%;a='';for (i=0;i^<WScript.Arguments.length;i++){a+=WScript.Arguments(i)+' '};s.Speak(a,0)>"%sayJS%"
rem Aufrufmakro (es wäre doch blöd jedesmal die ganze Befehlszeile von Cscript zu schreiben)
rem Achtung am Ende der folgenden Zeile befindet sich ein Leerzeichen! (nicht vergessen, dieses ist unsichtbar!)
rem Batch wartet bis die Ansage zu ende ist
set talk=cscript //nologo "%sayJS%"
rem startet die Sprachausgabe in einem parallelen Thread (die Batch lauft ohne warten weiter)
set talkAsync=start "" /b %talk%
::Ende Sprachausgabe einrichten
::::: Ende Vorbereitung :::::
:: Der Rest ist Demo:
rem einfach zur Demo Text variablen festlegen
set "Text1=ich labere"
set "Text2=was das Zeug herhält..."
rem Makro aufrufen
%talk% Ich bin die Stimme
echo Ich mache erst weiter wenn fertiggesprochen ist...
rem ... oder
%talk% "Halöchen Herr und Meister"
echo und habe wieder gewartet...
rem oder auch
%talk% %text1% %text2%
%talk% "wollen wir spielen"
rem würfle eine Zahl
set /a "wurf=%random% %% 6 +1"
%talk% "ich habe eine %wurf% gewürfelt"
%talkAsync% Es ist schon %time:~0,5% Uhr . Da spiele ich nicht mehr. ...ach, Deine Batch arbeitet ja schon weiter.
echo Es ist %time:~0,5% Uhr
for /l %%a in (1,1,15) do (
echo %%a Misisippi...
timeout 1 >nul
)
%talkAsync% und Tschüss
pause
oder eine einfache sprechende Uhr
quasseluhr.cmd
@echo off
chcp 65001>nul
rem fenstergröße
mode 50,2
title Quasseluhr
set "sayJS=%temp%\say.js"
set "Speed=-1"
set "Volume=100"
echo s=new ActiveXObject('SAPI.SpVoice');s.Rate=%Speed%;s.Volume=%Volume%;a='';for (i=0;i^<WScript.Arguments.length;i++){a+=WScript.Arguments(i)+' '};s.Speak(a,0)>"%sayJS%"
set talk=cscript //nologo "%sayJS%"
set talkAsync=start "" /b %talk%
%talk% Ich bin Deine Quassel-uhr.
%talk% Schön das du mich die Zeit ansagen lässt
:loop
rem erzeuge Beep...
start "" /b cmd /c echo ax^|choice /c x ^>nul
cls
echo He Meister, beim Piepton war es %time:~0,8% Uhr
rem sage die Uhrzeit
%talkAsync% He Meister, beim Piepton war es %time:~0,8% Uhr
rem warte eine Minute (kleine Zeitverschiebungen sind möglich, cls braucht einige Millisekunden und läuft nicht Asynchron)
timeout 60 >nul
goto :loop
Das obige ist noch relativ einfach gestaltet. Aber schon bei der Quasseluhr muss ich mit parallelen Prozessen arbeiten, da Batch normalerweiße wartet bis ein Programm-/Scriptaufruf abgearbeitet ist.
Batch verfügt über keine Ereignisgesteuerten Timer, als kann man Zeitabläufe nur über Wartezeiten einigermaßen steuern jeder serielle Befehl innerhalb einer Schleife erhöht die Ungenauigkeit. Dagegen lässt sich auch nichts tun.
Da Du auch noch innerhalb der Schleife den Zustand der Laufvariable abfragen musst ist es erforderlich das Geschehen in eine Subroutine auszulagern, da Batch innerhalb eines Schleifenbody nicht auf das Ergebnis einer Berechnung zugreifen kann (könnte schon, aber DelayedExpansion würde Dir den Schädel sprengen)
Erstmal die Realisation dessen, was Dir so vorschwebt:
demo.cmd
@echo off
chcp 65001>nul
set "sayJS=%temp%\say.js"
set "Speed=-1"
set "Volume=100"
echo s=new ActiveXObject('SAPI.SpVoice');s.Rate=%Speed%;s.Volume=%Volume%;a='';for (i=0;i^<WScript.Arguments.length;i++){a+=WScript.Arguments(i)+' '};s.Speak(a,0)>"%sayJS%"
set talk=cscript //nologo "%sayJS%"
set talkAsync=start "" /b %talk%
set "RunSeconds=3000"
set "MsgSeconds=20" &rem habe hier zur Demo mal 20 Sekunden angesetzt 2 Minuten wären zu langweilig, wenn nix geschieht
for /l %%a in (1,1,%RunSeconds%) do (
call :IsTimeToSay %%a
timeout 1 >nul &rem eine Sekunde warten
)
pause
exit /b
:::: Subroutines ::::
:IsTimeToSay %1=counter
rem berechne, ist der aktulle Counter ohne Rest durch 120 teilbar?
set /a "Rest=%1 %% MsgSeconds"
if %Rest% neq 0 exit /b &rem ...wenn nicht zurück in die Schleife
rem hier alles was getan werden soll
set /a "Restminuten=(RunSeconds-%1)/60 , RSecnd=(RunSeconds-%1)%%60"
rem alles was zu sagen ist in eine Zeile (max 8000 Zeichen)
rem das muss ja in einem parallelen Prozess laufen...
%talkAsync% Hallo Burtzel. Es ist %time:~0,5% Uhr . Laberrhababer. es bleiben noch %Restminuten% Minuten %RSecnd% Sekunden
exit /b
Ist natürlich wenig Ideal da sich bei einem Takt von einer Sekunde auch Ungenauigkeiten und Verzögerungen summieren.
Ich würd da lieber gleich mit Schritten von einer Minute oder dem Zeitinterval der Ansagen arbeiten:
@echo off
chcp 65001>nul
set "sayJS=%temp%\say.js"
set "Speed=-1"
set "Volume=100"
echo s=new ActiveXObject('SAPI.SpVoice');s.Rate=%Speed%;s.Volume=%Volume%;a='';for (i=0;i^<WScript.Arguments.length;i++){a+=WScript.Arguments(i)+' '};s.Speak(a,0)>"%sayJS%"
set talk=cscript //nologo "%sayJS%"
set talkAsync=start "" /b %talk%
set "RunSeconds=3000"
set "MsgSeconds=20"
rem lass die Zählschleife einfach größere Schritte machen
for /l %%a in (1,%MsgSeconds%,%RunSeconds%) do (
timeout %MsgSeconds% >nul
%talkAsync% Hallo Science198. Es ist %time:~0,5% Uhr . Laberrhababer.
)
pause