DIRECTORY Atom USING [ GetPropFromList, PutPropOnList ], FinchSynthesizer, FinchSmarts USING [ ConvDesc, LookupServiceInterface, RegisterForReports, ReportConversationStateProc, ReportRequestStateProc, VoiceConnect ], GList USING [ Nconc ], PupSocket USING [ GetUniqueID ], RefID USING [ ID ], RPC USING [ 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 GList, 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 { RETURN[NARROW[GList.Nconc[l1, l2]]]; }; synthesizerServer: SynthesizerServerRpcControl.InterfaceRecord _ NIL; defaultTranslateProc: FinchSynthesizer.SynthesizerTranslateProc _ NIL; shhh: SHHH; ConvStateReport: ENTRY FinchSmarts.ReportConversationStateProc = { sCDesc: FinchSynthesizer.SConvDesc = GetSCDesc[cDesc]; IF sCDesc=NIL THEN ERROR; 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; sCDesc: FinchSynthesizer.SConvDesc = GetSCDesc[cDesc]; IF sCDesc=NIL THEN ERROR; SELECT actionReport.actionClass FROM $synthesizer => { 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 = { ENABLE UNWIND=>NULL; 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 RETURN; -- Complain? 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]; 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] ={ cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([,cDesc, sCDesc]_SynthesizerConnect[convID]).nb#$success OR cDesc.situation.self.state#$active THEN RETURN; [] _ 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 UNWIND => NULL; cDesc: ConvDesc; sCDesc: FinchSynthesizer.SConvDesc; IF ([,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.VoiceConnect["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; RETURN[GetSCDesc[cDesc]]; }; GetSCDesc: INTERNAL PROC[ cDesc: ConvDesc ] RETURNS [sCDesc: FinchSynthesizer.SConvDesc] = { IF cDesc=NIL THEN RETURN[NIL]; sCDesc _ NARROW[Atom.GetPropFromList[cDesc.props, $SConvDesc]]; IF 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 sCDesc#NIL THEN { IF sCDesc.synthesizerServiceID#nullID THEN RETURN } ELSE IF synthesizerServer#NIL THEN RETURN; -- want interface only [nb, shhh, interfaceSpec] _ FinchSmarts.LookupServiceInterface["text-to-speech", "SynthesizerServer", cDesc]; IF nb#$success THEN RETURN; 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]; }; }. ŠFinchSynthesizerImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last Edited by: Swinehart, November 9, 1986 9:13:32 am PST Confusion about locks here and in FinchSmartsImpl; careful! Declarations Supervision [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 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™