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 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 Κ ˜Jšœ™šœB™BJšœ9™9—J˜šΟk ˜ Jšœœ$˜.J˜J˜§Jšœœ#˜/J˜Jšœœœ˜J˜MJšœS˜SJšœœ˜5Jšœœ˜4J˜J˜—šΟnœœ˜#JšΟt=™=Jšœ6˜=Jšœ˜J˜—™ J˜Jšœ œ˜&Jšœœ˜-Jšœœ œ˜J˜!Jšœœ œ˜Jšœ œΟcΠck ˜KJ˜šž œœœœ˜DIcodešœœœœ˜šœ$œœ˜9Kšœ œœœ˜6Kšœ˜—Kšœ˜Jšœ˜J˜—JšœBœ˜FJ˜™%JšœAœ˜EJšœœ˜ Jšœœ ˜J˜——šœ ™ J™šžœœ&˜;J™¦J˜J˜—šΠbnœœ,˜BJšœœœ™'Jšœœœ˜J˜6Jš œœœœ  ˜'šœ˜&šœ Πct B£˜YJšœœ £ 1£˜Q—Jšœ˜—Jš œ 2™PJ˜J˜—šž œœ'˜:JšœDœ™HJšœœ™!Jšœg™gJšœœœ˜šœ˜$šœ˜Jšœ6˜6Jš œœœœ "˜=Jš œ™šœ=œœ˜PKšœ*œœ˜6K˜ šœ˜#K™mKšœ7œ˜?—Kšœ˜Kšœ˜—Kš œœœœ £ £˜HK˜—šœ $˜=K™——Jšœ˜—J˜—™J™šž œ ˜š Ρcjk œ˜ Jšœ0˜0Kšœ!˜!Kšœ œœ˜KšœD˜HKšœœœ ˜8Kšœœ˜Kšœ˜—šœ˜ Kšœ œ ˜Kšœ!˜!Kšœ!˜!Kšœ˜—J˜J˜#š žœœœœœ˜7JšΠksΟs₯¦₯¦˜šœ1Ÿ˜2Jšœ‡œ ˜–—šœ ˜Jšœ6œ ˜G—Jšœ˜—Jšœ-˜-šœ œ˜J˜(Jšœ œ)˜8šœ ˜ Jšœ-œ˜RJšœ˜—šœœ˜$Jšœ ŸœŸœ Ÿ ˜G—šœœœ˜%Jšœ ŸœŸœ Ÿ œ˜H—Jšœ˜J˜—J˜J˜—š ž œœœœœœ˜Cšœ˜Jšœ œ>˜L—J˜J˜—šž œ ˜š € œ˜ Jšœ0˜0Kšœ9˜9Kšœ˜—šœ˜ Kšœ œ ˜Kšœ!˜!Kšœ!˜!Kšœ˜—šœ,˜,Jšœœ+œœ˜X—Jšœ˜J˜—šžœ œœ œ˜WJšœ%œ˜2Jšœ˜J˜—šž œœ˜Jšœ&œœ œ˜FJ˜J˜#Jšœ=œ$œœ˜qšœ0˜0Jšœc˜c—Jšœ˜J˜—šžœœœ'˜PKšœ œœœ˜VK™"J˜J˜#JšœEœ$œœ˜yšœ-˜-Jšœƒ˜ƒ—J˜K™—šžœ œ˜$Kšœ\œ˜dJ˜!J˜J™——™ J˜J˜šžœœ˜7Jšœœ:˜IJ˜CJšœ œœ˜Jšœ˜J˜)J˜J˜—šž œœœ˜Jšœœ)˜BJšœœœ˜Jšœœœœ˜Jšœœ˜J˜J˜—šž œœœ˜Jšœœœœ)˜XJš œœœœœ˜Jšœ œ0˜?Jš œ œœœœ˜'Jšœ œ&˜2J˜BJ˜J˜—šžœœ5˜OJšœœ˜J˜$Jš œœœ œœœ ˜Fš œœœ$œœ˜LJ™8—Jšœ9œ˜ZJšœ œœ˜šœœœ)˜DšœG˜GJ˜0—Jšœ$˜$J˜—Jšœ(˜(J˜Jšœ*˜*J˜J˜—Jšœ8˜8Jš žœœœœœœ˜GJ˜—J™˜šžœœœ˜+Jšœ:œ'˜dJ™LJ˜——J˜K™™)KšœYΟr™u—K™K™K™—…—Μ,i