<> <> <> <<>> <> <> DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Parse, Failed], Convert USING [IntFromRope], Jukebox USING [bytesPerChirp], Menus USING [MenuProc, MenuEntry, InsertMenuEntry, GetLine, SetLine, ChangeNumberOfLines], MessageWindow USING [Append, Blink], MBQueue USING [CreateMenuEntry], SoundList USING [LastSilenceInSoundList], TiogaOps USING [GetSelection, FirstChild, ViewerDoc, SaveSelA, RestoreSelA], TiogaOpsDefs USING [Location, Ref], ViewerClasses USING [Viewer], ViewerOps USING [FetchProp], VoiceAging USING [oldest], VoiceEditOps USING [ReplaceSelectionWithSavedInterval], VoiceInText USING [ChangeMenu, thrushHandle, voiceButtonQueue], VoicePlayBack USING [CancelPlayBack, PlaySlabSection], VoiceRecord USING [StopRecording, RecordInPlaceOfSelection], VoiceRope USING [Stop, VoiceRopeInterval], VoiceViewers USING [voiceViewerMenu, VoiceViewerInfo, soundRopeCharLength, GetVoiceLock, SelectionRec, IntPair, Selection, voiceViewerInfoList], DictationOps; <<>> DictationOpsImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, Menus, MessageWindow, MBQueue, SoundList, TiogaOps, ViewerOps, VoiceAging, VoiceEditOps, VoiceInText, VoicePlayBack, VoiceRecord, VoiceRope, VoiceViewers EXPORTS DictationOps = BEGIN <<>> DictationOps: PUBLIC Menus.MenuProc = { <> VoiceInText.ChangeMenu[NARROW[parent], dictationMenu] }; <<>> ToggleDictationMenu: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { <> VoiceInText.ChangeMenu[viewer, dictationMenu] }; FindEnd: PROC [viewerInfo: VoiceViewers.VoiceViewerInfo] RETURNS [sample: INT] = { <> IF viewerInfo.ropeInterval.start # 0 THEN ERROR; <> IF ~viewerInfo.color THEN RETURN [viewerInfo.ropeInterval.length] ELSE { minAge: INT _ VoiceAging.oldest+2; endOfAge: INT _ LAST[INT]; FOR l: LIST OF VoiceViewers.IntPair _ viewerInfo.ageList, l.rest WHILE l # NIL DO IF l.first.age <= minAge THEN { endOfAge _ IF l.rest=NIL THEN LAST[INT] ELSE l.rest.first.position; minAge _ l.first.age } ENDLOOP; RETURN [IF endOfAge = LAST[INT] THEN viewerInfo.ropeInterval.length ELSE endOfAge*VoiceViewers.soundRopeCharLength] } }; StillInVoiceViewerList: PROC [viewerInfo: VoiceViewers.VoiceViewerInfo] RETURNS [BOOLEAN] = { <> nextInfo: VoiceViewers.VoiceViewerInfo _ VoiceViewers.voiceViewerInfoList; DO IF nextInfo = NIL THEN { MessageWindow.Append["Voice viewer has been deleted (contents NIL): dictation operation therefore invalid", TRUE]; MessageWindow.Blink[]; RETURN[FALSE] }; IF nextInfo = viewerInfo THEN RETURN[TRUE]; nextInfo _ nextInfo.nextInfoRec ENDLOOP }; PlayFromSelection: Menus.MenuProc = { viewer: ViewerClasses.Viewer; start: TiogaOpsDefs.Location; viewerInfo: VoiceViewers.VoiceViewerInfo; node: TiogaOpsDefs.Ref; from, to: INT; [viewer: viewer, start: start] _ TiogaOps.GetSelection[]; IF viewer = NIL THEN { MessageWindow.Append["Make a selection first", TRUE]; MessageWindow.Blink[]; RETURN }; viewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF viewerInfo = NIL THEN { MessageWindow.Append["Make a selection in a voice viewer first", TRUE]; MessageWindow.Blink[]; RETURN }; VoiceRope.Stop[VoiceInText.thrushHandle]; VoicePlayBack.CancelPlayBack[]; VoiceRecord.StopRecording[]; IF ~StillInVoiceViewerList[viewerInfo] THEN RETURN; <<**** need to take the voice lock before performing the following!>> node _ TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]; from _ start.where; to _ FindEnd[viewerInfo]/VoiceViewers.soundRopeCharLength; IF to >= from THEN VoicePlayBack.PlaySlabSection[viewer, node, from, to] ELSE { MessageWindow.Append["Make a selection before the end of the most recent edit", TRUE]; MessageWindow.Blink[] }; }; ResumeFromSelection: Menus.MenuProc = { viewer: ViewerClasses.Viewer; start: TiogaOpsDefs.Location; viewerInfo: VoiceViewers.VoiceViewerInfo; node: TiogaOpsDefs.Ref; replaceRopeInterval: VoiceRope.VoiceRopeInterval; startDelete, endDelete: INT; [viewer: viewer, start: start] _ TiogaOps.GetSelection[]; IF viewer = NIL THEN { MessageWindow.Append["Make a selection first", TRUE]; MessageWindow.Blink[]; RETURN }; viewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF viewerInfo = NIL THEN { MessageWindow.Append["Make a selection in a voice viewer first", TRUE]; MessageWindow.Blink[]; RETURN }; VoiceRope.Stop[VoiceInText.thrushHandle]; VoicePlayBack.CancelPlayBack[]; VoiceRecord.StopRecording[]; IF ~StillInVoiceViewerList[viewerInfo] THEN RETURN; IF ~VoiceViewers.GetVoiceLock[viewerInfo] THEN RETURN; node _ TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]; startDelete _ start.where*VoiceViewers.soundRopeCharLength; endDelete _ FindEnd[viewerInfo]; IF startDelete>endDelete THEN { MessageWindow.Append["Make a selection before the end of the most recent edit", TRUE]; MessageWindow.Blink[]; viewerInfo.editInProgress _ FALSE; RETURN }; replaceRopeInterval _ [ropeID: viewerInfo.ropeInterval.ropeID, start: startDelete, length: endDelete - startDelete]; VoiceRecord.RecordInPlaceOfSelection[NEW[VoiceViewers.SelectionRec _ [viewer: viewer, voiceViewerInfo: viewerInfo, ropeInterval: replaceRopeInterval, displayNode: node]]] }; ResumeFromEnd: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent, ViewerClasses.Viewer]; viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; node: TiogaOpsDefs.Ref; replaceRopeInterval: VoiceRope.VoiceRopeInterval; VoiceRope.Stop[VoiceInText.thrushHandle]; VoicePlayBack.CancelPlayBack[]; VoiceRecord.StopRecording[]; IF ~StillInVoiceViewerList[viewerInfo] THEN RETURN; IF ~VoiceViewers.GetVoiceLock[viewerInfo] THEN RETURN; node _ TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]; replaceRopeInterval _ [ropeID: viewerInfo.ropeInterval.ropeID, start: FindEnd[viewerInfo], length: 0]; VoiceRecord.RecordInPlaceOfSelection[NEW[VoiceViewers.SelectionRec _ [viewer: viewer, voiceViewerInfo: viewerInfo, ropeInterval: replaceRopeInterval, displayNode: node]]] }; <<>> <<>> <<>> <<--------->> <> <<>> criticalSilenceLength: INT _ Jukebox.bytesPerChirp/2; <<>> SetCriticalSilenceLength: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; IF argv.argc # 2 THEN { msg _ "Usage: SetCriticalSilenceLength lengthInMilliseconds"; GOTO Quit }; criticalSilenceLength _ Convert.IntFromRope[argv[1]]*8; RETURN EXITS Quit => RETURN [$Failure, msg] }; AdjustSilences: Menus.MenuProc = { viewer: ViewerClasses.Viewer; viewerInfo: VoiceViewers.VoiceViewerInfo; selectionToRemove: VoiceViewers.Selection; startOfSilence, lengthOfSilence: INT; viewer _ NARROW [parent, ViewerClasses.Viewer]; viewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF ~VoiceViewers.GetVoiceLock[viewerInfo] THEN { MessageWindow.Append["Unable to examine silences in viewer - editing operation already in progress", TRUE]; MessageWindow.Blink[]; RETURN }; TiogaOps.SaveSelA[]; DO [startsAt: startOfSilence, lasts: lengthOfSilence] _ SoundList.LastSilenceInSoundList[soundList: viewerInfo.soundList, lengthGreaterThan: criticalSilenceLength]; IF lengthOfSilence = -1 THEN { viewerInfo.editInProgress _ FALSE; TiogaOps.RestoreSelA[]; RETURN }; selectionToRemove _ NEW[VoiceViewers.SelectionRec _ [viewer: viewer, voiceViewerInfo: viewerInfo, ropeInterval: [ropeID: viewerInfo.ropeInterval.ropeID, start: startOfSilence+criticalSilenceLength, length: lengthOfSilence-criticalSilenceLength], displayNode: TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]]]; viewerInfo.edited _ TRUE; [] _ VoiceEditOps.ReplaceSelectionWithSavedInterval[selection: selectionToRemove, soundInterval: NIL, leaveSelected: FALSE] <> <<>> <> ENDLOOP }; <<--------->> dictationMenu: Menus.MenuEntry; Menus.InsertMenuEntry[VoiceViewers.voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "AdjustSilences", AdjustSilences], 1]; Menus.InsertMenuEntry[VoiceViewers.voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "ResumeFromEnd", ResumeFromEnd], 1]; Menus.InsertMenuEntry[VoiceViewers.voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "ResumeFromSelection", ResumeFromSelection], 1]; Menus.InsertMenuEntry[VoiceViewers.voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "PlayFromSelection", PlayFromSelection], 1]; dictationMenu _ Menus.GetLine[VoiceViewers.voiceViewerMenu, 1]; Menus.SetLine[VoiceViewers.voiceViewerMenu, 1, NIL]; Menus.ChangeNumberOfLines[VoiceViewers.voiceViewerMenu, 1]; Commander.Register["SetCriticalSilenceLength", SetCriticalSilenceLength, "SetCriticalSilenceLength lengthInMilliseconds - when the AdjustSilences button is bugged for any voice viewer, all silences of more than this length will be reduced to this length"]; END.