Skript für Ansagen in mp3-Dateien

das gebe ich ein:

python add_lead_in_messages.py -i 'import' -o export --use-say

Meine Audiodateien befinden sich im Unterordner ‚import‘. Dieser befindet sich im selben Ordner wie das Skript.

Das ist die komplette Ausgabe

WARNING: It looks like you are using an old version of Python. Please use Python 3 if you intend to use Google Text to Speech.
Adding lead-in "-Auf dem Bauernhof" to /Users/lp-mj-02/Documents/TonUINO/TonUINO-DEV/tools/export/001-Auf_dem_Bauernhof.mp3

Generating: temp-lead-in.mp3 - -Auf dem Bauernhof
say: invalid option -- A
Usage: say [-v voice] [-o out] [-f in | message]
ffmpeg version 4.2.2 Copyright (c) 2000-2019 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.16)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.2.2_1 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags='-I/Library/Java/JavaVirtualMachines/adoptopenjdk-13.0.1.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/adoptopenjdk-13.0.1.jdk/Contents/Home/include/darwin -fno-stack-check' --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-libsoxr --enable-videotoolbox --disable-libjack --disable-indev=jack
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
temp.aiff: No such file or directory
Traceback (most recent call last):
  File "add_lead_in_messages.py", line 135, in <module>
    addLeadInMessage(args.input, args.output)
  File "add_lead_in_messages.py", line 55, in addLeadInMessage
    addLeadInMessage(os.path.join(inputPath, child), os.path.join(outputPath, child))
  File "add_lead_in_messages.py", line 84, in addLeadInMessage
    text_to_speech.textToSpeechUsingArgs(text=text, targetFile=tempLeadInFile, args=args)
  File "/Users/lp-mj-02/Documents/TonUINO/TonUINO-DEV/tools/text_to_speech.py", line 64, in textToSpeechUsingArgs
    textToSpeech(text, targetFile, lang=args.lang, useAmazon=args.use_amazon, useGoogleKey=args.use_google_key)
  File "/Users/lp-mj-02/Documents/TonUINO/TonUINO-DEV/tools/text_to_speech.py", line 97, in textToSpeech
    os.remove('temp.aiff')
OSError: [Errno 2] No such file or directory: 'temp.aiff'
1 „Gefällt mir“

Das sieht für mich nach einem Pfad Problem aus. Wechsle doch mal in den Ordner Import und rufe das Script via python ../add_lead_in_messages.py usw auf…

funktioniert auch nicht…

was bedeutet denn
say: invalid option -- A Usage: say [-v voice] [-o out] [-f in | message]

Kann es sein, dass

Generating: temp-lead-in.mp3 - -Auf dem Bauernhof

nicht funktioniert und daher temp.aiff nicht angelegt wird und selbstverständlich nicht gefunden wird?

Das Problem werden vermutlich - im Dateinamen sein. So funktioniert es bei mir einwandfrei:

Habe einen Ordner test

$ ls test
Das Testlied.mp3

Dann Script ausführen…

python3 tools/add_lead_in_messages.py -i test -o test2 --use-say --add-numbering

Ergebnis in Ordner test2

$ ls test2
001_Das Testlied.mp3
1 „Gefällt mir“

Perfekt. Vielen Dank. Das war die Lösung…
Es lag am Dateinamen…
Habe einmal alle „-“ und „_“ entfernt… jetzt geht es.

Habe den Befehl übrigens mit Hilfe von python3 ausgeführt

1 „Gefällt mir“

Das ist interessant und gut zu wissen, dass es einen Workaround gibt.
In bestimmten Fällen werden anscheinend intern die Parameter falsch zusammengebaut. Vermutlich ließe sich das leicht beheben, wenn man die richtige Stelle im Code findet.

das „-“-Zeichen im Dateinamen wird als Parameter für say interpretiert. Das ist ja definitiv falsch.
Daher kommt auch die Fehlermeldung

say: invalid option --A

Das „-A“ sind die erste beiden Zeichen des Dateinamen hinter der Nummerierung.
Da scheint der Code durcheinander zu kommen.
Leider kann ich kein Python… :frowning:

Vielleicht kann @Til da nochmal drauf schauen und mir einen PR schicken.

Ich vermute mal, dass das nur mit MacOS say und u.U. bei Amazon Polly passiert und zwar nur wenn der zu generierende Text mit einem Bindestrich anfängt. Bei Google TTS dürfte das nicht passieren, weil der Text da anders übergeben wird.

So wie es aussieht werden bereits eventuell vorhandene Nummern ignoriert (deshalb begann dein Text mit einem Bindestrich). Man könnte also relativ einfach zusätzlich weitere nachweislich problematische Zeichen am Anfang des Textes wegschneiden.

Alternativ könnte es auch helfen, wenn man den Text Parameter im Code in Anführungszeichen setzt. Ich habe allerdings keinen Mac und kenne weder die shell dort, noch die Parameter von say, also ist das auch nur eine Vermutung.

Für Windows habe ich jetzt folgende Lösung benutzt:
Ich habe die gTTS-Bibliothek in Python installiert. Dazu muss man in der Kommandozeile folgenden Befehl eingeben:

pip install gTTS

Danach habe ich im Grunde nur im Script text_to_speech.py den Teil des codes, der genutz wird wenn „say“ ausgewählt wurde:

subprocess.call([ 'say', '-v', sayVoiceByLang[lang], '-o', 'temp.aiff', text ])
subprocess.call([ 'ffmpeg', '-y', '-i', 'temp.aiff', '-acodec', 'libmp3lame', '-ab', '128k', '-ac', '1', targetFile ])
os.remove('temp.aiff')

durch folgendes ersetzt:

myobj = gTTS(text=text, lang=lang, slow=False)
myobj.save("temp.mp3")
subprocess.call([ 'ffmpeg', '-y', '-i', 'temp.mp3', '-acodec', 'libmp3lame', '-ab', '128k', '-ac', '1', targetFile ])
os.remove('temp.mp3')

Außerdem muss man am Anfang des Scripts noch die Zeile

from gtts import gTTS

einfügen damit die Bibliothek geladen wird.

Das hat bei mir tadellos funktioniert und man muss sich nirgends anmelden. Man hat keine Stimmenauswahl, aber es eine weibliche Stimme und es klinkt gut verständlich.

2 „Gefällt mir“

Kannst du das näher erläutern? :see_no_evil:

1 „Gefällt mir“

Mit Python wird das Tool pip installiert, mit dem man neue Bibliotheken für Python herunterladen und installieren kann.
Dazu muss man in der Kommandozeile den Befehl

pip install gTTS

eingeben. Die gTTS Bibliothek wird dann heruntergeladen und installiert und steht dann für Python zur Verfügung.

Ich habe das von dieser Internetseite: https://www.geeksforgeeks.org/convert-text-speech-python/
Ach so, man darf nicht vergessen am Anfang des Scripts text_to_speech.py die Zeile

from gtts import gTTS

einzufügen, damit die Bibliothek auch geladen wird. Das hatte ich oben vergessen.

1 „Gefällt mir“

Super Sache. Wenn das tatsächlich ohne Anmeldung oder Einschränkungen funktioniert würde es sich bestimmt lohnen das als zusätzliche Option im Skript einzubauen.

Die Frage ist wie ist die Qualität? Dazu kommt, dass man das Package installieren muss auch wenn man die Option nicht nutzt oder (kenne mich mit Python nicht so aus). Die Qualität von Google TTS und Amazon Polly ist halt schon sehr gut und „say“ unter macOS ist auch ganz gut.

Und zum Thema anmelden, für Google TTS wurde ja in diesem Thread ein Key verlinkt den man nutzen kann, falls man keinen eigenen erstellen will.

Zur Qualität kann ich nichts sagen, aber man könnte es sicher so bauen, dass alles andere auch ohne das gTTS Paket wie bisher funktioniert. Falls es nicht installiert ist und man es trotzdem nutzt könnte ja per Fehlermeldung darauf hingewiesen werden.

In Python ist das Installieren eines Package vergleichbar wie das Laden einer Library in C also wie eine Bibliothek einfügen mit der Arduino IDE.
Deshalb muß das Paket oder eine Funktion daraus im Code eingebunden werden, wie z.B.
#include <DFMiniMp3.h>
im TonUINO-Programm.
Das Installieren des Package hat also keine Betriebssystemsänderung gemacht, wie das bei manchen Programminstallationen gemacht wird, sondern stellt dem Interpreter Python die Zusatzfunktionen in den Librarypfad.

Ja, das ist mir schon klar. @Dave hatte schon verstanden wie ich das meinte. Ich will nicht dass man das installieren muss auch wenn man diesen TTS gar nicht nutzen will. Bisher läuft das Script nämlich ohne externe Abhängigkeiten.

Naja. Ohne ffmpeg gehts nicht. Zudem wurde ursprünglich curl für Google TTS benötigt, aber das hatte ich mal durch native Python Funktionen ersetzt, damit das Skript auch unter Windows und somit für so ziemlich alle User out of the Box läuft.

Da die Maxime dieses Projektes ganz klar auf Benutzerfreundlichkeit liegt sehe ich es auch so, dass man möglichst wenig externe Abhängigkeiten einbauen sollte.
Allerdings funktioniert die Installation eines Paketes mittels pip in der Regel problemlos und ist denke ich sogar schneller gemacht als z.B. einen Api Key bei Google oder Amazon einzurichten. Klingt für mich auf jeden Fall nach einer interessanten Alternative zu den bereits vorhandenen Optionen. Danke nochmal an @himmel9 dafür :slightly_smiling_face:

1 „Gefällt mir“

Google hab ich noch nicht versucht. Amazon habe ich momentan aufgegeben. Da muss man ja was weiß ich was alles machen. Nicht mal meine Amazon Daten haben die in AWS übernommen… Wenn die Stimmenqualität besser ist als beim Mac mit say dann installiere ich gerne noch ein Paket (wenn das einfacher geht) auf meinem Windows Rechner.
Just my 2ct

Also ich hab das mal schnell ausprobiert:

pip3 install gTTS

Und das Script wie oben provisorisch angepasst. Was soll ich sagen… es funktioniert, aber die Sprachausgabe ist - ich muss es leider so deutlich sagen - nicht gut. Trotzdem danke an @himmel9 für den Vorschlag, mein Fall ist das aber ehrlich gesagt nicht.