Block > text2youtubevideo.sh
12 min (2403 Wörter, 15527 Zeichen)
Inhaltsverzeichnis
Hinweis
Dieser Eintrag ist älter als 3 Jahre und entspricht vermutlich nicht mehr dem neuesten Stand der Technik/Realität.
Vor einiger Zeit entdeckte ich durch Zufall wieder das kleine Programm espeak , was Text in Phoneme umwandelt, die dann von einem anderen Programm, z.B. mbrola in Sprache umgewandelt werden kann (die dann gefuehlt besser klingt als Microsoft Sam ). Das an sich ist ja schonmal grossartig, und so habe ich einfach mal ein paar Stimmen runtergeladen und damit herumexperimentiert. Mbrola und acht deutsche Stimmen koennen unter ArchLinux aus dem AUR runtergeladen werden, espeak aus dem community -Repository:
yaourt -S mbrola mbrola-voices-de1 mbrola-voices-de2 \
mbrola-voices-de3 mbrola-voices-de4 mbrola-voices-de5 \
mbrola-voices-de6 mbrola-voices-de7 mbrola-voices-de8
sudo pacman -S espeak
Nach der Installation liess ich einfach mal einen kleinen Text von den verschiedenen Stimmen vorlesen:
text="Hallo, ich bin eine Computerstimme!"
espeak "$text" -vde
for i in $(seq 2 7) ; do # leider funktionieren nur die Stimmen 2-7
espeak "$text" -vmb-de$i
done
Und ab da hatte mich der Ehrgeiz gepackt und ich wollte mehr 😉
Ich finde es absolut faszinierend, aus reinem Text durch diverse Tools
sowas wie Bilder, PDFs, Videos, Audio, usw. entstehen zu lassen.
So kam mir die Idee, einen Text vorlesen zu lassen, mit
Hintergrundmusik und einer Videospur zu versehen und mit einem
Thumbnail und Untertiteln auf YouTube hochzuladen.
Nachdem ich einen Text gefunden hatte (naemlich die Martin Luther Uebersetzung der
Bibel von 1912 ), zerstueckelte ich ihn in passende Zeilenlaengen (mit
fmt
, also 75 Zeichen) und liess die ersten 100 Zeilen abwechselnd mit verschiedenen
Stimmen und zeilenabhaengigem Pitch mit espeak
vorlesen. Jede Zeile
liess ich in eine eigene Wav -Datei ausgeben.
Hintergrundmusik #
Die Hintergrundmusik fand ich schon etwas schwieriger. Angefangen habe
ich mit einem awk
-Script von kmkeen . Das gefiel mir auch
schon ganz gut, allerdings war da nichts drin, was sich in
Abhaengigkeit der Eingabe aendern wuerde, bzw. sah ich keine gute
Moeglichkeit dazu.
Dann habe ich auf der Suche die ABC-Notation , scala und
chasp entdeckt, was ich schonmal sehr geil fand, allerdings war es
mir zu viel Aufwand, den Eingabetext entsprechend zu formatieren (nur
Noten, dazu noch Notenlaengen usw.).
Und dann fand ich diesen Post , in dem durch ein kleines C-Programm
8-bit Musik generiert wird. Awesome!
Dazu z.B. einfach mal folgendes in eine Datei datei.c
schreiben:
main(t){for(;;t++)putchar((t*5&t>>7)|(t*3&t>>10));}
Das mit gcc
kompilieren:
gcc -w datei.c
Und ausfuehren, fuer unbegrenzte Musik:
./a.out
Geil! 😊
In dem Blogpost gibt es Links zu drei Videos, in denen einige
Funktionen genannt werden. Und noch mehr Funktionen gibt es in diesem
Thread .
Noch mehr zum Thema gibt es in diesem Post und es gibt sogar
eine Website , auf der fuer jede Stereo-Seite eine eigene
Funktion eingegeben und dann zusammen abgespielt werden kann. Awesome!
Jedenfalls war meine erste Idee, eine Funktion davon zu nehmen, und die
Zahlen durch andere Zahlen auszutauschen, die mir von einer kleinen Funktion
geliefert wird, die als Eingabe den Text bekommt, daraus den
SHA-512 -Hash bildet und mit tr
nur die Zahlen ausgibt. Die ersten
vier Zahlen davon ersetzen dann die Zahlen in dem C-Programm.
Allerdings gab es wegen zu grossen Zahlen Warnings, weswegen ich mich
dann einfach entschieden habe, abhaengig von der Textlaenge modulo 10
eine von zehn Funktionen fuer das C-Programm auszuwaehlen. Ist nicht
so toll, aber reicht fuer den Anfang. Verbesserungsvorschlaege sind
sehr willkommen! 😊
sha512sum input.txt | awk '{print $1}' | tr '[:alpha:]' ' ' | while read a b c d line ; do
echo "main(t){for(;;t++)putchar((t*$a&t>>$b)|(t*$c&t>>$d));}"
done
Eine weitere Idee war es, nur wenig Output von diesem Programm zu verwenden, um es dann mit paulstretch (leider nur eine GUI ) oder rubberband zu stretchen, allerdings fand ich das nicht so passend, da muesste ein besserer Input her.
Konkatenierung der Textstimmen & Vermischung mit der Hintergrundmusik #
Am Anfang dachte ich noch, die Konkatenierung der Textstimmen ist ja
recht trivial, einfach mit cat
die Dateien konkatenieren. Aber ja,
geht natuerlich nicht (Header und so). Ich habe dann eine Loesung mit
ffmpeg
gefunden (Quelle ):
ffmpeg -y -f concat -i <( for f in espeak-*.wav ; do echo "file '$f'" ; \
done ) -c copy concat.wav -loglevel quiet
Das klappte auch wunderbar. Erst spaeter fiel mir dann auf, dass die
Laenge der einzelnen .wav
-Dateien von der Laenge von concat.wav
abweicht. Nachdem ich mir die Dateien mit soxi espeak-*.wav
mal genauer
angesehen habe, stellte ich fest, dass die Sample Rate mal 22050 und
mal 16000 ist.
ffmpeg
ist dann so nett, und wandelt das anscheinend um, womit
manche Stimmen dann langsamer sind. Das wollte ich natuerlich nicht,
daher habe ich die Sample Rate der .wav
-Dateien mit sox
alle auf 16k
gesetzt und bei der Gelegenheit auch gleich mit einem 2. Channel
versehen:
for i in espeak-*.wav ; do sox $i -r 16k -c 2 $i.wav ; mv $i.wav $i ; done
Damit waren die Laengen der einzelnen Dateien (fast) identisch mit der von ffmpeg (Quelle ):
$ echo $(soxi -D espeak-*.wav | tr '\n' '+' | sed 's/+$//') | bc
45.917001
$ soxi -D concat.wav
45.917000
Soweit so gut, nun wollte ich also alles zusammenmischen.
Allerdings musste ich die Hintergrundmusik erst noch von Raw Audio in
etwas geeignetes umwandeln, und dann noch auf die passende Laenge
zurechtschneiden. Auch hier ist sox
wieder ein sehr gutes Tool.
Aber zuerst mal musste ich etwas Musik generieren und in eine Datei
schreiben lassen:
./a.out | head -n 1M > audio.raw
Update (2015-12-17)
meillo hat angemerkt, dass head
hier
nicht portabel ist, besser waere folgendes mit dd
:
./a.out | dd bs=1024 count=1024 > audio.raw
Ok, nun noch die Laenge von concat.wav
bestimmen, um die Laenge von
audio.raw dann direkt zu begrenzen (Quelle raw2wav ,
Quelle trim ):
sox -r 16k -e signed -b 16 -c 1 -v -0.1 audio.raw audio.wav \
trim 0 $(soxi -D concat.wav)
Direkt alles in einem Schritt 😊
Zuerst die Sample Rate auf 16k setzen, das ganze als signed, 16-Bit,
Stereo und etwas leiser umwandeln und eben noch mit trim begrenzen.
Und damit musste ich nur noch alles zusammenmischen, und zwar wieder
mit sox
:
sox -m audio.wav concat.wav output.wav
Update
Ich habe mich nun dazu entschlossen, den letzten Schritt nicht zu machen sondern stattdessen einfachconcat.wav
nach
output.wav
zu kopieren, sprich, die Hintergrundmusik wegzulassen, da
sie mit den Einstellungen einfach zu nervig war.
Awesome, was kann dieses Tool eigentlich nicht? 😄
Hier mal 15 Beispiele , was so alles mit sox
moeglich ist 😉
Video #
Das Video hinzufuegen war schon etwas schwieriger. Vor allem wusste ich erst mal
ueberhaupt nicht, was ich da nehmen sollte. Es sollte ja schon etwas
mit dem Eingabetext zu tun haben …
Beim Stoebern fand ich dann diese Frage bei StackExchange , wobei mir
die Antworten schonmal gut gefielen. Weiter gefunden habe ich was mit
gstreamer , allerdings war ich zu faul, mich damit zu
beschaeftigen, wie das mit wav anstatt mp3 funktioniert. Und dann noch
eine Frage .
Die erste Antwort hat mir gut gefallen, allerdings war das etwas
zuviel auf einmal. Ich habe mich dann einfach fuer avectorscope
entschieden:
ffmpeg -i output.wav -filter_complex avectorscope=s=1920x1080 -y \
-acodec aac -strict -2 video.mp4
Zuerst hatte ich noch die Idee, das ganze einfach nur mit Bildern zu
machen, allerdings waere das nicht so dynamisch gewesen.
Mit sox
ist es ziemlich einfach, ein Spectrogram zu erzeugen,
allerdings laesst sich damit zusammen mit gnuplot
auch leicht eine
Waveform erstellen .
Thumbnail #
Fuer YouTube sollte es dann auch ein eigenes Thumbnail geben. Hier war
zuerst meine Idee, die einzelnen Ziffern des Eingabetexts ins
Hexadezimalsystem umzuwandeln um dann Hexadezimal-3-Tupel als
RGB -Wert zu verwenden, um dann Pixel fuer Pixel ein Bild zu erstellen.
Nach einiger Suche fand ich dann eine gute Vorangehensweise , und zwar
mit dd
und convert
! Krass!
Zwar nicht genau das, was ich wollte, aber es erfuellte den Zweck
einer Thumbnailerstellung 😉
dd if=input.txt bs=$((1280*720*3)) count=1 | convert -size \
1280x720 -depth 8 rgb:- thumbnail.png
Das war mir dann aber doch etwas zu unschoen, und dann fiel mir wieder
gmic
und mein Script zum Erstellen von
Bildschirmhintergruenden ein.
Meine Idee war dann, den MD5 -Hash des Eingabetexts in 16 2-Tupel zu
zerlegen um somit 4 RGBA Werte zu erhalten (Quelle ). Damit
konnte ich dann den gmic
-Befehl fuettern, um ein Verlaufsbild zu
erstellen:
hex=$(md5sum input.txt | awk '{print $1}' | tr '[:lower:]' '[:upper:]')
hex1=$(cut -c-8 <<<$hex)
hex2=$(cut -c9-16 <<<$hex)
hex3=$(cut -c17-24 <<<$hex)
hex4=$(cut -c25-32 <<<$hex)
rgba1=$(printf "%d,%d,%d,%d" 0x${hex1:0:2} 0x${hex1:2:2} 0x${hex1:4:2} 0x${hex1:6:2})
rgba2=$(printf "%d,%d,%d,%d" 0x${hex2:0:2} 0x${hex2:2:2} 0x${hex2:4:2} 0x${hex2:6:2})
rgba3=$(printf "%d,%d,%d,%d" 0x${hex3:0:2} 0x${hex3:2:2} 0x${hex3:4:2} 0x${hex3:6:2})
rgba4=$(printf "%d,%d,%d,%d" 0x${hex4:0:2} 0x${hex4:2:2} 0x${hex4:4:2} 0x${hex4:6:2})
gmic 1280,720,1,3 -gimp_corner_gradient $rgba1,$rgba2,$rgba3,$rgba4 -o $thumbnail
Die Aufloesung haelt sich hier an die Best Pratices zur Thumbnailerstellung von YouTube .
Eine Beschriftung wollte ich dann auch noch haben, wobei sich dann
recht einfach mit convert
machen laesst:
text="Ich bin eine Beschriftung."
convert -background '#0008' -fill white -gravity center -size \
1280x180 caption:"$text" thumbnail.png +swap -gravity south \
-composite thumbnail_neu.png
Untertitel #
Zu guter Letzt wollte ich, wenn ich schonmal dabei bin, auch noch
Untertitel fuer das Video haben. Das ist ja in meinem Fall keine
grosse Sache, ich habe ja die Textzeilen und die Laenge der
Textstimmen kann ich ja bestimmen.
Bei der Erstellung der Textstimmen habe ich also einfach nur fuer jede
Textzeile eine srt -kompatible Form daraus gemacht. Die Laenge der
Textstimmen habe ich dabei von Sekunden mit einer kleinen Funktion in
hh:mm:ss:ms
umgewandelt.
Awesome! 😊
Alles zusammen #
Die einzelnen Dateien gibt es hier zum runterladen:
- martin_luther_uebersetzung_1912.txt
- text2youtubevideo.sh-bgmusic.wav
- text2youtubevideo.sh.c
- text2youtubevideo.sh.bin
- text2youtubevideo.sh-concat.wav
- text2youtubevideo.sh.mp4
- text2youtubevideo.sh.png
- text2youtubevideo.sh.srt
- text2youtubevideo.sh.wav
Das Video (dank <video>
-Tag im Browser abspielbar):
Und hier das Script zur Erstellung auf GitHub :
|
|