DIRECTORY Atom USING [ GetPropFromList, PutPropOnList ], FinchSynthesizer, FinchSmarts USING [ ConvDesc, ObtainServiceInterface, RegisterForReports, ReportConversationStateProc, ReportRequestStateProc, ReportSystemStateProc, ServiceConnect ], Random USING [ Create, NextInt, RandomStream ], RefID USING [ ID ], Rope USING [ ROPE ], Thrush USING [ ConversationID, InterfaceSpec, NB, nullConvID, nullID, SHHH ], Synthesizer USING [ ActionID, nullActionID, SynthSpec, SynthSpecBody, SynthSpecs ], SynthesizerServerRpcControl USING [InterfaceRecord ], SynthesizerServerSunImport USING [ ImportInterface ] ; FinchSynthesizerImpl: CEDAR MONITOR IMPORTS Random, SynthesizerServerSunImport, Atom, FinchSmarts EXPORTS FinchSynthesizer = { ConvDesc: TYPE = FinchSmarts.ConvDesc; ConversationID: TYPE = Thrush.ConversationID; NB: TYPE = Thrush.NB; nullID: RefID.ID = Thrush.nullID; SHHH: TYPE = Thrush.SHHH; SynthSpecs: TYPE = Synthesizer.SynthSpecs; -- LIST OF Synthesizer.SynthSpec NconcSpecs: PROC[l1, l2: SynthSpecs] RETURNS [SynthSpecs] = INLINE { IF l1=NIL THEN RETURN[l2]; FOR specs: SynthSpecs ¬ l1, specs.rest WHILE specs#NIL DO IF specs.rest=NIL THEN { specs.rest¬l2; RETURN[l1]; }; ENDLOOP; ERROR; }; defaultTranslateProc: FinchSynthesizer.SynthesizerTranslateProc ¬ NIL; synthesizerServer: SynthesizerServerRpcControl.InterfaceRecord ¬ NIL; shhh: SHHH; serviceID: RefID.ID ¬ nullID; SysStateReport: ENTRY FinchSmarts.ReportSystemStateProc = { }; ConvStateReport: ENTRY FinchSmarts.ReportConversationStateProc = { ENABLE UNWIND => NULL; sCDesc: FinchSynthesizer.SConvDesc = GetSCDesc[cDesc]; IF sCDesc=NIL THEN RETURN; -- No biggee SELECT cDesc.situation.self.state FROM $failed, $idle => -- If pending specs still exist, report aborted upstream (somehow)??? sCDesc.pendingSpecs ¬ NIL; -- For now, just zap them; problem is monitor locks. ENDCASE; }; ReportReport: ENTRY FinchSmarts.ReportRequestStateProc = { ENABLE UNWIND => NULL; SELECT actionReport.actionClass FROM $synthesizer => { sCDesc: FinchSynthesizer.SConvDesc = GetSCDesc[cDesc]; IF sCDesc=NIL THEN RETURN; -- presumably nothing was pending! FOR rqs: Synthesizer.SynthSpecs ¬ sCDesc.pendingSpecs, rqs.rest WHILE rqs#NIL DO IF actionReport.actionID#rqs.first.actionID THEN LOOP; betterActionRequest ¬ rqs.first; SELECT actionReport.actionType FROM $finished, $flushed => sCDesc.pendingSpecs ¬ rqs.rest; ENDCASE; EXIT; ENDLOOP; IF betterActionRequest=NIL THEN ERROR; -- Complain?["missing reports"] }; ENDCASE=> cDesc ¬ cDesc; -- a place to stand during debugging }; TextToSpeech: PUBLIC PROC -- TAKES -- [ convID: Thrush.ConversationID¬Thrush.nullConvID, synthSpec: Synthesizer.SynthSpec, queueIt: BOOL¬TRUE, synthesizerTranslateProc: FinchSynthesizer.SynthesizerTranslateProc¬NIL, synthesizerModel: ATOM¬NIL, -- Not presently interpreted synthesizerVersion: ATOM¬NIL ] RETURNS [ nb: Thrush.NB¬$success, newConvID: Thrush.ConversationID, newActionID: Synthesizer.ActionID ] = { cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; ScheduleSpeech: ENTRY PROC RETURNS[nb: NB¬$success] = { ENABLE UNWIND=>NULL; nb ¬ sCDesc.synthInterface.clientStubTextToSpeech[ sCDesc.synthInterface, sCDesc.synthShhh, cDesc.situation.self, sCDesc.synthesizerServiceID, synthSpec.textToSpeak, synthSpec.actionID, TRUE, queueIt]; IF nb=$success THEN sCDesc.pendingSpecs ¬ NconcSpecs[sCDesc.pendingSpecs, LIST[synthSpec]]; }; [nb,cDesc,sCDesc]¬SynthesizerConnect[convID]; IF nb=$success THEN { newConvID ¬ cDesc.situation.self.convID; synthSpec ¬ NEW[Synthesizer.SynthSpecBody ¬ synthSpec­]; newActionID ¬ IF synthSpec.actionID=Synthesizer.nullActionID THEN (synthSpec.actionID ¬ NewID[]) ELSE synthSpec.actionID; IF synthesizerTranslateProc#NIL THEN synthSpec.textToSpeak ¬ synthesizerTranslateProc[synthSpec.textToSpeak] ELSE IF defaultTranslateProc#NIL THEN synthSpec.textToSpeak ¬ synthesizerTranslateProc[synthSpec.textToSpeak]; nb ¬ ScheduleSpeech[]; }; }; SpeakText: PUBLIC PROC[textToSpeak: Rope.ROPE] RETURNS [nb: NB] = { RETURN[TextToSpeech[ synthSpec: NEW[Synthesizer.SynthSpecBody ¬ [textToSpeak: textToSpeak]]].nb]; }; StopSpeech: PUBLIC PROC -- TAKES -- [ convID: Thrush.ConversationID¬Thrush.nullConvID, actionID: Synthesizer.ActionID ¬ Synthesizer.nullActionID ] RETURNS [ nb: Thrush.NB¬$success, newConvID: Thrush.ConversationID, newActionID: Synthesizer.ActionID ] = { [nb, newConvID, newActionID] ¬ TextToSpeech[ convID, NEW[Synthesizer.SynthSpecBody ¬ [textToSpeak: NIL, actionID: actionID]], FALSE]; }; ResetSynthesizer: PUBLIC PROC[convID: Thrush.ConversationID] RETURNS [nb: Thrush.NB] ={ RETURN[DoStopSpeech[convID: convID, reset: TRUE]]; }; DoStopSpeech: PROC[ convID: Thrush.ConversationID, reset: BOOL] RETURNS [nb: Thrush.NB] ={ cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([nb,cDesc, sCDesc]¬SynthesizerConnect[convID]).nb#$success OR cDesc.situation.self.state#$active THEN RETURN; nb ¬ sCDesc.synthInterface.clientStubStopSpeech[ sCDesc.synthInterface, sCDesc.synthShhh, cDesc.situation.self, sCDesc.synthesizerServiceID, reset]; }; GetSynthesizerSpecifications: PUBLIC PROC[conversationID: Thrush.ConversationID] RETURNS [nb: Thrush.NB¬$success, synthesizerModel: ATOM, synthesizerVersion: ATOM] = { cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([nb,cDesc, sCDesc]¬SynthesizerConnect[conversationID]).nb#$success OR cDesc.situation.self.state#$active THEN RETURN; [nb, synthesizerModel, synthesizerVersion] ¬ sCDesc.synthInterface.clientStubGetSynthesizerSpecifications[sCDesc.synthInterface, sCDesc.synthShhh, sCDesc.synthesizerServiceID]; }; RegisterTranslateProc: PUBLIC PROC [ conversationID: Thrush.ConversationID, translate: FinchSynthesizer.SynthesizerTranslateProc¬NIL] = { defaultTranslateProc ¬ translate; }; SynthesizerConnect: PROC[convID: Thrush.ConversationID] RETURNS [nb: NB, cDesc: ConvDesc, sCDesc: FinchSynthesizer.SConvDesc] = { [nb, cDesc] ¬ FinchSmarts.ServiceConnect["text-to-speech", convID]; IF nb#$success THEN RETURN; sCDesc ¬ GetSCDescE[cDesc]; nb ¬ SynthesizerInterface[cDesc, sCDesc]; }; GetSCDescE: ENTRY PROC[ cDesc: ConvDesc ] RETURNS [sCDesc: FinchSynthesizer.SConvDesc] = { ENABLE UNWIND => NULL; IF cDesc=NIL THEN ERROR; RETURN[GetSCDesc[cDesc, TRUE]]; }; GetSCDesc: INTERNAL PROC[ cDesc: ConvDesc, createOK: BOOL¬FALSE ] RETURNS [sCDesc: FinchSynthesizer.SConvDesc] = { IF cDesc=NIL THEN RETURN[NIL]; sCDesc ¬ NARROW[Atom.GetPropFromList[cDesc.props, $SConvDesc]]; IF ~createOK OR sCDesc#NIL THEN RETURN; sCDesc ¬ NEW[FinchSynthesizer.SConvDescBody ¬ []]; cDesc.props ¬ Atom.PutPropOnList[cDesc.props, $SConvDesc, sCDesc]; }; SynthesizerInterface: PROC[cDesc: ConvDesc, sCDesc: FinchSynthesizer.SConvDesc] RETURNS [nb: NB¬$success] = { interfaceSpec: Thrush.InterfaceSpec; IF cDesc=NIL OR sCDesc = NIL THEN ERROR; -- we don't support this mode IF synthesizerServer#NIL AND sCDesc.synthesizerServiceID#nullID THEN RETURN; [nb, interfaceSpec] ¬ FinchSmarts.ObtainServiceInterface[NIL, "SynthesizerServer", cDesc]; IF nb#$success THEN RETURN; IF synthesizerServer=NIL OR interfaceSpec.serviceID#serviceID THEN { [synthesizerServer, shhh] ¬ SynthesizerServerSunImport.ImportInterface[ instance: interfaceSpec.interfaceName.instance]; serviceID ¬ interfaceSpec.serviceID; }; sCDesc.synthesizerServiceID ¬ serviceID; sCDesc.synthShhh ¬ shhh; sCDesc.synthInterface ¬ synthesizerServer; }; idStream: Random.RandomStream ¬ Random.Create[seed: -1]; NewID: PROC RETURNS[CARD]~{RETURN[LOOPHOLE[Random.NextInt[idStream]]]}; InitializeFinchSynthesizer: PUBLIC PROC = { FinchSmarts.RegisterForReports[key: $FinchSynthesizer, s: NIL, c: ConvStateReport, r: ReportReport]; }; }. œ FinchSynthesizerImpl.mesa Copyright Σ 1986, 1988, 1992 by Xerox Corporation. All rights reserved. Last Edited by: Swinehart, September 22, 1990 3:18 pm PDT Confusion about locks here and in FinchSmartsImpl; careful! Declarations Hints, valid if serviceID is current. Supervision At present, all that's necessary is to be sure no SCDescs remain in next iteration. Any actions will have been abandoned. We count on FinchSmarts to do that for us. [nb: NB, cDesc: ConvDesc, remark: ROPE] BROADCAST sCDesc.stateChange; -- This will be enough to alert interested parties [cDesc: ConvDesc, actionReport: Thrush.ActionReport, actionRequest: REF] RETURNS[betterActionRequest: REF] This one should get the reports first. Then the client that requested action reports can get them too. BROADCAST sCDesc.stateChange; Throw away pending intervals that are complete. This includes intervals preceding the one being reported on. Endcase events are now expected, since there is no event-filtering in FinchSmarts; these will be events for other applications. Client Functions Describe the assigned synthesizer. Utilities Count on validity of conversation to validate serviceID; Initialization Ask Finch to inform us of changes in conversation state, and action reports. Swinehart, October 3, 1986 4:40:54 pm PDT Based on a prototype FinchRecordingImpl, and on code extracted from old FinchSmartsImpls., DIRECTORY, }, PlaybackTune Κ •NewlineDelimiter –(cedarcode) style™šœ™Jšœ Οeœ=™HJšœ9™9—Icode˜šΟk ˜ Kšœžœ$˜.K˜K˜§Kšœžœ#˜/K˜Kšœžœžœ˜K˜MKšœS˜SKšœžœ˜5Kšœžœ˜4K˜K˜—šΟnœžœž˜#JšΟt=™=Kšžœ6˜=Kšžœ˜K˜—™ K˜Kšœ žœ˜&Kšœžœ˜-Kšžœžœ žœ˜K˜!Kšžœžœ žœ˜Kšœ žœΟcΠck‘˜KK˜šŸ œžœžœžœ˜DKšžœžœžœžœ˜šžœ$žœžœž˜9Kšžœ žœžœžœ˜6Kšžœ˜—Kšžœ˜Kšœ˜K˜—KšœBžœ˜FK˜™%KšœAžœ˜EKšœžœ˜ Kšœžœ ˜K˜——šœ ™ J™šŸœžœ&˜;J™¦K˜K˜—šΠbnœžœ,˜BJšœžœžœ™'Kšžœžœžœ˜K˜6Kš žœžœžœžœ‘ ˜'šžœž˜&šœ‘Πct‘B€˜YKšœžœ‘€‘1€˜Q—Kšžœ˜—Jšž œ‘2™PK˜K˜—šŸ œžœ'˜:JšœDžœ™HJšžœžœ™!Jšœg™gKšžœžœžœ˜šžœž˜$šœ˜Kšœ6˜6Kš žœžœžœžœ‘"˜=Jšž œ™šžœ=žœžœž˜PKšžœ*žœžœ˜6K˜ šžœž˜#K™mKšœ7žœ˜?—Kšžœ˜Kšžœ˜—Kš žœžœžœžœ‘€‘€˜HK˜—šžœ‘$˜=K™——Kšœ˜—K˜—™J™šŸ œž ˜š‘Ρcjk‘œ˜ K˜0Kšœ!˜!Kšœ žœžœ˜KšœDž˜HKšœžœžœ‘˜8Kšœžœž˜Kšœ˜—šžœ˜ Kšœ žœ ˜Kšœ!˜!Kšœ!˜!Kšœ˜—K˜K˜#š Ÿœžœžœžœžœ˜7KšΠksΟs¦§¦§˜šœ1 ˜2Kšœ‡žœ ˜–—šžœ ž˜Kšœ6žœ ˜G—Kšœ˜—K˜-šžœ žœ˜K˜(Kšœ žœ)˜8˜ Kšžœ-žœ˜RKšžœ˜—šžœžœž˜$Kšœ   œ œ œ   ˜G—šžœžœžœž˜%Kš œ   œ œ œ   œ˜H—K˜K˜—K˜K˜—š Ÿ œžœžœžœžœžœ˜Cšžœ˜Kšœ žœ>˜L—K˜K˜—šŸ œž ˜š‘₯‘œ˜ K˜0K˜9Kšœ˜—šžœ˜ Kšœ žœ ˜Kšœ!˜!Kšœ!˜!Kšœ˜—˜,Kšœžœ+žœžœ˜X—Kšœ˜K˜—šŸœž œžœ žœ˜WKšžœ%žœ˜2Kšœ˜K˜—šŸ œžœ˜Kšœ&žœžœ žœ˜FK˜K˜#Kšžœ=žœ$žœžœ˜q˜0Kšœc˜c—Kšœ˜K˜—šŸœžœžœ'˜PKšžœ žœžœžœ˜VK™"K˜K˜#KšžœEžœ$žœžœ˜y˜-Kšœƒ˜ƒ—K˜K™—šŸœž œ˜$Kšœ\žœ˜dK˜!K˜J™——™ K˜K˜šŸœžœ˜7Kšžœžœ:˜IK˜CKšžœ žœžœ˜K˜K˜)K˜K˜—šŸ œžœžœ˜Kšœžœ)˜BKšžœžœžœ˜Kšžœžœžœžœ˜Kšžœžœ˜K˜K˜—šŸ œžœžœ˜Kšœžœžœžœ)˜XKš žœžœžœžœžœ˜Kšœ žœ0˜?Kš žœ žœžœžœžœ˜'Kšœ žœ&˜2K˜BK˜K˜—šŸœžœ5˜OKšžœžœ˜K˜$Kš žœžœžœ žœžœžœ‘˜Fš žœžœžœ$žœžœ˜LJ™8—Kšœ9žœ˜ZKšžœ žœžœ˜šžœžœžœ)˜D˜GK˜0—K˜$K˜—K˜(K˜K˜*K˜K˜—K˜8Kš Ÿœžœžœžœžœžœ˜GK˜—J™˜šŸœžœžœ˜+Kšœ:žœ'˜dJ™LK˜——K˜K™™)KšœYΟr™u—K™K™K™—…—Κ,h