Author Topic: PLAY string$ visualizer  (Read 836 times)

0 Members and 1 Guest are viewing this topic.

FellippeHeitor

  • Guest
PLAY string$ visualizer
« on: May 23, 2020, 01:00:41 am »
I mentioned in another thread that I'd written this program but it was lost. I now found it in Pete's forum (dated October 2017): https://www.tapatalk.com/groups/qbasic/viewtopic.php?p=211344#p211344

Here's a copy of the original post I made there:

Hey there,

I'm writing a music visualizer for PLAY string commands. It's still in its infancy, but right now it does the following:

* Parse a string for PLAY commands.
* Draw the notes on screen accordingly, similar to midi sequencing programs out there.
* Mouse wheel (or up/down arrows) can be used to change zoom factor.
* Left/right arrow keys can be used to navigate the rendered "song"
* Click (or spacebar) to play the song.

I have some more plans for this, but for now it's just for fun, really. Hope you guys enjoy it.

I have included some sample songs and sound bits in there. Credit is in the code. Just uncomment the song line you want to visualize/hear.


Code: QB64: [Select]
  1. '--------------------------------------------------------------------
  2. SCREEN _NEWIMAGE(800, 620, 32)
  3. _TITLE "PLAY string$ visualizer"
  4. 'lovestory comes from an old lost .net post
  5. 'gorilla and gorilla2 come from programs/samples/misc/gor64.bas
  6. 'happynewyear, frosty and galleonschord come from the wiki
  7.  
  8.  
  9. REM Uncomment the lines of "PLAY string" below you want to visualize:
  10. gorilla: playString$ = "MBT160O1L8CDEDCDL4ECC"
  11. 'gorilla2: playString$ = "MF t120o1l16b9n0baan0bn0bn0baaan0b9n0baan0b o2l16e-9n0e-d-d-n0e-n0e-n0e-d-d-d-n0e-9n0e-d-d-n0e- o2l16g-9n0g-een0g-n0g-n0g-eeen0g-9n0g-een0g- o2l16b9n0baan0g-n0g-n0g-eeen0o1b9n0baan0b T160O0L32EFGEFDC T160O0L32EFGEFDC T160O0L32EFGEFDC T160O0L32EFGEFDC"
  12. 'galleonschord: playString$ = "v10l1c,l4egl2o5c,o4l4eg"
  13. 'frosty: playString$ = "t140o2p4g2e4.f8g4o3c2o2b8o3c8d4c4o2b4a8g2. o2b8o3c8d4c4o2b4a8a8g8o3c4o2e8e4g8a8g4f4e4f4g2. g2e4.f8g4o3c2o2b8o3c8d4c4o2b4a8g2. o2b8o3c8d4c4o2b4a8a8g8o3c4o2e8e4g8a8g4f4e4d4c2. c4a4a4o3c4c4o2b4a4g4e4f4a4g4f4e2. e8e8d4d4g4g4b4b4o3d4d8o2b8o3d4c4o2b4a4g4p4 g2g2e4.f8g4o3c2o2b8o3c8d4c4o2b4a8g8g2. o2b8o3c8d4c4o2b4a8a8g8o3c4o2e8e4g8a8g4f4e4d4c2.p4 t180g8g8g4g4g4a8g8g4g4g4a4g4e4g4d1 t180g8g8g4g4g4a8g8g4g4g4g8g8g4a4b4o3c2c4p1"
  14. 'lovestory: playString$ = "O2 L8 B- D D B- ML L2 B- L8 B- MN D D B- B- D E- D C C C A ML L2 A L8 A MN C C A A C D C < B- B- B- > G L2 G P8 L8 < B- B- > G G < B- > C < B- A A A > F# ML L2 F# L4 F# MN G A F# ML L2 D D MN P1 L8 B- D D B- ML L2 B- L8 B- MN D D B- B- D E- D C C C A ML L2 A L8 A MN C C A A C D C < B- B- B- > G L2 G P8 L8 < B- B- > G G < B- > C < B- A A A > F# ML L2 F# L4 F# MN G A F# ML L1 B L4 B MN > C D < G > L2 ML E- L8 E- MN < L8 G B- G G A ML L4 A L8 A MN > C E- C ML L2 D L8 D MN < F > D < F F G ML L4 G L8 G MN B- > D < B- > ML L2 C L8 C MN < A > C < A L4 B- L8 B- > D < G B- > D ML L2 E- L8 E- MN < G G B- L4 B- ML A L2 A MN L8 B- > C < E- ML L2 D L8 D MN D E F# L4 A ML L4 G L8 G MN G L8 F# E D ML L2 C# L8 C# MN L8 E G E ML L2 F# F# MN P1 L8 B- D D B- ML L2 B- L8 B- MN D D B- B- D E- D C C C A ML L2 A L8 A MN C C A A C D C < B- B- B- > G L2 G P8 L8 < B- B- > G G < B- > C < B- A A A > F# ML L2 F# L4 F# MN G A F# ML L2 G G MN P1"
  15. 'happynewyear: playString$ = " o3 l4 t 0120c ml<f1 ,a 1, >c 1, mnf .e 8f am l< e1 ,g 1, >c 1, mn g. f8 ga 8g 8m l< f2.,a2., >c 2. ,m nf .f 8a ml<f ,a,>c,mn >cd2.,<f2 .,d2 .,<b -2 .m lb -,>d,f,mn>d ml <c 1, <a 1, f1 ,m n> >c .< a8 af ml c1 ,< e1 ,g 1,m n> g.f8ga8g8m l< f1 ,d1, <b -1 ,m n> >f .d 8d c< f2 ., a2 ., c2 .,>f2. ml < b- ,> d, f, mn>dml <c 1,< a1 ,f 1, mn >> c. <a 8a fm lc 2.,< e2 .,g2 .,mn >g .f8 gml<b-,>d, f, mn >d ml <<f2.,a2., > c2.,m n> c.<a 8a ml <e, g, >c ,m n>cm l< <b -2 ., >d 2. ,f 2.,mn> d2.ml< <b -, >d ,f ,m n>dm l<<f1, a1,>c1,mn >c.<a 8a fmlc 1, <e1,g1,mn>g .f 8g a8 g8ml << b- 1, >d 1, f1 ,mn>f.d8dc l1 ml f, c, <a ,f"
  16.  
  17.  
  18. DIM SHARED noteHeight AS INTEGER
  19. DIM SHARED octave AS SINGLE, noteLength AS SINGLE, length AS SINGLE
  20. DIM SHARED tempo AS SINGLE, note AS SINGLE, volume AS SINGLE
  21. DIM SHARED pause AS SINGLE, pauseBetween AS SINGLE, theresMore AS _BYTE
  22.  
  23. 'defaults:
  24. octave = 4
  25. tempo = 120
  26. pauseBetween = 1
  27. volume = 50
  28. length = 4
  29.  
  30. noteHeight = 7
  31. zoom = 20
  32. maxZoom = 50
  33. reDraw:
  34. playString$ = FormatPlayString$(playString$)
  35. i = 1
  36. x = 1 + leftOffset
  37. DrawGrid
  38.     IF i > LEN(playString$) THEN EXIT DO
  39.     SELECT CASE LCASE$(MID$(playString$, i, 1))
  40.         CASE "c", "d", "e", "f", "g", "a", "b"
  41.             note = FindNote(LCASE$(MID$(playString$, i, 1)))
  42.             noteLength = length
  43.             SELECT CASE LCASE$(MID$(playString$, i + 1, 1))
  44.                 CASE "+", "#"
  45.                     note = note + 1
  46.                 CASE "-"
  47.                     note = note - 1
  48.                 CASE "."
  49.                     IF MID$(playString$, i + 2, 1) = "." THEN
  50.                         i = i + 1
  51.                         noteLength = noteLength + (3 / 4)
  52.                     ELSE
  53.                         noteLength = noteLength + (1 / 2)
  54.                     END IF
  55.                 CASE "0" TO "9"
  56.                     noteLength = GetNumber(playString$, i)
  57.                     SELECT CASE LCASE$(MID$(playString$, i + 1, 1))
  58.                         CASE "."
  59.                             i = i + 1
  60.                             IF LCASE$(MID$(playString$, i + 1, 1)) = "." THEN
  61.                                 i = i + 1
  62.                                 noteLength = noteLength + (3 / 4)
  63.                             ELSE
  64.                                 noteLength = noteLength + (1 / 2)
  65.                             END IF
  66.                     END SELECT
  67.             END SELECT
  68.             SELECT CASE LCASE$(MID$(playString$, i + 1, 1))
  69.                 CASE ","
  70.                     theresMore = -1
  71.                     i = i + 1
  72.             END SELECT
  73.             DrawNote
  74.             'IF NOT theresMore THEN
  75.             ' playstring$ = LEFT$(playstring$, i + 1) + " " + MID$(playstring$, i + 2)
  76.             ' i = i + 1
  77.             'END IF
  78.             theresMore = 0
  79.         CASE "m"
  80.             SELECT CASE LCASE$(MID$(playString$, i + 1, 1))
  81.                 CASE "s"
  82.                     'staccato
  83.                     pauseBetween = 2
  84.                     i = i + 1
  85.                 CASE "n"
  86.                     'normal
  87.                     pauseBetween = 1
  88.                     i = i + 1
  89.                 CASE "l"
  90.                     'legato
  91.                     pauseBetween = 0
  92.                     i = i + 1
  93.                 CASE "f"
  94.                     'foreground play
  95.                     i = i + 1
  96.                 CASE "b"
  97.                     'background play
  98.                     i = i + 1
  99.             END SELECT
  100.         CASE "o"
  101.             octave = GetNumber(playString$, i)
  102.         CASE ">"
  103.             octave = octave + 1
  104.         CASE "<"
  105.             octave = octave - 1
  106.         CASE "t"
  107.             tempo = GetNumber(playString$, i)
  108.         CASE "n"
  109.             note = GetNumber(playString$, i)
  110.             DrawNote
  111.         CASE "p"
  112.             pause = GetNumber(playString$, i)
  113.             noteLength = -pause
  114.             IF noteLength = 0 THEN noteLength = -length
  115.             'playstring$ = LEFT$(playstring$, i) + " " + MID$(playstring$, i + 1)
  116.             'i = i + 1
  117.             DrawNote
  118.         CASE "l"
  119.             length = GetNumber(playString$, i)
  120.         CASE "v"
  121.             volume = GetNumber(playString$, i)
  122.     END SELECT
  123.     i = i + 1
  124. maxDrawnLength = x - leftOffset
  125. LINE (0, 84 * noteHeight + 1)-STEP(_WIDTH - 1, 10), _RGB32(255, 255, 255), B
  126. COLOR _RGB32(233, 211, 94)
  127. _PRINTSTRING (0, _HEIGHT - _FONTHEIGHT * 1.5), "mousewheel (or up/down arrows) to change zoom factor; left/right arrows to scroll; click to play;"
  128.  
  129. prevZoom = zoom
  130.     WHILE _MOUSEINPUT: zoom = zoom + _MOUSEWHEEL: WEND
  131.     IF zoom < 1 THEN zoom = 1
  132.     IF zoom > maxZoom THEN zoom = maxZoom
  133.     IF zoom <> prevZoom THEN prevZoom = zoom: GOTO reDraw
  134.  
  135.         PLAY "MB" + playString$
  136.         WHILE _MOUSEBUTTON(1): i = _MOUSEINPUT: WEND
  137.     END IF
  138.  
  139.     k = _KEYHIT
  140.     SELECT CASE k
  141.         CASE 32
  142.             PLAY "MB" + playString$
  143.             DO: k = _KEYHIT: LOOP UNTIL k = -32
  144.         CASE 19712 'right
  145.             leftOffset = leftOffset - 50
  146.             IF leftOffset < _WIDTH - maxDrawnLength THEN leftOffset = _WIDTH - maxDrawnLength
  147.             GOTO reDraw
  148.         CASE 19200 'left
  149.             leftOffset = leftOffset + 50
  150.             IF leftOffset > 0 THEN leftOffset = 0
  151.             GOTO reDraw
  152.         CASE 18432 'up
  153.             IF zoom < maxZoom THEN zoom = zoom + 1
  154.         CASE 20480 'down
  155.             IF zoom > 1 THEN zoom = zoom - 1
  156.     END SELECT
  157.  
  158. FUNCTION GetNumber# (text$, position%)
  159.     DO
  160.         position% = position% + 1
  161.         IF position% > LEN(text$) THEN EXIT DO
  162.         IF ASC(text$, position%) < 48 OR ASC(text$, position%) > 57 THEN position% = position% - 1: EXIT DO
  163.         tempNum$ = tempNum$ + MID$(text$, position%, 1)
  164.     LOOP
  165.     GetNumber# = VAL(tempNum$)
  166.  
  167. SUB DrawGrid
  168.     LINE (0, 0)-(_WIDTH - 1, 84 * noteHeight), _RGB32(28, 28, 28), BF
  169.     FOR i = 0 TO 83
  170.         LINE (0, i * noteHeight)-STEP(_WIDTH - 1, noteHeight), _RGB32(44, 44, 44), B
  171.     NEXT
  172.  
  173. SUB DrawNote
  174.     i = 83 - note
  175.     IF noteLength < 0 THEN m = -1 ELSE m = 1
  176.     nl = (zoom * zoom) / (noteLength * m)
  177.     IF m > 0 THEN
  178.         LINE (x, i * noteHeight + 1)-STEP(nl, noteHeight - 2), _RGB32(100, 172, 100), BF
  179.         LINE (x, i * noteHeight + 1)-STEP(nl, noteHeight - 2), _RGB32(11, 17, 11), B
  180.         IF theresMore THEN EXIT SUB
  181.     END IF
  182.     x = x + nl + pauseBetween * zoom
  183.  
  184. FUNCTION FindNote (__n$)
  185.     n$ = LCASE$(__n$)
  186.     o% = 33 + (octave - 2) * 12 - 9
  187.     SELECT CASE n$
  188.         CASE "c"
  189.             FindNote = 0 + o%
  190.         CASE "d"
  191.             FindNote = 2 + o%
  192.         CASE "e"
  193.             FindNote = 4 + o%
  194.         CASE "f"
  195.             FindNote = 5 + o%
  196.         CASE "g"
  197.             FindNote = 7 + o%
  198.         CASE "a"
  199.             FindNote = 9 + o%
  200.         CASE "b"
  201.             FindNote = 11 + o%
  202.     END SELECT
  203.  
  204. FUNCTION FormatPlayString$ (__s$)
  205.     s$ = __s$
  206.     FOR i = 1 TO LEN(s$)
  207.         IF ASC(s$, i) <> 32 THEN n$ = n$ + MID$(s$, i, 1)
  208.     NEXT
  209.  
  210.     'remove MF and MB, and convert N0 to P
  211.     s$ = ""
  212.     FOR i = 1 TO LEN(n$)
  213.         IF LCASE$(MID$(n$, i, 2)) = "mf" OR LCASE$(MID$(n$, i, 2)) = "mb" THEN i = i + 1: _CONTINUE
  214.         IF LCASE$(MID$(n$, i, 2)) = "n0" THEN i = i + 1: s$ = s$ + "p": _CONTINUE
  215.         s$ = s$ + MID$(n$, i, 1)
  216.     NEXT
  217.  
  218.     FormatPlayString$ = s$
  219. '--------------------------------------------------------------------
« Last Edit: May 23, 2020, 01:02:39 am by FellippeHeitor »