DIRECTORY FS USING [Read], Jukebox USING [ bytesPerChirp, FindChirp, Handle, MissingChirp, pagesPerChirp, RunType, Tune, WindowOrigin, singlePktLength, RunComponent, EnergyRange, hangoverPackets], VM USING [AddressForPageNumber, Allocate, WordsForPages]; JukeboxIntervalImpl: MONITOR LOCKS self.LOCK USING self: Jukebox.Handle IMPORTS FS, Jukebox, VM EXPORTS Jukebox SHARES Jukebox = BEGIN OPEN Jukebox; Tune: TYPE = Jukebox.Tune; RunType: TYPE = Jukebox.RunType; FirstNoisyIntervalIn: PUBLIC PROC [ self: Handle, tune: Tune, start: INT, length: INT, minSilence: INT] RETURNS [intStart: INT, intLength: INT_0, nextNoise: INT_-1] = { ambientLevel: Jukebox.EnergyRange; samplesSinceLastNonSilence: INT _ 0; -- any value will do, since we are not interested until the precedingSilence state, when we will reset it and rerun SetRunType anyhow SetPosBefore: ENTRY PROC[self: Handle, tune: Tune, sample: INT] RETURNS [intStart, intEnd: INT, runType: RunType] = { ENABLE UNWIND => NULL; IF tune.runData#NIL AND sample=tune.samplesToChirp+tune.samplesInChirp THEN { intStart _ sample; intEnd _ intStart + NextElementLength[tune]; runType _ tune.runType; ambientLevel _ tune.runData.ambientLevel } ELSE [intStart, intEnd, runType] _ SetPosToChirp[self, tune, sample/Jukebox.bytesPerChirp]; }; SetPosToChirp: INTERNAL PROC[self: Handle, tune: Tune, chirp: INT] RETURNS [intStart, intEnd: INT, runType: RunType] = { samplesStart: INT; IF tune.runData=NIL THEN { tune.runSpace _ VM.Allocate[count: 1]; tune.runData _ VM.AddressForPageNumber[tune.runSpace.page] + ((Jukebox.bytesPerChirp/2) - VM.WordsForPages[Jukebox.pagesPerChirp-1]); tune.runChirp _ -1; }; samplesStart _ MIN[chirp, tune.size]*Jukebox.bytesPerChirp; IF chirp >= tune.size THEN { tune.samplesToChirp _ tune.samplesInChirp _ -1; RETURN[samplesStart, LAST[INT], end]; }; -- end of tune indication! IF chirp#tune.runChirp THEN { missing: BOOL_FALSE; chirpWindow: Jukebox.WindowOrigin; tune.runChirp _ chirp; chirpWindow _ Jukebox.FindChirp[self: self, tune: tune, chirp: chirp, signalMissingChirp: TRUE, signalEOF: TRUE!Jukebox.MissingChirp => { missing_TRUE; CONTINUE; }]; IF ~missing THEN { FS.Read[file: chirpWindow.file, from: chirpWindow.base + ( Jukebox.pagesPerChirp - 1), nPages: 1, to: VM.AddressForPageNumber[tune.runSpace.page]]; ambientLevel _ tune.runData.ambientLevel } ELSE -- empty chirp tune.runData.runArray[0] _ [silence[Jukebox.bytesPerChirp]] }; tune.runIndex _ 0; tune.samplesInChirp _ 0; tune.samplesToChirp _ samplesStart; SetRunType[tune]; RETURN[samplesStart, samplesStart + NextElementLength[tune], tune.runType]; }; NextRun: ENTRY PROC[self: Handle, tune: Tune] RETURNS [intStart, intEnd: INT, runType: RunType] = { ENABLE UNWIND => NULL; tune.samplesInChirp _ tune.samplesInChirp + NextElementLength[tune]; IF tune.samplesInChirp=Jukebox.bytesPerChirp THEN { [intStart, intEnd, runType] _ SetPosToChirp[self, tune, tune.runChirp+1]; RETURN; }; tune.runIndex _ tune.runIndex+(IF tune.runData.runArray[tune.runIndex].elementType = soundEnergy THEN 2 ELSE 1); SetRunType[tune]; runType _ tune.runType; intStart _ tune.samplesToChirp+tune.samplesInChirp; intEnd _ intStart + NextElementLength[tune]; }; NextElementLength: PROC[tune: Tune] RETURNS [length: NAT _ 0]= { SELECT tune.runData.runArray[tune.runIndex].elementType FROM silence => length _ NARROW[tune.runData.runArray[tune.runIndex], Jukebox.RunComponent[silence]].length; singlePkt => length _ singlePktLength; soundEnergy => length _ NARROW[tune.runData.runArray[tune.runIndex+1], Jukebox.RunComponent[soundLength]].length; soundLength => ERROR; ENDCASE }; SetRunType: PROC [tune: Tune] = { belowThreshold: BOOLEAN _ TRUE; samplesOmitted: BOOLEAN _ FALSE; WITH curr: tune.runData.runArray[tune.runIndex] SELECT FROM silence => samplesOmitted _ TRUE; singlePkt => belowThreshold _ (curr.energy <= ambientLevel); soundEnergy => belowThreshold _ (curr.energy <= ambientLevel); ENDCASE => ERROR; IF ~belowThreshold THEN samplesSinceLastNonSilence _ 0; tune.runType _ IF (~samplesOmitted) AND samplesSinceLastNonSilence <= Jukebox.hangoverPackets*Jukebox.singlePktLength THEN noisy ELSE silent; IF belowThreshold THEN samplesSinceLastNonSilence _ samplesSinceLastNonSilence + NextElementLength[tune] }; searchState: {beforeStart, precedingSilence, inNoise, lessThanMinSilence, followingSilence} _ beforeStart; runStart, runEnd: INT; runType: RunType; searchEnd: INT = start+length; intStart_start; IF start<0 OR length<0 THEN RETURN; [runStart, runEnd, runType] _ SetPosBefore[self, tune, start]; IF runType = end THEN RETURN; DO -- this is simply a state machine SELECT searchState FROM beforeStart => IF runEnd SELECT runType FROM silent => IF runEnd >= searchEnd THEN {intStart_start; searchState _ followingSilence} ELSE [runStart, runEnd, runType] _ NextRun[self, tune]; end => RETURN; noisy => {intStart _ IF runStart > start THEN runStart ELSE start; searchState _ inNoise}; ENDCASE => ERROR; inNoise => SELECT runType FROM noisy => IF searchEnd < runEnd THEN { intLength _ searchEnd - intStart; nextNoise _ searchEnd; RETURN } ELSE [runStart, runEnd, runType] _ NextRun[self, tune]; end => { intLength _ runStart - intStart; RETURN }; silent => { intLength _ runStart - intStart; searchState _ lessThanMinSilence }; ENDCASE => ERROR; lessThanMinSilence => SELECT runType FROM silent => IF runEnd - (intStart + intLength) >= minSilence THEN searchState _ followingSilence ELSE [runStart, runEnd, runType] _ NextRun[self, tune]; end => RETURN; noisy => searchState _ inNoise; ENDCASE => ERROR; followingSilence => SELECT runType FROM silent => [runStart, runEnd, runType] _ NextRun[self, tune]; end => RETURN; noisy => {nextNoise _ runStart; RETURN}; ENDCASE => ERROR; ENDCASE => ERROR; ENDLOOP }; END. œFILE: JukeboxIntervalImpl.mesa Last Edited by: Stewart, December 30, 1983 11:38 am, Cedar5 Last Edited by: Swinehart, September 25, 1984 4:41:48 pm PDT Ades, February 4, 1986 11:54:21 am PST Exported procedure variables referenced in the following nested procedures Place "cursor" at the beginning of chirp containing sample. Place "cursor" within chirp containing sample, somewhere before run containing sample. read just the last page of each chirp no need to set ambientLevel here, since it is only looked at when there are samples Current "pointer" always denotes a valid entry. Move to next valid entry, or indicate end. procedure uses the ambient level, current energy level and time since last over-threshold sound to determine if we should regard next element as sound or silence: it is not called in end-of-tune cases start of FirstNoisyIntervalIn routine body better to change the callers' parameter types, except lots of thing might need rewriting? all 'nosuch found' returns have inStart=start and intLength=0 resetting this and then calling SetRunType ensures that we don't pick up a short burst of below-ambience samples at the beginning of the NoisyInterval Κ‡˜Jšœ™Jšœ;™;™Jšœœœ˜J˜šœŸ!˜$Jšœ ˜˜Jšœœ3˜Kšœ"˜"JšœM˜MJ™–Jšœ˜Jšœ˜—Jšœ˜J˜—˜Jšœ ˜˜ Jšœœ2œ3˜„—˜Jšœ˜—˜Jšœ œœ œ˜9J˜—Jšœœ˜—˜ Jšœ ˜˜JšœœCœœ3˜‘—˜Jšœ#œ˜,—˜ J˜F—Jšœœ˜—J˜˜Jšœ ˜˜ Jšœ/œ œ3˜Œ—˜Jšœ˜—˜J˜—Jšœœ˜—J˜˜Jšœ ˜˜ J˜2—˜Jšœ˜—˜Jšœœ˜—Jšœœ˜J˜—Jšœœ˜—Jš˜—˜J˜—Jšœ˜J˜J˜—…—’"΅