PC speaker sound effects

When Doom was released, digital sound cards had not yet become as ubiquitous as they now are. Therefore, a large number of the computers playing Doom did not have sound cards. As a workaround for this, id Software included two sets of sound effects: alongside each of the digital sound effects that are played on sound cards, there is an equivalent PC speaker sound effect that plays through the PC speaker found on all PCs.

While digital sound effects have the prefix "DS" inside the Doom IWAD, PC speaker sound effects have the prefix "DP". For example, the sound of a pistol firing is stored in the lump named "DSPISTOL"; the corresponding PC speaker sound effect is named "DPPISTOL".

The format is notable in that it was the last WAD lump format to be properly decoded and understood. The Doom source code release did not include the PC speaker code, as it was part of the proprietary DMX sound code that was removed from the source code before its release (evidence of this can be seen in the Heretic source code). As PC speaker sound effects were no longer necessary by this time, little effort was made in properly determining the format.

The format was finally properly reverse-engineered in 2007 by Andrew Apted and Simon "Fraggle" Howard.

Format
PC speaker sound effects have a four byte header that is used to specify the length of the sound. That many bytes then follow.

Each byte corresponds to a tone that is played for 1/140th of a second (this corresponds to 4*35, where 35 is the number of frames per second in Doom). The frequency values used are on a musical scale; there are 24 notes per octave, which corresponds to double that of the western musical scale (12 notes per octave). The values are therefore a superset of the western musical scale, with an extra microtone inserted between each note.

Because of this, the frequencies increase exponentially with respect to the byte values. Adding 24 to the value doubles the frequency. A value of 0 causes silence.

Following simple program (Turbo/Borland Pascal for DOS is required; it might not be operable unless within raw DOS execution environment) can be used as example player of PC speaker sound effects lump.

USES Dos, CRT;

TYPE HugeArray=PACKED ARRAY [0..65519] OF Byte; DynamicArray=^HugeArray;

VAR oldTimer:Pointer; curBreak,ready:Boolean; curPos, dataLength: LongInt; data:DynamicArray; i:Integer; inFile:FILE; curFile:SearchRec; PredExitHandler:Pointer;

CONST clocker=1193180; ReCalc=15; Skip:Boolean=FALSE;

PROCEDURE RestoreEnv; FAR; BEGIN Port[$43]:=$36;               { 00 11 011 0 } Port[$40]:=0; Port[$40]:=0; SetIntVec(8, oldTimer); SetCBreak(curBreak); ExitProc:=PredExitHandler END;

PROCEDURE chainTimer; INLINE($9c/$ff/$1e/oldTimer);    {pushf ^ call ds:}

PROCEDURE Help; VAR HelpScreen:Text; Dir: DirStr; Name: NameStr; Ext: ExtStr; BEGIN Assign(HelpScreen, 'CON'); ReWrite(HelpScreen); FSplit(ParamStr(0), Dir, Name, Ext); WriteLn(HelpScreen, 'Usage:', Chr(9), Concat(Name, Ext), Chr(9), 'RAW_File'); Close(HelpScreen); Halt END;

PROCEDURE newTimer; INTERRUPT; CONST counter:Byte=0; BEGIN Inc(counter); IF counter=6 THEN BEGIN chainTimer; counter:=0 END ELSE Port[$20]:=$20; IF ready THEN BEGIN IF curPos=dataLength THEN BEGIN Port[$61]:=Port[$61] AND NOT 3; ready:=FALSE END ELSE IF data^[curPos]=0 THEN Port[$61]:=Port[$61] AND NOT 3 ELSE BEGIN Port[$43]:=$b6;          { 10110110 } Port[$42]:=clocker DIV (data^[curPos]*ReCalc) MOD 256; Port[$42]:=Byte(clocker DIV (data^[curPos]*ReCalc) DIV 256); Port[$61]:=Port[$61] OR 3 END; Inc(curPos) END END; BEGIN IF ParamCount<1 THEN Help;

PredExitHandler:=ExitProc; GetCBreak(curBreak); SetCBreak(FALSE); CheckBreak:=FALSE; GetIntVec(8, oldTimer); PredExitHandler:=ExitProc; ExitProc:=Addr(RestoreEnv); SetIntVec(8, Addr(newTimer)); Port[$43]:=$36;               { 00 11 011 0 } Port[$40]:=Byte(clocker DIV (18*6) AND 256); Port[$40]:=Byte(clocker DIV (18*6) SHR 8); FileMode:=0;

FOR i:=1 TO ParamCount DO BEGIN FindFirst(ParamStr(i), AnyFile AND NOT(Directory AND VolumeID), curFile); IF Skip THEN Break; WHILE (DosError=0) AND NOT Skip DO BEGIN Write(curFile.Name, '...'); Assign(inFile, curFile.Name); Reset(inFile, 1); GetMem(data, 4); BlockRead(inFile, data^, 4); dataLength:=data^[2]+data^[3] SHL 8; FreeMem(data, 4); GetMem(data, dataLength); BlockRead(inFile, data^, dataLength); ready:=TRUE; curPos:=0; WHILE ready DO; FreeMem(data, dataLength); Close(inFile); WriteLn(^H^H^H' done.'); Delay(500); WHILE KeyPressed DO Skip:=Skip OR (ReadKey=#27); FindNext(curFile) END END END.

Source ports with PC speaker sound effects support
In addition to the original DOS versions of Doom, several source ports can play back the PC speaker sound effects. These include the following ports:
 * Chocolate Doom
 * ReMooD
 * The Eternity Engine