supernova: fix for small audio vector sizes
[supercollider.git] / lang / LangPrimSource / SC_Speech.cpp
blob7b6fe5777f01bcb1ae509e0bf3466fea4944c557
1 /*
2 * SC_Speech.h
3 * SC3lang
5 * Created by jan truetzschler v. falkenstein on Wed Apr 16 2003.
6 * Copyright (c) 2003 sampleAndHold.org. All rights reserved.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <Carbon/Carbon.h>
26 #include "InitAlloc.h"
28 #include "SCBase.h"
29 #include "VMGlobals.h"
30 #include "PyrSymbolTable.h"
31 #include "PyrInterpreter.h"
32 #include "PyrKernel.h"
34 #include "PyrPrimitive.h"
35 #include "PyrObjectProto.h"
36 #include "PyrPrimitiveProto.h"
37 #include "PyrKernelProto.h"
38 #include "SC_InlineUnaryOp.h"
39 #include "SC_InlineBinaryOp.h"
40 #include "PyrSched.h"
41 #include "GC.h"
45 /////////////////////
46 const int kMaxSpeechChannels = 32;
47 PyrSymbol * s_speech;
48 PyrSymbol * s_speechwordAction;
49 PyrSymbol * s_speechdoneAction;
50 SpeechChannel fCurSpeechChannel[kMaxSpeechChannels];
51 char *speechStrings[kMaxSpeechChannels];
53 pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon );
54 pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon )
56 //call action here;
57 // post("text done");
58 pthread_mutex_lock (&gLangMutex);
59 VMGlobals *g = gMainVMGlobals;
60 g->canCallOS = true;
61 ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class
62 //set arguments:
63 ++g->sp;SetInt(g->sp, (int) inRefCon); //src
64 runInterpreter(g, s_speechdoneAction, 2);
65 if(speechStrings[(int) inRefCon] != NULL){
66 free(speechStrings[(int) inRefCon]);
67 speechStrings[(int) inRefCon] = NULL;
69 g->canCallOS = false;
70 pthread_mutex_unlock (&gLangMutex);
73 pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen);
74 pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) {
75 //post("word done");
76 pthread_mutex_lock (&gLangMutex);
77 VMGlobals *g = gMainVMGlobals;
78 g->canCallOS = true;
79 ++g->sp; SetObject(g->sp, s_speech->u.classobj);
80 //set arguments:
81 ++g->sp; SetInt(g->sp, (int) inRefCon); //src
82 runInterpreter(g, s_speechwordAction, 2);
84 g->canCallOS = false;
85 pthread_mutex_unlock (&gLangMutex);
88 int prInitSpeech(struct VMGlobals *g, int numArgsPushed);
89 int prInitSpeech(struct VMGlobals *g, int numArgsPushed){
91 OSErr theErr = noErr;
92 //PyrSlot *a = g->sp-1;
93 PyrSlot *b = g->sp;
94 int chan;
95 slotIntVal(b, &chan);
96 if (chan < 0 || chan >= kMaxSpeechChannels) return errIndexOutOfRange;
98 for (int i=0; i<chan; ++i) {
99 if(fCurSpeechChannel[i]) DisposeSpeechChannel(fCurSpeechChannel[i]);
100 NewSpeechChannel( NULL, fCurSpeechChannel+i );
101 theErr = SetSpeechInfo (fCurSpeechChannel[i], soSpeechDoneCallBack, (const void*)OurSpeechDoneCallBackProc);
102 theErr = SetSpeechInfo (fCurSpeechChannel[i], soWordCallBack, (const void*)OurWordCallBackProc);
103 theErr = SetSpeechInfo (fCurSpeechChannel[i], soRefCon, (void*) i);
105 return errNone;
108 //NewSpeechDoneUPP(SpeechDoneProcPtr userRoutine);
109 //theErr = SetSpeechInfo (fCurSpeechChannel, soSpeechDoneCallBack, OurSpeechDoneCallBackProc);
111 int prSpeakText(struct VMGlobals *g, int numArgsPushed);
112 int prSpeakText(struct VMGlobals *g, int numArgsPushed){
114 OSErr theErr = noErr;
115 PyrSlot *obj = g->sp-2;
116 PyrSlot *a = g->sp-1;
117 PyrSlot *str = g->sp;
119 int chan;
122 slotIntVal(a, &chan);
123 chan = sc_clip(chan, 0, kMaxSpeechChannels);
124 if(speechStrings[chan] != NULL) {
125 post("voice %i already speaking\n", chan);
126 return errNone;
127 } else {
128 // speechStrings[chan] = (char*)pyr_pool_compile->Alloc((slotRawObject(a)->size + 1)* sizeof(char));
129 speechStrings[chan] = (char*) malloc((slotRawObject(str)->size + 1)* sizeof(char));
131 MEMFAIL(speechStrings[chan]);
132 slotStrVal(str, speechStrings[chan], slotRawObject(str)->size+1);
134 //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel );
135 theErr = SpeakText( fCurSpeechChannel[chan], speechStrings[chan], strlen(speechStrings[chan]));
136 //should be freed only after the text was spoken!
137 // todo move this bit to the callback!
138 // pyr_pool_compile->Free(theTextToSpeak);
140 return errNone;
143 int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed);
144 int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed){
146 OSErr theErr = noErr;
147 //PyrSlot *a = g->sp-2;
148 PyrSlot *b = g->sp-1;
149 PyrSlot *c = g->sp;
150 double val;
151 int chan;
152 slotIntVal(b, &chan);
153 slotDoubleVal(c, &val);
154 Fixed newRate = (Fixed)(val * 65536.0);
155 // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel );
156 theErr = SetSpeechInfo (fCurSpeechChannel[chan], soRate, &newRate);
157 return errNone;
160 int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed);
161 int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed){
163 OSErr theErr = noErr;
164 //PyrSlot *a = g->sp-2;
165 PyrSlot *b = g->sp-1;
166 PyrSlot *c = g->sp;
167 double val;
168 int chan;
169 slotIntVal(b, &chan);
170 slotDoubleVal(c, &val);
171 Fixed newVal = (Fixed)(val * 65536.0);
172 //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel );
173 theErr = SetSpeechPitch (fCurSpeechChannel[chan], newVal);
174 return errNone;
177 int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed);
178 int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed){
180 OSErr theErr = noErr;
181 //PyrSlot *a = g->sp-2;
182 PyrSlot *b = g->sp-1;
183 PyrSlot *c = g->sp;
184 double val;
185 int chan;
186 slotIntVal(b, &chan);
187 slotDoubleVal(c, &val);
188 Fixed newVal = (Fixed)(val * 65536.0);
189 // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel );
190 theErr = SetSpeechInfo (fCurSpeechChannel[chan], soPitchMod, &newVal);
191 return errNone;
194 int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed);
195 int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed) {
197 OSErr theErr = noErr;
198 //PyrSlot *a = g->sp-2;
199 PyrSlot *b = g->sp-1;
200 PyrSlot *c = g->sp;
201 double val;
202 int chan;
203 slotIntVal(b, &chan);
204 slotDoubleVal(c, &val);
205 Fixed newVal = (Fixed)(val * 65536.0);
206 // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel );
207 theErr = SetSpeechInfo (fCurSpeechChannel[chan], soVolume, &newVal);
208 return errNone;
211 // theErr = PauseSpeechAt (fCurSpeechChannel, kImmediate);
212 // theErr = ContinueSpeech (fCurSpeechChannel);
213 int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed);
214 int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed){
216 OSErr theErr = noErr;
217 //PyrSlot *a = g->sp-2;
218 PyrSlot *b = g->sp-1;
219 PyrSlot *c = g->sp;
220 int val;
221 int chan;
222 slotIntVal(b, &chan);
223 slotIntVal(c, &val);
224 //Fixed newVal = (Fixed)(val * 65536.0);
225 if(val) {
226 theErr = ContinueSpeech(fCurSpeechChannel[chan] );
227 } else {
228 theErr = PauseSpeechAt(fCurSpeechChannel[chan], kImmediate);
230 return errNone;
233 int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed);
234 int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed){
236 OSErr theErr = noErr;
237 //PyrSlot *a = g->sp-2;
238 PyrSlot *b = g->sp-1;
239 PyrSlot *c = g->sp;
240 int selector [3] = {kImmediate, kEndOfWord, kEndOfWord};
241 int val;
242 int chan;
243 slotIntVal(b, &chan);
244 slotIntVal(c, &val);
245 StopSpeechAt(fCurSpeechChannel[chan], selector[val]);
246 if(speechStrings[chan] != NULL) {
247 free(speechStrings[chan]);
248 speechStrings[chan] = NULL;
251 return errNone;
254 int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed);
255 int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed){
257 OSErr theErr = noErr;
258 //PyrSlot *a = g->sp-2;
259 PyrSlot *b = g->sp-1;
260 PyrSlot *c = g->sp;
261 int val;
262 int chan;
264 VoiceSpec theVoiceSpec;
265 slotIntVal(b, &chan);
266 slotIntVal(c, &val);
267 theErr = GetIndVoice (val, &theVoiceSpec);
268 if (SetSpeechInfo (fCurSpeechChannel[chan], soCurrentVoice, &theVoiceSpec) == incompatibleVoice) return (!errNone);
270 return errNone;
273 int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed);
274 int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed){
275 PyrSlot *out = g->sp-1;
276 PyrSlot *b = g->sp;
277 int chan;
278 slotIntVal(b, &chan);
279 if(speechStrings[chan] != NULL) SetTrue(out);
280 else SetFalse(out);
281 return errNone;
285 void initSpeechPrimitives ()
287 int base, index;
289 base = nextPrimitiveIndex();
290 index = 0;
292 s_speechwordAction = getsym("doWordAction");
293 s_speechdoneAction = getsym("doSpeechDoneAction");
294 s_speech = getsym("Speech");
296 definePrimitive(base, index++, "_SpeakText", prSpeakText, 3, 0);
297 definePrimitive(base, index++, "_InitSpeech", prInitSpeech, 2, 0);
298 definePrimitive(base, index++, "_SetSpeechRate", prSetSpeechRate, 3, 0);
299 definePrimitive(base, index++, "_SetSpeechPitch", prSetSpeechPitch, 3, 0);
300 definePrimitive(base, index++, "_SetSpeechPitchMod", prSetSpeechPitchMod, 3, 0);
301 definePrimitive(base, index++, "_SetSpeechVoice", prSetSpeechVoice, 3, 0);
302 definePrimitive(base, index++, "_SetSpeechVolume", prSetSpeechVolume, 3, 0);
303 definePrimitive(base, index++, "_SetSpeechPause", prSetSpeechPause, 3, 0); //0 pause, 1 continue
304 definePrimitive(base, index++, "_SetSpeechStopAt", prSetSpeechStop, 3, 0); //0 kImmediate, 1 kEndOfWord, 2 kEndOfSentence
305 definePrimitive(base, index++, "_SpeechVoiceIsSpeaking", prSpeechVoiceIsSpeaking, 2, 0);
306 for(int i=0; i<kMaxSpeechChannels; ++i){
307 speechStrings[i] = NULL;
308 if(fCurSpeechChannel[i]) DisposeSpeechChannel(fCurSpeechChannel[i]);
309 fCurSpeechChannel[i] = NULL;