Advertisement
Kitomas

code for the 2nd music driver prototype as of 2025-06-20

Jun 20th, 2025
2,347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;"2nd_music_driver_2025-06-20\main.p8":
  4. %zeropage basicsafe
  5.  
  6. %import music
  7.  
  8.  
  9.  
  10.  
  11.  
  12. song_data {
  13.   %option ignore_unused
  14.  
  15.   const ubyte PULSE    = %00000000
  16.   const ubyte SAWTOOTH = %01000000
  17.   const ubyte TRIANGLE = %10000000
  18.   const ubyte NOISE    = %11000000
  19.  
  20.   const ubyte SILENT   = %00000000
  21.   const ubyte LEFT     = %01000000
  22.   const ubyte RIGHT    = %10000000
  23.   const ubyte STEREO   = %11000000
  24.  
  25.   ; 6 bytes per instrument
  26.   const ubyte INSTRUMENTS_LEN = sizeof(instruments)/6
  27.  
  28.   ; +1 for tick speed
  29.   const ubyte ORDERS_LEN = sizeof(orders)/(CHANNELS+1)
  30.  
  31.   ; 2 bytes per pattern pointer
  32.   const ubyte PATTERNS_LEN = sizeof(patterns)/2
  33.  
  34.   ; This is what you pass to music.play()
  35.   ; Note: mkword's first arg is the high byte, not the low byte!
  36.   uword[] @nosplit info = [mkword(INSTRUMENTS_LEN, CHANNELS),
  37.                            mkword(PATTERNS_LEN, ORDERS_LEN),
  38.                            mkword(0, 0), ; (Reserved)
  39.                            &instruments, &orders, &patterns]
  40.  
  41.  
  42.  
  43.   const uword INS_NULL      =  0
  44.   const uword INS_SAWLONG   =  1
  45.   const uword INS_PLSSHRT   =  2
  46.   const uword INS_PLSLONG   =  3
  47.   const uword INS_NOISHRT_L =  4
  48.   const uword INS_NOISHRT_R =  5
  49.   const uword INS_NOILONG_L =  6
  50.   const uword INS_NOILONG_R =  7
  51.   const uword INS_NOISHRT   =  8
  52.   const uword INS_NOILONG   =  9
  53.   const uword INS_CHIRP     = 10
  54.  
  55.   ; WAVEFORM|WIDTH, EAR_CHANLS|VOL, MAXVOL_6b, ATTACK_8b, SUSTAIN_8b, RELEASE_8b
  56.   ;
  57.   ; From psg.envelope()'s remarks:
  58.   ;   maxvolume = 0-63
  59.   ;   attack, sustain, release = 0-255 that determine the speed of the A/D/R:
  60.   ;   attack  time:   MAXVOL/15/attack sec.   higher value = faster attack.
  61.   ;   sustain time:   sustain/60 sec.         higher value = longer sustain.
  62.   ;   release time:   MAXVOL/15/release sec.  higher vaule = faster release.
  63.   ;
  64.   ; (A max volume of 0 is interpreted as 'no note', which can be used for
  65.   ;  envelopes longer than the row it resides in, as that current envelope
  66.   ;  will continue until the next row with an instrument without a maxvol of 0.)
  67.   ubyte[] instruments = [       0,        0,   0,  255,  0, 255, ;  0 NULL
  68.                          SAWTOOTH, STEREO|0,  30,  208,  0,   5, ;  1 SAWLONG
  69.                          PULSE|48, STEREO|0,  33,  170,  5,  44, ;  2 PLSSHRT
  70.                          PULSE|38, STEREO|0,  33,  170, 13,  44, ;  3 PLSLONG
  71.                          NOISE   ,   LEFT|0,  19,   58,  0,  16, ;  4 NOISHRT_L
  72.                          NOISE   ,  RIGHT|0,  19,   58,  0,  16, ;  5 NOISHRT_R
  73.                          NOISE   ,   LEFT|0,  19,   58,  0,   8, ;  6 NOILONG_L
  74.                          NOISE   ,  RIGHT|0,  19,   58,  0,   8, ;  7 NOILONG_R
  75.                          NOISE   , STEREO|0,  14,   58,  0,  16, ;  8 NOISHRT
  76.                          NOISE   , STEREO|0,  14,   58,  0,   8, ;  9 NOILONG
  77.                          PULSE| 9, STEREO|0,  21,  208,  0,   6] ; 10 CHIRP
  78.                        
  79.  
  80.  
  81.   ; Accepts values 1-6 (ORDERS_LEN = sizeof(orders)/CHANNELS)
  82.   const ubyte CHANNELS = 5
  83.  
  84.   ; Contains indices into the patterns array, where the actual
  85.   ; index equals i-1, and a value of 0 means no pattern at all
  86.   ;
  87.   ; The first byte of an order entry however, is the tick speed (frames per row)
  88.   ubyte[] orders = [
  89.                      8,  1, 2, 3, 4, 5,
  90.                     ]
  91.  
  92.  
  93.  
  94.   ; This is an array of pointers
  95.   ;
  96.   ; In each pattern, the first byte correlates to its length mask.
  97.   ; For example, a pattern with a length of 64 would have a mask of 63
  98.   ; (Pattern length must be a power of 2!)
  99.   ;
  100.   ; If the 2nd byte is nonzero, that pattern's array lacks the @nosplit tag.
  101.   ;
  102.   ; The words after are the pattern's rows:
  103.   ;   Bits 0-6 are: The note index; piano key starting from C0 (0-119)
  104.   ;                 (A note index of 0 indicates a silent note)
  105.   ;   Bits 7-F are: The instrument index (0-511)
  106.   uword[] @nosplit patterns = [pattern_hatLR,
  107.                                pattern_hatST,
  108.                                pattern_saw,
  109.                                pattern_pulse,
  110.                                pattern_chirp]
  111.  
  112.  
  113.  
  114.   ; 1
  115.   uword[] @nosplit pattern_hatLR = [mkword(0,7), ; Mask of 7, for 8 notes total
  116.                                     INS_NOISHRT_L<<7 | piano.KEY_C9,
  117.                                     INS_NOISHRT_R<<7 | piano.KEY_C9,
  118.                                     INS_NOILONG_L<<7 | piano.KEY_D9S,
  119.                                     INS_NULL     <<7 |            0,
  120.                                     INS_NOISHRT_R<<7 | piano.KEY_C9,
  121.                                     INS_NOISHRT_L<<7 | piano.KEY_C9,
  122.                                     INS_NOILONG_R<<7 | piano.KEY_D9S,
  123.                                     INS_NULL     <<7 |            0]
  124.  
  125.  
  126.  
  127.   ; 2
  128.   uword[] @nosplit pattern_hatST = [mkword(0,7), ; Mask of 7, for 8 notes total
  129.                                     INS_NOISHRT<<7 | piano.KEY_C9,
  130.                                     INS_NOISHRT<<7 | piano.KEY_C9,
  131.                                     INS_NOILONG<<7 | piano.KEY_D9S,
  132.                                     INS_NULL   <<7 |            0,
  133.                                     INS_NOISHRT<<7 | piano.KEY_C9,
  134.                                     INS_NOISHRT<<7 | piano.KEY_C9,
  135.                                     INS_NOILONG<<7 | piano.KEY_D9S,
  136.                                     INS_NULL   <<7 |            0]
  137.  
  138.  
  139.  
  140.   ; 3
  141.   uword[] @nosplit pattern_saw = [mkword(0,63), ; 64 notes total
  142.                                   INS_NULL   <<7 | 0,
  143.                                   INS_NULL   <<7 | 0,
  144.                                   INS_SAWLONG<<7 | piano.KEY_G2S,
  145.                                   INS_NULL   <<7 | 0,
  146.                                   INS_NULL   <<7 | 0,
  147.                                   INS_NULL   <<7 | 0,
  148.                                   INS_SAWLONG<<7 | piano.KEY_G2S,
  149.                                   INS_NULL   <<7 | 0,
  150.                                   INS_NULL   <<7 | 0,
  151.                                   INS_NULL   <<7 | 0,
  152.                                   INS_SAWLONG<<7 | piano.KEY_G2S,
  153.                                   INS_NULL   <<7 | 0,
  154.                                   INS_NULL   <<7 | 0,
  155.                                   INS_NULL   <<7 | 0,
  156.                                   INS_SAWLONG<<7 | piano.KEY_C3,
  157.                                   INS_NULL   <<7 | 0,
  158.                                   INS_NULL   <<7 | 0,
  159.                                   INS_NULL   <<7 | 0,
  160.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  161.                                   INS_NULL   <<7 | 0,
  162.                                   INS_NULL   <<7 | 0,
  163.                                   INS_NULL   <<7 | 0,
  164.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  165.                                   INS_NULL   <<7 | 0,
  166.                                   INS_NULL   <<7 | 0,
  167.                                   INS_NULL   <<7 | 0,
  168.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  169.                                   INS_NULL   <<7 | 0,
  170.                                   INS_NULL   <<7 | 0,
  171.                                   INS_NULL   <<7 | 0,
  172.                                   INS_SAWLONG<<7 | piano.KEY_A2S,
  173.                                   INS_NULL   <<7 | 0,
  174.                                   INS_NULL   <<7 | 0,
  175.                                   INS_NULL   <<7 | 0,
  176.                                   INS_SAWLONG<<7 | piano.KEY_F2,
  177.                                   INS_NULL   <<7 | 0,
  178.                                   INS_NULL   <<7 | 0,
  179.                                   INS_NULL   <<7 | 0,
  180.                                   INS_SAWLONG<<7 | piano.KEY_F2,
  181.                                   INS_NULL   <<7 | 0,
  182.                                   INS_NULL   <<7 | 0,
  183.                                   INS_NULL   <<7 | 0,
  184.                                   INS_SAWLONG<<7 | piano.KEY_F2,
  185.                                   INS_NULL   <<7 | 0,
  186.                                   INS_NULL   <<7 | 0,
  187.                                   INS_NULL   <<7 | 0,
  188.                                   INS_SAWLONG<<7 | piano.KEY_D2S,
  189.                                   INS_NULL   <<7 | 0,
  190.                                   INS_NULL   <<7 | 0,
  191.                                   INS_NULL   <<7 | 0,
  192.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  193.                                   INS_NULL   <<7 | 0,
  194.                                   INS_NULL   <<7 | 0,
  195.                                   INS_NULL   <<7 | 0,
  196.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  197.                                   INS_NULL   <<7 | 0,
  198.                                   INS_NULL   <<7 | 0,
  199.                                   INS_NULL   <<7 | 0,
  200.                                   INS_SAWLONG<<7 | piano.KEY_G2,
  201.                                   INS_NULL   <<7 | 0,
  202.                                   INS_NULL   <<7 | 0,
  203.                                   INS_NULL   <<7 | 0,
  204.                                   INS_SAWLONG<<7 | piano.KEY_G2S,
  205.                                   INS_NULL   <<7 | 0]
  206.  
  207.  
  208.  
  209.   uword[] @nosplit pattern_pulse = [mkword(0,63), ; 64 notes total
  210.                            ; 0 -> 7:
  211.                            INS_PLSSHRT<<7 | piano.KEY_F3,
  212.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  213.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  214.                            INS_PLSLONG<<7 | piano.KEY_G4,
  215.                            INS_NULL   <<7 | 0,
  216.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  217.                            INS_PLSLONG<<7 | piano.KEY_D4S,
  218.                            INS_NULL   <<7 | 0,
  219.                            ; 8 -> 15:
  220.                            INS_PLSSHRT<<7 | piano.KEY_F3,
  221.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  222.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  223.                            INS_PLSLONG<<7 | piano.KEY_G4,
  224.                            INS_NULL   <<7 | 0,
  225.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  226.                            INS_PLSLONG<<7 | piano.KEY_D4S,
  227.                            INS_NULL   <<7 | 0,
  228.                            ; 16 -> 23:
  229.                            INS_PLSSHRT<<7 | piano.KEY_D3S,
  230.                            INS_PLSSHRT<<7 | piano.KEY_G3,
  231.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  232.                            INS_PLSLONG<<7 | piano.KEY_G4,
  233.                            INS_NULL   <<7 | 0,
  234.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  235.                            INS_PLSLONG<<7 | piano.KEY_D4S,
  236.                            INS_NULL   <<7 | 0,
  237.                            ; 24 -> 31:
  238.                            INS_PLSSHRT<<7 | piano.KEY_D3S,
  239.                            INS_PLSSHRT<<7 | piano.KEY_G3,
  240.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  241.                            INS_PLSLONG<<7 | piano.KEY_G4,
  242.                            INS_NULL   <<7 | 0,
  243.                            INS_PLSSHRT<<7 | piano.KEY_C4,
  244.                            INS_PLSSHRT<<7 | piano.KEY_D4S,
  245.                            INS_PLSSHRT<<7 | piano.KEY_C4S,
  246.                            ; 32 -> 39:
  247.                            INS_PLSSHRT<<7 | piano.KEY_C3S,
  248.                            INS_PLSSHRT<<7 | piano.KEY_F3,
  249.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  250.                            INS_PLSLONG<<7 | piano.KEY_D4S,
  251.                            INS_NULL   <<7 | 0,
  252.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  253.                            INS_PLSLONG<<7 | piano.KEY_C4,
  254.                            INS_NULL   <<7 | 0,
  255.                            ; 40 -> 47:
  256.                            INS_PLSSHRT<<7 | piano.KEY_C3S,
  257.                            INS_PLSSHRT<<7 | piano.KEY_F3,
  258.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  259.                            INS_PLSLONG<<7 | piano.KEY_D4S,
  260.                            INS_NULL   <<7 | 0,
  261.                            INS_PLSSHRT<<7 | piano.KEY_G3S,
  262.                            INS_PLSLONG<<7 | piano.KEY_C4,
  263.                            INS_NULL   <<7 | 0,
  264.                            ; 48 -> 55:
  265.                            INS_PLSSHRT<<7 | piano.KEY_D3S,
  266.                            INS_PLSSHRT<<7 | piano.KEY_G3,
  267.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  268.                            INS_PLSLONG<<7 | piano.KEY_F4,
  269.                            INS_NULL   <<7 | 0,
  270.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  271.                            INS_PLSLONG<<7 | piano.KEY_C4S,
  272.                            INS_NULL   <<7 | 0,
  273.                            ; 56 -> 63:
  274.                            INS_PLSSHRT<<7 | piano.KEY_D3S,
  275.                            INS_PLSSHRT<<7 | piano.KEY_G3,
  276.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  277.                            INS_PLSLONG<<7 | piano.KEY_F4,
  278.                            INS_NULL   <<7 | 0,
  279.                            INS_PLSSHRT<<7 | piano.KEY_A3S,
  280.                            INS_PLSSHRT<<7 | piano.KEY_C4S,
  281.                            INS_PLSSHRT<<7 | piano.KEY_C4]
  282.  
  283.  
  284.  
  285.   const byte OCTAVE = 12
  286.   const byte CHIRPMOD = OCTAVE * 0
  287.  
  288.   uword[] @nosplit pattern_chirp = [mkword(0,15), ; 16 notes total
  289.                                     INS_NULL <<7 | 0,
  290.                                     INS_NULL <<7 | 0,
  291.                                     INS_NULL <<7 | 0,
  292.                                     INS_NULL <<7 | 0,
  293.                                     INS_CHIRP<<7 | (piano.KEY_G4  + CHIRPMOD),
  294.                                     INS_CHIRP<<7 | (piano.KEY_G4S + CHIRPMOD),
  295.                                     INS_CHIRP<<7 | (piano.KEY_A4S + CHIRPMOD),
  296.                                     INS_CHIRP<<7 | (piano.KEY_C5  + CHIRPMOD),
  297.                                     INS_CHIRP<<7 | (piano.KEY_G4  + CHIRPMOD),
  298.                                     INS_CHIRP<<7 | (piano.KEY_G4S + CHIRPMOD),
  299.                                     INS_CHIRP<<7 | (piano.KEY_A4S + CHIRPMOD),
  300.                                     INS_CHIRP<<7 | (piano.KEY_C5  + CHIRPMOD),
  301.                                     INS_CHIRP<<7 | (piano.KEY_G4  + CHIRPMOD),
  302.                                     INS_CHIRP<<7 | (piano.KEY_G4S + CHIRPMOD),
  303.                                     INS_CHIRP<<7 | (piano.KEY_A4S + CHIRPMOD),
  304.                                     INS_CHIRP<<7 | (piano.KEY_C5  + CHIRPMOD)]
  305.  
  306. }
  307.  
  308.  
  309.  
  310.  
  311.  
  312. main {
  313.   sub start() {
  314.     cx16.screen_set_charset(3+2, 0) ; +2 for upper/lower charset's thin variant
  315.    
  316.     txt.clear_screen()
  317.    
  318.     music.init()
  319.     music.play(song_data.info)
  320.    
  321.     music_debug.print_info()
  322.    
  323.     uword frame = 0
  324.    
  325.     repeat {
  326.       if (frame%music.STATE_ticksPerRow) == 0 {
  327.         ;txt.print("whichOrder = ")
  328.         ;printn.uw_dec(music.STATE_whichOrder)
  329.         ;txt.print(", whichRow = ")
  330.         txt.print("whichRow = ")
  331.         printn.ub_dec(music.STATE_whichRow)
  332.         txt.nl()
  333.       }
  334.    
  335.       sys.waitvsync()
  336.       frame++
  337.      
  338.     }
  339.    
  340.   }
  341.  
  342. }
  343. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  344. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  345. ;"2nd_music_driver_2025-06-20\music.p8":
  346. ; - PUBLIC ROUTINES -
  347. ; music.init() (only needs to be called once!)
  348. ; music.play(ptr_info)
  349. ; music.stop()
  350. ; music.stop_forced()
  351.  
  352. %import piano
  353.  
  354.  
  355.  
  356.  
  357.  
  358. ; - EXAMPLE SONG -
  359. ; CAN BE PLAYED WITH THESE 2 LINES:
  360. ;music.init()
  361. ;music.play(song_example.info)
  362.  
  363. song_example {
  364.   %option ignore_unused
  365.  
  366.   const ubyte PULSE    = %00000000
  367.   const ubyte SAWTOOTH = %01000000
  368.   const ubyte TRIANGLE = %10000000
  369.   const ubyte NOISE    = %11000000
  370.  
  371.   const ubyte SILENT   = %00000000
  372.   const ubyte LEFT     = %01000000
  373.   const ubyte RIGHT    = %10000000
  374.   const ubyte STEREO   = %11000000
  375.  
  376.   ; 6 bytes per instrument
  377.   const ubyte INSTRUMENTS_LEN = sizeof(instruments)/6
  378.  
  379.   ; +1 for tick speed
  380.   const ubyte ORDERS_LEN = sizeof(orders)/(CHANNELS+1)
  381.  
  382.   const ubyte PATTERNS_LEN = sizeof(patterns)/2
  383.  
  384.   ; This is what you pass to music.play()
  385.   ; Note: mkword's first arg is the high byte, not the low byte!
  386.   uword[] @nosplit info = [mkword(INSTRUMENTS_LEN, CHANNELS),
  387.                            mkword(PATTERNS_LEN, ORDERS_LEN),
  388.                            mkword(0, 0), ; (Reserved)
  389.                            &instruments, &orders, &patterns]
  390.  
  391.  
  392.  
  393.   ; WAVEFORM|WIDTH, EAR_CHANLS|VOL, MAXVOL_6b, ATTACK_8b, SUSTAIN_8b, RELEASE_8b
  394.   ;
  395.   ; From psg.envelope()'s remarks:
  396.   ;   maxvolume = 0-63
  397.   ;   attack, sustain, release = 0-255 that determine the speed of the A/D/R:
  398.   ;   attack  time:   MAXVOL/15/attack sec.   higher value = faster attack.
  399.   ;   sustain time:   sustain/60 sec.         higher value = longer sustain.
  400.   ;   release time:   MAXVOL/15/release sec.  higher vaule = faster release.
  401.   ;
  402.   ; (A max volume of 0 is interpreted as 'no note', which can be used for
  403.   ;  envelopes longer than the row it resides in, as that current envelope
  404.   ;  will continue until the next row with an instrument without a maxvol of 0.)
  405.   ubyte[] instruments = [PULSE|63, STEREO|63,  63,  255, 10, 128,
  406.                          TRIANGLE, STEREO|48,  63,    4, 60,   4]
  407.  
  408.  
  409.  
  410.   ; Accepts values 1-6 (ORDERS_LEN = sizeof(orders)/CHANNELS)
  411.   const ubyte CHANNELS = 6
  412.  
  413.   ; Contains indices into the patterns array, where the actual
  414.   ; index equals i-1, and a value of 0 means no pattern at all
  415.   ;
  416.   ; The first byte of an order entry however, is the tick speed (frames per row)
  417.   ubyte[] orders = [12,  1, 2, 0, 0, 0, 0]
  418.  
  419.  
  420.  
  421.   ; This is an array of pointers
  422.   ;
  423.   ; In each pattern, the first byte correlates to its length mask.
  424.   ; For example, a pattern with a length of 64 would have a mask of 63
  425.   ; (Pattern length must be a power of 2!)
  426.   ;
  427.   ; If the 2nd byte is nonzero, that pattern's array lacks the @nosplit tag.
  428.   ;
  429.   ; The words after are the pattern's rows:
  430.   ;   Bits 0-6 are: The note index; piano key starting from C0# (1-119)
  431.   ;                 (A note index of 0 indicates a silent note)
  432.   ;   Bits 7-F are: The instrument index (0-511)
  433.   uword[] @nosplit patterns = [pattern_1, pattern_2]
  434.  
  435.  
  436.  
  437.   uword[] @nosplit pattern_1 = [mkword(0,3), ; Mask of 3, for a total of 4 notes
  438.                                 0<<7 | piano.KEY_C4,
  439.                                 0<<7 | piano.KEY_G4,
  440.                                 0<<7 | piano.KEY_C5,
  441.                                 0<<7 | piano.KEY_G4]
  442.                                
  443.   uword[] @nosplit pattern_2 = [mkword(0,0), ; Mask of 0, for a total of 1 note
  444.                                 1<<7 | piano.KEY_C4]
  445.  
  446. }
  447.  
  448.  
  449.  
  450.  
  451.  
  452. ; Uses (at most) the upper 12 PSG channels
  453. music {
  454.   %option ignore_unused
  455.  
  456.   const uword NULL = 0 ; To make null pointer comparisons a bit more readable
  457.  
  458.   ; Byte indexes within song header
  459.   const ubyte INDEX_CHANNELS        =  0 ; LSB of uword 0
  460.   const ubyte INDEX_INSTRUMENTS_LEN =  1 ; MSB of uword 0
  461.   const ubyte INDEX_ORDERS_LEN      =  2 ; LSB of uword 1
  462.   const ubyte INDEX_PATTERNS_LEN    =  3 ; MSB of uword 1
  463.  ;const ubyte INDEX_?               =  4 ; LSB of uword 2
  464.  ;const ubyte INDEX_?               =  5 ; MSB of uword 2
  465.   const ubyte INDEX_INSTRUMENTS     =  6
  466.   const ubyte INDEX_ORDERS          =  8
  467.   const ubyte INDEX_PATTERNS        = 10
  468.  
  469.  
  470.  
  471.   ; - SONG DATA (AKA CONTENTS OF SONG INFO) -
  472.   ubyte SONG_channels
  473.   ubyte SONG_instruments_len
  474.   ubyte SONG_orders_len
  475.   ubyte SONG_patterns_len
  476.   ubyte SONG_order_size ; = channels+1 (used for alignment, mostly)
  477.  
  478.   uword SONG_ptr_info
  479.   uword SONG_ptr_instruments
  480.   uword SONG_ptr_orders
  481.   uword SONG_ptr_patterns
  482.  
  483.  
  484.  
  485.   ; - STATE VARIABLES -
  486.   bool STATE_isInit
  487.   bool STATE_isPlaying
  488.  
  489.   uword STATE_whichOrder ; Remember, this is a uword, not a ubyte!
  490.   ubyte STATE_whichRow
  491.   ubyte STATE_whichTick ; Actually decrements, loading a new row at 0
  492.   ubyte STATE_ticksPerRow
  493.   ubyte STATE_highestMask
  494.  
  495.   ; For every note, switch to an alternate channel
  496.   ; so that envelopes aren't cut off prematurely
  497.   ; (This is never reinitialized on purpose, as it's redundant!)
  498.   ;
  499.   ; (Also, this is of type ubyte[] instead of bool[],
  500.   ;  so I'm able to apply an XOR to easily flip the boolean)
  501.   ubyte[6] STATE_altChannel
  502.  
  503.   ; Determines the length of each pattern
  504.   ubyte[6] STATE_rowMasks
  505.  
  506.   ; Pointers to the currently loaded patterns
  507.   uword[6] STATE_ptrs_curOrder
  508.  
  509.  
  510.  
  511.  
  512.  
  513.   sub init() {
  514.     if STATE_isInit return
  515.  
  516.     psg.init()
  517.    
  518.     cx16.enable_irq_handlers(false)
  519.     cx16.set_vsync_irq_handler(&music.irq_routine)
  520.    
  521.     STATE_isInit = true
  522.  
  523.   }
  524.  
  525.  
  526.  
  527.  
  528.  
  529.   asmsub get_voice_num(ubyte channel @Y) clobbers(A) -> ubyte @Y {
  530.     ; Calculates the raw voice index, based on a channel index of 0 -> 5
  531.     ; returns: (4 + Y<<1 + alt_channel[Y])
  532.     ; (I might've been able to save some bytes by storing the boolean in X,
  533.     ;  but that would clobber another register, which is probably worse)
  534.     %asm {{
  535.       lda p8v_STATE_altChannel, y
  536.       beq _dont_increment ; If boolean is false, don't increment result
  537. ;_increment:
  538.       tya
  539.       asl    ; Y<<1
  540.       clc
  541.       adc #4 ; +4
  542.       tay  
  543.       iny    ; +alt_channel[Y]
  544.       rts
  545. _dont_increment:
  546.       tya
  547.       asl    ; Y<<1
  548.       clc
  549.       adc #4 ; +4
  550.       tay
  551.       rts
  552.     }}
  553.    
  554.   }
  555.  
  556.  
  557.  
  558.  
  559.  
  560.   ; Like peekw, but for split arrays
  561.   ; (I don't have time to make this an asmsub right now unfortunately)
  562.   ; TODO: This doesn't work in the context in which it's used; why?
  563.   sub get_split_uword(uword arr, ubyte arr_len, ubyte index) -> uword {
  564.     uword result
  565.     setlsb(result, arr[index])
  566.     arr += (arr_len as uword)
  567.     setmsb(result, arr[index])
  568.     return result
  569.  
  570.   }
  571.  
  572.  
  573.  
  574.  
  575.  
  576.   sub apply_key(ubyte whichVoice, ubyte whichKey) {
  577.     void piano.key(whichVoice, whichKey&%01111111)
  578.    
  579.   }
  580.  
  581.  
  582.  
  583.  
  584.  
  585.   ; Applies both voice and envelope
  586.   sub apply_instrument(ubyte whichVoice, uword whichInstrument) {
  587.     whichInstrument *= 6 ; Instrument index to byte offset (each are 6 bytes)
  588.     whichInstrument += SONG_ptr_instruments ; Byte offset to pointer
  589.    
  590.     ubyte wf_pw = whichInstrument[0] ; waveform | pulse_width
  591.     ubyte ec_sv = whichInstrument[1] ; ear_channels | start_vol
  592.    
  593.     ubyte maxvol  = whichInstrument[2]
  594.     ubyte attack  = whichInstrument[3]
  595.     ubyte sustain = whichInstrument[4]
  596.     ubyte release = whichInstrument[5]
  597.    
  598.     if maxvol == 0 {  return  }
  599.    
  600.     psg.voice(whichVoice, ec_sv&%11000000, ec_sv&%00111111,
  601.                           wf_pw&%11000000, wf_pw&%00111111)
  602.                          
  603.     psg.envelope(whichVoice, maxvol, attack, sustain, release)
  604.  
  605.   }
  606.  
  607.  
  608.  
  609.  
  610.  
  611.   sub load_order(uword whichOrder) {
  612.    ;STATE_whichOrder = whichOrder  ; (This line should be redundant)
  613.     whichOrder *= SONG_order_size ; Order index to byte offset
  614.     whichOrder += SONG_ptr_orders ; Byte offset to pointer
  615.  
  616.     STATE_whichRow    = 0
  617.     STATE_ticksPerRow = whichOrder[0]
  618.     STATE_highestMask = %00000001 ; A mask of 1 bit by default
  619.    
  620.     whichOrder++ ; whichOrder = &whichOrder[1] (skips the order's tick rate)
  621.    
  622.     &ubyte loop_i = &cx16.r4L ; Effectively an alias for cx16.r4L
  623.     ubyte loop_max = SONG_channels-1
  624.    
  625.      
  626.    
  627.     ; For each pattern ptr in current order
  628.     for loop_i in 0 to loop_max {
  629.       ubyte patternID = whichOrder[loop_i]
  630.      
  631.       &uword ptr_pattern = &cx16.r5 ; Alias for r5
  632.  
  633.       if patternID != 0 {
  634.         ptr_pattern = peekw( SONG_ptr_patterns + (((patternID-1) as uword)<<1) )
  635.       } else { ; A pattern ID of 0 indicates 'no pattern used'
  636.         ptr_pattern = NULL
  637.       }
  638.      
  639.       STATE_ptrs_curOrder[loop_i] = ptr_pattern
  640.      
  641.      
  642.      
  643.       if patternID != 0 {
  644.         ; First byte of pattern is the mask
  645.         ubyte rowMask = ptr_pattern[0]
  646.        
  647.         STATE_rowMasks[loop_i] = rowMask
  648.        
  649.         ; For finding the largest mask in all of the currently loaded patterns,
  650.         ; which is used to determine when an order is supposed to end
  651.         if STATE_highestMask < rowMask {  STATE_highestMask = rowMask  }
  652.        
  653.       }
  654.    
  655.     }
  656.    
  657.   }
  658.  
  659.  
  660.  
  661.  
  662.  
  663.   ; (Assumes order is already loaded)
  664.   sub load_row(ubyte whichRow) {
  665.     STATE_whichTick = STATE_ticksPerRow ; Decrements instead of incrementing
  666.  
  667.     &ubyte loop_i = &cx16.r4L ; Effectively an alias for cx16.r4L
  668.     ubyte loop_max = SONG_channels-1
  669.    
  670.    
  671.    
  672.     ; For each pattern ptr in current order
  673.     for loop_i in 0 to loop_max {
  674.       uword ptr_curPattern = STATE_ptrs_curOrder[loop_i]
  675.      
  676.       if ptr_curPattern == NULL {  continue  }
  677.       ubyte patternIsSplit = ptr_curPattern[1]
  678.       ptr_curPattern += 2 ; Skip the pattern's mask and split value
  679.      
  680.       ubyte patternMask = STATE_rowMasks[loop_i]
  681.       ubyte whichRowMasked  =  whichRow & patternMask
  682.      
  683.      
  684.      
  685.       uword rowValue
  686.      
  687.       if patternIsSplit != 0 {
  688.         ; TODO: Figure out why this doesn't work
  689.         ;rowValue = get_split_uword(ptr_curPattern, patternMask, whichRowMasked)
  690.       } else {
  691.         rowValue = peekw( ptr_curPattern + ((whichRowMasked as uword)<<1) )
  692.       }
  693.      
  694.      
  695.       ubyte whichKey        = lsb(rowValue) ;&%01111111 (this AND is redundant)
  696.       ubyte whichInstrument = (rowValue>>7) as ubyte
  697.       ubyte whichVoice      = get_voice_num(loop_i)
  698.      
  699.       if whichKey == 0 {  continue  }
  700.      
  701.       apply_key(whichVoice, whichKey) ; (Automatically unsets MSb of whichKey)
  702.       apply_instrument(whichVoice, whichInstrument)
  703.      
  704.       STATE_altChannel[loop_i] ^= 1 ; Flip the relevant bit
  705.    
  706.     }
  707.  
  708.   }
  709.  
  710.  
  711.  
  712.  
  713.  
  714.   ; Just 1 instruction (a 65C02-specific instruction :D)
  715.   ; Assuming that STATE_isPlaying is zeropage, 1 byte per call is actually saved
  716.   ; by inlining this lol (otherwise, the byte count is the same; 3 per call)
  717.   inline asmsub stop() clobbers() { %asm {{  stz p8v_STATE_isPlaying  }} }
  718.  
  719.   sub stop_forced() { stop() } ; TODO: Set all of the channels to mute here
  720.  
  721.  
  722.  
  723.  
  724.  
  725.   sub play(uword ptr_info) {
  726.     if ptr_info == NULL {  return  }
  727.    
  728.     SONG_channels        = ptr_info[INDEX_CHANNELS]
  729.     SONG_instruments_len = ptr_info[INDEX_INSTRUMENTS_LEN]
  730.     SONG_orders_len      = ptr_info[INDEX_ORDERS_LEN]
  731.     SONG_patterns_len    = ptr_info[INDEX_PATTERNS_LEN]
  732.     SONG_order_size      = SONG_channels+1
  733.    
  734.     SONG_ptr_info        = ptr_info
  735.     SONG_ptr_instruments = peekw(ptr_info + INDEX_INSTRUMENTS)
  736.     SONG_ptr_orders      = peekw(ptr_info + INDEX_ORDERS)
  737.     SONG_ptr_patterns    = peekw(ptr_info + INDEX_PATTERNS)
  738.    
  739.     STATE_whichOrder = 0
  740.     STATE_whichRow = 0 ; So that order 0 is immediately loaded next irq
  741.     STATE_whichTick = 0
  742.     STATE_highestMask = 255 ; Full mask by default, until order 0 is loaded
  743.    
  744.     STATE_isPlaying = true
  745.    
  746.   }
  747.  
  748.  
  749.  
  750.  
  751.  
  752.   sub irq_routine() -> bool {
  753.    
  754.     if not STATE_isPlaying {  goto lbl_songStopped  }
  755.    
  756.     ubyte whichRowMasked  =  STATE_whichRow & STATE_highestMask
  757.    
  758.     if whichRowMasked == 0 {
  759.       ; TODO: Looping is broken. Fix it.
  760.       load_order(STATE_whichOrder)
  761.       STATE_whichOrder++
  762.       ; Should be faster than a normal modulo
  763.       if STATE_whichOrder >= SONG_orders_len {
  764.         STATE_whichOrder -= SONG_orders_len
  765.       }
  766.     }
  767.    
  768.     if STATE_whichTick == 0 {
  769.       load_row(whichRowMasked)
  770.       STATE_whichRow++
  771.     }
  772.    
  773.     STATE_whichTick--
  774.    
  775.     lbl_songStopped:
  776.  
  777.     return psg.envelopes_irq()
  778.    
  779.   }
  780.  
  781. }
  782.  
  783.  
  784.  
  785.  
  786.  
  787. ;------------------------------------------------------------------------------;
  788.  
  789.  
  790.  
  791.  
  792.  
  793. %import textio
  794. %import conv
  795.  
  796. ; txt.clear_screen()
  797. ; txt.nl()
  798.  
  799. printn {
  800.   %option ignore_unused
  801.  
  802.   sub ub_dec(ubyte v) { txt.print(conv.str_ub(v)) }
  803.   sub  b_dec(byte  v) { txt.print(conv.str_b(v)) }
  804.   sub uw_dec(uword v) { txt.print(conv.str_uw(v)) }
  805.   sub  w_dec(word  v) { txt.print(conv.str_w(v)) }
  806.  
  807.   sub ub_bin(ubyte v) { txt.print(conv.str_ubbin(v)) }
  808.  
  809.   sub ub_hex(ubyte v) { txt.print(conv.str_ubhex(v)) }
  810.   sub uw_hex(uword v) { txt.print(conv.str_uwhex(v)) }
  811.  
  812. }
  813.  
  814. music_debug {
  815.   %option ignore_unused
  816.  
  817.   sub print_info() {
  818.     txt.print("channels        = ")
  819.     printn.ub_dec(music.SONG_channels)
  820.     txt.print("\ninstruments_len = ")
  821.     printn.ub_dec(music.SONG_instruments_len)
  822.     txt.print("\norders_len      = ")
  823.     printn.ub_dec(music.SONG_orders_len)
  824.     txt.print("\npatterns_len    = ")
  825.     printn.ub_dec(music.SONG_patterns_len)
  826.     txt.print("\norder_size      = ")
  827.     printn.ub_dec(music.SONG_order_size)
  828.    
  829.     txt.print("\nptr_instruments = $")
  830.     printn.uw_hex(music.SONG_ptr_instruments)
  831.     txt.print("\nptr_orders      = $")
  832.     printn.uw_hex(music.SONG_ptr_orders)
  833.     txt.print("\nptr_patterns    = $")
  834.     printn.uw_hex(music.SONG_ptr_patterns)
  835.     txt.nl()
  836.    
  837.   }
  838.  
  839.   sub print_state() {
  840.     txt.print("isInit      = ")
  841.     printn.ub_dec(music.STATE_isInit as ubyte)
  842.     txt.print("\nisPlaying   = ")
  843.     printn.ub_dec(music.STATE_isPlaying as ubyte)
  844.    
  845.     txt.print("\nwhichOrder  = ")
  846.     printn.uw_dec(music.STATE_whichOrder) ; uword, not ubyte
  847.     txt.print("\nwhichRow    = ")
  848.     printn.ub_dec(music.STATE_whichRow)
  849.     txt.print("\nwhichTick   = ")
  850.     printn.ub_dec(music.STATE_whichTick)
  851.     txt.print("\nticksPerRow = ")
  852.     printn.ub_dec(music.STATE_ticksPerRow)
  853.     txt.print("\nhighestMask = ")
  854.     printn.ub_dec(music.STATE_highestMask)
  855.    
  856.     &ubyte loop_i = &cx16.r6L
  857.    
  858.     txt.print("\naltChannel = [")
  859.     for loop_i in 0 to 5 {
  860.       printn.ub_dec(music.STATE_altChannel[cx16.r4L])
  861.       txt.print(", ")
  862.     }
  863.     txt.print("]\n")
  864.    
  865.     txt.print("rowMasks = [")
  866.     for loop_i in 0 to 5 {
  867.       printn.ub_dec(music.STATE_rowMasks[cx16.r4L])
  868.       txt.print(", ")
  869.     }
  870.     txt.print("]\n")
  871.    
  872.     txt.print("curOrder = [")
  873.     for loop_i in 0 to 5 {
  874.       txt.chrout('$')
  875.       printn.uw_hex(music.STATE_ptrs_curOrder[cx16.r4L])
  876.       txt.print(", ")
  877.     }
  878.     txt.print("]\n")
  879.  
  880.   }
  881.  
  882.   sub print_arr_ub(str prefix, uword ptr, ubyte index) {
  883.     txt.print(prefix)
  884.     txt.print(" = $")
  885.     printn.ub_hex(ptr[index])
  886.     txt.nl()
  887.  
  888.   }
  889.  
  890.   sub print_arr_uw(str prefix, uword ptr, ubyte index) {
  891.     txt.print(prefix)
  892.     txt.print(" = $")
  893.     printn.uw_hex(peekw( ptr + ((index as uword)<<1) ))
  894.     txt.nl()
  895.    
  896.   }
  897.  
  898. }
  899. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  900. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  901. ;"2nd_music_driver_2025-06-20\piano.p8":
  902. %import psg
  903.  
  904. piano {
  905.   ;%option no_symbol_prefixing, ignore_unused
  906.   %option ignore_unused
  907.  
  908.   ; Referring to the index in the lookup table,
  909.   ; not the actual frequency value, of course.
  910.   const ubyte KEY_C0   =   0  ;   16.35Hz
  911.   const ubyte KEY_C0S  =   1  ;   17.32Hz
  912.   const ubyte KEY_D0   =   2  ;   18.35Hz
  913.   const ubyte KEY_D0S  =   3  ;   19.44Hz
  914.   const ubyte KEY_E0   =   4  ;   20.60Hz
  915.   const ubyte KEY_F0   =   5  ;   21.82Hz
  916.   const ubyte KEY_F0S  =   6  ;   23.12Hz
  917.   const ubyte KEY_G0   =   7  ;   24.49Hz
  918.   const ubyte KEY_G0S  =   8  ;   25.95Hz
  919.   const ubyte KEY_A0   =   9  ;   27.50Hz
  920.   const ubyte KEY_A0S  =  10  ;   29.13Hz
  921.   const ubyte KEY_B0   =  11  ;   30.86Hz
  922.   const ubyte KEY_C1   =  12  ;   32.70Hz
  923.   const ubyte KEY_C1S  =  13  ;   34.64Hz
  924.   const ubyte KEY_D1   =  14  ;   36.70Hz
  925.   const ubyte KEY_D1S  =  15  ;   38.89Hz
  926.   const ubyte KEY_E1   =  16  ;   41.20Hz
  927.   const ubyte KEY_F1   =  17  ;   43.65Hz
  928.   const ubyte KEY_F1S  =  18  ;   46.24Hz
  929.   const ubyte KEY_G1   =  19  ;   48.99Hz
  930.   const ubyte KEY_G1S  =  20  ;   51.91Hz
  931.   const ubyte KEY_A1   =  21  ;   55.00Hz
  932.   const ubyte KEY_A1S  =  22  ;   58.27Hz
  933.   const ubyte KEY_B1   =  23  ;   61.73Hz
  934.   const ubyte KEY_C2   =  24  ;   65.40Hz
  935.   const ubyte KEY_C2S  =  25  ;   69.29Hz
  936.   const ubyte KEY_D2   =  26  ;   73.41Hz
  937.   const ubyte KEY_D2S  =  27  ;   77.78Hz
  938.   const ubyte KEY_E2   =  28  ;   82.40Hz
  939.   const ubyte KEY_F2   =  29  ;   87.30Hz
  940.   const ubyte KEY_F2S  =  30  ;   92.49Hz
  941.   const ubyte KEY_G2   =  31  ;   97.99Hz
  942.   const ubyte KEY_G2S  =  32  ;  103.82Hz
  943.   const ubyte KEY_A2   =  33  ;  110.00Hz
  944.   const ubyte KEY_A2S  =  34  ;  116.54Hz
  945.   const ubyte KEY_B2   =  35  ;  123.47Hz
  946.   const ubyte KEY_C3   =  36  ;  130.81Hz
  947.   const ubyte KEY_C3S  =  37  ;  138.59Hz
  948.   const ubyte KEY_D3   =  38  ;  146.83Hz
  949.   const ubyte KEY_D3S  =  39  ;  155.56Hz
  950.   const ubyte KEY_E3   =  40  ;  164.81Hz
  951.   const ubyte KEY_F3   =  41  ;  174.61Hz
  952.   const ubyte KEY_F3S  =  42  ;  184.99Hz
  953.   const ubyte KEY_G3   =  43  ;  195.99Hz
  954.   const ubyte KEY_G3S  =  44  ;  207.65Hz
  955.   const ubyte KEY_A3   =  45  ;  220.00Hz
  956.   const ubyte KEY_A3S  =  46  ;  233.08Hz
  957.   const ubyte KEY_B3   =  47  ;  246.94Hz
  958.   const ubyte KEY_C4   =  48  ;  261.62Hz
  959.   const ubyte KEY_C4S  =  49  ;  277.18Hz
  960.   const ubyte KEY_D4   =  50  ;  293.66Hz
  961.   const ubyte KEY_D4S  =  51  ;  311.12Hz
  962.   const ubyte KEY_E4   =  52  ;  329.62Hz
  963.   const ubyte KEY_F4   =  53  ;  349.22Hz
  964.   const ubyte KEY_F4S  =  54  ;  369.99Hz
  965.   const ubyte KEY_G4   =  55  ;  391.99Hz
  966.   const ubyte KEY_G4S  =  56  ;  415.30Hz
  967.   const ubyte KEY_A4   =  57  ;  440.00Hz
  968.   const ubyte KEY_A4S  =  58  ;  466.16Hz
  969.   const ubyte KEY_B4   =  59  ;  493.88Hz
  970.   const ubyte KEY_C5   =  60  ;  523.25Hz
  971.   const ubyte KEY_C5S  =  61  ;  554.36Hz
  972.   const ubyte KEY_D5   =  62  ;  587.32Hz
  973.   const ubyte KEY_D5S  =  63  ;  622.25Hz
  974.   const ubyte KEY_E5   =  64  ;  659.25Hz
  975.   const ubyte KEY_F5   =  65  ;  698.45Hz
  976.   const ubyte KEY_F5S  =  66  ;  739.98Hz
  977.   const ubyte KEY_G5   =  67  ;  783.99Hz
  978.   const ubyte KEY_G5S  =  68  ;  830.60Hz
  979.   const ubyte KEY_A5   =  69  ;  880.00Hz
  980.   const ubyte KEY_A5S  =  70  ;  932.32Hz
  981.   const ubyte KEY_B5   =  71  ;  987.76Hz
  982.   const ubyte KEY_C6   =  72  ; 1046.50Hz
  983.   const ubyte KEY_C6S  =  73  ; 1108.73Hz
  984.   const ubyte KEY_D6   =  74  ; 1174.65Hz
  985.   const ubyte KEY_D6S  =  75  ; 1244.50Hz
  986.   const ubyte KEY_E6   =  76  ; 1318.51Hz
  987.   const ubyte KEY_F6   =  77  ; 1396.91Hz
  988.   const ubyte KEY_F6S  =  78  ; 1479.97Hz
  989.   const ubyte KEY_G6   =  79  ; 1567.98Hz
  990.   const ubyte KEY_G6S  =  80  ; 1661.21Hz
  991.   const ubyte KEY_A6   =  81  ; 1760.00Hz
  992.   const ubyte KEY_A6S  =  82  ; 1864.65Hz
  993.   const ubyte KEY_B6   =  83  ; 1975.53Hz
  994.   const ubyte KEY_C7   =  84  ; 2093.00Hz
  995.   const ubyte KEY_C7S  =  85  ; 2217.46Hz
  996.   const ubyte KEY_D7   =  86  ; 2349.31Hz
  997.   const ubyte KEY_D7S  =  87  ; 2489.01Hz
  998.   const ubyte KEY_E7   =  88  ; 2637.02Hz
  999.   const ubyte KEY_F7   =  89  ; 2793.82Hz
  1000.   const ubyte KEY_F7S  =  90  ; 2959.95Hz
  1001.   const ubyte KEY_G7   =  91  ; 3135.96Hz
  1002.   const ubyte KEY_G7S  =  92  ; 3322.43Hz
  1003.   const ubyte KEY_A7   =  93  ; 3520.00Hz
  1004.   const ubyte KEY_A7S  =  94  ; 3729.31Hz
  1005.   const ubyte KEY_B7   =  95  ; 3951.06Hz
  1006.   const ubyte KEY_C8   =  96  ; 4186.00Hz
  1007.   const ubyte KEY_C8S  =  97  ; 4434.92Hz
  1008.   const ubyte KEY_D8   =  98  ; 4698.63Hz
  1009.   const ubyte KEY_D8S  =  99  ; 4978.03Hz
  1010.   const ubyte KEY_E8   = 100  ; 5274.04Hz
  1011.   const ubyte KEY_F8   = 101  ; 5587.65Hz
  1012.   const ubyte KEY_F8S  = 102  ; 5919.91Hz
  1013.   const ubyte KEY_G8   = 103  ; 6271.92Hz
  1014.   const ubyte KEY_G8S  = 104  ; 6644.87Hz
  1015.   const ubyte KEY_A8   = 105  ; 7040.00Hz
  1016.   const ubyte KEY_A8S  = 106  ; 7458.62Hz
  1017.   const ubyte KEY_B8   = 107  ; 7902.13Hz
  1018.   const ubyte KEY_C9   = 108  ; 8372.01Hz
  1019.   const ubyte KEY_C9S  = 109  ; 8869.84Hz
  1020.   const ubyte KEY_D9   = 110  ; 9397.27Hz
  1021.   const ubyte KEY_D9S  = 111  ; 9956.06Hz
  1022.   const ubyte KEY_E9   = 112  ;10548.08Hz
  1023.   const ubyte KEY_F9   = 113  ;11175.30Hz
  1024.   const ubyte KEY_F9S  = 114  ;11839.82Hz
  1025.   const ubyte KEY_G9   = 115  ;12543.85Hz
  1026.   const ubyte KEY_G9S  = 116  ;13289.75Hz
  1027.   const ubyte KEY_A9   = 117  ;14080.00Hz
  1028.   const ubyte KEY_A9S  = 118  ;14917.24Hz
  1029.   const ubyte KEY_B9   = 119  ;15804.26Hz
  1030.  
  1031.  
  1032.  
  1033.   ; PSG frequency lookup table (used by key(); private)
  1034.   ubyte[120] priv_freqs_lo = [44, 47, 49, 52, 55, 59, 62, 66, 70, 74, 78, 83, 88, 93, 99,104,111,117,124,132,139,148,156,166,176,186,197,209,221,234,248,  7, 23, 39, 57, 75, 95,116,138,162,186,213,241, 14, 45, 79,114,151,190,232, 20, 67,117,169,225, 28, 91,157,227, 46,125,208, 41,134,234, 83,194, 57,182, 58,199, 92,249,160, 81, 13,211,166,133,113,107,116,141,183,242, 64,162, 25,167, 76, 10,226,215,233, 27,110,229,129, 69, 51, 77,151, 19,196,173,210, 54,220,201,  2,138,102,155, 46, 38,136, 90,164,107,184]
  1035.   ubyte[120] priv_freqs_hi = [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  4,  4,  4,  4,  5,  5,  5,  6,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 27, 29, 31, 32, 34, 36, 39, 41, 43, 46, 49, 52, 55, 58, 62, 65, 69, 73, 78, 82, 87, 93, 98,104,110,117,124,131,139,147,156,165]
  1036.  
  1037.   ; voice_num: 0-15, which: 0-119
  1038.   ; returns: the resulting raw frequency value
  1039.   sub key(ubyte voice_num, ubyte which) -> uword {
  1040.     uword freq_full = mkword(priv_freqs_hi[which], priv_freqs_lo[which])
  1041.     psg.freq(voice_num, freq_full)
  1042.     return freq_full
  1043.    
  1044.   }
  1045.  
  1046. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement