<> <> <> 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; 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]; 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]; <> Info: PROC [self: Handle] RETURNS [name: Rope.ROPE, nPages, nTunes: INT]; <> CloseJukebox: PROC [self: Handle] RETURNS [Handle]; <> CreateTune: PROC [self: Handle, tuneId: INT _ 0] 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]; <> Scavenge: PROC [self: Handle, stream: IO.STREAM, makeFixes: BOOL] RETURNS[nFree: INT, recovered: INT]; < Free blocks after collection>> < Previously unknown blocks added to>> <> <> <> 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 8 pages. Chirps are page aligned, with 192 bytes per chirp thrown away to maintain alignment.>> <<(Actually the last 192 bytes are available for storage. VoiceStream uses them to save run coded silence.)>> <> 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. ]; 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}; 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. ]; 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 ]; END. December 26, 1983 7:35 pm, Stewart, Cedar 5