Batch file counter, timer mit vorleseoption?

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
Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren