mirror of
https://github.com/erkyrath/infocom-zcode-terps.git
synced 2026-01-13 07:10:02 +00:00
254 lines
5.7 KiB
OpenEdge ABL
254 lines
5.7 KiB
OpenEdge ABL
|
|
{ sound file munger for the Macintosh
|
|
WRITTEN BY: Duncan Blanchard 05-Feb-88
|
|
|
|
this is a sound pre-processor for the Mac, which takes an Amiga-format
|
|
sound file and does two things:
|
|
- map each sample byte from signed -> unsigned
|
|
- make waveform begin/end near zero (unsigned), to avoid a nasty click
|
|
|
|
for now, we read file 'SD' and write to 'SD.out'
|
|
}
|
|
|
|
PROGRAM MungSound;
|
|
|
|
{$SETC RAMP := TRUE} { false for some loud sounds }
|
|
|
|
{ The first two switches are specified in the command line that invokes
|
|
the compiler. Embedded names and range checking should be suppressed
|
|
in shipped code, but are useful for debugging. }
|
|
|
|
{cmdline $R-} { Turn on/off range checking }
|
|
{cmdline $D-} { Turn on/off procedure names in object code }
|
|
|
|
{ Exporting of names is off initially, then changed below. }
|
|
|
|
{$Z-} { do/don't export all routine names }
|
|
{$L-} { don't include lengthy interface files in listings }
|
|
USES
|
|
MemTypes,
|
|
QuickDraw,
|
|
OSIntf,
|
|
ToolIntf;
|
|
{ PackIntf }
|
|
{ MacPrint }
|
|
|
|
{$L+} { reenable listing for our code}
|
|
{$Z*} { Export following (all) routine names (but not vars)}
|
|
|
|
TYPE
|
|
{ the following record def combines two adjacent byte members, because
|
|
of the vagaries of Pascal packing }
|
|
|
|
SHeader = PACKED RECORD { sound file header format: }
|
|
flen: INTEGER; { len (bytes) of file following }
|
|
rp: INTEGER; { repeat count / midi pitch }
|
|
rate: INTEGER; { original sampling rate }
|
|
unused: INTEGER;
|
|
dlen: INTEGER { len (bytes) of data following }
|
|
END;
|
|
SHeaderPtr = ^SHeader;
|
|
|
|
CONST
|
|
ASHLEN = 10; { length, Activision sound header }
|
|
MSHLEN = 6; { length, Mac sound header }
|
|
MSLEN = (64 * 1024) + MSHLEN; { 64K max, plus space for header }
|
|
|
|
VAR
|
|
sheadp: SHeaderPtr;
|
|
soundp: FFSynthPtr;
|
|
inChan, outChan: INTEGER;
|
|
|
|
{-------------------------------}
|
|
{ MungSnd }
|
|
{-------------------------------}
|
|
|
|
FUNCTION MungSnd (id: INTEGER): INTEGER;
|
|
CONST
|
|
RAMPTIME = 30; { minimum ramp is (1/100?) (1/150?) sec }
|
|
|
|
VAR
|
|
p, begp, endp: Ptr; { ptr to unsigned byte (see mem mgr) }
|
|
n: LONGINT; { len passed & actual len /returned/ here }
|
|
dlen32: LONGINT; { sound data len (unsigned, 32 bits) }
|
|
err: INTEGER;
|
|
i, rampLen: INTEGER;
|
|
x: LONGINT; { big enough for our ramp calc }
|
|
|
|
BEGIN
|
|
{ make sure buffers exist }
|
|
|
|
IF (sheadp = NIL) OR (soundp = NIL) THEN
|
|
BEGIN
|
|
MungSnd := -1;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
{ open sound data file (ignore id arg for now ...) }
|
|
|
|
err := FSOpen ('SD', 0, inChan);
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
inChan := 0; { mark as unopened }
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
{ get data header, and data body }
|
|
|
|
n := ASHLEN;
|
|
err := FSRead (inChan, n, Ptr(sheadp));
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
dlen32 := BAND (sheadp^.dlen, $0FFFF); { unsigned! }
|
|
n := dlen32;
|
|
begp := Ptr (ORD4(soundp) + MSHLEN); { leave space for Mac header }
|
|
endp := Ptr (ORD4(begp) + dlen32);
|
|
|
|
err := FSRead (inChan, n, begp); { get data }
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
{ for Mac, map each sample byte from signed -> unsigned }
|
|
|
|
p := begp;
|
|
WHILE ORD4(p) < ORD4(endp) DO
|
|
BEGIN
|
|
p^ := BXOR (p^, $080);
|
|
p := Ptr (ORD4(p) + 1);
|
|
END;
|
|
|
|
{$IFC RAMP}
|
|
|
|
{ To avoid a loud "click," especially in quieter effects, seems that
|
|
we must "ramp up" from zero at the beginning of the waveform, and
|
|
"ramp down" at the end. The ramp length should be as short as is
|
|
needed to remove the click.
|
|
|
|
In certain louder effects ramping may actually be undesirable,
|
|
since the "click" may be unnoticable but the silence may cause a
|
|
slight but audible break between loops. }
|
|
|
|
rampLen := sheadp^.rate DIV RAMPTIME;
|
|
|
|
p := begp;
|
|
FOR i := 0 TO rampLen-1 DO
|
|
BEGIN
|
|
x := BAND (p^, $0FF); { unsigned fer shure }
|
|
p^ := (x * i) DIV rampLen;
|
|
p := Ptr (ORD4(p) + 1);
|
|
END;
|
|
|
|
p := endp;
|
|
FOR i := 0 TO rampLen-1 DO
|
|
BEGIN
|
|
p := Ptr (ORD4(p) - 1); { work backwards from end }
|
|
x := BAND (p^, $0FF);
|
|
p^ := (x * i) DIV rampLen;
|
|
END;
|
|
|
|
{$ENDC}
|
|
|
|
{ create/open an output file (ignore id arg for now ...) Don't set
|
|
creator = INFO, to avoid click-launching. No type yet, either. }
|
|
|
|
err := Create ('SD.out', 0, ' ', ' ');
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
outChan := 0; { mark as unopened }
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
err := FSOpen ('SD.out', 0, outChan);
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
outChan := 0; { mark as unopened }
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
{ write header, write data }
|
|
|
|
n := ASHLEN;
|
|
err := FSWrite (outChan, n, Ptr(sheadp));
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
n := dlen32;
|
|
err := FSWrite (outChan, n, begp);
|
|
IF err <> 0 THEN
|
|
BEGIN
|
|
MungSnd := err;
|
|
EXIT (MungSnd);
|
|
END;
|
|
|
|
MungSnd := 0; { all okay }
|
|
END;
|
|
|
|
{-------------------------------}
|
|
{ Cleanup }
|
|
{-------------------------------}
|
|
|
|
PROCEDURE Cleanup;
|
|
VAR
|
|
err: INTEGER;
|
|
BEGIN
|
|
IF inChan <> 0 THEN
|
|
err := FSClose (inChan);
|
|
|
|
IF outChan <> 0 THEN
|
|
err := FSClose (outChan);
|
|
|
|
err := FlushVol (NIL, 0); { make sure disk is updated }
|
|
END;
|
|
|
|
{-------------------------------}
|
|
{ ZSound }
|
|
{-------------------------------}
|
|
|
|
PROCEDURE ZSound;
|
|
VAR
|
|
n: INTEGER;
|
|
BEGIN
|
|
{ one-time allocation of buffers for sound data }
|
|
|
|
sheadp := SHeaderPtr (NewPtr(ASHLEN));
|
|
soundp := FFSynthPtr (NewPtr(MSLEN));
|
|
|
|
n := MungSnd (99);
|
|
IF n <> 0 THEN
|
|
BEGIN
|
|
SysBeep (8); SysBeep (8); SysBeep (8); { cheap error signal }
|
|
END;
|
|
|
|
Cleanup; { close files }
|
|
END;
|
|
|
|
{-------------------------------}
|
|
{ Main }
|
|
{-------------------------------}
|
|
|
|
BEGIN
|
|
MoreMasters; { could probably skip most inits }
|
|
InitGraf (@thePort);
|
|
InitWindows;
|
|
InitFonts;
|
|
InitMenus;
|
|
InitCursor;
|
|
FlushEvents (everyEvent,0);
|
|
|
|
ZSound;
|
|
END.
|
|
|