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]; 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 ]; 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 ÆFILE: Jukebox.mesa Last Edited by: Swinehart, March 1, 1983 2:47 pm Last Edited by: Stewart, December 30, 1983 11:33 am This procedure creates a new jukebox by the given name (which must not exist already, containing the given number of pages, and having space for nTune tune descriptors. The jukebox is NOT opened. Delete a jukebox, it must not be open. This returns the jukebox if it is already open, otherwise returns NIL. This just opens a juke box and loads state into memory so that the jukebox can be used. This just returns information about the open jukebox. If the jukebox is not open, then name is NIL. Otherwise, name is the name of the open jukebox, nPages is the number of pages total in the jukebox, and nTunes is the total number of tunes it can store. Does the obvious thing: moves everything of interest in the jukebox back to disk. Returns NIL. Creates and opens a tune. If tuneId is negative, then we allocate a new tuneId of our choosing. Otherwise, the given tuneId is used, and if the tune already exists then it is nulled. Recycles the chirp storage for the tune and marks the tune as no longer in use (this means that a later call to CreateTune[] may allocate this tune. Opens a tune for reading or writing. The tune must exist. Closes a tune and updates disk information. Returns size of tune in chirps. Returns information that can be used to read or write a given chirp in a given open tune. Returns information that can be used to read or write the client space for a given tune. nFree => Free blocks after collection recovered => Previously unknown blocks added to free list This procedure examines the entire jukebox (which must be open) to find chirps that are used in more than one place, for example in two different tunes or in one tune and on the free list. If makeFixes is TRUE then the inconsistencies are resolved by removing one of the pointers. Furthermore, if a bogus format is discovered in a tune header and makeFixes is TRUE, then the whole tune is deleted. Private Definitions: The structure of a jukebox file is as follows: 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.) The following are "magic" numbers placed at the beginning of all blocks to aid in detecting misuse of jukeboxes. This record is read and written directly from the first page of jukebox files. It contains overall descriptive information about the jukebox. This record is read and written directly from the tune header bitmap pages. One bit is contained for each tune header. One means header is available. Defines the structure and usage of a voice recording. This is read and written directly from the tune header pages on disk. The first definitions are kept on disk, as well as being used in main memory when the tune is "open". Pointers to first 50 chirps of tune. a ChirpList of chirp pointers). contains ChirpList of indirect chirps). The following entries are used only in the main-memory version when the tune is open. These records are read and written directly from the chirp list blocks on disk. The following values are only used when ChirpLists are in main memory. These records are read and written directly from the free list blocks on disk. The first free pointer in the block refers to the block itself. ÊÒ˜Jšœ™Jšœ0™0Jšœ3™3J˜šÏk ˜ Jšœ œœ˜Jšœœ˜"Jšœœœ˜Jšœœœ˜Jšœœ˜"J˜—Jšœ œ˜Jš˜J˜Jš œœœœœ˜,Jšœœ˜Jšœœ˜Jšœ œœ˜J˜šœ œÉ˜ØJ˜—Jšœœœ˜1J˜Jšœœ˜J˜Jšœœ˜ J˜Jšœœœœ˜BJ˜š Ïn œœ œ œ œ˜@JšœÅ™ÅJ˜—šž œœ œ˜&Jšœ&™&J˜—šž œœ œœ ˜5JšœF™FJ˜—šž œœ œœ ˜5JšœW™WJ˜—š žœœœ œœ˜IJšœ€™€J˜—šž œœœ ˜3Jšœ`™`J˜—šž œœœœ˜@Jšœ¸™¸J˜—šž œœœ˜-Jšœ”™”J˜—š žœœœ œœ˜GJšœ:™:J˜—šž œœ˜+Jšœ+™+J˜—š žœœœœœœ˜JJšœ™J˜—šž œœ#œœœ œœœ˜‰JšœY™YJ˜—šžœœœœ˜IJšœX™XJ˜—šžœœœœ œœœ œ˜fJšœ Ïc™%šœ Ÿ"™/Jšœ ™ —Jšœ™J˜—Jšœ™J˜Jšœœœ˜!J˜šœœ œœ˜(Jšœ œ˜4Jš œœœœœ˜)Jšœ œ œ˜(Jšœœ˜Jšœœ˜Jš œœœœ œ˜%Jšœ œ œ˜)Jšœœ˜ Jšœœ˜Jšœœ˜Jšœœ˜J˜J˜—Jšœ.™.J™Jšœn™nJšœ_™_Jšœð™ðJšœ™J™jJ˜Jšœq™qJ˜Jšœœœ ˜,Jšœœœ ˜)Jšœœœ ˜)Jšœœœ˜'Jšœœœ ˜'Jšœœœ ˜(Jšœ œœ˜#J˜šœœœœ˜&JšœN™NJšœ>™>J˜JšœœŸ+˜GJšœœŸ$˜@Jšœ œ Ÿ˜5Jšœ œŸ"˜>JšœŸ)˜EJšœŸ-˜IJ˜J˜—Jšœ œœ˜ J˜šœ œœœ˜#JšœK™KJšœJ™JJ˜JšœœŸ'˜=Jšœœœ˜'J˜J˜—Jšœ œœ Ÿ0˜WJšœ œœ˜0J˜šœœœœ˜&Jšœã™ãJ˜Jšœœ Ÿ'˜BJ˜Jšœœ˜Jšœœ˜Jšœœ˜JšœœŸ˜6šœœœ ˜,Jšœ$™$—šœŸ0˜JJšœ™—šœŸ.˜HJšœ'™'J˜—JšœU™UJ˜JšœœŸ˜.Jšœ œŸ%˜?JšœŸ&˜@JšœœŸ*˜DJšœ œ Ÿ(˜BJšœœŸ.˜HJšœœ Ÿ/˜JJšœœœœ ˜)Jšœ œ˜Jšœ œ Ÿ/˜IJšœ œœœ Ÿ˜6J˜J˜—Jšœœœ˜$J˜šœ œœœ˜"JšœO™OJ˜JšœœŸ'˜CJšœœœ ˜/J˜JšœF™FJ˜JšœœŸ ˜