ewa@beowulf.ucsd.edu (Eric Anderson) (05/11/91)
Does anyone know if it is possible to use MacRecorder (from Farallon) to perform instant processing of live audio? For example, a VU meter, or even a frequency analyzer? The basic question is, can samples be read continuously from MacRecorder, or is there a big buffering delay somewhere along the path? How about the microphone port built in to the newer Macs? Please respond by mail (or mail and posting). Thanks! Eric Anderson ewa@cs.ucsd.edu Computer Systems Laboratory (619)534-8604 Department of Computer Science and Engineering University of California, San Diego 9500 Gilman Drive 0114 La Jolla, CA 92093-0114
trebor@lkbreth.foretune.co.jp (Robert J Woodhead) (05/12/91)
Boy is this your lucky day. As it happens I asked the same
question here not a week ago. Several people sent me copies
of the MacRecorder hackers toolkit. There are several
versions of this floating around, all in C. As it happens,
I program mostly in Pascal, so I converted the stuff into
PASCAL, and also wrote a software VU meter function.
Below is the basic software in MPW Assembler and PASCAL to
do what you want. Hope it helps.
** I HEREBY PLACE THIS CODE IN THE PUBLIC DOMAIN **
** Robert J Woodhead, 5/12/1991 **
;
; assembly language interface to the Macrecorder
; modified by RJW from Macrecorder hackers toolkit
;
machine mc68020
mc68881
;
; function flip(x:integer):integer;
;
; flips the bits in the byte x and returns the
; new bits
;
flip FUNC EXPORT
retAddr equ A0 ; Pascal return address
param equ D1 ; x, our parameter
;
; start of code, stack is as follows:
;
; tos-> return address ; pointer
; param ; word
; func result ; word
;
move.l (sp)+,retAddr ; save return address
move.w (sp)+,param ; and parameter
moveq #7,D2 ; loop counter
moveq #0,D0 ; our result
loop_top roxl.b #1,D1 ; get a bit from source
roxr.b #1,D0 ; put into destination
dbra d2,loop_top ; and loop
move.w D0,(sp) ; our result
jmp (retAddr)
ENDF
;
; function mono22(fromwhere:ptr; outbuf:ptr; fliptable:ptr; len:longint):longint;
;
; reads the macRecorder from port fromwhere and puts the bytes in outbuf.
; Uses tables fliptable to correct the bytes. Records a maximum of len
; bytes. Returns the number of bytes read.
;
mono22 FUNC EXPORT
;
; start of code, stack is as follows:
;
; tos-> return address ; pointer
; len ; longint
; fliptable ; pointer
; outbuf ; pointer
; fromwhere ; pointer
; func result ; longint
;
retAddr equ A0
len equ D1
fliptab equ A1
outbuf equ A2
from equ A3
toutbuf equ D0 ; temp outbuf area
tfrom equ D2 ; temp tfrom area
result equ D0 ; return result
sound equ D2 ; sound byte we get
timer equ D3 ; watchdog timer
savelen equ D4 ; saved copy of length
move.l (sp)+,retAddr ; return address
move.l (sp)+,len
move.l (sp)+,fliptab
move.l (sp)+,toutbuf ; temp location
move.l (sp)+,tfrom ; temp location
movem.l A2-A3/D2-D4,-(sp) ; save regs we use
move.l toutbuf,outbuf ; put pointers into aregs
move.l tfrom,from ; address of sccRd
moveq #-1,result ; result code, assume failure
moveq #0,sound ; sound byte holder
move.l len,savelen ; # of bytes to get
reset move.l #50000,timer ; timeout
loop subq.l #1,timer ; decrement timeout
bmi.s timeout
btst #0,(from) ; data yet?
beq.s loop
move.b 4(from),sound ; get the byte
move.b 0(fliptab,sound),(outbuf)+ ; and save it
subq.l #1,len ; one less to do
bne.s reset ; and get another
exit sub.l len,savelen ; figure out how many done
move.l savelen,result ; save in return result
timeout movem.l (sp)+,A2-A3/D2-D4 ; restore registers
move.l result,(sp) ; fix return result
jmp (A0) ; and done
ENDF
;
; function lvl22(fromwhere:ptr; fliptable:ptr; len:longint):longint;
;
; reads the macRecorder from port fromwhere and figures intensity.
; Uses tables fliptable to correct the bytes. Records a maximum of len
; bytes. Returns the hi+lo-256 of the bytes read.
;
lvl22 FUNC EXPORT
;
; start of code, stack is as follows:
;
; tos-> return address ; pointer
; len ; longint
; fliptable ; pointer
; fromwhere ; pointer
; func result ; longint
;
retAddr equ A0
len equ D1
fliptab equ A1
from equ A3
tfrom equ D2 ; temp tfrom area
result equ D0 ; return result
sound equ D2 ; sound byte we get
timer equ D3 ; watchdog timer
savelen equ D4 ; saved copy of length
lowlvl equ D5 ; lowest level seen
hilvl equ D6 ; highest level seen
flag equ D7 ; ignore 1st byte flag
move.l (sp)+,retAddr ; return address
move.l (sp)+,len
move.l (sp)+,fliptab
move.l (sp)+,tfrom ; temp location
movem.l A2-A3/D2-D7,-(sp) ; save regs we use
move.l tfrom,from ; address of sccRd
move.l #256,result ; result code, assume nothing
moveq #0,sound ; sound byte holder
move.l len,savelen ; # of bytes to get
move.l #128,hilvl ; init counters
move.l #128,lowlvl
reset move.l #50000,timer ; timeout
loop subq.l #1,timer ; decrement timeout
bmi.s timeout
btst #0,(from) ; data yet?
beq.s loop
move.b 4(from),sound ; get the byte
move.b 0(fliptab,sound),sound ; xlate it
cmp.l len,savelen ; equal lengths, ignore
beq.s lbot ; so exit
cmp.b sound,hilvl ; compare hi levels
bmi.s hipast
move.b sound,hilvl
hipast cmp.b lowlvl,sound ; and low levels
bmi.s lbot
move.b sound,lowlvl
lbot subq.l #1,len ; one less to do
bne.s reset ; and get another
exit move.l lowlvl,result ; add the two quantities
add.l hilvl,result ; save in return result
timeout movem.l (sp)+,A2-A3/D2-D7 ; restore registers
move.l result,(sp) ; fix return result
jmp (A0) ; and done
ENDF
;
; procedure sccInit(scc:ptr)
;
; sets up the scc for proper reading and writing
;
MACRO
sccwait
movem.l A2-A5/D0-D7,-(sp) ; waste some time
movem.l (sp)+,A2-A5/D0-D7 ; noted comment in IM3:25 about
movem.l A2-A5/D0-D7,-(sp) ; accessing scc to quickly...
movem.l (sp)+,A2-A5/D0-D7 ;
ENDM
MACRO
sccpoke ®,&data ; poke reg & data into the scc
move.b ®,(A1)
move.b &data,(A1)
sccwait
ENDM
sccInit PROC EXPORT
move.l (sp)+,A0 ; return address
move.l (sp)+,A1 ; SCC address
sccpoke #9,#2 ; do the poking...
sccpoke #4,#12
sccpoke #1,#1
sccpoke #3,#193
sccpoke #5,#122
sccpoke #11,#48
sccpoke #14,#1
sccpoke #15,#8
sccpoke #64,#64
sccpoke #9,#10
jmp (A0) ; return
ENDP
;
; procedure intOn;
; procedure intOff;
;
; turn interrupts on and off
;
intOn PROC EXPORT ; turn interrupts on
move.l (sp)+,A0 ; return address
andi #$F8FF,SR ; change status register
jmp (A0)
ENDP
intOff PROC EXPORT
move.l (sp)+,A0
ori #$0700,SR
jmp (A0)
ENDP
END
{[n+,u+,r+,d+,#+,j=13-/40/1o,t=2,o=95] PasMat formatting options}
(* Sample the MacRecorder *)
{$R-}
PROGRAM sound;
USES
Memtypes,
Quickdraw,
OSIntf,
ToolIntf,
PackIntf,
CursorCtl, { for the spinning cursor}
Signal, { to handle command-period}
PasLibIntf, { for standard I/O, etc.}
IntEnv; { for argV and argC}
type
fliparr = packed array[0..255] of char;
bufarr = packed array[0..16385] of char;
cptr = ^bufarr;
lptr = ^longint;
var
i,j,k,a1,a2:integer;
l,t: longint;
sccRd,
sccWr: ptr;
fliptab: fliparr;
buf: bufarr;
FUNCTION flip(i:integer):integer; EXTERNAL;
FUNCTION mono22(from:ptr; buffer:ptr; fliptable:ptr; len:longint):longint; EXTERNAL;
PROCEDURE sccInit(sccWr:ptr); EXTERNAL;
PROCEDURE intOn; EXTERNAL;
PROCEDURE intOff; EXTERNAL;
PROCEDURE buildFlipTable;
var i:integer;
BEGIN
for i:=0 to 255 do
fliptab[i]:=chr(flip(i));
END;
BEGIN
Writeln('Test of input from MacRecorder');
writeln('Initializing fliptable');
buildFlipTable;
writeln('Initializing SCC');
sccRd:=Pointer(lptr($1D8)^+2);
sccWr:=Pointer(lptr($1DC)^+2);
writeln('SCCrd $1D8 -> ',lptr($1D8)^,' = ',longint(sccRd));
writeln('SCCwr $1DC -> ',lptr($1DC)^,' = ',longint(sccWr));
intOff;
sccInit(sccWr);
intOn;
l:=256;
for j:=0 to l-1 do
buf[j]:=chr(0);
Writeln('GO!');
intOff;
l:=mono22(sccRd,@buf,@fliptab,l);
intOn;
Writeln('Done!');
if (l<1) then
writeln('Error, could not read!')
else
begin
a1:=255; a2:=0;
for j:=0 to l-1 do
begin
write(ord(buf[j]):4);
if ((j mod 10) = 9) then
writeln;
t:=t+ord(buf[j]);
if ord(buf[j])>a2 then a2:=ord(buf[j]);
if ord(buf[j])<a1 then a1:=ord(buf[j]);
end;
t:=t div l;
writeln;
writeln;
writeln('Statistics : bytes = ',l,' lo = ',a1,' hi = ',a2,' avg = ',t);
end;
END.
Using the LVL22 function should also be pretty easy. I built a video VU meter
that output onto my CS2 in an hour or so. Hope this helps.
--
+--------------------------------------------------------------------------+
| Robert J. Woodhead, Biar Games / AnimEigo, Incs. trebor@foretune.co.jp |
| "The Force. It surrounds us; It enfolds us; It gets us dates on Saturday |
| Nights." -- Obi Wan Kenobi, Famous Jedi Knight and Party Animal. |