2023-11-16 18:19:54 -05:00

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.