Author Topic: Drum Machine Prototype by Dav  (Read 129 times)

Offline Qwerkey

  • Moderator
  • Forum Resident
  • Posts: 655
Drum Machine Prototype by Dav
« on: May 08, 2020, 04:40:58 AM »
Drum Machine Prototype

Author: @Dav
Source: qb64.org Forum
URL: https://www.qb64.org/forum/index.php?topic=2459.msg117923#msg117923
Version: v0.1c
Tags: [Music], [Graphics]

Description:
Here's a drum machine, or beat maker.  I started making another puzzle game, but it turned into a little music making program instead.   With this you can make drum beats using 14 drum instrument samples.

Controls:
L Load Pattern
S Save Pattern
M Toggle Metronome

Source Code:
The code is given here for reference.  You will need to load all the files from the .zip.
Code: QB64: [Select]
  1. '=======================
  2. 'DRUMMACHINE.BAS - v0.1c
  3. '=======================
  4. 'QB64 Drum machine
  5. 'Make drum beats using 16 drum sounds.
  6. 'Coded by Dav for QB64, MAY/2020
  7.  
  8. 'Follow this programs development here:
  9. 'https://www.qb64.org/forum/index.php?topic=2459.0
  10.  
  11. '===================================================================
  12. 'New in v0.1c...
  13.  
  14. 'Added: Added program _TITLE and _ICON.
  15. 'Added: New logo with keyboard command help.
  16. 'Added: Shows big TEMPO (BMP) font at top left.
  17. 'Added: Shows green playing position line down grid.
  18. '       (replaced little white moving marker)
  19. 'Added: Give user notices when a Save/Load is done.
  20. 'Added: Instrument names can now be clicked on to mute/unmute.
  21. 'Added: Now shows on screen if metronome is ON/OFF
  22. 'Fixed: Changed keyboard input method. Much more responsive.
  23. '
  24. '===================================================================
  25. ''NOTE: You need "\drummachine-data\" and all of its data files!
  26. '===================================================================
  27.  
  28. '=====
  29. 'ABOUT:
  30. '=====
  31.  
  32. 'This is a very basic drum machine with limited capabilities.
  33. 'With it you can program beats (limited to 2 bars of 4/4 now).
  34. 'It uses 16 real drum sounds to make a real sound drum beat.
  35. 'Drum patterns can be saved and loaded by file DRUMMACHINE.SAV.
  36. 'I just wanted to see if QB64 can handle something like this,
  37. 'and it looks like it can.  So a more serious program can be tackled.
  38. 'The real drum sound samples were all found in public domain.
  39.  
  40. '==========
  41. 'HOW TO USE:
  42. '==========
  43.  
  44. 'The grid represents bars and notes that you can click on.
  45. 'Click on squares in a row to to add sound for that beat.
  46. 'Click an square again to turn it back off or change it's volume.
  47. 'A bright red square is loudest, a darker red is softer volume.
  48.  
  49. 'Click on the instrument name on left screen to mute/unmute it.
  50.  
  51. 'The following keys can be used as well:
  52.  
  53. '* +/- keys:  Speeds up and slow down tempo (shown upper left)
  54. '* SPACE key: Will pause and resume the playback.
  55. '* ENTER:     Resets current playback marker to the beginning.
  56. '* M:         Turns on/off metonome click sound (default is on)
  57. '* C:         Clears the playing grid (starts over).
  58. '* L:         Loads last saved grid pattern from DRUMMACHINE.SAV
  59. '* S:         Saves current grid pattern to DRUMMACHINE.SAV.
  60. '* D:         Enters drawing mode (fast filling of boxes.
  61. '             (While in it, enter ESC to exit drawing mode)
  62. '* ESC:       Exits program. DOES NOT ATUMATICALLY SAVE ON EXIT.
  63.  
  64. '======================================================================
  65.  
  66. $EXEICON:'.\drummachine-data\icon.ico'
  67.  
  68. 'define playing grid and button deminsions
  69. DIM SHARED row: row = 16 'rows in playing grid
  70. DIM SHARED col: col = 8 * 4 'columns in grid (8 beats, 4 boxes per beat)
  71. DIM SHARED size: size = 30 ' pixel size of buttons
  72. DIM SHARED buttons: buttons = row * col ' total number of buttons on playing grid
  73.  
  74. 'define button data
  75. DIM SHARED buttonv(row * col) ' num data for button
  76. DIM SHARED buttonx(row * col), buttony(row * col) 'top x/y cords of buttons
  77. DIM SHARED buttonx2(row * col), buttony2(row * col) ' bottom x/y cords of buttons
  78.  
  79. 'define intrument name data
  80. DIM SHARED instv(row * col) 'value for is intrument on or off
  81. DIM SHARED instx(row * col), insty(row * col) 'top x/y cords of instr names
  82.  
  83. 'share these sound files
  84. DIM SHARED crash&, crash2&, ride&, ride2&, hhopen&, hhclosed&, snare&, kick&, tamb&, gong2&
  85. DIM SHARED tomhigh&, tommid&, tomlow&, cowbell&, shaker&, gong&, vibraslap&, vibraslap2&
  86. DIM SHARED clave&, trianglelong&, triangleshort&
  87.  
  88. '====================================================
  89.  
  90. 'Set screen based on grid deminsions
  91.  
  92. SCREEN _NEWIMAGE(size * col + 100, size * row + 100, 32)
  93. DO: LOOP UNTIL _SCREENEXISTS 'Make sure window exists before TITLE used.
  94.  
  95. _TITLE "QB64 Drum Machine"
  96.  
  97. '===================================================
  98.  
  99. CLS , _RGB(42, 42, 42)
  100.  
  101. 'Load title top area.
  102. ttmp = _LOADIMAGE("drummachine-data\title.png")
  103. _PUTIMAGE (5, 5), ttmp: _FREEIMAGE ttmp
  104.  
  105. 'Load media sounds used
  106. click& = _SNDOPEN("drummachine-data\click.ogg")
  107. hhopen& = _SNDOPEN("drummachine-data\hhopen.ogg")
  108. hhclosed& = _SNDOPEN("drummachine-data\hhclosed.ogg")
  109. kick& = _SNDOPEN("drummachine-data\kick.ogg")
  110. snare& = _SNDOPEN("drummachine-data\snare.ogg")
  111. crash& = _SNDOPEN("drummachine-data\crash.ogg")
  112. crash2& = _SNDOPEN("drummachine-data\crash.ogg")
  113. ride& = _SNDOPEN("drummachine-data\ride.ogg")
  114. ride2& = _SNDOPEN("drummachine-data\ride.ogg")
  115. tomhigh& = _SNDOPEN("drummachine-data\tomhigh.ogg")
  116. tommid& = _SNDOPEN("drummachine-data\tommid.ogg")
  117. tomlow& = _SNDOPEN("drummachine-data\tomlow.ogg")
  118. cowbell& = _SNDOPEN("drummachine-data\cowbell.ogg")
  119. shaker& = _SNDOPEN("drummachine-data\shaker.ogg")
  120. vibraslap& = _SNDOPEN("drummachine-data\vibraslap.ogg")
  121. gong& = _SNDOPEN("drummachine-data\gong.ogg")
  122. vibraslap2& = _SNDOPEN("drummachine-data\vibraslap.ogg")
  123. gong2& = _SNDOPEN("drummachine-data\gong.ogg")
  124. tamb& = _SNDOPEN("drummachine-data\tamb.ogg")
  125. clave& = _SNDOPEN("drummachine-data\clave.ogg")
  126. trianglelong& = _SNDOPEN("drummachine-data\trianglelong.ogg")
  127. triangleshort& = _SNDOPEN("drummachine-data\triangleshort.ogg")
  128.  
  129. 'Load special number font images fro BMP display
  130. DIM SHARED num&(0 TO 9)
  131. FOR t = 0 TO 9
  132.     n$ = LTRIM$(RTRIM$(STR$(t)))
  133.     num&(t) = _LOADIMAGE("drummachine-data\font\" + n$ + ".png")
  134.  
  135.  
  136. '===================================================
  137.  
  138. 'Set program defaults
  139.  
  140. beats = 8 'number of beats in pattern
  141. tempo = 80 'tempo of drum pattern
  142. curbeat = 1 'start at bar 1
  143. clickon = 1 'turn on click sound, on the beat
  144. playing = 1 'Pattern is playing
  145. firstlaunch = 1 'flag to know when program first launches
  146.  
  147.  
  148. '=========================================================
  149. START:
  150. '========
  151.  
  152. 'Init the grids button values (x/y, data)
  153. bc = 1 'counter
  154. FOR r = 1 TO row
  155.     FOR c = 1 TO col
  156.         x = (c * size) + 100: y = (r * size) + 100
  157.         buttonx(bc) = x - size: buttonx2(bc) = x ' generate x/y values
  158.         buttony(bc) = y - size: buttony2(bc) = y
  159.         buttonv(bc) = 0 'default button is OFF
  160.         bc = bc + 1
  161.     NEXT
  162.  
  163. 'Show metronome on/off
  164. Metronome clickon
  165.  
  166. 'Show the grid buttons
  167. bc = 1
  168. FOR r = 1 TO row
  169.     FOR c = 1 TO col
  170.         Show "drummachine-data\off.jpg", buttonx(bc), buttony(bc), 0
  171.         bc = bc + 1
  172.     NEXT
  173.  
  174.  
  175. 'Draw beat lines, every 4 squares ...
  176. bc = 1
  177. FOR c = 1 TO col STEP 4
  178.     LINE (buttonx(bc), buttony(bc))-(buttonx(bc), buttony(bc) + (size * row)), _RGB(128, 128, 0), B
  179.     bc = bc + 4
  180.  
  181. '====================================
  182.  
  183. 'Init Instrument name data
  184. FOR c = 1 TO 16
  185.     instv(c) = 1 'all instruments on by default
  186. bc = 1
  187. FOR c = 1 TO col * row STEP col
  188.     instx(bc) = 0: insty(bc) = 70 + (bc * 30)
  189.     bc = bc + 1
  190. 'show the nstrument names
  191. FOR c = 1 TO 16
  192.     ShowInst c, instx(c), insty(c)
  193.  
  194. '==============================================
  195.  
  196. 'Show current TEMPO (BMP) on upper left
  197. FPRINT 140, 15, 20, 40, LTRIM$(RTRIM$(STR$(tempo)))
  198.  
  199. '================================================
  200.  
  201. 'If firstlaunch, load the saved pattern file
  202. IF firstlaunch = 1 THEN
  203.     firstlaunch = 0
  204.     GOSUB loadfile
  205.  
  206. '============================================================
  207.  
  208. MAIN:
  209. '=====
  210.  
  211. 'Main Loop here
  212.  
  213.     GOSUB GetUserInput
  214.  
  215.     IF playing THEN
  216.  
  217.         IF clickon THEN
  218.             SELECT CASE curbeat
  219.                 CASE 1, 2, 3, 4, 5, 6, 7, 8: _SNDPLAY click&
  220.             END SELECT
  221.         END IF
  222.  
  223.         IF curbeat = 1 THEN PlayBeat (1)
  224.         IF curbeat = 1.25 THEN PlayBeat (2)
  225.         IF curbeat = 1.50 THEN PlayBeat (3)
  226.         IF curbeat = 1.75 THEN PlayBeat (4)
  227.         IF curbeat = 2 THEN PlayBeat (5)
  228.         IF curbeat = 2.25 THEN PlayBeat (6)
  229.         IF curbeat = 2.50 THEN PlayBeat (7)
  230.         IF curbeat = 2.75 THEN PlayBeat (8)
  231.         IF curbeat = 3 THEN PlayBeat (9)
  232.         IF curbeat = 3.25 THEN PlayBeat (10)
  233.         IF curbeat = 3.50 THEN PlayBeat (11)
  234.         IF curbeat = 3.75 THEN PlayBeat (12)
  235.         IF curbeat = 4 THEN PlayBeat (13)
  236.         IF curbeat = 4.25 THEN PlayBeat (14)
  237.         IF curbeat = 4.50 THEN PlayBeat (15)
  238.         IF curbeat = 4.75 THEN PlayBeat (16)
  239.         IF curbeat = 5 THEN PlayBeat (17)
  240.         IF curbeat = 5.25 THEN PlayBeat (18)
  241.         IF curbeat = 5.50 THEN PlayBeat (19)
  242.         IF curbeat = 5.75 THEN PlayBeat (20)
  243.         IF curbeat = 6 THEN PlayBeat (21)
  244.         IF curbeat = 6.25 THEN PlayBeat (22)
  245.         IF curbeat = 6.50 THEN PlayBeat (23)
  246.         IF curbeat = 6.75 THEN PlayBeat (24)
  247.         IF curbeat = 7 THEN PlayBeat (25)
  248.         IF curbeat = 7.25 THEN PlayBeat (26)
  249.         IF curbeat = 7.50 THEN PlayBeat (27)
  250.         IF curbeat = 7.75 THEN PlayBeat (28)
  251.         IF curbeat = 8 THEN PlayBeat (29)
  252.         IF curbeat = 8.25 THEN PlayBeat (30)
  253.         IF curbeat = 8.50 THEN PlayBeat (31)
  254.         IF curbeat = 8.75 THEN PlayBeat (32)
  255.  
  256.         curbeat = curbeat + .25
  257.         IF curbeat > beats + .75 THEN curbeat = 1
  258.  
  259.         'Delay routine, based on TEMP
  260.         d1 = TIMER
  261.         DO
  262.             d2 = TIMER
  263.  
  264.             'still get user input while delaying....
  265.             GOSUB GetUserInput
  266.  
  267.         LOOP UNTIL d2 - d1 >= (60 / 4 / tempo)
  268.  
  269.     END IF
  270.  
  271.  
  272. '===============================
  273.  
  274. EndProgram:
  275.  
  276. _SNDCLOSE click&
  277. _SNDCLOSE hhopen&
  278. _SNDCLOSE hhclosed&
  279. _SNDCLOSE kick&
  280. _SNDCLOSE snare&
  281. _SNDCLOSE crash&
  282. _SNDCLOSE crash2&
  283. _SNDCLOSE ride&
  284. _SNDCLOSE ride2&
  285. _SNDCLOSE tomhigh&
  286. _SNDCLOSE tommid&
  287. _SNDCLOSE tomlow&
  288. _SNDCLOSE cowbell&
  289. _SNDCLOSE shaker&
  290. _SNDCLOSE vibraslap&
  291. _SNDCLOSE gong&
  292. _SNDCLOSE vibraslap2&
  293. _SNDCLOSE gong2&
  294. _SNDCLOSE tamb&
  295. _SNDCLOSE clave&
  296. _SNDCLOSE trianglelong&
  297. _SNDCLOSE triangleshort&
  298.  
  299.  
  300.  
  301.  
  302. '================================================
  303. GetUserInput:
  304. '============
  305.  
  306.  
  307. 'if left mouse button clicked
  308.  
  309.     mx = _MOUSEX: my = _MOUSEY 'current mouse position
  310.  
  311.     'see if a grid button was pressed
  312.     FOR t = 1 TO buttons
  313.         bx = buttonx(t): bx2 = buttonx2(t)
  314.         by = buttony(t): by2 = buttony2(t)
  315.  
  316.         'If clicked on a grid button...
  317.         IF mx >= bx AND mx <= bx2 AND my >= by AND my <= by2 THEN
  318.             IF _MOUSEBUTTON(1) THEN
  319.  
  320.                 'change its value...
  321.                 buttonv(t) = buttonv(t) + 1
  322.                 IF buttonv(t) > 2 THEN buttonv(t) = 0
  323.                 'LOCATE 1, 1: PRINT t   'for testing purposes...
  324.                 SELECT CASE buttonv(t)
  325.                     CASE 0: Show "drummachine-data\off.jpg", buttonx(t), buttony(t), 0
  326.                     CASE 1: Show "drummachine-data\hot.jpg", buttonx(t), buttony(t), 0
  327.                     CASE 2: Show "drummachine-data\med.jpg", buttonx(t), buttony(t), 0
  328.                 END SELECT
  329.             ELSE
  330.                 buttonv(t) = 0
  331.                 Show "drummachine-data\off.jpg", buttonx(t), buttony(t), 0
  332.             END IF
  333.  
  334.         END IF
  335.     NEXT
  336.  
  337.     'see if a instrument name was pressed
  338.     FOR t = 1 TO 16
  339.         bx = instx(t): bx2 = instx(t) + 100
  340.         by = insty(t): by2 = insty(t) + 30
  341.  
  342.         'If clicked on an instrument name...
  343.         IF mx >= bx AND mx <= bx2 AND my >= by AND my <= by2 THEN
  344.             IF _MOUSEBUTTON(1) THEN
  345.  
  346.                 'change its value...
  347.                 instv(t) = instv(t) + 1
  348.                 IF instv(t) > 1 THEN instv(t) = 0
  349.                 'redraw instrument name here
  350.                 ShowInst t, instx(t), insty(t)
  351.             END IF
  352.  
  353.         END IF
  354.     NEXT
  355.  
  356.  
  357.         'wait until mouse button up to continue
  358.         WHILE _MOUSEBUTTON(1) <> 0: n = _MOUSEINPUT: WEND
  359.     END IF
  360.  
  361.  
  362.  
  363. 'check is user made a keypress
  364.  
  365.  
  366.     CASE "D": 'd enters drawing mode
  367.         DO
  368.             trap = _MOUSEINPUT
  369.             IF _MOUSEBUTTON(1) OR _MOUSEBUTTON(2) THEN
  370.                 mx = _MOUSEX: my = _MOUSEY
  371.                 'see if a button was pressed
  372.                 FOR t = 1 TO buttons
  373.                     bx = buttonx(t): bx2 = buttonx2(t)
  374.                     by = buttony(t): by2 = buttony2(t)
  375.                     IF mx >= bx AND mx <= bx2 AND my >= by AND my <= by2 THEN
  376.                         IF _MOUSEBUTTON(1) THEN
  377.                             buttonv(t) = 1
  378.                             Show "drummachine-data\hot.jpg", buttonx(t), buttony(t), 0
  379.                         ELSE
  380.                             buttonv(t) = 0
  381.                             Show "drummachine-data\off.jpg", buttonx(t), buttony(t), 0
  382.                         END IF
  383.                     END IF
  384.                 NEXT
  385.             END IF
  386.         LOOP UNTIL INKEY$ = CHR$(27)
  387.  
  388.     CASE "C": GOTO START 'C clears playing grid, starts over
  389.  
  390.     CASE "S": 's = saves current pattern to file
  391.         backtmp& = _COPYIMAGE(_DISPLAY)
  392.         f$ = "drummachine-data\savingpattern.png"
  393.         ttmp = _LOADIMAGE(f$)
  394.         _PUTIMAGE (350, 250), ttmp: _FREEIMAGE ttmp
  395.         _DELAY 1
  396.         OPEN "drummachine.sav" FOR OUTPUT AS #3
  397.         PRINT #3, MKI$(tempo);
  398.         PRINT #3, MKI$(buttons);
  399.         FOR fs = 1 TO buttons
  400.             PRINT #3, MKI$(buttonv(fs));
  401.         NEXT
  402.         CLOSE #3
  403.         _PUTIMAGE (0, 0), backtmp&
  404.  
  405.     CASE "L"
  406.         backtmp& = _COPYIMAGE(_DISPLAY)
  407.         f$ = "drummachine-data\loadingpattern.png"
  408.         ttmp = _LOADIMAGE(f$)
  409.         _PUTIMAGE (350, 250), ttmp: _FREEIMAGE ttmp
  410.         _DELAY .5
  411.         _PUTIMAGE (0, 0), backtmp&
  412.         GOSUB loadfile
  413.  
  414.     CASE " " 'SPACE pauses and resumes playing
  415.         IF playing = 1 THEN
  416.             playing = 0
  417.         ELSE
  418.             playing = 1
  419.         END IF
  420.  
  421.     CASE CHR$(13) 'ENTER resets marker to beginning
  422.         'erase all marker positions
  423.         FOR e = 1 TO 32
  424.             SELECT CASE e
  425.                 CASE 1, 5, 9, 13, 17, 21, 25, 29
  426.                     LINE (buttonx(e), buttony(e))-(buttonx(e), buttony(e) + (size * row)), _RGB(128, 128, 0), B
  427.                 CASE ELSE
  428.                     LINE (buttonx(e), buttony(e))-(buttonx(e), buttony(e) + (size * row)), _RGB(0, 0, 0), B
  429.             END SELECT
  430.         NEXT
  431.         LINE (buttonx(1), buttony(1))-(buttonx(1), buttony(1) + (size * row)), _RGB(0, 255, 128), B
  432.         curbeat = 1: GOTO MAIN
  433.  
  434.     CASE "M" 'm = turn metronome click on/off
  435.         IF clickon = 1 THEN
  436.             clickon = 0
  437.         ELSE
  438.             clickon = 1
  439.         END IF
  440.         Metronome clickon
  441.  
  442.     CASE "+": tempo = tempo + 1: IF tempo > 280 THEN tempo = 280
  443.         FPRINT 140, 15, 20, 40, LTRIM$(RTRIM$(STR$(tempo)))
  444.  
  445.     CASE "-": tempo = tempo - 1: IF tempo < 40 THEN tempo = 40
  446.         FPRINT 140, 15, 20, 40, LTRIM$(RTRIM$(STR$(tempo)))
  447.     CASE CHR$(27): GOTO EndProgram
  448.  
  449.  
  450.  
  451.  
  452. '=================================================================
  453.  
  454. loadfile: 'Loads pattern from save file
  455. '=======
  456.  
  457. fil$ = "drummachine.sav"
  458.     OPEN fil$ FOR BINARY AS #3
  459.     IF LOF(3) <= 1028 THEN
  460.         tempo = CVI(INPUT$(2, 3))
  461.         bb = CVI(INPUT$(2, 3))
  462.         FOR b = 1 TO bb
  463.             buttonv(b) = CVI(INPUT$(2, 3))
  464.             SELECT CASE buttonv(b)
  465.                 CASE 0: Show "drummachine-data\off.jpg", buttonx(b), buttony(b), 0
  466.                 CASE 1: Show "drummachine-data\hot.jpg", buttonx(b), buttony(b), 0
  467.                 CASE 2: Show "drummachine-data\med.jpg", buttonx(b), buttony(b), 0
  468.             END SELECT
  469.         NEXT
  470.         CLOSE 3
  471.         'Show current TEMPO (BMP) on upper left
  472.         FPRINT 140, 15, 20, 40, LTRIM$(RTRIM$(STR$(tempo)))
  473.         GOTO MAIN
  474.     ELSE
  475.         CLOSE 3
  476.         'print error message here
  477.     END IF
  478.  
  479.  
  480. '========================================================
  481.  
  482. SUB Show (nam$, x, y, dly)
  483.     'Loads & puts image filename img$ on screen at x,y
  484.     'dly is optional delay after putting image on screen
  485.     'SUB frees up image handle after loading file.
  486.     ttmp = _LOADIMAGE(nam$)
  487.     _PUTIMAGE (x + 1, y + 1)-(x - 1 + size - 1, y - 1 + size - 1), ttmp: _FREEIMAGE ttmp
  488.     IF dly <> 0 THEN _DELAY dly
  489.  
  490. '===============================================
  491.  
  492. SUB ShowInst (num, x, y)
  493.     'This SUB loads the instrumet name image files
  494.     src$ = "drummachine-data\"
  495.     IF instv(num) = 1 THEN pre$ = "_" ELSE pre$ = ""
  496.     IF num = 1 THEN n$ = pre$ + "crash.png"
  497.     IF num = 2 THEN n$ = pre$ + "ride.png"
  498.     IF num = 3 THEN n$ = pre$ + "hhopen.png"
  499.     IF num = 4 THEN n$ = pre$ + "hhclosed.png"
  500.     IF num = 5 THEN n$ = pre$ + "tomhigh.png"
  501.     IF num = 6 THEN n$ = pre$ + "tommid.png"
  502.     IF num = 7 THEN n$ = pre$ + "tomlow.png"
  503.     IF num = 8 THEN n$ = pre$ + "snare.png"
  504.     IF num = 9 THEN n$ = pre$ + "kick.png"
  505.     IF num = 10 THEN n$ = pre$ + "cowbell.png"
  506.     IF num = 11 THEN n$ = pre$ + "shaker.png"
  507.     IF num = 12 THEN n$ = pre$ + "tambourine.png"
  508.     IF num = 13 THEN n$ = pre$ + "vibraslap.png"
  509.     IF num = 14 THEN n$ = pre$ + "gong.png"
  510.     IF num = 15 THEN n$ = pre$ + "triangle.png"
  511.     IF num = 16 THEN n$ = pre$ + "clave.png"
  512.  
  513.     fil$ = src$ + n$
  514.     ttmp = _LOADIMAGE(fil$)
  515.     _PUTIMAGE (x, y), ttmp: _FREEIMAGE ttmp
  516.  
  517. '===============================================
  518.  
  519. SUB PlayBeat (num)
  520.     'This SUB plays the sounds on current beat position.
  521.     'It also shows the playing marker moving across the grid
  522.  
  523.     'erase previous marker pos displayed first, and redraw the 4 beat lines...
  524.     IF num = 1 THEN
  525.         'erase the end playing position on grid
  526.         LINE (buttonx(col), buttony(col))-(buttonx(col), buttony(col) + (size * row)), _RGB(0, 0, 0), B
  527.     ELSE
  528.         'erase the last beat position
  529.         LINE (buttonx(num - 1), buttony(num - 1))-(buttonx(num - 1), buttony(num - 1) + (size * row)), _RGB(0, 0, 0), B
  530.         'if last position was one of the 4 beat lines, redraw it
  531.         SELECT CASE (num - 1)
  532.             CASE 1, 5, 9, 13, 17, 21, 25, 29
  533.                 LINE (buttonx(num - 1), buttony(num - 1))-(buttonx(num - 1), buttony(num - 1) + (size * row)), _RGB(128, 128, 0), B
  534.         END SELECT
  535.     END IF
  536.  
  537.     'Show curreny marker position
  538.     'Now Draw current playing position beat line
  539.     LINE (buttonx(num), buttony(num))-(buttonx(num), buttony(num) + (size * row)), _RGB(0, 255, 128), B
  540.  
  541.     'Play sounds on the current beat position, if inst not muted
  542.     'play crash
  543.     IF instv(1) = 1 THEN
  544.         IF buttonv(num) = 1 THEN _SNDVOL crash&, 6: _SNDPLAY crash& '1
  545.         IF buttonv(num) = 2 THEN _SNDVOL crash2&, .2: _SNDPLAY crash2& '1
  546.     END IF
  547.     'play ride
  548.     IF instv(2) = 1 THEN
  549.         IF buttonv(num + (col * 1)) = 1 THEN _SNDVOL ride&, 5: _SNDPLAY ride& '2
  550.         IF buttonv(num + (col * 1)) = 2 THEN _SNDVOL ride2&, .2: _SNDPLAY ride2& '2
  551.     END IF
  552.     'play hhopen
  553.     IF instv(3) = 1 THEN
  554.         IF buttonv(num + (col * 2)) = 1 THEN _SNDSETPOS hhopen&, 0: _SNDVOL hhopen&, 5: _SNDPLAY hhopen& '3
  555.         IF buttonv(num + (col * 2)) = 2 THEN _SNDSETPOS hhopen&, 0: _SNDVOL hhopen&, .15: _SNDPLAY hhopen& '3
  556.     END IF
  557.     'play hhclosed
  558.     IF instv(4) = 1 THEN
  559.         IF buttonv(num + (col * 3)) = 1 THEN _SNDSTOP hhopen&: _SNDVOL hhclosed&, 1: _SNDPLAY hhclosed& '4
  560.         IF buttonv(num + (col * 3)) = 2 THEN _SNDSTOP hhopen&: _SNDVOL hhclosed&, .2: _SNDPLAY hhclosed& '4
  561.     END IF
  562.     'play tom high
  563.     IF instv(5) THEN
  564.         IF buttonv(num + (col * 4)) = 1 THEN _SNDVOL tomhigh&, 9: _SNDPLAY tomhigh& '5
  565.         IF buttonv(num + (col * 4)) = 2 THEN _SNDVOL tomhigh&, .1: _SNDPLAY tomhigh& '5
  566.     END IF
  567.     'play tom mid
  568.     IF instv(6) THEN
  569.         IF buttonv(num + (col * 5)) = 1 THEN _SNDVOL tommid&, 9: _SNDPLAY tommid& '6
  570.         IF buttonv(num + (col * 5)) = 2 THEN _SNDVOL tommid&, .1: _SNDPLAY tommid& '6
  571.     END IF
  572.     'play tom low
  573.     IF instv(7) THEN
  574.         IF buttonv(num + (col * 6)) = 1 THEN _SNDVOL tomlow&, 9: _SNDPLAY tomlow& '7
  575.         IF buttonv(num + (col * 6)) = 2 THEN _SNDVOL tomlow&, .1: _SNDPLAY tomlow& '7
  576.     END IF
  577.     'play snare
  578.     IF instv(8) THEN
  579.         IF buttonv(num + (col * 7)) = 1 THEN _SNDVOL snare&, 1: _SNDPLAY snare& '8
  580.         IF buttonv(num + (col * 7)) = 2 THEN _SNDVOL snare&, .1: _SNDPLAY snare& '8
  581.     END IF
  582.     'play kick
  583.     IF instv(9) THEN
  584.         IF buttonv(num + (col * 8)) = 1 THEN _SNDVOL kick&, 1: _SNDPLAY kick& '9
  585.         IF buttonv(num + (col * 8)) = 2 THEN _SNDVOL kick&, .1: _SNDPLAY kick& '9
  586.     END IF
  587.     'play cowbell
  588.     IF instv(10) THEN
  589.         IF buttonv(num + (col * 9)) = 1 THEN _SNDVOL cowbell&, .3: _SNDPLAY cowbell& '10
  590.         IF buttonv(num + (col * 9)) = 2 THEN _SNDVOL cowbell&, .02: _SNDPLAY cowbell& '10
  591.     END IF
  592.     'play shaker
  593.     IF instv(11) THEN
  594.         IF buttonv(num + (col * 10)) = 1 THEN _SNDVOL shaker&, .6: _SNDPLAY shaker& '11
  595.         IF buttonv(num + (col * 10)) = 2 THEN _SNDVOL shaker&, .1: _SNDPLAY shaker& '11
  596.     END IF
  597.     'play tambourine
  598.     IF instv(12) THEN
  599.         IF buttonv(num + (col * 11)) = 1 THEN _SNDVOL tamb&, 1: _SNDPLAY tamb& '12
  600.         IF buttonv(num + (col * 11)) = 2 THEN _SNDVOL tamb&, .1: _SNDPLAY tamb& '12
  601.     END IF
  602.     'play vibraslap
  603.     IF instv(13) THEN
  604.         IF buttonv(num + (col * 12)) = 1 THEN _SNDVOL vibraslap&, .1: _SNDPLAY vibraslap& '13
  605.         IF buttonv(num + (col * 12)) = 2 THEN _SNDVOL vibraslap2&, .05: _SNDPLAY vibraslap2& '13
  606.     END IF
  607.     'play gong
  608.     IF instv(14) THEN
  609.         IF buttonv(num + (col * 13)) = 1 THEN _SNDVOL gong&, .1: _SNDPLAY gong& '14
  610.         IF buttonv(num + (col * 13)) = 2 THEN _SNDVOL gong2&, .03: _SNDPLAY gong2& '14
  611.     END IF
  612.     'play triangle
  613.     IF instv(15) THEN
  614.         IF buttonv(num + (col * 14)) = 1 THEN _SNDVOL trianglelong&, .3: _SNDPLAY trianglelong& '15
  615.         IF buttonv(num + (col * 14)) = 2 THEN _SNDVOL triangleshort&, .3: _SNDPLAY triangleshort& '15
  616.     END IF
  617.     'play clave
  618.     IF instv(16) THEN
  619.         IF buttonv(num + (col * 15)) = 1 THEN _SNDVOL clave&, .6: _SNDPLAY clave& '16
  620.         IF buttonv(num + (col * 15)) = 2 THEN _SNDVOL clave&, .02: _SNDPLAY clave& '16
  621.     END IF
  622.  
  623. SUB FPRINT (x, y, xsize, ysize, num$)
  624.     LINE (x, y)-(x + 100, y + ysize), _RGB(42, 42, 42), BF
  625.     FOR t = 1 TO LEN(num$)
  626.         n = VAL(MID$(num$, t, 1))
  627.         _PUTIMAGE (x, y)-(x + xsize, y + ysize), num&(n)
  628.         x = x + xsize: y = y + zsize
  629.     NEXT
  630.  
  631. SUB Metronome (way)
  632.     IF way = 1 THEN
  633.         f$ = "drummachine-data\metron.png"
  634.     ELSE
  635.         f$ = "drummachine-data\metroff.png"
  636.     END IF
  637.     ttmp = _LOADIMAGE(f$)
  638.     _PUTIMAGE (875, 72), ttmp: _FREEIMAGE ttmp
  639.