DIRECTORY Convert USING [RopeFromInt], IO USING [PutFR, int], DictationOps USING [DictationOps], MBQueue USING [CreateMenuEntry], Menus USING [Menu, AppendMenuEntry, CreateEntry, MenuProc, CreateMenu], MessageWindow USING [Blink, Append], Rope USING [ROPE, Concat], SoundList USING [SoundListFromIntervalSpecs, SoundChars], SourceMarkerTracking USING [RegisterViewer], TiogaOps USING [SaveSelA, SelectDocument, SetLooks, SetStyle, RestoreSelA, FirstChild, ViewerDoc], TiogaOpsDefs USING [Location], ViewerClasses USING [Viewer], ViewerEvents USING [EventRegistration, RegisterEventProc, UnRegisterEventProc, EventProc], ViewerLocks USING [CallUnderWriteLock], ViewerOps USING [CreateViewer, AddProp, FetchProp, SetMenu, PaintViewer], ViewerTools USING [TiogaContents, TiogaContentsRec, SetTiogaContents], VoiceAging USING [youngest, oldest, AgeAllViewers, ReColorViewer], VoiceInText USING [voiceButtonQueue, StoreVoiceAtSelection, CancelProc, DebugRope, DeleteSourceMarker, SaveRopeAtSourceMarker, thrushHandle], VoiceMarkers USING [AddCharMark, DeleteCharMarks, TextListFromRope, RopeFromTextList, RedrawTextMarkers], VoicePlayBack USING [PlayBackMenuProc, RemoveViewerReferences, RedrawViewer], VoiceRecord USING [AddVoiceProc, DictationMachine], VoiceRope USING [IntervalSpecs, Length, DescribeRope, VoiceRopeInterval], WindowManager USING [colorDisplayOn], VoiceViewers; VoiceViewersImpl: CEDAR MONITOR IMPORTS Convert, DictationOps, IO, MBQueue, Menus, MessageWindow, Rope, SoundList, SourceMarkerTracking, TiogaOps, ViewerEvents, ViewerLocks, ViewerOps, ViewerTools, VoiceAging, VoiceInText, VoiceMarkers, VoicePlayBack, VoiceRecord, VoiceRope, WindowManager EXPORTS VoiceViewers = BEGIN voiceViewerMenu: PUBLIC Menus.Menu; CreateVoiceViewerMenu: PROC = { voiceViewerMenu _ Menus.CreateMenu[]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Add", VoiceRecord.AddVoiceProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Play", VoicePlayBack.PlayBackMenuProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "STOP", VoiceInText.CancelProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Save", SaveVoice]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Store", StoreVoice]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Redraw", RedrawViewer]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Mark", VoiceMarkers.AddCharMark]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "DeleteMarks", VoiceMarkers.DeleteCharMarks]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "DictationMachine", VoiceRecord.DictationMachine]]; Menus.AppendMenuEntry[voiceViewerMenu, Menus.CreateEntry["DictationOps", DictationOps.DictationOps]]; }; voiceViewerInfoList: PUBLIC VoiceViewers.VoiceViewerInfo _ NIL; BuildVoiceViewer: PUBLIC PROC [voiceID: Rope.ROPE, textInVoice: Rope.ROPE, youngVoice: BOOLEAN] RETURNS [viewer: ViewerClasses.Viewer, viewerInfo: VoiceViewers.VoiceViewerInfo, viewerNumber: INT] = { viewerInfo _ InsertVoiceViewerInfo[]; viewer _ ViewerOps.CreateViewer[ flavor: $Text, info: [ name: Rope.Concat["Sound Viewer #", Convert.RopeFromInt[viewerInfo.viewerNumber]], column: IF WindowManager.colorDisplayOn THEN color ELSE left, iconic: FALSE ], paint: TRUE]; viewer.inhibitDestroy _ FALSE; viewerNumber _ viewerInfo.viewerNumber; ViewerOps.AddProp[viewer, $voiceViewerInfo, viewerInfo]; viewerInfo.viewer _ viewer; viewerInfo.color _ viewer.column = color; ViewerOps.SetMenu[viewer, voiceViewerMenu]; viewerInfo.destroyEvent _ ViewerEvents.RegisterEventProc[ proc: DestroyViewerEvent, event: destroy, filter: viewer, before: TRUE]; viewerInfo.changeColumnEvent _ ViewerEvents.RegisterEventProc[ proc: ChangeColumnEvent, event: changeColumn, filter: viewer, before: FALSE]; SetViewerContents[viewer, viewerInfo, voiceID, textInVoice, youngVoice]; MakeNotEdited[viewer] }; SetViewerContents: PUBLIC PROC [viewer: ViewerClasses.Viewer, viewerInfo: VoiceViewers.VoiceViewerInfo, voiceID: Rope.ROPE, textInVoice: Rope.ROPE, youngVoice: BOOLEAN] = { viewercontents: ViewerTools.TiogaContents _ NEW[ViewerTools.TiogaContentsRec _ []]; intervals: VoiceRope.IntervalSpecs; viewerInfo.soundList _ NIL; IF voiceID # NIL THEN { -- **** ought to check here that the rope actually exists viewerInfo.ropeInterval _ [voiceID, 0, VoiceRope.Length[VoiceInText.thrushHandle, NEW [VoiceRope.VoiceRopeInterval _ [voiceID, 0, 0]]]]; intervals _ VoiceRope.DescribeRope[VoiceInText.thrushHandle, NEW [VoiceRope.VoiceRopeInterval _ viewerInfo.ropeInterval]]; viewerInfo.soundList _ SoundList.SoundListFromIntervalSpecs[intervals, viewerInfo.ropeInterval.length]; [soundRope: viewercontents.contents, remnant: viewerInfo.remnant] _ SoundList.SoundChars[viewerInfo]; viewerInfo.textMarkList _ VoiceMarkers.TextListFromRope[textInVoice]; viewerInfo.ageList _ CONS [[0, IF youngVoice THEN VoiceAging.youngest-1 ELSE VoiceAging.oldest], NIL] } ELSE { viewercontents.contents _ " "; viewerInfo.ropeInterval _ [NIL, 0, 0]; }; ViewerTools.SetTiogaContents[viewer, viewercontents]; TiogaOps.SaveSelA[]; TiogaOps.SelectDocument[viewer]; TiogaOps.SetStyle["voiceProfile", root]; TiogaOps.SetLooks["v"]; TiogaOps.RestoreSelA[]; VoiceMarkers.RedrawTextMarkers[viewer, TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]]; IF voiceID # NIL AND viewerInfo.ageList.first.age = VoiceAging.youngest-1 THEN VoiceAging.AgeAllViewers[viewer] ELSE VoiceAging.ReColorViewer[viewer, viewerInfo]; IF viewerInfo.textMarkList # NIL THEN ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: TRUE, whatChanged: NIL]; viewerInfo.editInProgress _ (voiceID = NIL) -- can do this because the viewer is created with editInProgress = TRUE, so nobody else can have grabbed the lock }; MakeNotEdited: PROC [viewer: ViewerClasses.Viewer] = { DoIt: PROC = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; viewerInfo.edited _ viewer.newVersion _ viewer.newFile _ FALSE; ViewerOps.PaintViewer[viewer, caption, FALSE]; }; ViewerLocks.CallUnderWriteLock[DoIt, viewer] }; SetVoiceViewerEditStatus: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { DoIt: PROC = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF viewerInfo.edited # viewer.newVersion THEN { viewer.newVersion _ viewerInfo.edited; IF ~viewerInfo.edited THEN viewer.newFile _ FALSE; ViewerOps.PaintViewer[viewer, caption, FALSE]; } }; ViewerLocks.CallUnderWriteLock[DoIt, viewer] }; SetParentViewer: PUBLIC PROC [viewerInfo: VoiceViewers.VoiceViewerInfo, parentViewer: ViewerClasses.Viewer, positionInParent: TiogaOpsDefs.Location] = { viewerInfo.parentViewer _ parentViewer; viewerInfo.positionInParent _ positionInParent; SourceMarkerTracking.RegisterViewer[parentViewer] }; RemoveParentViewer: PUBLIC PROC [viewerNumber: INT] = { FOR info: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList, info.nextInfoRec WHILE info # NIL DO IF info.viewerNumber = viewerNumber THEN {info.parentViewer _ NIL; RETURN} ENDLOOP }; InsertVoiceViewerInfo: PROC RETURNS [newViewerInfo: VoiceViewers.VoiceViewerInfo] = { restOfList: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList; newViewerInfo _ NEW[VoiceViewers.VoiceViewerInfoRec]; IF voiceViewerInfoList = NIL THEN { newViewerInfo.viewerNumber _ 1; voiceViewerInfoList _ newViewerInfo; RETURN }; IF voiceViewerInfoList.viewerNumber > 1 THEN { newViewerInfo.viewerNumber _ 1; newViewerInfo.nextInfoRec _ voiceViewerInfoList; voiceViewerInfoList _ newViewerInfo; RETURN }; DO IF restOfList.nextInfoRec = NIL OR restOfList.nextInfoRec.viewerNumber > restOfList.viewerNumber + 1 THEN { newViewerInfo.viewerNumber _ restOfList.viewerNumber + 1; newViewerInfo.nextInfoRec _ restOfList.nextInfoRec; restOfList.nextInfoRec _ newViewerInfo; RETURN }; restOfList _ restOfList.nextInfoRec ENDLOOP }; StoreVoice: Menus.MenuProc = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[NARROW[parent], $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; oldParentViewer: ViewerClasses.Viewer _ viewerInfo.parentViewer; oldPosition: TiogaOpsDefs.Location _ viewerInfo.positionInParent; IF VoiceInText.StoreVoiceAtSelection[viewerInfo] THEN { MakeNotEdited[NARROW[parent]]; IF oldParentViewer # NIL THEN VoiceInText.DeleteSourceMarker[oldParentViewer, oldPosition, viewerInfo.viewerNumber] } }; SaveVoice: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF ~viewerInfo.edited THEN { MessageWindow.Append["voice viewer is not edited", TRUE]; RETURN }; IF viewerInfo.parentViewer = NIL THEN { MessageWindow.Append["voice viewer has no parent text viewer", TRUE]; MessageWindow.Blink[]; RETURN }; IF ~VoiceInText.SaveRopeAtSourceMarker[viewerInfo.parentViewer, viewerInfo.positionInParent, viewerInfo.viewerNumber, viewerInfo.ropeInterval.ropeID, VoiceMarkers.RopeFromTextList[viewerInfo.textMarkList]] THEN { MessageWindow.Append["unable to find source marker for voice window: voice not saved", TRUE]; MessageWindow.Blink[]; RETURN }; MakeNotEdited[viewer] }; RemoveVoiceViewerInfo: PROC [viewerInfo: VoiceViewers.VoiceViewerInfo] = { IF voiceViewerInfoList = NIL THEN ERROR; IF voiceViewerInfoList = viewerInfo THEN voiceViewerInfoList _ viewerInfo.nextInfoRec ELSE { ptrToCurrInfo: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList; currInfo: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList.nextInfoRec; DO IF currInfo = NIL THEN ERROR; IF currInfo = viewerInfo THEN { ptrToCurrInfo.nextInfoRec _ viewerInfo.nextInfoRec; RETURN }; ptrToCurrInfo _ currInfo; currInfo _ currInfo.nextInfoRec ENDLOOP } }; DestroyViewerEvent: ViewerEvents.EventProc = { RETURN [~DestroyVoiceInfo[viewer]] }; DestroyVoiceInfo: PROC [viewer: ViewerClasses.Viewer] RETURNS [didIt: BOOLEAN _ TRUE] = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF ~VoicePlayBack.RemoveViewerReferences[viewer] THEN { MessageWindow.Append["Wait until voice cue disappears before destroying viewer", TRUE]; MessageWindow.Blink[]; RETURN [FALSE] }; IF viewerInfo.parentViewer = NIL THEN VoiceInText.DebugRope[IO.PutFR["Voice viewer %d had no parent\n", IO.int[viewerInfo.viewerNumber]]] ELSE VoiceInText.DeleteSourceMarker[viewerInfo.parentViewer, viewerInfo.positionInParent, viewerInfo.viewerNumber]; RemoveVoiceViewerInfo[viewerInfo]; ViewerEvents.UnRegisterEventProc[viewerInfo.destroyEvent, destroy]; ViewerEvents.UnRegisterEventProc[viewerInfo.changeColumnEvent, changeColumn]; }; RedrawViewer: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF GetVoiceLock[viewerInfo] THEN { trueContents: Rope.ROPE _ SoundList.SoundChars[viewerInfo].soundRope; [] _ VoicePlayBack.RedrawViewer[viewer, trueContents, 0, 0, 0, viewerInfo.remnant, FALSE, unAltered]; SetVoiceViewerEditStatus[viewer]; viewerInfo.editInProgress _ FALSE } }; ChangeColumnEvent: ViewerEvents.EventProc = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF (viewer.column = color) # viewerInfo.color THEN { viewerInfo.color _ viewer.column = color; IF GetVoiceLock[viewerInfo] THEN { trueContents: Rope.ROPE _ SoundList.SoundChars[viewerInfo].soundRope; [] _ VoicePlayBack.RedrawViewer[viewer, trueContents, 0, 0, 0, viewerInfo.remnant, FALSE, unAltered]; SetVoiceViewerEditStatus[viewer]; viewerInfo.editInProgress _ FALSE } ELSE { MessageWindow.Append["Cannot repaint viewer during edit: click REDRAW to change window between color and monchrome if the wrong state persists", TRUE]; MessageWindow.Blink[] } } }; GetVoiceLock: PUBLIC ENTRY PROC [info: VoiceViewers.VoiceViewerInfo] RETURNS [gotIt: BOOLEAN] = { gotIt _ ~ info.editInProgress; IF info.editInProgress THEN MessageWindow.Append["Try again when the viewer's contents are stable", TRUE] ELSE info.editInProgress _ TRUE; }; CreateVoiceViewerMenu[]; END. ÊVoiceViewersImpl.mesa routines to create and delete viewers for editing voice and to copy voice back into normal tioga documents, plus a monitor routine for locking a viewer against simultaneous attempts to manipulate it Ades, May 1, 1986 1:34:00 pm PDT icon: create one of these **** the Plass-bug: shouldn't be necessary and he says he'll have a look at it this procedure will make a voice viewer think itself unedited, when we wish to assert that there is no voice rope held only in it - use carefully!! this is similar to the above, except that it ensures that the viewer has the same idea about whether the voice is edited as the VoiceInfo record. For use by functions [such as moving a visual cue along a voice viewer during playback] which need to edit the viewer but not the voice and then want to reflect this fact in the viewer's status **** locking against edits in this and the next one? should check also whether viewer is undergoing editing Ê ˜šœ™™ÆIcode™ K™——šÏk ˜ Kšœœ˜Kšœœ˜Kšœ œ˜"Kšœœ˜ Kšœœ<˜GKšœœ˜$Kšœœœ ˜Kšœ œ*˜9Kšœœ˜,Kšœ œT˜bKšœ œ ˜Kšœœ ˜Kšœ œH˜ZKšœ œ˜'Kšœ œ:˜IKšœ œ5˜FKšœ œ2˜BKšœ œ|˜Kšœ œW˜iKšœœ:˜MKšœ œ"˜3Kšœ œ:˜IKšœ%˜%Kšœ ˜ —K™Kš Ïnœœœœœáœ˜¾K˜Kšœœ ˜#K˜šžœœ˜Kšœ%˜%Kšœ˜Kšœ†˜†Kšœ~˜~Kšœq˜qKšœs˜sKšœv˜vKšœ€˜€Kšœ‹˜‹Kšœ˜Kšœe˜e—K˜K˜šœœ œ˜?K™—šžœœœœœœœXœ˜ÇK˜%Kšœ ˜ šœ˜šœZ˜ZJšœ>˜>Jšœ ˜šœ™Jšœ˜——Jšœœ˜ —Jšœœ˜J™šœ'˜'J˜—Jšœ8˜8J˜J˜)J˜Jšœ+˜+J™Jšœ€œ˜†Jšœ‰œ˜J˜JšœH˜HJ˜J˜—Jšœ˜J˜š žœœœXœœœ˜¬Jšœ,œ$˜SJšœ#˜#Jšœœ˜J˜Jšœ œœ˜šœÏc9˜