home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / audio / NotePlayer.lha / notesys.asm < prev    next >
Assembly Source File  |  1992-05-10  |  21KB  |  690 lines

  1. * notesys.asm - NotePlayer module for Amiga using system (audio.device)
  2. * Copyright 1992 Bryan Ford
  3. * See distribution terms in NotePlayer.doc
  4. * $Id: notesys.asm,v 1.3 92/05/10 14:10:01 BAF Exp $
  5.  
  6.         include "exec/types.i"
  7.         include "exec/io.i"
  8.         include "exec/tasks.i"
  9.         include "exec/funcdef.i"
  10.         include "exec/exec_lib.i"
  11.         include "devices/audio.i"
  12.         include "bry/macros.i"
  13.  
  14. VERSION         equ     1       ; Version of Player.doc this NotePlayer is written for
  15. REVISION        equ     0
  16.  
  17. IOREQS          equ     3*4+2   ; Two WRITEs and another command per channel, plus two extra for good measure
  18.  
  19. STACKSIZE       equ     256
  20.  
  21. CLOCK           equ     3579545
  22.  
  23.         code    text
  24.  
  25. *** NoteSys - Jump table providing standard note player interface
  26.         xdef    NoteSys,_NoteSys
  27. NoteSys
  28. _NoteSys
  29.         jmp     noteinfo(pc)
  30.         jmp     noteinit(pc)
  31.         jmp     notefinish(pc)
  32.         jmp     notestart(pc)
  33.         jmp     notestop(pc)
  34.         jmp     notefreqvol(pc)
  35.         jmp     notefreq(pc)
  36.         jmp     notevol(pc)
  37.  
  38. *** NoteSysMasterVol - Set the (mono) master volume at which to play notes
  39. * d0 = New master volume, 0-$100
  40.         xdef    NoteSysMasterVol,_NoteSysMasterVol,@NoteSysMasterVol
  41. _NoteSysMasterVol
  42.         move.w  4+2(sp),d0
  43. NoteSysMasterVol
  44. @NoteSysMasterVol
  45.         move.w  d0,d1
  46.         bra     NoteSysMasterVolBal
  47.  
  48. *** NoteSysMasterVolBal - Set the master volume/balance
  49. * d0 = New master volume for left channels, 0-$100
  50. * d1 = New master volume for right channels, 0-$100
  51.         xdef    NoteSysMasterVolBal,_NoteSysMasterVolBal,@NoteSysMasterVolBal
  52. _NoteSysMasterVolBal
  53.         movem.l 4(sp),d0/d1
  54. NoteSysMasterVolBal
  55. @NoteSysMasterVolBal
  56.         movem.l d2/d6-d7/a4/a6,-(sp)
  57.         lea     k,a4
  58.  
  59.         st.b    volinitflag-k(a4)
  60.  
  61.         lsr.w   #2,d0
  62.         lsr.w   #2,d1
  63.  
  64.         cmp.b   mastervoltab+1-1-k(a4),d0
  65.         bne     \changed
  66.         cmp.b   mastervoltab+2-1-k(a4),d1
  67.         beq     \out
  68. \changed
  69.         move.b  d0,mastervoltab-1+1-k(a4)
  70.         move.b  d1,mastervoltab-1+2-k(a4)
  71.         move.b  d1,mastervoltab-1+4-k(a4)
  72.         move.b  d0,mastervoltab-1+8-k(a4)
  73.  
  74.         move.b  channels-k(a4),d2
  75.         subq.b  #1,d2
  76. \loop
  77.         bsr     findquickreq
  78.         bz      \next
  79.         move.w  chanpervol-k(a4,d6.w),ioa_Period(a1)
  80.         move.w  IO_UNIT+2(a1),d1
  81.         moveq   #0,d0
  82.         move.b  mastervoltab-1-k(a4,d1.w),d0
  83.         mulu.w  chanpervol+2-k(a4,d6.w),d0
  84.         move.w  d0,-(sp)
  85.         move.b  (sp)+,ioa_Volume+1(a1)
  86.         moveq   #ADCMD_PERVOL,d0
  87.         bsr     doquickreq
  88. \next
  89.         dbra    d2,\loop
  90. \out
  91.         movem.l (sp)+,d2/d6-d7/a4/a6
  92.         rts
  93.  
  94. *** noteinfo - Return information about this note player
  95. noteinfo
  96.         lea     \noteinfo(pc),a0
  97.         move.l  a0,d0
  98.         rts
  99.  
  100. \noteinfo
  101.         dc.b    VERSION
  102.         dc.b    REVISION
  103.         dc.b    3 ; NOTEF_CHIPSAMPLES!NOTEF_PERIOD
  104.         dc.b    4
  105.         dc.l    \noteplayername
  106. \noteinfoend
  107.  
  108. \noteplayername         dc.b    "Amiga audio.device NotePlayer",0
  109.         even
  110.  
  111. *** noteinit - Initialize the note player
  112. * d0.b = Number of channels needed (1-128)
  113. * a0 = Preferred stereo orientation for each channel (NULL = Amiga default)
  114. * Returns: d0 = Zero if successful, pointer to error message on failure
  115. noteinit
  116.         movem.l d2/a2/a4/a6,-(sp)
  117.         move.l  4,a6
  118.         lea     k,a4
  119.  
  120.         cmp.b   #4,d0                           ; Number of channels requested
  121.         bhi     \toomanychannels
  122.         move.b  d0,channels-k(a4)
  123.  
  124.         lea     chanpos-k(a4),a1                ; Copy channel position preference array
  125.         clr.l   (a1)
  126.         move.l  a0,d1
  127.         bz      \defchanprefs
  128. \chanprefsloop
  129.         move.b  (a0)+,(a1)+
  130.         subq.b  #1,d0
  131.         bhi     \chanprefsloop
  132. \defchanprefs
  133.  
  134.         bsr     notefinish                      ; Stop anything we were doing before
  135.  
  136.         bset.b  #0,volinitflag-k(a4)            ; Make sure master volume is initialized
  137.         bnz     \masvolinit
  138.         moveq   #$40,d0
  139.         move.b  d0,mastervoltab-1+1-k(a4)
  140.         move.b  d0,mastervoltab-1+2-k(a4)
  141.         move.b  d0,mastervoltab-1+4-k(a4)
  142.         move.b  d0,mastervoltab-1+8-k(a4)
  143. \masvolinit
  144.  
  145.         lea     sitport-k+MP_MSGLIST(a4),a1     ; Initialize sitport
  146.         NEWLIST a1
  147.         move.b  #NT_MSGPORT,sitport-k+LN_TYPE(a4)
  148.         move.b  #PA_IGNORE,sitport-k+MP_FLAGS(a4)
  149.  
  150.         lea     taskport-k+MP_MSGLIST(a4),a1    ; Initialize taskport
  151.         NEWLIST a1
  152.         move.b  #NT_MSGPORT,taskport-k+LN_TYPE(a4)
  153.         move.b  #PA_IGNORE,taskport-k+MP_FLAGS(a4)      ; The task will change this right away
  154.  
  155.         lea     sitport-k(a4),a0                ; Initialize the first IO request
  156.         move.l  a0,ioreqs+MN_REPLYPORT-k(a4)
  157.         clr.l   ioreqs+ioa_Length-k(a4)         ; Don't allocate channels on opening the device
  158.  
  159.         lea     \audiodevname(pc),a0            ; Open audio.device
  160.         moveq   #0,d0
  161.         lea     ioreqs-k(a4),a1
  162.         moveq   #0,d1
  163.         jsr     _LVOOpenDevice(a6)
  164.         tst.b   d0
  165.         bne     \openfail
  166.  
  167.         move.w  #(IOREQS-1)*ioa_SIZEOF/4-1,d0   ; Replicate the IO request
  168.         lea     ioreqs-k(a4),a0
  169.         lea     ioa_SIZEOF(a0),a1
  170.         move.b  #NT_REPLYMSG,LN_TYPE(a0)
  171. \rep
  172.         move.l  (a0)+,(a1)+
  173.         dbra    d0,\rep
  174.  
  175.         moveq   #IOREQS-1,d2                    ; Collect all requests on the sitport
  176.         lea     ioreqs-k(a4),a2
  177. \collect
  178.         move.l  a2,a1
  179.         jsr     _LVOReplyMsg(a6)
  180.         lea     ioa_SIZEOF(a2),a2
  181.         dbra    d2,\collect
  182.  
  183.         move.w  #(NT_TASK<<8)!(100),tc-k+LN_TYPE(a4)    ; Initialize task
  184.         move.l  #\notetaskname,tc-k+LN_NAME(a4)
  185.         move.l  #stack,tc-k+TC_SPLOWER(a4)
  186.         lea     stack+STACKSIZE-k(a4),a0
  187.         move.l  a0,tc-k+TC_SPUPPER(a4)
  188.         move.l  a0,tc-k+TC_SPREG(a4)
  189.         lea     tc-k+TC_MEMENTRY(a4),a0
  190.         NEWLIST a0
  191.  
  192.         lea     tc-k(a4),a1                     ; Start the task
  193.         lea     notetask(pc),a2
  194.         jsr     _LVOAddTask(a6)
  195.         tst.l   d0
  196.         bnz     \taskok
  197.         cmp.w   #36,LIB_VERSION(a6)
  198.         bhs     \addtaskfail
  199. \taskok
  200.         st.b    taskadded-k(a4)
  201.  
  202.         move.b  channels-k(a4),d2               ; Try to allocate the channels we need now
  203.         subq.b  #1,d2
  204.         clr.l   chanallocflags-k(a4)
  205. \allocloop
  206.         bsr     notestop
  207.         subq.b  #1,d2
  208.         bhs     \allocloop
  209.  
  210.         moveq   #0,d0
  211. \out
  212.         movem.l (sp)+,d2/a2/a4/a6
  213.         rts
  214.  
  215. \openfail
  216.         clr.l   ioreqs+IO_DEVICE-k(a4)
  217.         pea     \openfailmes(pc)
  218.         bra     \errerr
  219. \addtaskfail
  220.         pea     \addtaskfailmes(pc)
  221.         bra     \errerr
  222. \toomanychannels
  223.         pea     \toomanychannelsmes(pc)
  224. \errerr
  225.         bsr     notefinish
  226.         move.l  (sp)+,d0
  227.         bra     \out
  228.  
  229. \audiodevname           dc.b    "audio.device",0
  230.  
  231. \notetaskname           dc.b    "NotePlayer",0
  232.  
  233. \toomanychannelsmes     dc.b    "Too many channels requested",0
  234. \addtaskfailmes         dc.b    "Unable to create NotePlayer task",0
  235. \openfailmes            dc.b    "Unable to open audio.device",0
  236.  
  237.         even
  238.  
  239. *** notefinish - Shut down the note player, free audio hardware
  240. notefinish
  241.         movem.l d2/a2/a4/a6,-(sp)
  242.         lea     k,a4
  243.         move.l  4,a6
  244.  
  245.         jsr     _LVOForbid(a6)                  ; Maybe not necessary, but just in case...
  246.  
  247.         sub.l   a1,a1                           ; Point both ports to this task for closing down
  248.         jsr     _LVOFindTask(a6)
  249.         move.l  d0,sitport+MP_SIGTASK-k(a4)
  250.         move.w  #(PA_SIGNAL<<8)!(SIGB_SINGLE),sitport+MP_FLAGS-k(a4)
  251.         move.l  d0,taskport+MP_SIGTASK-k(a4)
  252.         move.w  #(PA_SIGNAL<<8)!(SIGB_SINGLE),taskport+MP_FLAGS-k(a4)
  253.  
  254.         tst.b   taskadded-k(a4)                 ; Get rid of the task
  255.         bz      \notask
  256.         lea     tc-k(a4),a1
  257.         jsr     _LVORemTask(a6)
  258.         clr.b   taskadded-k(a4)
  259. \notask
  260.  
  261.         jsr     _LVOPermit(a6)
  262.  
  263.         tst.l   ioreqs+IO_DEVICE-k(a4)
  264.         bz      \audioclosed
  265.  
  266.         moveq   #4-1,d2                         ; Free all audio channels
  267. \freechans
  268.         lea     ioreqs-k(a4),a1
  269.         move.w  #ADCMD_FREE,IO_COMMAND(a1)
  270.         move.b  chanmasks-k(a4,d2),IO_UNIT+3(a1)
  271.         jsr     _LVODoIO(a6)
  272.         dbra    d2,\freechans
  273. \alreadyfree
  274.         clr.l   chanmasks-k(a4)
  275.  
  276.         moveq   #IOREQS-1,d2                    ; Abort any IO requests still in progress
  277.         lea     ioreqs-k(a4),a2
  278. \abortreqs
  279.         move.l  a2,a1
  280.         jsr     _LVOAbortIO(a6)
  281.         move.l  a2,a1
  282.         jsr     _LVOWaitIO(a6)
  283.         lea     ioa_SIZEOF(a2),a2
  284.         dbra    d2,\abortreqs
  285.  
  286.         lea     ioreqs-k(a4),a1                 ; Close the audio.device
  287.         jsr     _LVOCloseDevice(a6)
  288.         clr.l   ioreqs+IO_DEVICE-k(a4)
  289. \audioclosed
  290.  
  291.         movem.l (sp)+,d2/a2/a4/a6
  292.         rts
  293.  
  294. *** findquickreq - Find an available IOAudio and prepare it for quick I/O
  295. * d2.b = Channel number (NOT.B to set ADIOF_SYNCCYCLE)
  296. * a4 = k
  297. * Returns:
  298. * NZ if successful, a1 = Ready IOAudio (still on sitport)
  299. * Z if failed, d0 = 0
  300. * d2.w = Real channel number
  301. * d6.w = Channel number * 4
  302. * d7.b = Flags for IORequest
  303. findquickreq
  304.         move.l  sitport+MP_MSGLIST+LH_HEAD,a1   ; Find any available request
  305.         move.l  LN_SUCC(a1),d0                  ; (Don't even need to Disable around this)
  306.         bz      \out
  307.  
  308.         moveq   #IOF_QUICK,d7                   ; Find channel and flags
  309.         ext.w   d2
  310.         bpl     \nosync
  311.         moveq   #IOF_QUICK!ADIOF_SYNCCYCLE,d7
  312.         not.w   d2
  313. \nosync
  314.  
  315.         move.b  chanmasks-k(a4,d2.w),IO_UNIT+3(a1)
  316.         bz      \nochan
  317.  
  318.         move.w  d2,d6
  319.         lsl.w   #2,d6
  320.  
  321.         move.b  d7,IO_FLAGS(a1)
  322. \out
  323.         rts
  324.  
  325. \nochan
  326.         bsr     allocbounce
  327.         moveq   #0,d0
  328.         rts
  329.  
  330. *** findreq - Find an available IOAudio and prepare it for slow I/O
  331. * d2.w = Real channel number
  332. * d7.b = Flags for IORequest
  333. * a4 = k
  334. * Returns:
  335. * NZ if successful, a1 = Ready IOAudio (removed from sitport), a6 = IO_DEVICE from IO request
  336. * Z if failed, d0 = 0
  337. findreq
  338.         move.l  4,a6                            ; Remove an IO request
  339.         lea     sitport,a0
  340.         jsr     _LVOGetMsg(a6)
  341.         tst.l   d0
  342.         bz      \out
  343.         move.l  d0,a1
  344.  
  345.         move.b  chanmasks-k(a4,d2.w),IO_UNIT+3(a1)
  346.  
  347.         move.l  IO_DEVICE(a1),a6                ; Find audio.device address
  348.  
  349.         moveq   #1,d0
  350. \out
  351.         rts
  352.  
  353. *** notestop - Stop any currently playing note in a channel
  354. * May be called from interrupt code level 4 or lower
  355. * d2.b = Channel number (NOT.B to stop only after the current cycle completes)
  356. notestop
  357.         moveq   #0,d0
  358.         moveq   #0,d1
  359.         ; fall through...
  360. *** notestart - Start playing a note immediately
  361. * May be called from interrupt code level 4 or lower
  362. * d2.b = Channel number (NOT.B to make the change only after the current cycle completes)
  363. * a0 = One-shot sample data
  364. * d0.l = One-shot sample length (0 if no one-shot part)
  365. * a1 = Repeat sample data
  366. * d1.l = Repeat sample length (0 if no repeat part)
  367. * d3.w = Sample frequency (if 0, then high word contains period)
  368. * d4.w = Volume at which to play sample (0-$100)
  369. notestart
  370.         movem.l d0-d2/d6-d7/a0-a2/a4/a6,-(sp)
  371.         lea     k,a4
  372.  
  373.         tst.b   d2                              ; Stop current note
  374.         bpl     \stopnow
  375. \stopcycle                                      ; Stop at the end of this cycle
  376.         bsr     findquickreq
  377.         bz      \out
  378.         move.l  chanoneshot-k(a4,d6.w),d0       ; Cancel the repeat part if we haven't gotten to it yet
  379.         bz      \canrepout
  380.         move.l  d0,a0
  381.         cmp.b   #NT_MESSAGE,LN_TYPE(a0)
  382.         bne     \canrepout
  383.         move.l  chanrepeat-k(a4,d6.w),d0
  384.         bz      \canrepout
  385.         move.b  IO_UNIT+3(a1),d1
  386.         move.l  a1,-(sp)
  387.         move.l  d0,a1
  388.         cmp.b   IO_UNIT+3(a1),d1
  389.         bne     \canrepout2
  390.         move.l  IO_DEVICE(a1),a6
  391.         jsr     DEV_ABORTIO(a6)
  392. \canrepout2
  393.         move.l  (sp)+,a1
  394. \canrepout
  395.         moveq   #ADCMD_FINISH,d0
  396.         bsr     doquickreq
  397.         bz      \stopout
  398.         bra     \out
  399. \stopnow                                        ; Stop immediately
  400.         bsr     findquickreq
  401.         bz      \out
  402.         moveq   #CMD_FLUSH,d0
  403.         bsr     doquickreq
  404.         bnz     \out
  405. \stopout
  406.  
  407.         sub.l   a2,a2                           ; One-shot part
  408.         tst.l   (sp)
  409.         bz      \nooneshot
  410.         bsr     findreq
  411.         bz      \out
  412.         move.w  #CMD_WRITE,IO_COMMAND(a1)
  413.         move.l  20(sp),ioa_Data(a1)
  414.         move.l  (sp),ioa_Length(a1)
  415.         move.w  #1,ioa_Cycles(a1)
  416.         move.b  #ADIOF_PERVOL,IO_FLAGS(a1)
  417.         move.l  a1,a2
  418.         bsr     calcper
  419.         bsr     calcvol
  420.         jsr     DEV_BEGINIO(a6)
  421. \nooneshot
  422.         move.l  a2,chanoneshot-k(a4,d6.w)
  423.  
  424.         sub.l   a2,a2                           ; Repeat part
  425.         tst.l   4(sp)
  426.         bz      \norepeat
  427.         bsr     findreq
  428.         bz      \out
  429.         move.w  #CMD_WRITE,IO_COMMAND(a1)
  430.         move.l  24(sp),ioa_Data(a1)
  431.         move.l  4(sp),ioa_Length(a1)
  432.         moveq   #0,d7
  433.         move.w  d7,ioa_Cycles(a1)
  434.         tst.l   (sp)
  435.         bnz     \pervolalreadyset
  436.         moveq   #ADIOF_PERVOL,d7
  437.         bsr     calcper
  438.         bsr     calcvol
  439.         move.w  d0,ioa_Volume(a1)
  440. \pervolalreadyset
  441.         move.b  d7,IO_FLAGS(a1)
  442.         move.l  a1,a2
  443.         jsr     DEV_BEGINIO(a6)
  444. \norepeat
  445.         move.l  a2,chanrepeat-k(a4,d6.w)
  446.  
  447. \out
  448.         movem.l (sp)+,d0-d2/d6-d7/a0-a2/a4/a6
  449.         rts
  450.  
  451. *** calcper - Calculate period and insert it in an IOAudio
  452. * d3.l = Frequency/period value
  453. * d6.w = Channel * 4
  454. * a1 = IOAudio to put period into
  455. * a4 = k
  456. calcper
  457.         tst.w   d3
  458.         bnz     \freq
  459.         swap    d3
  460.         move.w  d3,ioa_Period(a1)
  461.         move.w  d3,chanpervol-k(a4,d6.w)
  462.         swap    d3
  463.         rts
  464. \freq
  465.         move.l  #CLOCK,d0
  466.         divu.w  d3,d0
  467.         move.w  d0,ioa_Period(a1)
  468.         move.w  d0,chanpervol-k(a4,d6.w)
  469.         rts
  470.  
  471. *** calcvol - Calculate volume and insert it in an IOAudio
  472. * d4.w = Volume (0-$100)
  473. * d6.w = Channel * 4
  474. * a1 = IOAudio to put period into
  475. * a4 = k
  476. calcvol
  477.         move.w  d4,chanpervol+2-k(a4,d6.w)
  478.         move.w  IO_UNIT+2(a1),d1
  479.         moveq   #0,d0
  480.         move.b  mastervoltab-1-k(a4,d1.w),d0
  481.         mulu.w  d4,d0
  482.         move.w  d0,-(sp)
  483.         move.b  (sp)+,ioa_Volume+1(a1)
  484.         rts
  485.  
  486. *** notefreqvol - Change the frequency and volume of the currently playing note
  487. * May be called from interrupt code level 4 or lower
  488. * d2.b = Channel number (NOT.B to make the change only after the current cycle completes)
  489. * d3.w = New sample frequency (if 0, then high word contains period)
  490. * d4.w = New volume (0-$100)
  491. notefreqvol
  492.         movem.l d2/d6-d7/a4/a6,-(sp)
  493.         lea     k,a4
  494.  
  495.         bsr     findquickreq
  496.         bz      \out
  497.         bsr     calcper
  498.         bsr     calcvol
  499.         moveq   #ADCMD_PERVOL,d0
  500.         bsr     doquickreq
  501. \out
  502.         movem.l (sp)+,d2/d6-d7/a4/a6
  503.         rts
  504.  
  505. *** notefreq - Change the frequency of the currently playing note
  506. * May be called from interrupt code level 4 or lower
  507. * d2.b = Channel number (NOT.B to make the change only after the current cycle completes)
  508. * d3.w = New sample frequency (if 0, then high word contains period)
  509. notefreq
  510.         movem.l d2/d6-d7/a4/a6,-(sp)
  511.         lea     k,a4
  512.  
  513.         bsr     findquickreq
  514.         bz      \out
  515.  
  516.         bsr     calcper
  517.  
  518.         move.w  IO_UNIT+2(a1),d1
  519.         moveq   #0,d0
  520.         move.b  mastervoltab-1-k(a4,d1.w),d0
  521.         mulu.w  chanpervol+2-k(a4,d6.w),d0
  522.         move.w  d0,-(sp)
  523.         move.b  (sp)+,ioa_Volume+1(a1)
  524.  
  525.         moveq   #ADCMD_PERVOL,d0
  526.         bsr     doquickreq
  527. \out
  528.         movem.l (sp)+,d2/d6-d7/a4/a6
  529.         rts
  530.  
  531. *** notevol - Change the volume of the currently playing note
  532. * May be called from interrupt code level 4 or lower
  533. * d2.b = Channel number (NOT.B to make the change only after the current cycle completes)
  534. * d4.w = New volume (0-$100)
  535. notevol
  536.         movem.l d2/d6-d7/a4/a6,-(sp)
  537.         lea     k,a4
  538.  
  539.         bsr     findquickreq
  540.         bz      \out
  541.  
  542.         cmp.w   chanpervol+2-k(a4,d6.w),d4
  543.         beq     \out
  544.  
  545.         move.w  chanpervol-k(a4,d6.w),ioa_Period(a1)
  546.  
  547.         bsr     calcvol
  548.  
  549.         moveq   #ADCMD_PERVOL,d0
  550.         bsr     doquickreq
  551. \out
  552.         movem.l (sp)+,d2/d6-d7/a4/a6
  553.         rts
  554.  
  555. *** doquickreq - Send an immediate command to the audio.device
  556. * d0.w = IO Command
  557. * a1 = IOAudio
  558. * d2.w = Real channel number
  559. * a4 = k
  560. * Returns: Z = Successful, NZ = Audio error (generally channel stolen)
  561. doquickreq
  562.         move.w  d0,IO_COMMAND(a1)
  563.         move.l  IO_DEVICE(a1),a6
  564.         move.l  a1,-(sp)
  565.         jsr     DEV_BEGINIO(a6)
  566.         move.l  (sp)+,a1
  567.         tst.b   IO_ERROR(a1)
  568.         bnz     \err
  569.         rts
  570.  
  571. \err
  572.         bsr     allocbounce
  573.         moveq   #1,d0
  574.         rts
  575.  
  576. *** allocbounce - Bounce an IOAudio to the note player task for allocation
  577. * a1 = IOAudio (on sitport)
  578. * d2.w = Real channel number
  579. * a4 = k
  580. * Returns:
  581. * a6 = SysBase
  582. allocbounce
  583.         move.l  4,a6
  584.  
  585.         bset.b  #0,chanallocflags-k(a4,d2.w)    ; Prevent multiple allocation requests from piling up
  586.         bnz     \out
  587.  
  588.         move.l  a1,-(sp)                        ; Take the request off the sitport
  589.         jsr     _LVODisable(a6)
  590.         move.l  (sp),a1
  591.         jsr     _LVORemove(a6)
  592.         jsr     _LVOEnable(a6)
  593.         move.l  (sp)+,a1
  594.  
  595.         move.w  #ADCMD_ALLOCATE,IO_COMMAND(a1)  ; Setup request for channel allocation
  596.         move.w  d2,ioa_WriteMsg+LN_NAME(a1)     ; Hide the channel number in the message
  597.  
  598.         tst.b   chanpos-k(a4,d2.w)              ; Find the appropriate channel preference array
  599.         bz      \middle
  600.         bpl     \right
  601. \left
  602.         lea     \leftarray(pc),a0
  603.         bra     \gotarray
  604. \right
  605.         lea     \rightarray(pc),a0
  606.         bra     \gotarray
  607. \middle
  608.         lea     \middlearray(pc),a0
  609. \gotarray
  610.         move.l  a0,ioa_Data(a1)
  611.         moveq   #4,d0
  612.         move.l  d0,ioa_Length(a1)
  613.  
  614.         move.l  #taskport,MN_REPLYPORT(a1)      ; Send it off to our task
  615.         jsr     _LVOReplyMsg(a6)
  616.  
  617. \out
  618.         rts
  619.  
  620. \leftarray      dc.b    %1000,%0001,%0100,%0010
  621. \rightarray     dc.b    %0100,%0010,%1000,%0001
  622. \middlearray    dc.b    %1000,%0100,%0010,%0001
  623.  
  624. *** notetask - Entrypoint for NotePlayer task
  625. notetask
  626.         move.l  4,a6
  627.  
  628.         lea     taskport,a2                     ; Activate the taskport
  629.         move.l  #tc,MP_SIGTASK(a2)
  630.         move.w  #(PA_SIGNAL<<8)!(SIGB_SINGLE),MP_FLAGS(a2)
  631.  
  632. \loop
  633.         move.l  a2,a0                           ; Grab waiting messages
  634.         jsr     _LVOGetMsg(a6)
  635.         tst.l   d0
  636.         bz      \nomsgs
  637.         move.l  d0,a3
  638.  
  639.         move.w  ioa_WriteMsg+LN_NAME(a3),d2     ; Channel number (d2)
  640.  
  641.         move.l  a3,a1                           ; IORequest is all ready for action
  642.         jsr     _LVODoIO(a6)
  643.  
  644.         tst.b   IO_ERROR(a3)                    ; Remember the allocated channel
  645.         bnz     \allocfailed
  646.         move.b  IO_UNIT+3(a3),chanmasks-taskport(a2,d2.w)
  647. \allocfailed
  648.  
  649.         move.l  #sitport,MN_REPLYPORT(a3)       ; Back to the menagerie it goes
  650.         move.l  a3,a1
  651.         jsr     _LVOReplyMsg(a6)
  652.  
  653.         clr.b   chanallocflags-taskport(a2,d2.w)
  654.  
  655.         bra     \loop
  656.  
  657. \nomsgs
  658.         move.l  a2,a0
  659.         jsr     _LVOWaitPort(a6)
  660.         bra     \loop
  661.  
  662.         bss     __MERGED
  663.  
  664. k:
  665.  
  666. chanmasks       ds.b    4                       ; IO_UNIT for each channel
  667. chanpos         ds.b    4                       ; Stereo position of each channel
  668. chanallocflags  ds.b    4                       ; Set if an allocation request is pending
  669. chanpervol      ds.w    4*2                     ; Current period (+0) and volume (+2) (0-$100)
  670. chanoneshot     ds.l    4                       ; IOAudio of current one-shot sample
  671. chanrepeat      ds.l    4                       ; IOAudio of current repeat sample
  672.  
  673. mastervoltab    ds.b    8                       ; Master volume (0-$40)
  674.  
  675. sitport         ds.b    MP_SIZE                 ; "Silent" port where idle IORequests sit around
  676. taskport        ds.b    MP_SIZE                 ; Port where allocation requests go to
  677.  
  678. ioreqs          ds.b    ioa_SIZEOF*IOREQS       ; A bunch of IO requests for playing notes and such
  679.  
  680. tc              ds.b    TC_SIZE                 ; Task control block
  681. stack           ds.b    STACKSIZE               ; Stack for task
  682.  
  683. taskadded       ds.b    1                       ; The allocation task is currently running
  684.  
  685. channels        ds.b    1                       ; Number of channels we're using
  686.  
  687. volinitflag     ds.b    1                       ; Nonzero if master volume's been initialized
  688.  
  689.         end
  690.