Program Play8; { Play8.p Play a one-shot 8SVX IFF sound file. The command line is simply Play8 filename, where the filename is any path and must be present. This code was derived from Eric Jacobsen's spIFF.c. The differences between this and spIFF.c: a) This was translated from C to Pascal b) Several sound files in my collection had odd-length name or annotation fields. That is, the field lengths in the file were odd, but the actual data was padded with an extra 0 byte. So this program handles that. c) I added decompression routines taken from an old IFF documentation disk. I couldn't find any properly formatted compressed sound files, however, so I'm not sure if the decompression is accurate. The program will certainly try to decompress files, but mine came out garbage. Based on the samples I've accumulated, it seems that few of them are compressed anyway. In my distribution, I included a sample sample, as it were, called UseTheForce.8SVX, which obviously came from Star Wars. } {$I "Include:Devices/Audio.i"} {$I "Include:Exec/IO.i"} {$I "Include:Utils/IOUtils.i"} {$I "Include:Libraries/DOS.i"} {$I "Include:Utils/StringLib.i"} {$I "Include:Utils/Parameters.i"} {$I "Include:Exec/Memory.i"} {$I "Include:Exec/Devices.i"} type Voice8Header = record oneShotHiSamples, repeatHiSamples, samplesPreHiCycle : Integer; samplesPerSec : Short; ctOctave : Byte; sCompression : Byte; volume : Integer; end; type FibTable = Array [0..15] of Byte; const ckname : String = Nil; NoMem : String = "\nNot enough memory.\n"; reps : Integer = 1; wrt_flg : Boolean = True; ioa : IOAudioPtr = Nil; dbuf : Address = Nil; FP : FileHandle = Nil; codeToDelta : FibTable = (-34, -21, -13, -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8, 13, 21); var VHeader : Voice8Header; chan : Char; s, ps : String; dlen, oerr, i : Integer; chnk : ^Integer; ckbuffer : Array [0..2] of Short; t : Address; Function D1Unpack(source : String; n : Integer; dest : String; x : Byte) : Byte; var d : Byte; i, lim : Integer; begin lim := n shl 1; for i := 0 to lim - 1 do begin d := Ord(Source[i shr 1]); if Odd(i) then d := d and 15 else d := d shr 4; x := x + codeToDelta[d]; dest[i] := Chr(x); end; D1Unpack := x; end; Procedure DUnpack(source : String; n : Integer; dest : Address); var x : Byte; begin x := D1Unpack(Adr(source[1]), n - 2, dest, Ord(source[0])); end; Procedure OpenFile; var NameBuffer : Array [0..127] of char; Name : String; begin Name := Adr(NameBuffer); GetParam(1, Name); if strlen(Name) = 0 then begin Writeln('Usage: Play8 filename'); Exit(10); end; FP := DOSOpen(Name, MODE_OLDFILE); if FP = Nil then begin Writeln('Could not open ', Name); Exit(10); end; end; procedure CleanUp; begin if ioa <> Nil then begin with ioa^.ioa_Request.io_Message do begin if mn_ReplyPort <> Nil then DeletePort(mn_ReplyPort); end; FreeMem(ioa, SizeOf(IOAudio)); end; if dbuf <> Nil then FreeMem(dbuf, dlen); if FP <> nil then DOSClose(FP); end; Procedure pExit(Msg : String); begin Writeln(Msg); CleanUp; Exit(20); end; Procedure DoRead(Buffer : Address; Length : Integer); var ReadResult : Integer; begin ReadResult := DOSRead(FP, Buffer, Length); if ReadResult <> Length then pExit("Read error"); end; Procedure WriteData(len : Integer); var MBuffer : Array [0..127] of Char; MString : String; begin MString := Adr(MBuffer); if Odd(len) then len := Succ(len); MBuffer[127] := '\0'; while len > 127 do begin DoRead(MString, 127); if wrt_flg then Write(MString); len := len - 127; end; if len > 0 then begin DoRead(MString, len); MString[len] := '\0'; if wrt_flg then Writeln(MString); end; wrt_flg := True; end; begin ckname := Adr(ckbuffer); ckname[4] := '\0'; chan := Chr(15); OpenFile; DoRead(ckname, 4); if streq(ckname, "FORM") then begin DoRead(ckname,4); { Get size out of the way. } DoRead(ckname,4); if streq(ckname,"8SVX") then begin DoRead(ckname,4); while not streq(ckname,"BODY") do begin DoRead(Adr(dlen), 4); if streq(ckname,"VHDR") then DoRead(Adr(VHeader), SizeOf(Voice8Header)) else begin chnk := Address(ckname); case chnk^ of $4e414d45: Write("\nName of sample: "); $41555448: Write("\nAuthor: "); $28432920, $28632920, $2843294a, $2863294a: Write("\n(c) notice: "); $414e4e4f: WriteLn("\nAnnotation field:"); else wrt_flg := True; end; WriteData(dlen); end; DoRead(ckname, 4); end; DoRead(Adr(dlen), 4); Writeln(dlen, ' bytes at ', VHeader.samplesPerSec, 'Hz'); end else pExit("Not an 8SVX sound file.") end else pExit("Not an IFF file."); ioa := AllocMem(SizeOf(IOAudio), MEMF_PUBLIC); if ioa = Nil then pExit(NoMem); with ioa^.ioa_Request.io_Message do begin mn_ReplyPort := CreatePort(Nil, 0); if mn_ReplyPort = nil then pExit("Unable to allocate port"); end; dbuf := AllocMem(dlen, MEMF_PUBLIC + MEMF_CHIP); if dbuf = Nil then pExit(NoMem); with ioa^ do begin ioa_Request.io_Message.mn_Node.ln_Pri := 10; ioa_Data := Adr(chan); ioa_Length := 1; ioa_AllocKey := 0; end; oerr := OpenDevice(AUDIONAME, 0, IORequestPtr(ioa), 0); if oerr <> 0 then pExit("Can't open audio device"); if dlen > 131000 then begin { Supposed hardware limitation. } dlen := 131000; end else if Odd(dlen) then dlen := Pred(dlen); DoRead(dbuf, dlen); if VHeader.sCompression = 1 then begin t := AllocMem(dlen shl 1, MEMF_CHIP + MEMF_PUBLIC); if t = Nil then pExit("Not enough memory for decompression"); DUnpack(dbuf, dlen, t); FreeMem(dbuf, dlen); dbuf := t; dlen := dlen shl 1; end else if VHeader.sCompression > 1 then pExit("Unknown compression type"); with ioa^ do begin ioa_Request.io_Command := CMD_WRITE; ioa_Request.io_Flags := ADIOF_PERVOL; ioa_Data := dbuf; ioa_Cycles := 1; { 1 or from command line. } ioa_Length := dlen; ioa_Period := 3579546 div VHeader.samplesPerSec; ioa_Volume := 64; { Always use maximum volume. } end; BeginIO(IORequestPtr(ioa)); oerr := WaitIO(IORequestPtr(ioa)); if oerr <> 0 then Writeln('Error ', oerr, ' playing sample'); CloseDevice(IORequestPtr(ioa)); CleanUp; end.