«SpeechRender / SpeechBuffer» by rukano
on 11 Feb'12 19:35 inLittle class I made two years ago to generate buffers out of the speech synthesis engine in Mac OS X. If there is something similar from the command line in Linux or windows, should be easy to adapt the command for those platforms. One of the first things one learn as SC beginner is "bla bla".speak and it is a lot of fun. But one of the most common problems is: one wants to use that command in SynthDefs. If you like the speech synthesizer now you can turn it into a buffer and use it as you wish.
Usage:
b = SpeechBuffer("I am Super... Collider", 3); // string, voice
b.play;
play{ PlayBuf.ar(1, b, BufRateScale.kr(b) * 0.5, loop:1)!2 }
And you have to clean up your rendering directory with:
SpeechBuffer.cleanUp // or: SpeechRender.cleanUp
If maybe someone want, this could be turned into a Quark (?) Have fun!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/* Little class to render terminal voices into a temp folder (or a given path) Also can be loaded as buffer. Subclass SpeechBuffer calls the render and loads the buffer automatically. May be adaptable to work on linux (if I knew the command used on linux for rendering from speech synthesis) // USAGE: b = SpeechBuffer("I am Super... Collider", 3); // string, voice b.play; play{ PlayBuf.ar(1, b, BufRateScale.kr(b) * 0.5, loop:1)!2 } // WARNING! // do this regularily until I find a better way to deal with the temp files SpeechBuffer.cleanUp // WARNING! // Files have a 22050Hz sample rate! */ SpeechRender { classvar <>voices, <>defaultVoice; classvar <>tempDir, <>tempPrefix; var <cmd, <filePath; *initClass { voices = (); voices.all = [ // 0..4 'Agnes', 'Kathy', 'Princess', 'Vicki', 'Victoria', // 5..9 'Bruce', 'Fred', 'Junior', 'Ralph', 'Alex', // 10..15 'Albert', 'Bad News', 'Bahh', 'Bells', 'Boing', 'Bubbles', // 16..20 'Cellos', 'Deranged', 'Good News', 'Hysterical', 'Pipe Organ', // 21..23 'Trinoids', 'Whisper', 'Zarvox' ]; voices.male = ['Bruce', 'Fred', 'Junior', 'Ralph', 'Alex']; voices.female = ['Agnes', 'Kathy', 'Princess', 'Vicki', 'Victoria']; voices.others = [ 'Albert', 'Bad News', 'Bahh', 'Bells', 'Boing', 'Bubbles', 'Cellos', 'Deranged', 'Good News', 'Hysterical', 'Pipe Organ', 'Trinoids', 'Whisper', 'Zarvox' ]; defaultVoice = voices.male[0]; tempPrefix = "temp_speech_"; tempDir = thisProcess.platform.recordingsDir +/+ "SpeechRenderings"; File.exists(tempDir).not.if { ("mkdir -p " + tempDir.escapeChar($ )).systemCmd; }; } *new { |string, voice, path, opt| ^super.new.init(string, voice, path, opt) } *cleanUp { ("rm" + (tempDir.escapeChar($ )) +/+ tempPrefix ++ "*").systemCmd; "Removed all temporary buffers from %\n".postf(tempDir); } init { |string, voice, path, opt| // start the command cmd = "say"; // add the voice - sybols and strings pass through (voice.isNil).if { voice = defaultVoice }; (voice.class == Integer).if { voice = voices.all[voice] }; cmd = cmd + "-v" + voice.asString; // add more options opt.isNil.if { opt = "" }; cmd = cmd + opt; // add output file path path.isNil.if { filePath = tempDir +/+ tempPrefix ++ Date.localtime.stamp ++ ".aiff" } { filePath = path }; // cmd is ready!!! cmd = cmd + "-o" + (filePath.escapeChar($ )) + string; cmd.systemCmd; // works ok? sync for buffer? ^this } asBuffer { |server| server.isNil.if { server = Server.default }; ^Buffer.read(server, filePath) } } SpeechBuffer : SpeechRender { *new { |string, voice, path, opt, server| ^super.new(string, voice, path, opt).asBuffer(server) } }
Awesome