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. |