*
*   DeluxeBeep.s
*
*   A stupid little gadget that play's a sample each time
*   Intuition's "DisplayBeep" routine is called showing you
*   the power of exec's "SetFunction" routine.
*
                incdir  sys:devpac_inc/
                include exec/exec_lib.i
                include exec/memory.i
                include libraries/dos_lib.i
                include intuition/intuition_lib.i
                include hardware/custom.i
                include hardware/intbits.i
                include hardware/dmabits.i

_custom     equ     $dff000

*
* open intuition
*
                move.l  a0,a4               ; arg to a4
                move.l  d0,d3               ; arg_len to d3
                move.l  #int_name,a1        ; pointer to "intuition.library"
                moveq   #0,d0               ; any version (I don't care)
                CALLEXEC    OpenLibrary     ; let's open it
                move.l  d0,_IntuitionBase   ; and store the base pointer
                beq     NoLib               ; what's this ? it failed to open
*
* check if the patch is already there, if so remove it
*
                move.l  d0,a2               ; IntuitionBase to a2
                move.l  _LVODisplayBeep+2(a2),a2    ; old routine address
                cmp.l   #'BEEP',-12(a2)     ; Beep already installed ?
                bne     SetPatch            ; no set it quickly !

                move.l  -8(a2),d0           ; old intuition beep routine
                move.l  _IntuitionBase,a1   ; IntuitionBase
                move.l  #_LVODisplayBeep,a0 ; table offset
                CALLEXEC    SetFunction     ; normal again !

                lea.l   -12(a2),a1          ; pointer to the memory it takes
                move.l  -4(a2),d0           ; size of the memory it takes
                CALLEXEC    FreeMem         ; and it's gone ! (phoe)

                cmp.w   #2,d3               ; one letter argument ?
                bhi.s   Remove              ; no, more so remove
                cmp.b   #'F',(a4)           ; arg 'F' ?
                beq     SetPatch            ; yes, set new patch
                cmp.b   #'f',(a4)           ; arg 'f' ?
                beq     SetPatch            ; yes. set new patch
Remove:         move.l  #rem,a2             ; write a message saying that
                move.l  #rems,a3            ; DeluxeBeep has been removed
                bsr     PrintMsg            ; from the system
                bra     NoMem
*
* reserve memory for the patch
*
SetPatch:       move.l  #patch_end-patch_start+12,d0    ; size of the patch
                move.l  #MEMF_CHIP+MEMF_CLEAR,d1    ; CHIP mem ! (sound data)
                CALLEXEC    AllocMem        ; let's reserve it
                move.l  d0,Func             ; and store the pointer
                beq.s   NoMem               ; jeee wizzz it failed !
*
* get old vector
*
                move.l  _IntuitionBase,a0   ; IntuitionBase to a0
                move.l  _LVODisplayBeep+2(a0),OldVec+2 ; store the orig address
*
* copy the patch in the new memory
*
                move.l  #patch_start,a0     ; start of patch routine
                move.l  Func,a1             ; destenation area
                move.l  #'BEEP',(a1)+       ; so we known it's there already
                move.l  OldVec+2,(a1)+      ; so we known the old address
                move.l  #patch_end-patch_start,(a1)
                move.l  (a1),d0
                add.l   #12,(a1)+           ; so we know the size allocated
                CALLEXEC    CopyMem         ; fire away !
*
* set the patch
*
                move.l  #_LVODisplayBeep,a0 ; table offset
                move.l  _IntuitionBase,a1   ; library base address
                move.l  Func,d0             ; new function
                add.l   #12,d0              ; add 12 bytes
                CALLEXEC    SetFunction     ; and were in !

                move.l  #ins,a2             ; print a message saying
                move.l  #inss,a3            ; that DeluxeBeep is hanging
                bsr     PrintMsg            ; in the system.

                suba.l  a0,a0               ; call it once to let them
                CALLINT DisplayBeep         ; hear it !

NoMem:          move.l  _IntuitionBase,a1   ; close intuition
                CALLEXEC    CloseLibrary    ; like a good boy.
NoLib:          moveq   #0,d0               ; clear return code
                rts                         ; and that's it !
*
* print a message
*
PrintMsg:       move.l  #dos_name,a1        ; pointer to "dos.library"
                moveq   #0,d0               ; any version (I still don't care)
                CALLEXEC    OpenLibrary     ; open it now
                move.l  d0,_DOSBase         ; and store the base pointer
                beq.s   NoDos               ; failed, no message ?!?!
                CALLDOS Output              ; get output handle
                move.l  d0,d1               ; put it in d1
                move.l  a2,d2               ; message to d2
                move.l  a3,d3               ; size to d3
                CALLDOS Write               ; write it to the console
                move.l  _DOSBase,a1         ; and close dos again
                CALLEXEC    CloseLibrary    ; yes close it now !
NoDos:          rts                         ; bye bye

*
* the actual patch which plays the sample and call's
* the original "DisplayBeep" routine !
*
INTF_AUD    equ INTF_AUD0!INTF_AUD1         ; only voice 0 and 1
DMAF_AUD    equ DMAF_AUD0!DMAF_AUD1         ; same here

patch_start:
                move.l  a5,-(sp)                ; save a5 on stack
                lea.l   _custom,a5              ; custombase in a5
                move.w  intenar(a5),-(sp)       ; stack intenar
                move.w  #DMAF_AUD,dmacon(a5)    ; audio off
                move.w  #dsize/2,aud0+ac_len(a5)  ; num of samples voice 0
                move.w  #dsize/2,aud1+ac_len(a5)  ; num of samples voice 1
                move.l  a0,-(sp)                ; stack a0 (screen arg!)
                lea.l   data(pc),a0             ; pointer to sample data
                move.l  a0,aud0+ac_ptr(a5)      ; data voice 0
                move.l  a0,aud1+ac_ptr(a5)      ; data voice 1
                move.w  #40,aud0+ac_vol(a5)     ; full volume voice 0
                move.w  #40,aud1+ac_vol(a5)     ; full volume voice 1
                move.w  #sper,aud0+ac_per(a5)   ; sample freq voice 0
                move.w  #sper,aud1+ac_per(a5)   ; sample freq voice 1
                move.w  #INTF_AUD,intena(a5)    ; disable audio interrupt
                move.w  #INTF_AUD,intreq(a5)    ;    "      "      "
                move.w  #DMAF_SETCLR!DMAF_MASTER!DMAF_AUD,dmacon(a5) ; audio on
wait:           move.w  intreqr(a5),d0          ; wait for audio interrupt
                and.w   #INTF_AUD,d0
                cmp.w   #INTF_AUD,d0
                bne     wait
                move.w  d0,intreq(a5)           ; store audio bits in intreq
                move.l  (sp)+,a0                ; pull arguments (screen !)
OldVec:         jsr $000000                     ; Intuition's flash
                lea     _custom,a5              ; pointer to custom base
wait1:          move.w  intreqr(a5),d0          ; wait for audio dma done
                and.w   #INTF_AUD,d0
                cmp.w   #INTF_AUD,d0
                bne     wait1
                move.w  d0,intreq(a5)           ; store audio bits in intreq
                move.w  #DMAF_AUD,dmacon(a5)    ; audio off
                move.w  (sp)+,d0                ; pull intenar bits
                and.w   #INTF_AUD,d0            ; filter audio bits
                or.w    #INTF_SETCLR,d0         ; INTF_SETCLR
                move.w  d0,intena(a5)           ; bits to intena
                move.l  (sp)+,a5                ; restore a5
                rts                             ; done
data:
                incbin  'Sample'                ; here you can put the name
                                                ; of another RAW sample if
                                                ; you like.

patch_end:      dc.w    0

sper    equ     240                             ; sample frequency. if it
                                                ; goes to fast or to slow
                                                ; change this.
*
* some global data's and definitions
*
dsize equ   patch_end-data

dos_name:   dc.b    'dos.library',0
            even
int_name:   dc.b    'intuition.library',0
            even
ins:        dc.b    10,'DeluxeBeep Installed !',10
            dc.b    'Everytime a program call',39,'s  intuition',39,'s',10
            dc.b    'DisplayBeep routine you will hear this.',10,10
inse:       even
inss        equ     inse-ins
rem:        dc.b    10,'DeluxeBeep Removed !',10
            dc.b    'Intuition',39,'s DisplayBeep routine',10
            dc.b    'works normal again (sigh).',10,10
reme:       even
rems        equ     reme-rem
_IntuitionBase: dc.l    0
_DOSBase:       dc.l    0
Func:   dc.l    0
