DIRECTORY Atom USING [ GetPropFromList, PutPropOnList ], FinchSynthesizer, FinchSmarts USING [ ConvDesc, ObtainServiceInterface, RegisterForReports, ReportConversationStateProc, ReportRequestStateProc, ReportSystemStateProc, ServiceConnect ], PupSocket USING [ GetUniqueID ], RefID USING [ ID ], RPC USING [ CallFailed, ImportFailed ], Thrush USING [ ConversationID, InterfaceSpec, NB, nullConvID, nullID, SHHH ], Synthesizer USING [ ActionID, nullActionID, SynthSpec, SynthSpecBody, SynthSpecs ], SynthesizerServerRpcControl USING [ ImportNewInterface, InterfaceRecord, GetSynthesizerSpecifications, StopSpeech, TextToSpeech ] ; FinchSynthesizerImpl: CEDAR MONITOR IMPORTS SynthesizerServerRpcControl, Atom, FinchSmarts, PupSocket, RPC 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; }; synthesizerServer: SynthesizerServerRpcControl.InterfaceRecord _ NIL; defaultTranslateProc: FinchSynthesizer.SynthesizerTranslateProc _ NIL; shhh: SHHH; 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; RPC.CallFailed => { IF synthesizerServer=NIL THEN { nb _ $serverDown; CONTINUE; }; synthesizerServer _ NIL; RETRY; -- Will attempt reconnection via main Finch connectiononce }; }; nb _ synthesizerServer.TextToSpeech[ shhh, 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[]; }; }; StopSpeech: PUBLIC PROC[convID: Thrush.ConversationID] RETURNS [nb: Thrush.NB] ={ RETURN[DoStopSpeech[convID: convID, reset: 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] ={ ENABLE RPC.CallFailed => { IF synthesizerServer=NIL THEN { nb _ $serverDown; CONTINUE; }; synthesizerServer _ NIL; RETRY; -- Will attempt reconnection via main Finch connectiononce }; cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([nb,cDesc, sCDesc]_SynthesizerConnect[convID]).nb#$success OR cDesc.situation.self.state#$active THEN RETURN; nb _ synthesizerServer.StopSpeech[ shhh, cDesc.situation.self, sCDesc.synthesizerServiceID, reset]; }; GetSynthesizerSpecifications: PUBLIC PROC[conversationID: Thrush.ConversationID] RETURNS [nb: Thrush.NB_$success, synthesizerModel: ATOM, synthesizerVersion: ATOM] = { ENABLE RPC.CallFailed => { IF synthesizerServer=NIL THEN { nb _ $serverDown; CONTINUE; }; synthesizerServer _ NIL; RETRY; -- Will attempt reconnection via main Finch connectiononce }; cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([nb,cDesc, sCDesc]_SynthesizerConnect[conversationID]).nb#$success OR cDesc.situation.self.state#$active THEN RETURN; [nb, synthesizerModel, synthesizerVersion] _ synthesizerServer.GetSynthesizerSpecifications[shhh, 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 synthesizerServer#NIL AND (sCDesc=NIL OR sCDesc.synthesizerServiceID#nullID) THEN RETURN; [nb, shhh, interfaceSpec] _ FinchSmarts.ObtainServiceInterface[NIL, "SynthesizerServer", cDesc]; IF nb#$success THEN RETURN; IF synthesizerServer=NIL THEN synthesizerServer _ SynthesizerServerRpcControl.ImportNewInterface[ interfaceName: interfaceSpec.interfaceName, hostHint: interfaceSpec.hostHint!RPC.ImportFailed => CONTINUE ]; IF synthesizerServer=NIL THEN RETURN[$noSynthesizerServerInterface]; IF sCDesc#NIL THEN sCDesc.synthesizerServiceID _ interfaceSpec.serviceID; }; NewID: PROC RETURNS[LONG CARDINAL] ={RETURN[LOOPHOLE[PupSocket.GetUniqueID[]]]}; InitializeFinchSynthesizer: PUBLIC PROC = { FinchSmarts.RegisterForReports[s: NIL, c: ConvStateReport, r: ReportReport, before: TRUE]; }; }. nFinchSynthesizerImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Swinehart, July 19, 1987 9:29:57 pm PDT Confusion about locks here and in FinchSmartsImpl; careful! Declarations 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 sCDesc=NIL if we're only interested in importing the interface. 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šœ™šœ Οmœ1™Jš§˜Jš¦§Πcs;˜BJš§˜—Jš§˜—šœ œ  ˜$Jšœdžœ ˜s—šžœ ž˜Jšœ6žœ ˜G—Jšœ˜—Jšœ-˜-šžœ žœ˜J˜(Jšœ žœ)˜8šœ ˜ Jšžœ-žœ˜RJšžœ˜—šžœžœž˜$Jšœ  œ œ   ˜G—šžœžœžœž˜%Jšœ  œ œ   œ˜H—Jšœ˜J˜—J˜J˜—šŸ œž œžœ žœ˜QJšžœ%žœ˜3Jšœ˜J˜—šŸœž œžœ žœ˜WJšžœ%žœ˜2Jšœ˜J˜—šŸ œžœ˜Jšœ&žœžœ žœ˜Fš¦§˜Jš§>˜>Jš§˜Jš¦§¨;˜BJš§˜—J˜J˜#Jšžœ=žœ$žœžœ˜qšœ"˜"Jšœ@˜@—Jšœ˜J˜—šŸœžœžœ'˜PKšžœ žœžœžœ˜VK™"š¦§˜Jš¦§¦§¦§¦§˜>Jš§˜Jš¦§¨;˜BJš§˜—J˜J˜#JšžœEžœ$žœžœ˜yšœ-˜-JšœR˜R—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˜$š žœžœžœ žœžœ$˜OJšžœžœ˜ —Jšœ?žœ˜`Jšžœ žœžœ˜šžœžœž˜šœC˜CJ˜+Jšœ!žœž˜=J˜——Jšžœžœžœžœ ˜DJšžœžœžœ7˜IJ˜J˜—JšŸœžœžœžœžœžœžœ˜PJ˜—J™˜šŸœžœžœ˜+Jšœ"žœ/žœ˜ZJ™LJ˜——J˜K™™)KšœYΟr™u—K™K™K™—…—^+ρ