RecordPlayImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Swinehart, June 22, 1986 9:51:26 pm PDT
DIRECTORY
FinchSmarts USING [CurrentFinchState, FinchState, GetProcs, Procs],
Intervoice,
LoganBerry USING [ Entry ],
Rope USING [Cat, ROPE],
Thrush USING [ ConversationID, EncryptionKey, NB, nullConvID ],
UserProfile USING [ Token ],
VoiceDB USING [ Create, Error, ErrorCode, Forget, Open, Query, Retain, VoiceDBHandle ], -- Need to do failure analysis throughout, here and in db impl
VoiceTemp USING [ IntervalSpec, IntervalSpecs, TuneID ],
VoiceUtils USING [ Problem, RnameToRspec ]
;
RecordPlayImpl:
CEDAR
MONITOR
IMPORTS FinchSmarts, Rope, UserProfile, VoiceDB, VoiceUtils
EXPORTS Intervoice = {
Definitions
Handle: TYPE = REF HandleRec;
HandleRec:
PUBLIC
TYPE =
RECORD [
-- Concrete implementation of Intervoice.Handle
procs: FinchSmarts.Procs←NIL,
convID: Thrush.ConversationID ← Thrush.nullConvID, -- conv hint
vdbHandle: VoiceDB.VoiceDBHandle,
Complain: PROC[complaint: Rope.ROPE]
];
defaultHandle: Handle←NIL;
Intervoice Implementations for Record and Playback
Record:
PUBLIC
PROC[handle: Handle]
RETURNS [voiceFileID: Rope.
ROPE] =
{
ENABLE VoiceDB.Error => { handle.Complain[explanation];
CONTINUE; };
Nothing much can be done about it; just tell the user. Should eventually log for system administrator's benefit.
intervalSpec: VoiceTemp.IntervalSpec;
intervalSpecs: VoiceTemp.IntervalSpecs;
key: Thrush.EncryptionKey;
nb: Thrush.NB;
handle ← ValidateHandle[handle];
IF StartFinch[handle]#running THEN RETURN;
Play[handle: handle, refID: "BeepTune", refIDType: "SysNoises", failOK: TRUE];
[nb, intervalSpec, key, handle.convID] ← handle.procs.recordTune[convID: handle.convID, queueIt: TRUE];
IF nb#$success THEN RETURN;
intervalSpecs ← handle.procs.describeInterval[intervalSpec].intervals;
IF intervalSpecs#
NIL
THEN {
intervalSpec ← intervalSpecs.first;
FOR is: VoiceTemp.IntervalSpecs ← intervalSpecs, is.rest
WHILE is#
NIL
DO
IF is.rest=
NIL
THEN
intervalSpec.length ← (is.first.start+is.first.length) - intervalSpec.start;
ENDLOOP;
};
voiceFileID ← VoiceDB.Create[
handle: handle.vdbHandle, tuneID: intervalSpec.tuneID, start: intervalSpec.start, length: intervalSpec.length, key: key].voiceFileID;
};
Play:
PUBLIC
PROC[
handle: Handle,
refID: Rope.ROPE←NIL, refIDType: Rope.ROPE←NIL, voiceFileID: Rope.ROPE←NIL,
queueIt: BOOL←TRUE,
failOK: BOOL←FALSE,
wait: BOOL←FALSE
] = {
In the refID case, multiple voiceID's are possible
ENABLE VoiceDB.Error => { handle.Complain[explanation]; CONTINUE; };
intervalSpec: VoiceTemp.IntervalSpec;
key: Thrush.EncryptionKey;
ent: LoganBerry.Entry;
handle ← ValidateHandle[handle];
IF StartFinch[handle]#running THEN RETURN;
[intervalSpec, key, ent, ] ←
VoiceDB.Query[handle.vdbHandle, voiceFileID, refID, refIDType];
IF ent=NIL THEN RETURN; -- Better to complain, first
handle.convID←handle.procs.playbackTune[
convID: handle.convID, intervalSpec: intervalSpec, key: key, queueIt: queueIt, failOK: failOK].newConvID;
};
Stop:
PUBLIC
PROC[handle: Handle] = {
Sender and Walnut Message viewer STOP buttons
ENABLE UNWIND => NULL;
handle ← ValidateHandle[handle];
IF StartFinch[handle, FALSE]#running THEN RETURN;
handle.procs.stopTune[handle.convID];
};
Intervoice Implementations that probably belong somewhere else, but in any case just relay their calls
Retain:
PUBLIC PROC [
handle: Handle,
voiceFileID: Rope.ROPE,
refID: Rope.ROPE,
refIDType: Rope.ROPE
] = {
ENABLE VoiceDB.Error => { handle.Complain[explanation]; CONTINUE; };
handle ← ValidateHandle[handle];
[]←VoiceDB.Retain[handle.vdbHandle, voiceFileID, refID, refIDType];
};
Forget:
PUBLIC PROC [
handle: Handle,
refID: Rope.ROPE,
refIDType: Rope.ROPE
] = {
ENABLE VoiceDB.Error => { handle.Complain[explanation]; CONTINUE; };
handle ← ValidateHandle[handle];
VoiceDB.Forget[handle.vdbHandle, refID, refIDType];
};
Initialization (Walnut Voice and Finch)
Open:
PUBLIC
PROC[
tunesDBName: Rope.ROPE ← NIL,
tunesDBInstance: Rope.ROPE ← NIL,
localName: Rope.ROPE ← NIL,
Complain: PROC[complaint: Rope.ROPE]←NIL] RETURNS [handle: Handle] = {
server: Rope.ROPE← UserProfile.Token["ThrushClientServerInstance", "Strowger.Lark"];
vdbHandle: VoiceDB.VoiceDBHandle;
ec: VoiceDB.ErrorCode;
expl: Rope.ROPE;
IF Complain = NIL THEN Complain ← FinchProblem;
IF tunesDBInstance = NIL THEN tunesDBInstance ← server;
IF tunesDBName =
NIL
THEN
tunesDBName ← Rope.Cat["///", VoiceUtils.RnameToRspec[server].simpleName, "/Tunes"];
[vdbHandle, ec, expl] ← VoiceDB.Open[tunesDBName, tunesDBInstance, "Morley.Lark"];
IF ec#NIL THEN Complain[expl]; -- Trouble opening; success of future calls in doubt
handle ← NEW[HandleRec ← [vdbHandle: vdbHandle, Complain: Complain ]];
};
FinchProblem: PROC[complaint: Rope.ROPE] = { VoiceUtils.Problem[complaint, $Finch]; };
StartFinch:
PROC[handle: Handle, complain:
BOOL←
TRUE]
RETURNS [state: FinchSmarts.FinchState] = {
Should arrange to load Finch if not loaded, start it if not started.
At present, does neither, tells caller what's what, and complains if asked to.
RW:
PROC[c: Rope.
ROPE] = {
IF ~complain THEN RETURN;
handle.Complain[complaint: c];
};
SELECT (state ← FinchSmarts.CurrentFinchState[])
FROM
unknown => RW["Sorry, Finch needs to be loaded and started.\n"];
stopped => RW["Sorry, Finch needs to be connected to telephone server.\nUse \"Finch\" command.\n"];
running => NULL;
ENDCASE => ERROR;
handle.procs ← IF state=unknown THEN NIL ELSE FinchSmarts.GetProcs[];
};
ValidateHandle:
PROC[oldHandle: Handle]
RETURNS [handle: Handle] = {
handle ← oldHandle;
IF handle=NIL THEN handle ← defaultHandle;
IF handle=NIL THEN handle ← defaultHandle ← Open[];
};
}.
Swinehart, May 19, 1986 9:19:05 am PDT
Cedar 6.1
changes to: DIRECTORY, RecordPlayImpl, Open, FinchProblem
Swinehart, June 21, 1986 7:08:19 pm PDT
New Thrush
changes to: DIRECTORY, Record, Play, Stop