Skip to content

Instantly share code, notes, and snippets.

@jacksonrayhamilton
Last active December 10, 2020 21:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacksonrayhamilton/7496687 to your computer and use it in GitHub Desktop.
Save jacksonrayhamilton/7496687 to your computer and use it in GitHub Desktop.
Text-to-speech bash script using libttspico. Encodes to ogg and/or mp3. Decent quality. Got me through my literature class.
#!/bin/bash
#
# Takes a text file and makes an audiobook for it.
#
# Specifically:
# Converts a single text file to multiple ogg and/or mp3 files.
#
# Requires:
# libttspico-data libttspico0 libttspico-utils
# libttspico-dev lame vorbis-tools
#
# Use:
# Say you have a book in plain-text format called "book.txt".
# $ bash ~/Apps/bash/tts.sh book.txt
#
# Process commandline arguments
while getopts "f:sh" opt
do
case $opt in
f)
format="$OPTARG"
;;
s)
single=1
;;
h)
echo "Usage: `basename $0` [OPTION]... FILE
Perform text-to-speech on FILE.
-f specify output format
if unspecified, outputs both formats
possible arguments:
ogg
mp3
-s single audio file
encode as 'filename.ogg', rather than
the default 'filename-part-i-of-n.ogg'
-h display help and exit
Examples:
`basename $0` book.txt
`basename $0` -f ogg -s snippet.txt"
exit 1
;;
esac
done
shift $(($OPTIND - 1))
file="$1" # book.txt
filename="${file%.*}" # book
workingDir=".$filename-tts" # .book-tts
filePartPrefix="$filename-part-" # book-part-
filePartOutput="$workingDir/$filePartPrefix" # .book-tts/book-part-
# Determine how many parts there will be
bytes=$(wc -c < $file)
parts=$(( bytes/32000 ))
if [ $(( bytes%32000 )) -gt 0 ]
then
((parts++))
fi
if [ -n "$single" ] && [ "$parts" -gt 1 ]
then
echo "Error: More than 1 part.
Reduce filesize to <= 32000 bytes or do not specify the '-s' flag."
exit 1
fi
# Make a temporary working directory
mkdir "$workingDir"
# Split the file into chunks that pico2wave can manage
# (the maximum bytes allowed is around 2^15)
echo "Splitting file into $parts parts ..."
split --bytes=32000 --suffix-length=4 --numeric-suffixes "$file" "$filePartOutput"
for aFile in $(ls $filePartOutput*)
do
mv $aFile ${aFile}.txt
done
# Perform text-to-speech using pico2wave
echo "Performing text-to-speech ..."
i=1
for part in $filePartOutput[0-9]*.txt
do
if [ -n "$single" ]
then
ttsFilename="$filename"
else
ttsFilename="$filePartPrefix$i-of-$parts"
fi
ttsWav="$workingDir/$ttsFilename.wav"
# Perform text-to-speech for this part
echo "TTSing part $i of $parts ... ($part)"
fileContents=$(<"$part")
pico2wave -l=en-US -w="$ttsWav" "$fileContents"
# Encode audio to distributable formats
# Encode to both if '-f' flag is unspecified
# If '-f' flag is specified, only encode to the argument format
if [ -z "$format" -o "$format" == "ogg" ]
then
echo "Encoding to ogg ..."
oggenc "$ttsWav" --output="$ttsFilename.ogg"
fi
if [ -z "$format" -o "$format" == "mp3" ]
then
echo "Encoding to mp3 ..."
lame -V 8 --vbr-new -h -q 0 "$ttsWav" "$ttsFilename.mp3"
fi
((i++))
done
# Clean up
rm -rf $workingDir
echo "TTS complete."
@rojenzaman
Copy link

I write Google TTS version.
Check it here: Simple Text To Speech (Bash Script - Google TTS)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment