summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Gahan2015-06-29 02:45:18 -0400
committerChris Gahan2015-06-29 02:45:18 -0400
commit1cb45d8f227db3c9b46d5e5e574120ead8e4a3c8 (patch)
tree21379ff427b43e2e574c48fb62902b2223cb7c7e
downloadaur-1cb45d8f227db3c9b46d5e5e574120ead8e4a3c8.tar.gz
1.0+git20130326 Release
-rw-r--r--.SRCINFO26
-rw-r--r--PKGBUILD57
-rw-r--r--picospeaker167
3 files changed, 250 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..353c1ebeff51
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,26 @@
+# Generated by makepkg 4.2.1
+# Wed May 27 03:23:39 UTC 2015
+pkgbase = svox-pico-bin
+ pkgdesc = The text-to-speech engine used on Android phones
+ pkgver = 1.0+git20130326
+ pkgrel = 1
+ url = https://android.googlesource.com/platform/external/svox/+/master
+ arch = i686
+ arch = x86_64
+ license = custom
+ depends = popt
+ optdepends = sox: for using the picospeaker script
+ noextract = libttspico0_1.0+git20130326-1ubuntu1_amd64.deb
+ noextract = libttspico-data_1.0+git20130326-1ubuntu1_all.deb
+ noextract = libttspico-utils_1.0+git20130326-1ubuntu1_amd64.deb
+ source = http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico0_1.0+git20130326-1ubuntu1_amd64.deb
+ source = http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico-data_1.0+git20130326-1ubuntu1_all.deb
+ source = http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico-utils_1.0+git20130326-1ubuntu1_amd64.deb
+ source = picospeaker
+ sha256sums = 93384ae527250eb8edba9c48da806c59386214b0769ef1da9b4a6054885eb387
+ sha256sums = c761855de47e4e21ec8ddca5ed55dec4690928f0c8bdf1120dfd9af85b5a1335
+ sha256sums = 767880e8d29e5c84a635b54dc096d78ccfeb32c15e2d41c948eda26cd3702f2b
+ sha256sums = a1fa3f1938b6856254d09cf51d7c6344b79cff25c807adf39bb26b141910e492
+
+pkgname = svox-pico-bin
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..ec62e765c3bd
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,57 @@
+# Maintainer: epitron <chris@ill-logic.com>
+pkgname=svox-pico-bin
+pkgver=1.0+git20130326
+pkgrel=1
+pkgdesc='The text-to-speech engine used on Android phones'
+url='https://android.googlesource.com/platform/external/svox/+/master'
+license=('custom')
+arch=('i686' 'x86_64')
+
+if [[ $CARCH = i686 ]]; then
+ _arch=i386
+
+ sha256sums=(
+ f6c95bbe61a443a11ae3bf415f0873908994784faa74cf68de53b36bfe67a5ff
+ c761855de47e4e21ec8ddca5ed55dec4690928f0c8bdf1120dfd9af85b5a1335
+ 6c47e936341b6d2f23d62b29902b7b72dffed02e9d9e9ed2878a61a9611dc698
+ a1fa3f1938b6856254d09cf51d7c6344b79cff25c807adf39bb26b141910e492
+ )
+else
+ _arch=amd64
+
+ sha256sums=(
+ 93384ae527250eb8edba9c48da806c59386214b0769ef1da9b4a6054885eb387
+ c761855de47e4e21ec8ddca5ed55dec4690928f0c8bdf1120dfd9af85b5a1335
+ 767880e8d29e5c84a635b54dc096d78ccfeb32c15e2d41c948eda26cd3702f2b
+ a1fa3f1938b6856254d09cf51d7c6344b79cff25c807adf39bb26b141910e492
+ )
+fi
+
+source=(
+ "http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico0_1.0+git20130326-1ubuntu1_${_arch}.deb"
+ "http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico-data_1.0+git20130326-1ubuntu1_all.deb"
+ "http://mirrors.kernel.org/ubuntu/pool/multiverse/s/svox/libttspico-utils_1.0+git20130326-1ubuntu1_${_arch}.deb"
+ "picospeaker"
+)
+
+noextract=(
+ "libttspico0_1.0+git20130326-1ubuntu1_${_arch}.deb"
+ "libttspico-data_1.0+git20130326-1ubuntu1_all.deb"
+ "libttspico-utils_1.0+git20130326-1ubuntu1_${_arch}.deb"
+)
+
+depends=('popt')
+optdepends=('sox: for using the picospeaker script')
+
+# picospeaker source: https://raw.githubusercontent.com/the-kyle/picospeaker/master/picospeaker
+
+package() {
+ for deb in "${noextract[@]}"; do
+ ar p "$deb" data.tar.gz | tar zx -C "$pkgdir/"
+ done
+
+ mv "$pkgdir/usr/lib/"*-linux-gnu/* "$pkgdir/usr/lib"
+ rmdir "$pkgdir/usr/lib/"*-linux-gnu
+
+ install -D -m755 picospeaker ${pkgdir}/usr/bin/picospeaker
+}
diff --git a/picospeaker b/picospeaker
new file mode 100644
index 000000000000..d424880e391b
--- /dev/null
+++ b/picospeaker
@@ -0,0 +1,167 @@
+#!/usr/bin/python2
+### PicoSpeaker
+### Written by Kyle
+### A small program that speaks text on its command line or standard input using SVox Pico and Sox
+### Speech rate, pitch, volume and language can be specified, and output can be saved to many file formats
+### This program is free and unencumbered software released into the public domain. See UNLICENSE for details.
+### SVox Pico and Sox are covered by their own open source licenses and copyrights,
+### and are therefore not covered by the UNLICENSE included with PicoSpeaker.
+
+from sys import argv, stdin, stderr, exit
+from subprocess import call, Popen
+from os import environ as env, remove
+from time import sleep
+
+# help and version tuples
+version = (
+ 'PicoSpeaker 0.6.2',
+ 'Written by Kyle',
+ 'This program is free and unencumbered software released into the public domain.',
+ 'See the included UNLICENSE file for details.')
+help = (
+ 'Usage:',
+ argv[0] + ' [options] <text>',
+ '',
+ 'Options:',
+ '-l|--language <language> Language to speak: (default is en-US)',
+ '-v|--volume <number> Output volume: (default is 1.0)',
+ '-r|--rate <number> Rate of speech from -90 to 9900: (default is 0)',
+ '-p|--pitch <number> Voice pitch from -79 to 39: (default is 0)',
+ '-o|--output <file> Output to the specified file: (default is sound card output)',
+ '-c|--compress|-q|--quality <number> Compression/quality level of output file, depends on file type',
+ ' This option causes an error if no output file is specified.',
+ '-t|--type <type> Save output file as <type>. Only needed if saving with a nonstandard extension.',
+ ' This option causes an error if no output file is specified.',
+ '-V|--version Print version information',
+ '-h|--help|-u|--usage Print this help message')
+
+# Spoken text is stored in this temp file; unfortunately, pico2wave doesn't pipe
+temp = '/tmp/picospeaker-' + env['USER'] + '.wav'
+
+def parse ():
+ 'Parse the command line and return settings and text to be spoken in a dictionary object'
+ settings = {} #Voice parameters and command line options, the object returned by the function
+
+ # The parser loop, which populates the settings object and handles usage and version options
+ skip = False #set True to skip the next item in the sequence.
+ for opt in range(1,len(argv)):
+ if skip:
+ skip = False
+ continue
+ if ( argv[opt] == '-V' ) or ( argv[opt] == '--version' ):
+ for line in version: stderr.write(line + '\n')
+ exit(0)
+ elif ( argv[opt] == '-h' ) or ( argv[opt] == '--help' ) \
+ or ( argv[opt] == '-u' ) or ( argv[opt] == '--usage' ):
+ for line in version: stderr.write(line + '\n')
+ stderr.write('\n')
+ for line in help: stderr.write(line + '\n')
+ exit(0)
+ elif ( argv[opt] == '-l' ) or ( argv[opt] == '--language' ):
+ languages = ('en-US', 'en-GB', 'de-DE', 'es-ES', 'fr-FR', 'it-IT')
+ if ( argv[opt+1] in languages ):
+ settings['language'] = argv[opt+1]
+ else:
+ stderr.write('Language ' + argv[opt+1] + ' is currently not available.\n')
+ stderr.write('Available languages are ' + ', '.join(languages[:-1]) + ' and ' + languages[-1] + '.\n')
+ exit(1)
+ skip = True
+ continue
+ elif ( argv[opt] == '-p' ) or ( argv[opt] == '--pitch' ):
+ try:
+ if ( int(argv[opt+1]) in range(-79, 40) ):
+ settings['pitch'] = argv[opt+1]
+ else: raise ValueError
+ except ValueError:
+ stderr.write('Pitch must be a whole number from -79 to 39.\n')
+ exit(1)
+ skip = True
+ continue
+ elif ( argv[opt] == '-r' ) or ( argv[opt] == '--rate' ):
+ try:
+ if ( int(argv[opt+1]) in range(-90, 9901) ):
+ settings['rate'] = argv[opt+1]
+ else: raise ValueError
+ except ValueError:
+ stderr.write('Rate must be a whole number from -90 to 9900.\n')
+ exit(1)
+ skip = True
+ continue
+ elif ( argv[opt] == '-v' ) or ( argv[opt] == '--volume' ):
+ try:
+ float(argv[opt+1])
+ except ValueError:
+ stderr.write('Volume must be a number.\n')
+ exit(1)
+ settings['volume'] = argv[opt+1]
+ skip = True
+ continue
+ elif ( argv[opt] == '-o' ) or ( argv[opt] == '--output' ):
+ # TODO: Check for settings['filetype'] if output file extension would be unrecognized by Sox: may not be possible here
+ settings['output'] = argv[opt+1]
+ skip = True
+ continue
+ elif ( argv[opt] == '-c' ) or ( argv[opt] == '--compress' ) \
+ or ( argv[opt] == '-q' ) or ( argv[opt] == '--quality' ):
+ try:
+ float(argv[opt+1]) #must be a number
+ except ValueError:
+ stderr.write('Compression/quality level must be a number.\n')
+ exit(1)
+ settings['compression'] = argv[opt+1]
+ skip = True
+ continue
+ elif ( argv[opt] == '-t' ) or ( argv[opt] == '--type' ):
+ settings['filetype'] = argv[opt+1]
+ skip = True
+ continue
+ else:
+ # First, die with an error if compression and/or type are set but no output file is specified
+ if ( ( 'compression' in settings ) or ( 'filetype' in settings ) ) and ( 'output' not in settings ):
+ stderr.write('You must specify the output file.\n')
+ exit(1)
+ # Now the text can be added to the settings object and the loop can be broken
+ settings['text'] = ' '.join(argv[opt:])
+ break
+ return settings
+
+def tts():
+ 'convert text to speech data and store it in a temporary file using the pico2wave utility from SVox Pico'
+ command = ['pico2wave', '-w', temp]
+ if ( 'language' in settings ): command += ['-l', settings['language']]
+ command += ['--', settings['text']]
+ try:
+ call(command)
+ except OSError:
+ stderr.write('FIXME: text is too large.\n')
+ exit(1)
+
+def speaker():
+ 'speaks the text, or saves it if an output file was specified on the command line'
+ command = ['/usr/bin/play', '-q']
+ if ( 'volume' in settings ): command += ['-v', settings['volume']]
+ command.append(temp)
+ if ( 'output' in settings ):
+ command[0] = '/usr/bin/sox'
+ del command[1]
+ if ( 'filetype' in settings ): command += ['-t', settings['filetype']]
+ if ( 'compression' in settings ): command += ['-C', settings['compression']]
+ command.append(settings['output'])
+ if ( 'pitch' in settings ): command += ['gain', '-0.15', 'pitch', str(float(settings['pitch'])*100)]
+ if ( 'rate' in settings ): command += ['gain', '-0.1', 'tempo', '-s', str(1+float(settings['rate'])/100)]
+ speak = Popen(command)
+ sleep(0.1) # the temp file should be open by now
+ # The temp file can be removed as soon as it is opened in case PicoSpeaker is killed while speaking
+ remove(temp)
+ speak.wait() # Don't leave this function until the command is completed
+
+try:
+ settings = parse()
+ if ( 'text' not in settings ):
+ settings['text'] = stdin.read()
+ tts()
+ speaker()
+except KeyboardInterrupt:
+ stderr.write('Keyboard interrupt received. Cleaning up.\n')
+ try: remove(temp) # The temp file may not have been removed yet
+ except OSError: pass # The file doesn't exist and therefore doesn't need to be removed