RecordPlayImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Swinehart, September 29, 1986 6:39:46 am PDT
DIRECTORY
FinchRecording USING [DescribeInterval, InitializeFinchRecording, PlaybackTune, RecordTune, StopTune],
FinchSmarts USING [FinchIsRunning],
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 FinchRecording, FinchSmarts, Rope, UserProfile, VoiceDB, VoiceUtils
EXPORTS Intervoice = {
Definitions
Handle: TYPE = REF HandleRec;
HandleRec: PUBLIC TYPE = RECORD [ -- Concrete implementation of Intervoice.Handle
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] THEN RETURN;
Play[handle: handle, refID: "BeepTune", refIDType: "SysNoises", failOK: TRUE];
[nb, intervalSpec, key, handle.convID] ← FinchRecording.RecordTune[convID: handle.convID, queueIt: TRUE];
IF nb#$success THEN RETURN;
intervalSpecs ← FinchRecording.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.ROPENIL, refIDType: Rope.ROPENIL, voiceFileID: Rope.ROPENIL,
queueIt: BOOLTRUE,
failOK: BOOLFALSE,
wait: BOOLFALSE
] = {
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] THEN RETURN;
[intervalSpec, key, ent, ] ←
VoiceDB.Query[handle.vdbHandle, voiceFileID, refID, refIDType];
IF ent=NIL THEN RETURN; -- Better to complain, first
handle.convID𡤏inchRecording.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] THEN RETURN;
FinchRecording.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.ROPENIL,
tunesDBInstance: Rope.ROPENIL,
localName: Rope.ROPENIL,
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: BOOLTRUE]
RETURNS [on: BOOL] = {
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 (on ← FinchSmarts.FinchIsRunning[]) FROM
FALSE => RW["Sorry, Finch needs to be connected to telephone server.\nUse \"Finch\" command.\n"];
TRUE => FinchRecording.InitializeFinchRecording[];
ENDCASE;
};
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