home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Sound / DeliTrackerII / Bonus / PlayAY100.lha / PlayAY / dev / src / Amadeus.S next >
Text File  |  1997-04-28  |  22KB  |  664 lines

  1.  
  2.     incdir    Include:
  3.     include    misc/AYPlayer.i
  4.     include    misc/mine.i
  5.     incdir    ''
  6.  
  7. *** Amadeus AY Player for my DT2 Play AY Emulator Interface, (C) 1994 Raxoft
  8. *** This is an example how your own AY Player could look like...
  9.  
  10. * 1 Initial version
  11. * 2 Added pushtranspose (143) a poptranspose (144) commands
  12. * 3 Protected volume envelope streams from causing enforcer hits
  13.  
  14. ;This is how single Amadeus song looks like.
  15. ;Note that each module can contain several songs like this one...
  16. ;See aym_ structure for more info
  17.  
  18.     STRUCTURE    AMAD_Song,0
  19.     UWORD    ams_getabs    ;where the original channelA located in ZX ram
  20.     UBYTE    ams_andsix    ;strange F.F.s thing. Should be 31 normally.
  21.     UBYTE    ams_loops    ;how many loops before songend
  22.     UWORD    ams_looplen    ;len of one song loop in VBIs
  23.     WORD    ams_fadeoffset    ;precise fade specification
  24.     UWORD    ams_fadelen    ;how long to fade (not supported by DT so far)
  25.                 ;set to zero for neverending song
  26.     UBYTE    ams_assignA    ;0-3 specifies, what amiga channel will be
  27.     UBYTE    ams_assignB    ;assigned to each ay channel (A-C, noise)
  28.     UBYTE    ams_assignC
  29.     UBYTE    ams_assignN
  30.     ;original ZX data follow. First three ptrs to init channels
  31.     UWORD    ams_channelA    ;these are the original ZX data.
  32.     UWORD    ams_channelB    ;ayp_getabs says, where the ams_channelA was
  33.     UWORD    ams_channelC    ;located when it was in ZX RAM.
  34.     ;and so on...
  35.  
  36. ; The Player itself. See AYPlayer.i for more info about players in general.
  37.  
  38. dd    ;Section    AmadeusCode,code    commented because of QUICK_HACK
  39.  
  40.     AYPLAYERHEADER    AMAD
  41.     dc.b    12-1        ;custom ayfreq transpose: up octave - 1 tone
  42. AYbase    ds.l    1        ;where ay registers should be "outed"
  43. AYass    ds.l    1        ;where ay channel assignment should be copied
  44. AYfreq    ds.l    1        ;from where we can take AY frequencies
  45.     dc.w    0        ;initplayer
  46.     dc.w    0        ;endplayer
  47.     dc.w    initsound-*
  48.     dc.w    0        ;endsound
  49.     dc.w    interrupt-*
  50.     dc.w    0        ;No pattern support (patterns are pretty
  51.     dc.w    0        ;limitating and bad idea IMHO)
  52.     dc.b    'Amadeus 1.1',0
  53.     dc.b    '(C) 1987 Frantisek Fuka - Fuxoft',0
  54.     dc.b    '(C) 1992-1997 Patrik Rak - Raxoft',0
  55.     even
  56.  
  57. ;Here is the song preparation entry... PlayAY passes us ptr to our custom
  58. ;AMAD_SongStructure in a0, so it is our job to initialize our player pointers
  59. ;Also we calculate the songlen we will use later.
  60. ;Also, this is where we CAN assign AY channels to amiga channels
  61. ;(otherwise standard 0,1,2,3 assignment is made.)
  62.  
  63. initsound
  64.     lea    ams_channelA(a0),a1
  65.     moveq    #0,d0
  66.     move.w    (a0)+,d0    ;careful with the words >32767 :-)
  67.     sub.l    d0,a1
  68.     move.l    a1,getabsset    ;for ZX -> Amiga RAM relocation
  69.     move.b    (a0)+,andsix    ;FFs internal
  70.     moveq    #0,d0
  71.     move.b    (a0)+,d0    ;loops
  72.     mulu    (a0)+,d0    ;looplen
  73.     add.w    (a0)+,d0    ;add/sub offset
  74.     lea    songlen,a1
  75.     move.w    d0,(a1)+    ;store songlen
  76.     move.w    (a0)+,(a1)    ;store fadelen
  77.     move.l    AYass(pc),a1
  78.     move.l    (a0)+,(a1)    ;copy channel assignment
  79.     move.l    a0,a1        ;point to channelA
  80.     bra.b    cold        ;skip to orig. amad init routine
  81.  
  82. ;This routine is called every 1/50th of second (usually)
  83. ;Here you should process your music data and load the AY regs
  84. ;also, you can do the song len counting here - return null if song should
  85. ;continue. To signal end, return non zero value telling how many VBIs should
  86. ;DT fade.
  87.  
  88. interrupt
  89.  
  90.     bsr.w    warm    ;call orig. amadeus int. routine
  91.  
  92.     ;This is how signal songend routine should ALWAYS look like
  93.     ;Note that you MAY NOT return nonzero value more then once per song!!!
  94.     
  95.     moveq    #0,d0    ;signal continue
  96.     lea    songlen,a0
  97.     tst.w    (a0)
  98.     beq.b    .exit    ;already signalled
  99.     subq.w    #1,(a0)+    ;decrease songlen and point to fadelen
  100.     bne.b    .exit    ;not end yet
  101.     move.w    (a0),d0    ;if zero, then will never fade. Otherwise fade for x VBIs
  102. .exit    rts
  103.  
  104.  
  105. ***************************************************************************
  106.  
  107. ;Amadeus (Amiga Version for AY-3-8912 Emulator) 1.00 by Raxoft 1992
  108. ;Based on Original Amadeus V8 (C) Fuxoft 1987
  109.  
  110. ;I am not going to comment this source too detailed, because no one is going
  111. ;to read it and understand Amadeus DATA format anyway... So only roughly...
  112.  
  113. ;This code is rewrite from Z80 code, as you can see from the code design.
  114. ;I did only few optimalizations, because I didn't want to create some
  115. ;incompatibility by my mistake... So have it in mind and don't blame me...
  116.  
  117. ;Code has been sligthly rearanged by me and Delirium in 1994.
  118.  
  119. ;===========================================================================
  120.  
  121. ;Support routines for easier Z-80 emulation in 68000 code
  122.  
  123. ;GetAbs replaces this code, which is used very often in amadeus (and other
  124. ;routines as well):
  125. ;    LD    (HL),E        ;imagine that HL is a1 and DE is D7
  126. ;    INC    HL
  127. ;    LD    (HL),D
  128. ;    INC    HL
  129. ;and DE is not just some value, it is another Address Pointer to ZX data...
  130. ;This allows that there is no need to change the original data at all...
  131.  
  132. getabs    moveq    #0,d7        ;Simulates reading word address from ZX
  133.     move.b    (a1)+,d6    ;memory and recalculates it to the
  134.     move.b    (a1)+,d7    ;amiga memory. Note that ZX has LSB
  135.     lsl.w    #8,d7        ;followed MSB. And word can be on
  136.     move.b    d6,d7        ;odd address as well.
  137.     add.l    getabsset,d7    ;Returns Address in d7, also increases
  138.     rts            ;that pointer...
  139.  
  140. ;Because data in ZX memory often use direct addressing, it is necessary to
  141. ;recalculate it to your Amiga memory. Let's say you have ZX data, which were
  142. ;located on 53000, and you have them on $534a3 in your amiga memory. So you
  143. ;have to set this to $534a3-53000, otherwise the getabs won't work properly...
  144.  
  145. getabsset    dc.l    0        ;Base for your ZX memory
  146.  
  147. ;===========================================================================
  148.  
  149.  
  150. ;This code initiates all important values needed later.
  151. ;On ZX it also installed IM2 routine.
  152.  
  153. ;a1 contains pointer to first data stream
  154.  
  155. cold    lea    worksp,a6    ;Workspace
  156.  
  157.     bsr.b    getabs        ;Read three channel pointers
  158.     move.l    d7,(a6)        ;and install them to workspace
  159.     bsr.b    getabs    
  160.     move.l    d7,wrk2(a6)
  161.     bsr.b    getabs    
  162.     move.l    d7,wrk3(a6)
  163.  
  164.     move.w    #$0108,d0    ;Set note len to 1 and strobe to 8
  165.     move.w    d0,wrk1+len(a6)
  166.     move.w    d0,wrk2+len(a6)
  167.     move.w    d0,wrk3+len(a6)
  168.  
  169.     lea    stacks+stacksize-worksp(a6),a1    ;Init Channel stacks
  170.     move.l    a1,stk1-worksp(a6)
  171.     lea    stacksize(a1),a1
  172.     move.l    a1,stk2-worksp(a6)
  173.     lea    stacksize(a1),a1
  174.     move.l    a1,stk3-worksp(a6)
  175.  
  176.     clr.w    wrk1+flags(a6)    ;reset flags and transpositions
  177.     clr.w    wrk2+flags(a6)
  178.     clr.w    wrk3+flags(a6)
  179.  
  180.     clr.l    wrk1+freqbeg(a6);reset frequency envelopes starts
  181.     clr.l    wrk2+freqbeg(a6);don't think it is necessary
  182.     clr.l    wrk3+freqbeg(a6);but recoded it as well :-)
  183.  
  184.     clr.l    wrk1+envbeg(a6);reset volume envelopes starts
  185.     clr.l    wrk2+envbeg(a6);this is checked against zero to prevent
  186.     clr.l    wrk3+envbeg(a6);enforcer hit in some amadeus tunes
  187.  
  188.     sf    barva-worksp(a6);Clear noise color/frequency
  189.     rts
  190.  
  191. ;===========================================================================
  192.  
  193. ;This was the original routine which was called by Z80 every interrupt, pushed
  194. ;registers, called warm, poped registers, EI, RET. Now, it is the same as WARM
  195. ;indeed
  196.     
  197. ;inter    equ    warm
  198.  
  199. ;===========================================================================
  200.  
  201. ;This routine originally disabled IM2, turned on IM1 and stopped AY sound.
  202. ;Now it does only the latter, although you can also call AYoff and it will do
  203. ;the same as calling StopAMAD & AYemulate. It just puts 255 to the strobe
  204. ;register
  205.  
  206. ;No need for this routine, since the playAY will turn of the AY anyway
  207. ;(something not possible on ZX :-)
  208.  
  209. ;stopamad    lea    worksp(pc),a6
  210. ;    moveq    #-1,d0
  211. ;    bra.b    stopout
  212.  
  213. ;===========================================================================
  214.  
  215. ;Main routine, should be called every 50th of second, followed by the call
  216. ;to AYemulate.
  217.  
  218. ;Of course that you first have to install Data for amadeus, THEN call Cold, 
  219. ;and THEN you can call this.
  220.  
  221. ;It does everything: advances in all channels, generates new notes, new
  222. ;envelopes, all effects, everything...
  223.  
  224. warm    lea    worksp,a6    ;Workspace pointer to a6 as base
  225.  
  226.     lea    (a6),a5            ;Proccess Channel 1
  227.     move.l    stk1-worksp(a6),a4    ;get stack pointer
  228.     moveq    #1,d0            ;channel number
  229.     bsr.b    main            ;Oh man, DO IT !!!
  230.     move.l    a4,stk1-worksp(a6)    ;store stack pointer
  231.     
  232.     lea    wrk2(a6),a5        ;Channel 2
  233.     move.l    stk2-worksp(a6),a4
  234.     moveq    #2,d0
  235.     bsr.b    main
  236.     move.l    a4,stk2-worksp(a6)
  237.     
  238.     lea    wrk3(a6),a5        ;Channel 3
  239.     move.l    stk3-worksp(a6),a4
  240.     moveq    #3,d0
  241.     bsr.b    main
  242.     move.l    a4,stk3-worksp(a6)
  243.     
  244.     move.b    wrk3+master(a6),d0    ;Get enable bits of all
  245.     add.b    d0,d0            ;three channels and generate
  246.     or.b    wrk2+master(a6),d0    ;strobe
  247.     add.b    d0,d0
  248.     or.b    wrk1+master(a6),d0
  249.     
  250. stopout    moveq    #7,d5            ;"Out" it to the AY backup reg.
  251.     bsr.b    out            ;and fall down to outy
  252.  
  253. ;===========================================================================
  254.  
  255. ;routine which originally OUTed all register stored in memory to the AY
  256. ;at once. Now, it just copies them from AY Backup registers (note that
  257. ;everything was prepared in memory at first) to the "AY register" (in our
  258. ;case, just another part of memory:-)
  259.  
  260. ;Originally it was send there from reg 13 to reg 0, but here is no reason
  261. ;to do that so... Although in Z80 it was better solution :-)
  262.  
  263. outy    moveq    #14/2-1,d5        ;14 register to copy
  264.     lea    output-worksp(a6),a1     ;pointer to my ay output buffer
  265.     move.l    AYbase,a3        ;pointer to AY registers
  266.     
  267. outy1    move.w    (a1)+,(a3)+        ;And feed them all :-)
  268.     dbra    d5,outy1
  269.     rts
  270.  
  271. ;===========================================================================
  272.  
  273. ;Originally it was a little longer routine, which stored one byte to the
  274. ;output table. Motorola makes it in one instruction :-)
  275.  
  276. out    move.b    d0,output-worksp(a6,d5.w)
  277.     rts
  278.  
  279. ;===========================================================================
  280.  
  281. ;Main processing routine for single channel
  282.  
  283. ;a4 stack pointer for this buffer
  284.  
  285. main    move.b    d0,hlas-worksp(a6)    ;store channel number
  286.     
  287.     subq.b    #1,len(a5)    ;decrease note length, skip
  288.     beq.w    nova        ;if we need to read new one.
  289.     
  290. hl11    subq.b    #1,envper(a5)    ;dec volume envelope delay counter
  291.     bne.B    hlst        ;skip if still same volume
  292.     
  293.     move.l    envpos(a5),d0    ;Pointer to Vol Envelope stream
  294.     beq.b    nohit1        ;!!!Just to be sure, FF is sclerotic !!!
  295.     move.l    d0,a1        ;On ZX it loads 243 from 0, but here... ?
  296.  
  297. hl1    move.b    (a1)+,d0    ;Read next volume/command
  298.     cmp.b    #128,d0        ;is it Jump?
  299.     bne.b    neskhl        ;Skip if not.
  300.     
  301.     bsr.w    getabs        ;Get the Jump destination
  302.     move.l    d7,a1        ;
  303.     bra.b    hl1        ;And continue there...
  304.     
  305. neskhl    cmp.b    #30,d0        ;0-30 used for volume 0-15
  306.     bcs.b    neskh0        ;followed by volume delay
  307.     
  308.     sub.b    #50,d0        ;values above 50 used for
  309. nohit1    move.b    d0,vol(a5)    ;volume 0-15, which has automatically
  310.     move.b    #1,envper(a5)    ;env volume delay = 1 (often used ->
  311.     bra.b    contx1        ;safes data)
  312.     
  313. neskh0    move.b    d0,vol(a5)    ;Ranges 0-30 and 50-255 are strange,
  314.     move.b    (a1)+,envper(a5);but better than try to always add
  315.                     ;128 or like by yourself... And FF
  316.                     ;wrote his musics in asm, of course...
  317. contx1    move.l    a1,envpos(a5)    ;Store the volume envelope position
  318.     
  319. hlst    move.w    freq(a5),d0    ;Skip if freq is 0 -> Generates
  320.     beq.b    playit        ;no tone
  321.     
  322.     btst    #2,flags(a5)    ;Is it first Edge? If it is, so go and
  323.     bne.b    playit        ;playit
  324.     
  325.     move.l    freqpos(a5),d0    ;Pointer to Freq envelope stream
  326.     beq.b    playit    ;!!!Just to be sure, FF is sclerotic !!!
  327.     move.l    d0,a1    ;On ZX it loads 243 from 0, but here... ?
  328.         
  329. frqc1    moveq    #0,d0        ;Get next freq/command
  330.     move.b    (a1)+,d0    
  331.     move.l    a1,freqpos(a5)    ;Store pointer to stream for next time
  332.     
  333.     cmp.b    #128,d0        ;Is it jump?
  334.     bne.b    nojpfr        ;skip if not
  335.     
  336.     bsr.w    getabs        ;Get jump destination address
  337.     move.l    d7,a1        ;as new stream
  338.     bra.b    frqc1        ;and continue there
  339.     
  340. nojpfr    cmp.b    #130,d0        ;Is it Tone Slide On command?
  341.     bne.b    nicfr1        ;Nope
  342.     
  343.     bset    #3,flags(a5)    ;Set that we will do Tone Slides
  344.     bra.b    frqc1        ;next freq/command
  345.     
  346. nicfr1    cmp.b    #131,d0        ;Is it Freq Slide On command?
  347.     bne.b    nicfr2        ;Nope
  348.     
  349.     bclr    #3,flags(a5)    ;Clear it, so we now do Freq Slides
  350.     bra.b    frqc1        ;next freq/command
  351.     
  352. nicfr2    cmp.b    #132,d0        ;Is it Tone/Noise Toggler?
  353.     bne.b    nicfr3        ;Nope
  354.     
  355.     eor.b    #9,master(a5)    ;Toggle Tone / Noise on flags
  356.     bra.b    frqc1        ;Next command
  357.  
  358. ;d0 was no command, so it is either Tone or Freq change value (depends)
  359.     
  360. nicfr3    btst    #3,flags(a5)    ;Are we in Tone Slide mode?
  361.     beq.b    nojpf0        ;Skip if in Freq Slide mode.
  362.     
  363.     add.b    tone(a5),d0    ;Add/Sub value from currently played
  364.     move.b    d0,tone(a5)    ;note and store it back
  365.  
  366. ;Note that following part can perhaps read values out of table, if not
  367. ;used carefully in music data! Also note, that value 0 is not here checked for
  368. ;silence - so it sometimes happened, that when one channel was playing only
  369. ;noise (like drum), and the transposition unforunatelly set the note to zero,
  370. ;value from (freq-2) was loaded to freq. It was OK till it was not zero (it
  371. ;was never so on ZX Amadeus), but when it happened (and of course it happened),
  372. ;value of 0 was loaded to freq here, thus disabling tone (which was disabled
  373. ;by strobe anyway), but also noise (by seting volume to zero), although it
  374. ;should play... Took me quite a while, why in several songs the drums
  375. ;sometimes sounded quite strange... That's the reason why I put
  376. ;dc.w 65535 before freqs table in FXS, just to be NOT ZERO... Now, the
  377. ;freq table goes up to 13.75 Hz, so there is a non zero value...
  378.     
  379.     add.b    d0,d0        ;Get AY frequency from the table
  380.     move.l    AYfreq(pc),a3    ;Note that first note is 1,
  381.     move.w    (a3,d0.w),freq(a5)    ;not 0 - 0 is for silence
  382.     bra.b    playit        ;and go to play sound
  383.     
  384. nojpf0    ext.w    d0        ;So it is Freq change value
  385.     
  386.     add.w    d0,d0    ;Correction - change AY freq change to
  387.     add.w    d0,d0    ;Amiga freq change...
  388.     add.w    d0,d0
  389.     
  390.     add.w    d0,freq(a5)    ;And store new frequency
  391.     
  392. ;Well, so volume and Frequency is already generated, so it is showtime
  393.  
  394. playit    move.b    barva-worksp(a6),d0    ;"Out" Noise freq
  395.  
  396.     and.b    andsix-worksp(a6),d0    ;FF sometimes use only range 0-15 ?!?!?
  397.  
  398.     moveq    #6,d5    ;(Why is it here in single channel processing?)
  399.     bsr.w    out    ;(Well, don't ask me :-)
  400.  
  401.     bclr    #2,flags(a5)    ;Set flag First Edge of Note played
  402.  
  403.     moveq    #7,d5
  404.     add.b    hlas-worksp(a6),d5 ;Get Channel number + 7 (8-10)
  405.     move.w    freq(a5),d0    ;Check frequency - if zero, then
  406.     beq.b    mlc        ;no tone AND no noise !!!
  407.     
  408.     move.b    vol(a5),d0    ;Else "Out" channel volume
  409.  
  410. mlc    bsr.w    out        ;Channel volume OR zero
  411.  
  412.     subq.b    #8,d5    ;Get channel number - 1 (0-2)
  413.     add.b    d5,d5    ;Get Freq reg position (0,2,4)
  414.     
  415.     move.b    freq(a5),d0    ;"Out" frequency
  416.     bsr.w    out
  417.     
  418.     addq.b    #1,d5
  419.     move.b    freq+1(a5),d0
  420.     bsr.w    out
  421.     
  422. navrat    rts            ;return
  423.  
  424. ;===========================================================================
  425.  
  426. ;Just store channel position as we proccess it... Originally much longer
  427. ;routine, of course :-), because of z80...
  428.  
  429. ;putpos    move.l    a1,(a5)
  430. ;    rts
  431.  
  432. ;changed to inline instruction
  433. ;and changed spec subroutines so it is not almost used... :-)
  434.  
  435. putpos    macro
  436.     move.l    a1,(a5)
  437.     endm
  438.  
  439. ;===========================================================================
  440.  
  441. ;This is called whenever new note is going to be played
  442.  
  443. nova    move.l    (a5),a1        ;Get channel position
  444. nova2    moveq    #0,d0        ;Get next note/command
  445.     move.b    (a1)+,d0
  446.     putpos            ;Remember position
  447.     
  448.     btst    #7,d0        ;Is it special command?
  449.     bne.B    spec        ;Go there if it is
  450.  
  451.     moveq    #0,d5        ;Fake freq = 0 -> will cause silence
  452.                     ;later
  453.     tst.b    d0        ;Is the note 0 (silence) ?
  454.     beq.B    notran        ;Go further if it is...
  455.     
  456.     add.b    trans(a5),d0    ;Add current Transposition to note
  457.     move.b    d0,tone(a5)    ;and store it
  458.     bclr    #3,flags(a5)    ;Turn Freq Slides on (default)
  459.     add.b    d0,d0        ;Get note frequency
  460.     move.l    AYfreq,a3
  461.     move.w    (a3,d0.w),d5
  462.     
  463. notran    move.b    (a1)+,len(a5)    ;Get number of VBIs for which it will
  464.     putpos        ;sound (0=256) and store pointer
  465.     move.w    d5,freq(a5)    ;store frequency or 0 for silence
  466.     move.l    freqbeg(a5),freqpos(a5) ;Re-Set Freq Env stream
  467.     bset    #2,flags(a5)    ;Say This is First Edge of Note
  468.                 ;to prevent early Freq Stream proccessing
  469.                 ;in case we will now jump to hl11 to
  470.                 ;keep everything synchronized
  471.                 
  472. ;Next part is little tricky. It handles continuous Volume Envelope streams,
  473. ;so eg. Volume can still fade even if we play a lot different notes.
  474. ;Bit 0 of flags says, if we want to turn this feature on, bit 1 says if
  475. ;it is already on. To turn it off, it is necessary turn both bits off.
  476. ;It is quite clever, allows control even in music nesting etc.
  477.  
  478.     btst    #1,flags(a5)    ;Already continuous Vol Envs?
  479.     bne.w    hl11        ;Proccess it if so..
  480.     
  481.     btst    #0,flags(a5)    ;Do we want turn it on?
  482.     beq.b    nic0        ;Skip if not...
  483.     
  484.     bset    #1,flags(a5)    ;From now, Vol Envs are continuous...
  485.     
  486. nic0    move.l    envbeg(a5),d0    ;Get begin of Vol Env stream
  487.     move.l    d0,a3        ;!!!Just to be sure, FF is sclerotic !!!
  488.     beq.b    nohit2        ;On ZX it loads 243 from 0, but here... ?
  489.     move.b    (a3)+,vol(a5)    ;and load first volume and delay
  490.     move.b    (a3)+,envper(a5);note that cannot use that +50 mode
  491. nohit2    move.l    a3,envpos(a5)    ;here. Re-Set Vol Env position.
  492.     bra.w    playit        ;And finally, play the note...
  493.  
  494. ;===========================================================================
  495.  
  496. ;This part proccesses all speciall commands found in the main channel stream,
  497. ;like gosubs, for-nexts, etc.
  498.  
  499. ;Note that we trust the data - so there is no Command Code check, and no
  500. ;Stack overflow check because of too much Gosubs or For-Nexts
  501.  
  502. spec    lea    nova2(pc),a0    ;to save some bytes
  503.     add.b    d0,d0        ;Execute proper routine...
  504.                 ;Perhaps should be slightly
  505.     lea.l    jptabl(pc,d0.w),a3 ;more CRASH PROOF :-)
  506.     add.w    (a3),a3
  507.     jmp    (a3)
  508.     
  509. jptabl    dc.w    jp-*,call-*,for_-*,next-*
  510.     dc.w    zm6-*,zmch-*,frqsta-*,def-*
  511.     dc.w    transp-*,ret_-*
  512.     dc.w    join-*,unjoin-*,usr-*
  513.     dc.w    add6-*,addtra-*
  514.     dc.w    pushtra-*,poptra-*
  515.     
  516. ;===========================================================================
  517.  
  518. jp    bsr.w    getabs        ;Stream Jump to some address
  519.     move.l    d7,a1        ;load new position.
  520.     jmp    (a0)
  521.     
  522. ;===========================================================================
  523.  
  524. call    bsr.w    getabs        ;Stream call. Remember position
  525.     move.l    a1,-(a4)
  526.     move.l    d7,a1        ;on the stack and load new one.
  527.     jmp    (a0)
  528.     
  529. ;===========================================================================
  530.  
  531. for_    move.b    (a1)+,-(a4)
  532.     subq.l    #1,a4
  533.     move.l    a1,-(a4)    ;For. Remember count and position
  534.     jmp    (a0)        ;on the steck
  535.     
  536. ;===========================================================================
  537.  
  538. next    subq.b    #1,5(a4)
  539.     beq.b    next1
  540.     move.l    (a4),a1
  541.     jmp    (a0)
  542. next1    addq.l    #6,a4
  543.     jmp    (a0)
  544.     
  545. ;===========================================================================
  546.  
  547. zm6    move.b    (a1)+,barva-worksp(a6) ;change Frequency of Noise Channel
  548.     jmp    (a0)
  549.     
  550. ;===========================================================================
  551.  
  552. zmch    move.b    (a1)+,master(a5);Select Tone AND/OR Noise On/Off
  553.     jmp    (a0)    ;Note also Toggler in Freq Env Stream, used
  554.             ;to generate pretty interesting sounds...
  555.     
  556. ;===========================================================================
  557.  
  558. def    bsr.w    getabs        ;Define Volume Envelope Stream begin
  559.     move.l    d7,envbeg(a5)    ;for following notes
  560.     jmp    (a0)
  561.     
  562. ;===========================================================================
  563.  
  564. transp    move.b    (a1)+,trans(a5)    ;Change transposition directly
  565.     jmp    (a0)
  566.     
  567. ;===========================================================================
  568.  
  569. ret_    move.l    (a4)+,a1    ;Return from subchannel. Get position from stack.
  570.     jmp    (a0)
  571.     
  572. ;===========================================================================
  573.  
  574. frqsta    bsr.w    getabs        ;Define Frequency Envelope Stream begin
  575.     move.l    d7,freqbeg(a5)    ;for following notes
  576.     jmp    (a0)
  577.     
  578. ;===========================================================================
  579.  
  580. join    bset    #0,flags(a5)    ;Turn on Continuous Volume Envelopes
  581.     bra.b    unjin
  582. ;    bclr    #1,flags(a5)
  583. ;    jmp    (a0)
  584.     
  585. ;===========================================================================
  586.  
  587. unjoin    bclr    #0,flags(a5)    ;Turn off Continuous Volume Envelopes
  588. unjin    bclr    #1,flags(a5)
  589.     jmp    (a0)
  590.     
  591. ;===========================================================================
  592.  
  593. usr    addq.l    #2,a1    ;This function was used for USER calls to any
  594.             ;Z80 code (eg. for synchronizing picture with
  595.     jmp    (a0)    ;sound as in Indiana Jones 3 by F.F.)
  596.                 ;Not implemented, OF COURSE :-)
  597.  
  598. ;===========================================================================
  599.  
  600. add6    move.b    (a1)+,d0    ;Increase/Decrease Noise Channel Freq
  601.     add.b    d0,barva-worksp(a6)    ;Used for some effects...
  602.     jmp    (a0)
  603.     
  604. ;===========================================================================
  605.  
  606. addtra    move.b    (a1)+,d0    ;Increase/Decrease Transposition level
  607.     add.b    d0,trans(a5)
  608.     jmp    (a0)
  609.     
  610. ;===========================================================================
  611.  
  612. pushtra    move.b    trans(a5),d0    ;Store Transposition level
  613.     move.w    d0,-(a4)
  614.     jmp    (a0)
  615.     
  616. ;===========================================================================
  617.  
  618. poptra    move.w    (a4)+,d0    ;Retore Transposition level
  619.     move.b    d0,trans(a5)
  620.     jmp    (a0)
  621.     
  622. ;===========================================================================
  623.  
  624.  
  625.     section    AmadeusData,bss
  626.  
  627. output    ds.b    14    ;Output space for AY registers
  628.  
  629. barva    ds.b    1    ;Noise Frequency
  630. hlas    ds.b    1    ;Temporary, for channel number
  631.  
  632. stk1    ds.l    1    ;Stack pointers for all three channels
  633. stk2    ds.l    1
  634. stk3    ds.l    1
  635.  
  636. stacksize    equ    128    ;even bigger then on ZX I think...
  637.  
  638. worksp    ds.b    3*30    ;WorkSpace for three channels, see below
  639. stacks    ds.b    3*stacksize    ;Space for Channel Stacks, used to store
  640.                 ;Gosub & For-Next informations.
  641.  
  642. wrk1    equ    0    ;Offset definitions
  643. wrk2    equ    30
  644. wrk3    equ    60
  645.  
  646. data    equ    0    ;l    ;Current Main Channel position
  647. len    equ    4    ;b    ;Delay remaining to the end of note
  648. master    equ    5    ;b    ;Partial Strobe (0,3), see AY strobe
  649. envpos    equ    6    ;l    ;Current Volume Envelope Stream Pos.
  650. envper    equ    10    ;b    ;Delay till pickup of next volume
  651. vol    equ    11    ;b    ;current volume
  652. freq    equ    12    ;w    ;current frequency
  653. envbeg    equ    14    ;l    ;Start of Volume Envelope Stream
  654. freqpos    equ    18    ;l    ;Current Freq Env Stream position.
  655. flags    equ    22    ;b    ;Flags - see code for more
  656. trans    equ    23    ;b    ;Current Transposition
  657. freqbeg    equ    24    ;l    ;Start of Freq Env Stream
  658. tone    equ    28    ;b    ;Current note
  659.  
  660. songlen    ds.w    1
  661. fadelen    ds.w    1
  662. andsix    ds.b    1
  663.  
  664.