;
; 8Player
; Example Program: Plays an 8-Channel-Song.
;
; THIS PROGRAM IS BASED ON THE "8-Channel-Player.a"
;
; REQUIRED FILEs:
;    .sdata
;    .i or .ip, where the LIB-DISK-Mode is NOT supported.
;

 SECTION Pseudo,CODE

; PLAYER ROUTINES
  xref _generalsndinit,_generalsndreset,_soundon,_soundoff,_decrunchinstrs
  xref _setvolume,_maketables,_setmixbuffers,_obtainmixbuflen
  xref _setalertreaction

; FLAGS
  xref _fadeflag,_fadefinished,_channelsfinished

; THE INTERRUPT PROGRAM
  xref _generalplay

INSTNUM equ 26 ; Don't change !!!

; CODE START ---------------------------------------

start:
 bra.s realstart
 dc.b '$VER: MM_V8-8Player V1.787 (25 Aug 1991)',$0d,$0a
realstart:
 lea.l argvBuffer,a2          ; CLI - Parameters
 lea.l argvArray,a3
 moveq.l #0,d2
3$: move.b (a0)+,d1
    subq.l #1,d0
    bls.s parmExit
    cmpi.b #' ',d1
     bls.s 3$
    addq.l #1,d2
    move.l a2,(a3)+
    bra.s 5$
4$: move.b (a0)+,d1
    subq.l #1,d0
    cmpi.b #' ',d1
     bls.s 6$
5$: move.b d1,(a2)+
    bra.s 4$
6$: clr.b (a2)+
    bra.s 3$
parmExit:
 clr.b (a2)+
 clr.l (a3)+
 move.l d2,argc

 lea.l start-4(PC),a0
 clr.l (a0)
 move.l $4,a6
 lea.l dosname,a1
 jsr -408(a6)
 move.l d0,a6
 move.l #procname,d1
 moveq.l #0,d2
 move.l #procstart-4,d3
 lsr.l #2,d3
 move.l #4096,d4
 jsr -138(a6)              ; Create 8Player-Process, and
 moveq.l #0,d0             ; RETURN to CLI !
 rts

 SECTION 8Player,CODE

procstart:
 move.l 4,a6               ; my openlib stuff
 lea.l dosname(PC),a1      ; for
 jsr -408(a6)
 move.l d0,dosbase         ;    dos.library
 lea.l intname(PC),a1
 jsr -408(a6)
 move.l d0,intbase         ;    intuition.library

 moveq.l #1,d0
 cmp.l argc(PC),d0
 beq.s ok_inp1
  bsr FLASH
  bra EXIT
ok_inp1:                ; but we're right here now: parameters are correct
 move.l argvArray,a0
 lea.l macrosfile,a1    ; create <FILE>.sdata and <FILE>.i
 lea.l instrsfile,a2
namecopyloop:
  move.b (a0),(a1)+
  move.b (a0)+,(a2)+
 bne.s namecopyloop
 move.b #'.',-1(a1)
 move.b #'s',(a1)+
 move.b #'d',(a1)+
 move.b #'a',(a1)+
 move.b #'t',(a1)+
 move.b #'a',(a1)+
 clr.b (a1)
 move.b #'.',-1(a2)
 move.b #'i',(a2)+
 clr.b (a2)
 move.l a2,ifilenameendptr

 move.l dosbase(PC),a6     ; "LVOexamine" files to find filelength
 move.l #macrosfile,d1
 bsr examinefile
 move.l d0,macroslength
 bmi fileopenerror
 sf packedflag
 move.l #instrsfile,d1
 bsr examinefile
 move.l d0,instrslength    ; if no ".i"-file, then try ".ip"
 bpl.s ifileavailable
  move.l ifilenameendptr(PC),a0
  move.b #'p',(a0)+        ; append "p"
  clr.b (a0)
  move.l #instrsfile,d1
  bsr examinefile
  move.l d0,instrslength
  bmi fileopenerror
  st packedflag
ifileavailable:

 move.l $4,a6
 move.l instrslength(PC),d0
 move.l #$10001,d1
 jsr -198(a6)          ; allocmem for instrs (.i-File)
 move.l d0,instrdata
 beq error1

 move.l macroslength(PC),d0
 move.l #$10001,d1
 jsr -198(a6)          ; allocmem for melody (.sdata-file)
 move.l d0,macrosdata
 beq error2

 move.l dosbase(PC),a6
 move.l #instrsfile,d1      ; LOAD INSTRUMENTS
 move.l #1005,d2
 jsr -30(a6)
 move.l d0,d7
 beq fileerror1
 move.l d0,d1
 move.l instrdata(PC),d2
 move.l instrslength(PC),d3
 jsr -42(a6)
 move.l d7,d1
 jsr -36(a6)
 tst.b packedflag
 bne.s nolib1
  move.l instrdata(PC),a0     ; check if LIB-DISK mode.
  moveq.l #-1,d0              ;
  cmp.l (a0)+,d0              ;
  bne.s nolib1                ;
  cmp.l (a0),d0               ;
  beq fileerror1              ;
nolib1:                       ;

 move.l #macrosfile,d1    ; LOAD MACROS&MELODY (.sdata)
 move.l #1005,d2
 jsr -30(a6)
 move.l d0,d7
 beq fileerror1
 move.l d0,d1
 move.l macrosdata(PC),d2
 move.l macroslength(PC),d3
 jsr -42(a6)
 move.l d7,d1
 jsr -36(a6)
 move.l macrosdata(PC),a0    ; check if 8-Channel-song
 cmpi.w #'SE',(a0)           ;
 bne testiffileOK1           ;
  adda.w #22,a0              ;
testiffileOK1:               ;
 cmpi.b #$ff,(a0)            ;
 bne fileerror1              ;

; ==== START OF SOUND-INITIALIZATION: =========================

 tst.b packedflag
 beq isNOTpacked
; THE FOLLOWING ROUTINE CALCULATES THE MEMORY-REQUIREMENT FOR THE
; INSTRUMENTS FROM A ".ip"-File.
   moveq.l #INSTNUM,d1  ; instinfo: INSTNUM*8  Bytes
   lsl.w #3,d1
   move.l d1,d3
   addq.l #4,d1         ; defsnd
   move.l instrdata(PC),a0
   move.w 26*8(a0),d7
   moveq.l #INSTNUM-1,d0
calcinstlens:
      moveq.l #0,d2
      move.w (a0),d2    ; add the instrslen.
      beq.s 3$
       add.l d2,d1
       mulu d7,d2
       addq.l #8,d2
       lsr.l #3,d2
       add.l d2,d3
3$:
      addq.l #8,a0
  dbra d0,calcinstlens
  addq.l #2,d3        ; fibbits:  WORD
  moveq.l #1,d0       ; fibtable: 1<<fibbits
  move.w (a0)+,d2
  lsl.l d2,d0
  add.l d0,d3
  move.l instrdata(PC),a0
  lea.l 0(a0,d3.l),a0
  addi.l #15*2,d1
  moveq.l #15-1,d0
addtheLFOs:
      moveq.l #0,d2
      move.b (a0)+,d2
      lsl.w #8,d2
      move.b (a0)+,d2
      add.l d2,d1
  dbra d0,addtheLFOs
; for security, add 8 another bytes.
  addq.l #8,d1
  move.l instrslength(PC),realinstrslen
  move.l d1,instrslength
  move.l $4,a6
  move.l d1,d0
  move.l #$10001,d1
  jsr -198(a6)
  tst.l d0
  beq fileerror1
  move.l instrdata(PC),realinstrdata
  move.l d0,instrdata
  move.l realinstrdata(PC),a0
  move.l d0,a1
  jsr _decrunchinstrs
isNOTpacked:

 move.l macrosdata(PC),a0
 jsr _obtainmixbuflen   ; find mixbufferlength for this song
 move.l d0,mixbuflen    ; (depends on speed and hitable)

 move.l $4,a6
 move.l mixbuflen(PC),d0
 lsl.l #3,d0            ; 8 buffers required
 move.l #$10003,d1
 jsr -198(a6)           ; allocmem for MIXBUFFERS
 move.l d0,mixbufferstart
 beq mixbuffermemerror

 moveq.l #0,d0         ; STOP if mixing takes more time than allowed
 jsr _setalertreaction ; analogy to "Mix-Player Emergency"-Flag !

; NOW HAVE SOME MIXBUFFERS:
 move.l mixbufferstart(PC),a0
 move.l mixbuflen(PC),d0
 moveq.l #8-1,d1     ; example for setting up a verctor field as needed
mixfieldbuildloop:   ; for "_setmixbuffers"
  move.l a0,-(a7)
  adda.w d0,a0
 dbra d1,mixfieldbuildloop
 move.l a7,a0
 jsr _setmixbuffers
 lea.l 8*4(a7),a7

; WELL, HOW 'BOUT SOME TABLES (REQUIRED BY MULTI-CHANNEL-PLAYER)
; NEED NOT BE PLACED IN CHIP-MEM
 move.l 4,a6
 move.l #256+(64*2)+(65*32*2)+(64*256),d0
 move.l #$10001,d1
 jsr -198(a6)           ; allocmem for table
 move.l d0,tablemem
 beq tablememerror

 move.l d0,a0
;              free space of 256+(64*2)+(65*32*2)+(d0*d1) bytes
 moveq.l #64,d0  ; -specifies volume resolution.      /\__________
 moveq.l #-1,d1  ; -in this case: table unpacked:    /            \
 jsr _maketables ;  memory requirement is: packed 128,  unpacked 256

; ----------   INTERLUDE: Open out window
 move.l intbase(PC),a6
 lea.l mywindow(PC),a0
 jsr -204(a6)
 move.l d0,window
  beq cantopenwindow
 move.l d0,a0
 move.l 86(a0),userport
; ----------

; EXAMPLE for calling FINAL sound initialization
  moveq.l #0,d0            ; play 0=loop, <>0=oneshot
  move.l instrdata(PC),a1
  move.l macrosdata(PC),a2
  suba.l a3,a3
  jsr _generalsndinit

; THIS SETS UP MY OWN LEVEL 4 INTERRUPT HANDLER
; EVEN THOUGH THIS IS A NON-SYSTEM-VERSION, leave system alive ... !
  move.w #$0780,$dff09a
  move.l $70,oldint4
  move.l #_generalplay,$70
  move.w #$0780,$dff09c

; SWITCHING sound ON
  jsr _soundon

; === NOW DO ANYTHING YOU WANT
; (we wait for a window-message)
nogoodmsg:                  ; The intuition-message stuff
  move.l $4,a6
  move.l userport(PC),a0
  jsr -384(a6)
  move.l userport(PC),a0
  jsr -372(a6)
  move.l d0,a1
  move.l 20(a1),d2
  jsr -378(a6)
  move.l d2,d3
  andi.l #$00000200,d2      ; close-gadget ???  -> QUIT
   bne.s endofplay
  andi.l #$00000040,d3      ; gadgup ??? -> Volume Button !
   bne.s recalcvolume
 bra.s nogoodmsg

recalcvolume:               ; user set a new volume !
 lea.l prop1(PC),a0
 moveq.l #0,d0
 move.w 2(a0),d0
 divu 6(a0),d0
 jsr _setvolume         ; Sets general volume - thats the right thing !
 bra.s nogoodmsg        ; and back to WaitPort-Loop

endofplay:                  ; end of program
; FADE SOUND OUT after closing-gadget has been activated
 move.b #110,_fadeflag   ; fadespeed 50(=very fast) - 120 (slow)

; WAIT FOR FADE TO FINISH
waitforfade:
   tst.b _fadefinished
 beq.s waitforfade

; SWITCHING SOUND OFF IMMEDIATLY
 jsr _soundoff

; SWITCHING LOW PASS FILTER TO ORIG STATE
 bclr.b #1,$bfe001

; IF YOU WANT YOUR SOUND START AGAIN
; DO THE FOLLOWING:
; moveq.l #0,d0  OR  moveq.l #1,d0   FOR LOOP/ONESHOT
; jsr _generalsndreset
; jsr _soundon

; IF YOU WANT TO PLAY ANOTHER SOUND, YOU MUST CALL
; jsr _generalsndinit  INSTEAD OF _generalsndreset
; WITH THE REGISTERS SET AS FAR ABOVE.

; THIS IS MY EXIT-STUFF    ; ---------------------------------------
 move.l oldint4(PC),$70

 bsr closewindow
 tst.b packedflag
 beq.s 1$
   bsr freepackmem
1$:
 bsr freetable
 bsr freemixbuffers
 bsr freememmelody
 bsr freememinstrs
EXIT:
 move.l $4,a6
 jsr -132(a6)              ; FORBID
 move.l dosbase(PC),a6
 move.l #procstart-4,d1
 lsr.l #2,d1
 jsr -156(a6)              ; UnLoad our Segment
 moveq.l #0,d0
 rts                       ; AND: So far - So long - See ya ...

cantopenwindow:
 bsr freetable
tablememerror:
 bsr freemixbuffers
mixbuffermemerror:
 tst.b packedflag
 beq.s fileerror1
   bsr freepackmem
fileerror1:
 bsr FLASH
 bsr freememmelody
error2:
 bsr freememinstrs
error1:
 bra EXIT

freepackmem:
 move.l 4,a6
 move.l realinstrslen(PC),d0
 move.l realinstrdata(PC),a1
 jmp -210(a6)

freememinstrs:
 move.l 4,a6
 move.l instrslength(PC),d0
 move.l instrdata(PC),a1
 jmp -210(a6)

freememmelody:
 move.l 4,a6
 move.l macroslength(PC),d0
 move.l macrosdata(PC),a1
 jmp -210(a6)

freetable:
 move.l 4,a6
 move.l #(64*2)+(65*32*2)+(64*256),d0
 move.l tablemem(PC),a1
 jmp -210(a6)

freemixbuffers:
 move.l 4,a6
 move.l mixbuflen(PC),d0
 lsl.l #3,d0
 move.l mixbufferstart(PC),a1
 jmp -210(a6)

closewindow:
 move.l intbase(PC),a6     ; Finish up with my window
 move.l window(PC),a0
 jmp -72(a6)

examinefile:
 moveq.l #-2,d2
 jsr -84(a6)
 move.l d0,d7
 beq.s filenotfound
 move.l d0,d1
 move.l #fileinfo,d2
 jsr -102(a6)
 move.l d7,d1
 jsr -90(a6)
 move.l fileinfo+124,d0
 rts
filenotfound:
 moveq.l #-1,d0
 rts

fileopenerror:
 bsr.s FLASH
 bra EXIT

FLASH:
 suba.l a0,a0
 move.l intbase(PC),a6
 jmp -96(a6)

; ---------------
; MYPRIVATEROUTINE, called, when "$" is in a macro.
; gets pointer to itself in a0, and called-count.w in d0
; SHOULD NOT TAKE THAT LONG (called from a VERY time critical level4 int!!!)
myprivateroutine:
 move.w #$0f00,$dff180
 rts ; always ends up by this !

; ---------------

oldint4:        dc.l 0
instrslength:   dc.l 0
realinstrslen:  dc.l 0
macroslength:   dc.l 0
instrdata:      dc.l 0
realinstrdata:  dc.l 0
macrosdata:     dc.l 0
mixbufferstart: dc.l 0
tablemem:       dc.l 0
mixbuflen:      dc.l 0
ifilenameendptr: dc.l 0
packedflag:     dc.b 0
 cnop 0,2
dosbase:        dc.l 0
intbase:        dc.l 0
argc:           dc.l 0

dosname:        dc.b 'dos.library',0
intname:        dc.b 'intuition.library',0
 cnop 0,2

window:    dc.l 0
userport:  dc.l 0
mywindow:
 dc.w 387,0,200,21,$0201
 dc.l $00000240,$0003000e,firstgadget,0,mytitle,0,0
 dc.w 0,0,0,0,$0001
 cnop 0,4
procname: 
mytitle: dc.b '8Player',0
 cnop 0,2
firstgadget:
 dc.l 0
 dc.w (8*7)+8,12,132,$0006,$0003,$0001,$0003
 dc.l gadgetrender1,0,text1,0,prop1
 dc.w $0001,0,0
prop1:
 dc.w $0013,$ffff,0,$0204,0,0,0,0,0,0,0,$0204,0,0
gadgetrender1:
 dc.w -2,-1,$0300,$0005
 dc.l xytable,0
xytable:
 dc.l $00000000,$00a700a7,$00070007,$00000007,$00000000
 cnop 0,2
text1:
 dc.w $0100,$0100,-((8*7)+4),-1,0,0
 dc.l text11,0
text11: dc.b 'Volume:'
 cnop 0,4


 SECTION mybss,BSS

fileinfo:       ds.b 290
macrosfile:     ds.b 60
instrsfile:     ds.b 60
argvArray:      ds.l 10
argvBuffer:     ds.b 128

 END

