Author Topic: Next one Music Visualizer  (Read 1292 times)

0 Members and 1 Guest are viewing this topic.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Next one Music Visualizer
« on: March 12, 2022, 12:49:01 pm »
Hi. This program try generate terrain (not smooth) using music file.

Do not forget overwriting your sound file name on row 17 in this source code.

Code: QB64: [Select]
  1. Texture = NewImage(255, 255, 32)
  2. Dest Texture
  3. Cls , &HFFFF0000
  4. For diY = 0 To 100
  5.     Line (diY + 20, diY + 20)-(235 - diY, 235 - diY), RGB32(diY, 0, 0), B
  6. Dest 0
  7. Dim As Long SND, Position, FillCachem, HT
  8. Dim As Float IL, IR, IntensityLeft, IntensityRight
  9. Dim As MEM L, R
  10. Dim As Unsigned Byte Rc, Gc, Bc
  11. ReDim LightsL(10) As Unsigned Byte
  12. ReDim LightsR(10) As Unsigned Byte
  13. Dim M3D(90, 90) As Single
  14. Dim M2D(90, 90) As Single
  15. SND = SndOpen("bb.mp3") '            <-----------------  insert here your sound file name!
  16. VOL = 10
  17. SndVol SND, VOL / 20
  18. L = MemSound(SND, 1)
  19. R = MemSound(SND, 2)
  20. DW = DesktopWidth
  21. DH = DesktopHeight
  22. HT = CopyImage(Texture, 33)
  23. FreeImage Texture
  24. Screen NewImage(DW, DH, 32)
  25. FullScreen
  26. SndPlay SND
  27. Do Until Position >= L.SIZE - 8192
  28.     ShiftIt = 89
  29.     Do Until ShiftIt < 0
  30.         For rows = 0 To 90
  31.             Swap M3D(rows, ShiftIt), M3D(rows, ShiftIt + 1)
  32.             Swap M2D(rows, ShiftIt), M2D(rows, ShiftIt + 1)
  33.         Next
  34.         ShiftIt = ShiftIt - 1
  35.     Loop
  36.     Depth = 0
  37.     Do Until Depth = 90000
  38.         If Depth + Position > L.SIZE Then End
  39.         M3D(ra, 0) = MemGet(L, L.OFFSET + Position + Depth, Integer) / 32768 * 1.7
  40.         M2D(ra, 0) = MemGet(R, R.OFFSET + Position + Depth, Integer) / 32768 * 1.7
  41.         Depth = Depth + 1000
  42.         ra = ra + 1
  43.     Loop
  44.     ra = 0
  45.     For Z = 0 To 89
  46.         For X = 0 To 89
  47.             HX = -45 + X
  48.             HX2 = HX + 1
  49.             HZ = -89 + Z
  50.             HZ2 = HZ + 1
  51.             HY1 = -3 + M3D(X, Z): HY2 = -3 + M3D(X + 1, Z): HY3 = -3 + M3D(X, Z + 1): HY4 = -3 + M3D(X + 1, Z + 1)
  52.             HY11 = 3 - M2D(X, Z): HY12 = 3 - M2D(X + 1, Z): HY13 = 3 - M2D(X, Z + 1): HY14 = 3 - M2D(X + 1, Z + 1)
  53.             MapTriangle (0, 0)-(255, 0)-(0, 255), HT To(HX, HY1, HZ)-(HX2, HY2, HZ)-(HX, HY3, HZ2), 0, Smooth
  54.             MapTriangle (255, 0)-(0, 255)-(255, 255), HT To(HX2, HY2, HZ)-(HX, HY3, HZ2)-(HX2, HY4, HZ2), 0, Smooth
  55.             MapTriangle (0, 0)-(255, 0)-(0, 255), HT To(HX, HY11, HZ)-(HX2, HY12, HZ)-(HX, HY13, HZ2), 0, Smooth
  56.             MapTriangle (255, 0)-(0, 255)-(255, 255), HT To(HX2, HY12, HZ)-(HX, HY13, HZ2)-(HX2, HY14, HZ2), 0, Smooth
  57.     Next X, Z
  58.  
  59.     '----------------------------------------------------------------------------------------------------------- CIRCLES --------------------------------------------------------------
  60.     FillCache = 0
  61.     IntensityLeft = 0
  62.     IntensityRight = 0
  63.     Do Until FillCache = 8192
  64.         IntensityLeft = IntensityLeft + Abs(MemGet(L, L.OFFSET + Position + FillCache, Integer) / 32768)
  65.         IntensityRight = IntensityRight + Abs(MemGet(R, R.OFFSET + Position + FillCache, Integer) / 32768)
  66.         FillCache = FillCache + 2
  67.     Loop
  68.     IL = IntensityLeft / 2 '                                                                   recalc values as decimal
  69.     IR = IntensityRight / 2
  70.     ReDim LightsL(10) As Unsigned Byte
  71.     ReDim LightsR(10) As Unsigned Byte
  72.     CLL = 0
  73.     Do Until IL <= 0
  74.         If IL > 28 Then LightsL(CLL) = 255 Else LightsL(CLL) = IL * 8
  75.         IL = IL - 28
  76.         CLL = CLL + 1
  77.         MAX CLL, 10
  78.     Loop
  79.     CLR = 0
  80.     Do Until IR <= 0
  81.         If IR > 28 Then LightsR(CLR) = 255 Else LightsR(CLR) = IR * 8
  82.         IR = IR - 28
  83.         CLR = CLR + 1
  84.         MAX CLR, 10
  85.     Loop
  86.     IL = 0
  87.     IR = 0
  88.     For DL = 0 To 10
  89.         Select Case DL
  90.             Case 0 TO 5
  91.                 Rc = 0: Gc = 255: Bc = 0
  92.             Case 6 TO 8
  93.                 Rc = 255: Gc = 255: Bc = 0
  94.             Case Is > 8
  95.                 Rc = 255: Gc = 0: Bc = 0
  96.         End Select
  97.         CircleFill Width / 2 - 50 - DL * 80, Height / 2, 30, &HFF000000
  98.         CircleFill Width / 2 - 50 - DL * 80, Height / 2, 30, RGBA32(Rc, Gc, Bc, LightsL(DL))
  99.         CircleFill Width / 2 + 50 + DL * 80, Height / 2, 30, &HFF000000
  100.         CircleFill Width / 2 + 50 + DL * 80, Height / 2, 30, RGBA32(Rc, Gc, Bc, LightsR(DL))
  101.     Next
  102.     Display
  103.     Limit 50
  104.     Position = SndGetPos(SND) * SndRate * 2
  105.  
  106.  
  107. Sub MAX (Value, mv)
  108.     If Value > mv Then Value = mv
  109.  
  110. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, C As _Unsigned Long)
  111.     ' CX = center x coordinate
  112.     ' CY = center y coordinate
  113.     '  R = radius
  114.     '  C = fill color
  115.     Dim Radius As Integer, RadiusError As Integer
  116.     Dim X As Integer, Y As Integer
  117.     Radius = Abs(R)
  118.     RadiusError = -Radius
  119.     X = Radius
  120.     Y = 0
  121.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  122.     Line (CX - X, CY)-(CX + X, CY), C, BF
  123.     While X > Y
  124.         RadiusError = RadiusError + Y * 2 + 1
  125.         If RadiusError >= 0 Then
  126.             If X <> Y + 1 Then
  127.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  128.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  129.             End If
  130.             X = X - 1
  131.             RadiusError = RadiusError - X * 2
  132.         End If
  133.         Y = Y + 1
  134.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  135.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  136.     Wend
  137.  
« Last Edit: March 12, 2022, 01:07:40 pm by Petr »

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
Re: Next one Music Visualizer
« Reply #1 on: March 14, 2022, 03:43:47 am »
Very cool indeed! Well done!
Logic is the beginning of wisdom.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: Next one Music Visualizer
« Reply #2 on: March 16, 2022, 01:04:37 pm »
@johnno56

Thank you for trying it. I am glad, that you like it!

Offline SierraKen

  • Forum Resident
  • Posts: 1454
Re: Next one Music Visualizer
« Reply #3 on: March 16, 2022, 07:01:18 pm »
Incredible Petr! There was something similar to this a year or 2 ago on here that I was messing with on songs, but it wasn't terrain. Good work! I'm going to have to learn how you made the terrain  without the music. Thank you!

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
Re: Next one Music Visualizer
« Reply #4 on: March 18, 2022, 03:38:34 pm »
That's an amazing effect. I ran a mp3 song through it and noticed the amplitude of the terrain suddenly increased significantly while the sound remained relatively the same. Must have been picking up something subtle in the encoding...

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: Next one Music Visualizer
« Reply #5 on: March 19, 2022, 05:59:34 am »
That's an amazing effect. I ran a mp3 song through it and noticed the amplitude of the terrain suddenly increased significantly while the sound remained relatively the same. Must have been picking up something subtle in the encoding...

Yes, this is because it is used to visualize the line every 8192th audio sample. Then the line is moved one step closer in the Z axis (it has a higher coordinate number, the nearest visible one is -1, 0 is no longer invisible and 1 is basically in front of the monitor). For a finer display, I had each sample drawn, it's this source code, the edit is on line 39. Still, not every sample will be rendered now. Why?
In order to render virtually every sound sample, you must first determine in how many frames per second the program will run.
Suppose you set 50 frames per second for smooth graphics. For sound, this means 44100 (SNDRATE) / 50 samples per second, that is 882 samples. But that also means overwriting 882 values in memory 50 times per second.
In this program, this is solved by not tracking exactly where you ended up rendering. Simply take the current position of the sound and load more samples from it. Therefore, it can easily happen that some samples simply fall out before the whole thing is rendered.
  Under line 61, the program solves normal 2D graphics for blinking background circles.

This source code try use "every" sample:

Code: QB64: [Select]
  1. 'sky texture
  2. Texture2 = NewImage(255, 255, 32)
  3. Dest Texture2
  4. For diY = 0 To 100
  5.     Line (diY + 20, diY + 20)-(235 - diY, 235 - diY), RGBA32(67, 100, 255 - diY, 255 - diY), B
  6.     Circle (127, 127), 100 + diY, RGBA32(155 - diY, diY / 2, 20 + diY, 155 - diY)
  7. 'earth texture
  8. Texture = NewImage(255, 255, 32)
  9. Dest Texture
  10. Cls , &HFFFF0000
  11. For diY = 0 To 100
  12.     Line (diY + 20, diY + 20)-(235 - diY, 235 - diY), RGB32(diY, 0, 0), B
  13. Dest 0
  14. Dim As Long SND, Position, FillCachem, HT
  15. Dim As Float IL, IR, IntensityLeft, IntensityRight
  16. Dim As MEM L, R
  17. Dim As Unsigned Byte Rc, Gc, Bc
  18. ReDim LightsL(10) As Unsigned Byte
  19. ReDim LightsR(10) As Unsigned Byte
  20. Dim M3D(90, 90) As Single
  21. Dim M2D(90, 90) As Single
  22. SND = SndOpen("bb.mp3") '            <-----------------  insert here your sound file name!
  23. VOL = 10
  24. SndVol SND, VOL / 20
  25. L = MemSound(SND, 1)
  26. R = MemSound(SND, 2)
  27. DW = DesktopWidth
  28. DH = DesktopHeight
  29. HT = CopyImage(Texture, 33)
  30. HT2 = CopyImage(Texture2, 33)
  31. FreeImage Texture
  32. Screen NewImage(DW, DH, 32)
  33. FullScreen
  34. SndPlay SND
  35. Do Until Position >= L.SIZE - 882 'CHANGED
  36.     ShiftIt = 89
  37.     Do Until ShiftIt < 0
  38.         For rows = 0 To 90
  39.             Swap M3D(rows, ShiftIt), M3D(rows, ShiftIt + 1)
  40.             Swap M2D(rows, ShiftIt), M2D(rows, ShiftIt + 1)
  41.         Next
  42.         ShiftIt = ShiftIt - 1
  43.     Loop
  44.     Depth = 0
  45.     Do Until Depth = 180 '                              This fill 3D visualisation in X axis. One sample is long 2 bytes, one row is 90 points long. This fill 90 points.
  46.         If Depth + Position > L.SIZE Then End
  47.         M3D(ra, 0) = MemGet(L, L.OFFSET + Position + Depth, Integer) / 32768 * 1.7
  48.         M2D(ra, 0) = MemGet(R, R.OFFSET + Position + Depth, Integer) / 32768 * 1.7
  49.         Depth = Depth + 2 '                            This is byte counter and now use all samples not every 8192th as in previous case (first source code in this thread)
  50.         ra = ra + 1
  51.     Loop
  52.     ra = 0
  53.     For Z = 0 To 89
  54.         For X = 0 To 89
  55.             HX = -45 + X
  56.             HX2 = HX + 1
  57.             HZ = -89 + Z
  58.             HZ2 = HZ + 1
  59.             HY1 = -3 + M3D(X, Z): HY2 = -3 + M3D(X + 1, Z): HY3 = -3 + M3D(X, Z + 1): HY4 = -3 + M3D(X + 1, Z + 1)
  60.             HY11 = 3 - M2D(X, Z): HY12 = 3 - M2D(X + 1, Z): HY13 = 3 - M2D(X, Z + 1): HY14 = 3 - M2D(X + 1, Z + 1)
  61.             MapTriangle (0, 0)-(255, 0)-(0, 255), HT To(HX, HY1, HZ)-(HX2, HY2, HZ)-(HX, HY3, HZ2), 0, Smooth
  62.             MapTriangle (255, 0)-(0, 255)-(255, 255), HT To(HX2, HY2, HZ)-(HX, HY3, HZ2)-(HX2, HY4, HZ2), 0, Smooth
  63.             MapTriangle (0, 0)-(255, 0)-(0, 255), HT2 To(HX, HY11, HZ)-(HX2, HY12, HZ)-(HX, HY13, HZ2), 0, Smooth
  64.             MapTriangle (255, 0)-(0, 255)-(255, 255), HT2 To(HX2, HY12, HZ)-(HX, HY13, HZ2)-(HX2, HY14, HZ2), 0, Smooth
  65.     Next X, Z
  66.  
  67.     '----------------------------------------------------------------------------------------------------------- CIRCLES --------------------------------------------------------------
  68.     FillCache = 0
  69.     IntensityLeft = 0
  70.     IntensityRight = 0
  71.     Do Until FillCache = 882
  72.         IntensityLeft = IntensityLeft + Abs(MemGet(L, L.OFFSET + Position + FillCache, Integer) / 32768)
  73.         IntensityRight = IntensityRight + Abs(MemGet(R, R.OFFSET + Position + FillCache, Integer) / 32768)
  74.         FillCache = FillCache + 2
  75.     Loop
  76.     IL = IntensityLeft / 2 '                                                                   recalc values as decimal
  77.     IR = IntensityRight / 2
  78.     ReDim LightsL(10) As Unsigned Byte
  79.     ReDim LightsR(10) As Unsigned Byte
  80.     CLL = 0
  81.     Do Until IL <= 0
  82.         If IL > 4.41 Then LightsL(CLL) = 255 Else LightsL(CLL) = IL * 57
  83.         IL = IL - 4.41
  84.         CLL = CLL + 1
  85.         MAX CLL, 10
  86.     Loop
  87.     CLR = 0
  88.     Do Until IR <= 0
  89.         If IR > 4.41 Then LightsR(CLR) = 255 Else LightsR(CLR) = IR * 57
  90.         IR = IR - 4.41
  91.         CLR = CLR + 1
  92.         MAX CLR, 10
  93.     Loop
  94.     IL = 0
  95.     IR = 0
  96.     For DL = 0 To 10
  97.         Select Case DL
  98.             Case 0 TO 5
  99.                 Rc = 0: Gc = 255: Bc = 0
  100.             Case 6 TO 8
  101.                 Rc = 255: Gc = 255: Bc = 0
  102.             Case Is > 8
  103.                 Rc = 255: Gc = 0: Bc = 0
  104.         End Select
  105.         CircleFill Width / 2 - 50 - DL * 80, Height / 2, 30, &HFF000000
  106.         CircleFill Width / 2 - 50 - DL * 80, Height / 2, 30, RGBA32(Rc, Gc, Bc, LightsL(DL))
  107.         CircleFill Width / 2 + 50 + DL * 80, Height / 2, 30, &HFF000000
  108.         CircleFill Width / 2 + 50 + DL * 80, Height / 2, 30, RGBA32(Rc, Gc, Bc, LightsR(DL))
  109.     Next
  110.     Display
  111.     Limit 50
  112.     Position = SndGetPos(SND) * SndRate * 2
  113.  
  114.  
  115. Sub MAX (Value, mv)
  116.     If Value > mv Then Value = mv
  117.  
  118. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, C As _Unsigned Long)
  119.     ' CX = center x coordinate
  120.     ' CY = center y coordinate
  121.     '  R = radius
  122.     '  C = fill color
  123.     Dim Radius As Integer, RadiusError As Integer
  124.     Dim X As Integer, Y As Integer
  125.     Radius = Abs(R)
  126.     RadiusError = -Radius
  127.     X = Radius
  128.     Y = 0
  129.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  130.     Line (CX - X, CY)-(CX + X, CY), C, BF
  131.     While X > Y
  132.         RadiusError = RadiusError + Y * 2 + 1
  133.         If RadiusError >= 0 Then
  134.             If X <> Y + 1 Then
  135.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  136.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  137.             End If
  138.             X = X - 1
  139.             RadiusError = RadiusError - X * 2
  140.         End If
  141.         Y = Y + 1
  142.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  143.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  144.     Wend
  145.  

Due to the adjustment, I also had to adjust the rendering of the circles. This brought a noticeable increase in speed (not so many shades are used anymore, only about 5 for the color intensity of the circle)
« Last Edit: March 19, 2022, 06:16:44 am by Petr »