<> <> <> <> DIRECTORY BasicTime USING [GMT], FS USING [nullOpenFile, OpenFile], IO USING [STREAM], Rope USING [ROPE], VM USING [Interval, nullInterval]; Jukebox: DEFINITIONS = BEGIN Tune: TYPE = LONG POINTER TO TuneDescriptor; pagesPerChirp: CARDINAL = 16; bytesPerChirp: CARDINAL = 8000; bytesPerMS: CARDINAL = 8; PageNumber: TYPE = INT; ErrorCode: TYPE = {JukeboxExists, JukeboxOpen, NoJukebox, NoTunesAvailable, BadTune, JukeboxFormat, TooManyTunes, TuneLocked, Bug, TuneTooLarge, NoFreeChirps, BadTunePointer, TunesOpen, BadChirpPointer, NoDiskSpace}; Error: ERROR[reason: ErrorCode, rope: Rope.ROPE]; MissingChirp: ERROR; EOF: ERROR; WindowOrigin: TYPE = RECORD [file: FS.OpenFile, base: PageNumber]; instances: LIST OF Handle; <> <> CreateJukebox: PROC [name: Rope.ROPE, nPages: INT, nTunes: INT]; <> DeleteJukebox: PROC [name: Rope.ROPE]; <> FindJukebox: PROC [name: Rope.ROPE] RETURNS [Handle]; <> OpenJukebox: PROC [name: Rope.ROPE] RETURNS [Handle]; <> CloseJukebox: PROC [self: Handle] RETURNS [Handle]; <> Info: PROC [self: Handle] RETURNS [name: Rope.ROPE, nPages, nTunes: INT, tuneHWM: INT]; <> <> CreateTune: PROC [self: Handle, tuneId: INT _ -1] RETURNS [Tune]; <> DeleteTune: PROC [self: Handle, tuneId: INT]; <> OpenTune: PROC [self: Handle, tuneId: INT, write: BOOL] RETURNS [Tune]; <> CloseTune: PROC [self: Handle, tune: Tune]; <> TuneSize: PROC [tune: Tune] RETURNS [INT] = INLINE { RETURN[tune.size]; }; <> FindChirp: PROC [self: Handle, tune: Tune, chirp: INT, signalMissingChirp: BOOL _ FALSE, signalEOF: BOOL _ FALSE] RETURNS [WindowOrigin]; <> FindClientSpace: PROC [self: Handle, tuneId: INT] RETURNS [WindowOrigin]; <> FirstNoisyIntervalIn: PROC [ self: Handle, tune: Tune, start: INT, length: INT, minSilence: INT_1] RETURNS [intStart, intLength, nextNoise: INT]; <> Scavenge: PROC [self: Handle, stream: IO.STREAM, makeFixes: BOOL] RETURNS[nFree: INT, recovered: INT]; < Free blocks after collection>> < Previously unknown blocks added to>> <> <> <> ArchiveCloseTune: PROC [self: Handle, tune: Tune]; <> <> Handle: TYPE = REF JukeboxObject; JukeboxObject: TYPE = MONITORED RECORD [ window: Jukebox.WindowOrigin _ [FS.nullOpenFile, 0], hdr: LONG POINTER TO JukeboxHeader _ NIL, hdrSpace: VM.Interval _ VM.nullInterval, currentMapPageNumber: INT _ 0, maxMapPageNumber: INT _ 0, free: LONG POINTER TO FreeList _ NIL, freeSpace: VM.Interval _ VM.nullInterval, currentFreeChirpNumber: INT _ 0, firstDesPageNumber: INT _ 0, openTuneHeaderList: Tune _ NIL, jukeboxName: Rope.ROPE _ NIL ]; <> <<>> <<1) The first page contains the jukebox header, including chirp allocation and other miscellaneous information.>> <<2) The second and following pages contain a bitmap indicating the availability of tune headers.>> <<3) After the tune header bit map come many pages of tune headers, two pages for each possible tune. The first page of each tune header is for Bluejay use only, and the second page is for client use only (Bluejay provides ops to read it and write it). Tune headers are allocated statically, and are similar in format to Unix i-nodes (three levels of block directory).>> <<4) All pages after the tune header are used for storage of the tunes, and for indirect tune chirp lists, and for free list blocks. The pages of a tune are grouped into "chirps". Each chirp contains several pages, in order to reduce disk access time. Each chirp contains one second of conversation in 16 pages. Chirps are page aligned, with the 192 bytes per chirp following the speech samples used as a run list for interpreting the sequence of the samples, as defined below. >> <> magicJukeboxHeader: PRIVATE INTEGER = 14513; magicTuneBitMap: PRIVATE INTEGER = 14722; magicTuneHeader: PRIVATE INTEGER = 28617; magicChirpList: PRIVATE INTEGER = 7111; magicDeepList: PRIVATE INTEGER = -4613; magicFreeList: PRIVATE INTEGER = -15322; magicChirp: PRIVATE INTEGER = 6215; JukeboxHeader: PRIVATE TYPE = RECORD [ <> <> magic: INTEGER, -- Magic number for consistency checks. nTunes: INT, -- Number of tune headers allocated. nFreeChirps: INT, -- Number of free chirps. nChirps: INT, -- Total no. of chirps in jukebox. freeListHead: PageNumber, -- Pointer to chirp at head of free list. firstChirp: PageNumber, -- Pointer to first chirp above tune headers. tuneHWM: INT -- highest number tune that has ever been allocated in jukebox ]; bitMapSize: PRIVATE INTEGER = 4; TuneBitMap: PRIVATE TYPE = RECORD [ <> <> magic: INTEGER, -- Magic number for consistency checks. bits: ARRAY [0..bitMapSize) OF CARDINAL ]; nHdrChirps: PRIVATE INTEGER = 10; -- Number of zeroth-level chirps in tune header. tuneState: PUBLIC TYPE = {inUse, available}; RunType: TYPE = { end, noisy, silent }; TuneDescriptor: PUBLIC TYPE = RECORD [ <> magic: INTEGER, -- Magic number for consistency checks. state: tuneState, createDate: BasicTime.GMT, appendDate: BasicTime.GMT, playDate: BasicTime.GMT, size: INT, -- Number of chirps in tune. chirps: ARRAY [0..nHdrChirps) OF PageNumber, <> indirectChirp: PageNumber,-- Pointer to indirect chirp (each page contains <> deepChirp: PageNumber, -- Pointer to doubly-indirect chirp (each page <> <> tuneId: INT, -- Name of the tune. openCount: INTEGER, -- Number of times this tune is open. next: Tune, -- All open tunes are linked together. space: VM.Interval, -- Space used to write descriptor to disk. writable: BOOL, -- TRUE means only one access at a time. kill: BOOL, -- Deallocate tune as soon as it's not in use. indirectSpace: VM.Interval,-- A space and pointer are cached (potentially) indirectCache: LONG POINTER TO ChirpList, indirect: INT, deepSpace: VM.Interval, -- for one single indirect block and the double deepCache: LONG POINTER TO ChirpList, -- indirect block. <<>> <> runSpace: VM.Interval, -- for one block containing chirp run table runChirp: INT, -- chirp # currently occupying runSpace runData: RunData, -- NIL when run table stuff not initialized. runIndex: RunArrayRange, -- current index into current run table. samplesInChirp: INT, -- position corresponding to index samplesToChirp: INT, -- position in tune corresponding to beginning of chirp runSize: INT, -- length of current run (0-length intervening runs don't clear it) runType: RunType -- noisy, silent, end ]; chirpListSize: PRIVATE INTEGER = 64; ChirpList: PRIVATE TYPE = RECORD [ <> magic: INTEGER, -- Magic number for consistency checks. chirps: ARRAY [0..chirpListSize) OF PageNumber, <> dirty: BOOL, -- This is always FALSE on disk. page: PageNumber -- Page from which list was read. ]; freeListSize: PRIVATE INTEGER = 16; FreeList: PRIVATE TYPE = RECORD [ <> <> magic: INTEGER, -- Magic number for consistency checks. nChirps: INTEGER, -- Number of valid chirps in the array. next: PageNumber, -- Next chirp in free list chain. chirps: ARRAY [0..freeListSize) OF PageNumber ]; RunArrayRange: TYPE = [0..95); RunElementType: TYPE = {silence,singlePkt,soundEnergy,soundLength}; maxEnergy: INTEGER = (LAST[NAT])/2; EnergyRange: TYPE = [0..maxEnergy]; LengthRange: TYPE = [0..bytesPerChirp]; <> <<>> RunArray: TYPE = ARRAY RunArrayRange OF RunComponent; << >> RunDataObject: TYPE = RECORD [ <> runArray: RunArray, ambientLevel: EnergyRange ]; RunComponent: TYPE = MACHINE DEPENDENT RECORD [ <> variantTag (0: 0..15): SELECT elementType (0: 0..1): RunElementType FROM silence => [length (0: 2..15): LengthRange], singlePkt => [energy (0: 2..15): EnergyRange], soundEnergy => [energy (0: 2..15): EnergyRange], soundLength => [length (0: 2..15): LengthRange] ENDCASE ]; SilentRun: TYPE = silence RunComponent; singlePktLength: CARDINAL = 20*bytesPerMS; RunData: TYPE = LONG POINTER TO RunDataObject; hangoverPackets: INT = 20; <> larkAmbientNoiseThreshold: EnergyRange = 144; END. December 26, 1983 7:35 pm, Stewart, Cedar 5 <> <> <<>> <<>> <<>>