Author Topic: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)  (Read 16411 times)

0 Members and 1 Guest are viewing this topic.

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #15 on: December 31, 2020, 05:42:10 pm »
Not in the works as of yet. Bear in mind we have _SNDRAW for sound generation.
« Last Edit: December 31, 2020, 05:43:39 pm by FellippeHeitor »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #16 on: December 31, 2020, 06:03:54 pm »
WORKS AS EXPECTED!

  [ You are not allowed to view this attachment ]  

HAPPY NEW YEAR! NOW MIDNIGHT HERE!


FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #17 on: December 31, 2020, 06:04:38 pm »
Happy New Year! Can't wait to see what you'll come up with this ❤️

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #18 on: December 31, 2020, 06:14:28 pm »
I'll start with that in the morning. I will experiment a lot, the end of the restriction is amazing. A wonderful beginning of the new year. I like the way you made a option for shift in the music track in the window at the bottom. Even the pause mark is nice. Now testing, all pass.

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #19 on: December 31, 2020, 06:15:05 pm »
I just updated the code in the box above to make the tracker more visible when you move down the mouse.

« Last Edit: December 31, 2020, 06:18:24 pm by FellippeHeitor »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #20 on: December 31, 2020, 06:38:56 pm »
Yes, now it's better see now. This music is a bit familiar to me :)  Thank you again!

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #21 on: December 31, 2020, 06:40:49 pm »
This music is a bit familiar to me :) 

😉

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #22 on: January 01, 2021, 06:11:41 am »
It's just an absolutely amazing thing. It's just something perfect. I made such an attempt. Take two different songs and create a one new from them - place the left channel of the first song in the left channel and place the left channel of the second song in the second channel. Previously? It was only possible with the WAV format and required a really large program. Now? It's really very simple! In addition, the program solves what QB64 cannot solve on its own yet, even though it is so easy! You can use the function in this program and you will never have a problem converting an OFFSET type to another numeric type.

Try it. Take two different songs (in order for the resulting mix to be heard well, you need to make sure that both have about the same volume) and go through it with this program. The result is a WAV file with mixed sound.

Of course, what can be done next? Sound effects, blending the left track to the right and vice versa, muting in the recording, inserting speech - and then saving it all. Of course, this is my first experiment of my own and it works great.

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack, which mix left channel from audio 1 and right channel from audio 2
  2. INPUT "Insert audio file name nr. 1:"; a1$
  3. INPUT "Insert audio file name nr. 2:"; a2$
  4. a = _SNDOPEN(a1$)
  5. IF a THEN PRINT "Audio file 1 opened" ELSE PRINT "Audio file 1 opening error.": END
  6. b = _SNDOPEN(a2$)
  7. IF b THEN PRINT "Audio file 2 opened" ELSE PRINT "Audio file 2 opening error.": END
  8. LENa = _CEIL(_SNDLEN(a))
  9. LENb = _CEIL(_SNDLEN(b))
  10.  
  11. PRINT "Track 1 (Audio file 1) lenght:"; LENa
  12. PRINT "Track 2 (Audio file 2) lenght:"; LENb
  13.  
  14. IF LENa > LENb THEN NewTrackTime = LENb ELSE NewTrackTime = LENa
  15. PRINT "Mixed audio track lenght: "; NewTrackTime
  16.  
  17. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Driver AS _OFFSET
  18. Left = _MEMSOUND(a, 1)
  19. Right = _MEMSOUND(b, 2)
  20. IF Right.SIZE = 0 THEN Right = _MEMSOUND(b, 1) 'if track 2 is mono, use left channel from track 2
  21.  
  22. NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  23. NewSound = _MEMNEW(NewSoundSize&)
  24.  
  25. PRINT "SndRate:"; _SNDRATE
  26. PRINT "Track 1 memory len:"; Left.SIZE
  27. PRINT "Track 2 memory len:"; Right.SIZE
  28. PRINT "New audio memory len:"; NewSound.SIZE
  29.  
  30. IF Left.SIZE < Right.SIZE THEN Driver = Left.SIZE ELSE Driver = Right.SIZE
  31.  
  32. DO UNTIL Create& = Driver
  33.     _MEMGET Left, Left.OFFSET + Create&, Audio
  34.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio
  35.     NewAudio& = NewAudio& + 2 'because record lenght is 2 byte, use INTEGER
  36.     _MEMGET Right, Right.OFFSET + Create&, Audio
  37.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio
  38.     NewAudio& = NewAudio& + 2 'because record lenght is 2 byte, use INTEGER
  39.     Create& = Create& + 2
  40.  
  41. PRINT "New sound created. Saving as Tracks-mix.wav..."
  42. SAVESOUND16S NewSound, "Tracks-mix.wav"
  43. PRINT "Playing mixed sound"
  44. _SNDPLAYFILE ("tracks-mix.wav")
  45.  
  46.  
  47. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  48.     DIM o AS _INTEGER64, mo AS _MEM
  49.     mo = _MEM(o)
  50.     _MEMPUT mo, mo.OFFSET, OffsetVal
  51.     _MEMFREE mo
  52.     OFFSETasI64&& = o
  53.  
  54.  
  55. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  56.  
  57.     TYPE head16
  58.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  59.         size AS LONG '              4 bytes  (file size)
  60.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  61.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  62.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  63.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  64.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  65.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  66.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  67.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  68.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  69.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  70.         lenght AS LONG '            4 bytes  Data block size
  71.     END TYPE '                     44 bytes  total
  72.     DIM H16 AS head16
  73.     ch = FREEFILE
  74.  
  75.     H16.chunk = "RIFF"
  76.     H16.size = 44 + OFFSETasI64(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  77.  
  78.     H16.fomat = "WAVE"
  79.     H16.sub1 = "fmt "
  80.     H16.subchunksize = 16
  81.     H16.format = 1
  82.     H16.channels = 2
  83.     H16.rate = 44100
  84.     H16.ByteRate = 44100 * 2 * 16 / 8
  85.     H16.Block = 4
  86.     H16.Bits = 16
  87.     H16.subchunk2 = "data"
  88.     H16.lenght = OFFSETasI64(arr.SIZE)
  89.     IF _FILEEXISTS(file$) THEN KILL file$
  90.  
  91.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  92.     _MEMGET arr, arr.OFFSET, Audio$
  93.  
  94.     OPEN file$ FOR BINARY AS #ch
  95.     PUT #ch, , H16
  96.     PUT #ch, , Audio$
  97.     Audio$ = ""
  98.  
  99.     CLOSE ch
  100.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #23 on: January 01, 2021, 08:15:57 am »
Hi @Fellippe, try listening your songs with echo effect:

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack + add echo
  2.  
  3. EchoLenght = 0.25 '0.25 seconds is echo duration
  4. Echo& = _SNDRATE * EchoLenght
  5.  
  6. DO UNTIL Echo& MOD 2 = 0
  7.     Echo& = Echo& + 1
  8.  
  9.  
  10. INPUT "Insert audio file name:"; a1$
  11. a = _SNDOPEN(a1$)
  12. IF a THEN PRINT "Audio file 1 opened" ELSE PRINT "Audio file 1 opening error.": END
  13. LENa = _CEIL(_SNDLEN(a)) + EchoLenght
  14. PRINT "Audio file lenght:"; LENa
  15. NewTrackTime = LENa
  16.  
  17.  
  18.  
  19. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Audio2 AS INTEGER, Audio3 AS INTEGER, Audio4 AS INTEGER
  20. Left = _MEMSOUND(a, 1)
  21. Right = _MEMSOUND(a, 2)
  22.  
  23. NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  24. NewSound = _MEMNEW(NewSoundSize&)
  25.  
  26. PRINT "SndRate:"; _SNDRATE
  27. PRINT "Track memory len:"; Left.SIZE
  28.  
  29.  
  30. DO UNTIL Create& = Left.SIZE
  31.     _MEMGET Left, Left.OFFSET + Create&, Audio
  32.     _MEMGET Right, Right.OFFSET + Create&, Audio2
  33.  
  34.     IF Create& > Echo& THEN
  35.         _MEMGET Left, Left.OFFSET + Create& - Echo&, Audio3
  36.         Audio = (Audio + Audio3 * .75) \ 2
  37.  
  38.         _MEMGET Right, Right.OFFSET + Create& - Echo&, Audio3
  39.         Audio2 = (Audio2 + Audio3 * .75) \ 2
  40.     END IF
  41.  
  42.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio 'left channel
  43.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio& + 2, Audio2 'right channel
  44.     NewAudio& = NewAudio& + 4
  45.     Create& = Create& + 2
  46.  
  47. PRINT "New sound created. Saving as Tracks-mix.wav..."
  48. SAVESOUND16S NewSound, "Tracks-mix.wav"
  49. PRINT "Sound saved, erasing RAM..."
  50. _MEMFREE Right
  51. _MEMFREE NewSound
  52.  
  53. PRINT "Playing mixed sound"
  54. _SNDPLAYFILE ("tracks-mix.wav")
  55.  
  56.  
  57. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  58.     DIM o AS _INTEGER64, mo AS _MEM
  59.     mo = _MEM(o)
  60.     _MEMPUT mo, mo.OFFSET, OffsetVal
  61.     _MEMFREE mo
  62.     OFFSETasI64&& = o
  63.  
  64.  
  65. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  66.  
  67.     TYPE head16
  68.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  69.         size AS LONG '              4 bytes  (file size)
  70.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  71.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  72.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  73.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  74.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  75.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  76.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  77.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  78.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  79.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  80.         lenght AS LONG '            4 bytes  Data block size
  81.     END TYPE '                     44 bytes  total
  82.     DIM H16 AS head16
  83.     ch = FREEFILE
  84.  
  85.     H16.chunk = "RIFF"
  86.     H16.size = 44 + OFFSETasI64(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  87.  
  88.     H16.fomat = "WAVE"
  89.     H16.sub1 = "fmt "
  90.     H16.subchunksize = 16
  91.     H16.format = 1
  92.     H16.channels = 2
  93.     H16.rate = 44100
  94.     H16.ByteRate = 44100 * 2 * 16 / 8
  95.     H16.Block = 4
  96.     H16.Bits = 16
  97.     H16.subchunk2 = "data"
  98.     H16.lenght = OFFSETasI64(arr.SIZE)
  99.     IF _FILEEXISTS(file$) THEN KILL file$
  100.  
  101.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  102.     _MEMGET arr, arr.OFFSET, Audio$
  103.  
  104.     OPEN file$ FOR BINARY AS #ch
  105.     PUT #ch, , H16
  106.     PUT #ch, , Audio$
  107.     Audio$ = ""
  108.  
  109.     CLOSE ch
  110.  

« Last Edit: January 01, 2021, 08:18:03 am by Petr »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #24 on: January 01, 2021, 09:39:35 am »
This return better echo output:

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack + add echo
  2.  
  3. EchoLenght = 0.06 '0.06 seconds is echo duration
  4. OverSampling = 10 'number of echoes sample passes
  5.  
  6. Echo& = _SNDRATE * EchoLenght
  7.  
  8. DO UNTIL Echo& MOD 2 = 0
  9.     Echo& = Echo& + 1
  10.  
  11. INPUT "Insert audio file name:"; a1$
  12. a = _SNDOPEN(a1$)
  13. IF a THEN PRINT "Audio file 1 opened" ELSE PRINT "Audio file 1 opening error.": END
  14. LENa = _CEIL(_SNDLEN(a)) + EchoLenght
  15. PRINT "Audio file lenght:"; LENa
  16. NewTrackTime = LENa
  17.  
  18.  
  19.  
  20. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Audio2 AS INTEGER, Audio3 AS INTEGER, Audio4 AS INTEGER
  21. Left = _MEMSOUND(a, 1)
  22. Right = _MEMSOUND(a, 2)
  23.  
  24. NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  25. NewSound = _MEMNEW(NewSoundSize&)
  26.  
  27. PRINT "SndRate:"; _SNDRATE
  28. PRINT "Track memory len:"; Left.SIZE
  29. PRINT "Creating audio..."
  30.  
  31. VolDown = 1 / OverSampling
  32.  
  33. DO UNTIL Create& >= Left.SIZE - 2
  34.     _MEMGET Left, Left.OFFSET + Create&, Audio
  35.     _MEMGET Right, Right.OFFSET + Create&, Audio2
  36.  
  37.     IF Create& > Echo& THEN
  38.  
  39.         E& = Create&
  40.         Vol = 1
  41.         DO UNTIL E& <= Create& - OverSampling
  42.             Vol = Vol - VolDown
  43.             _MEMGET Left, Left.OFFSET + Create& - Echo&, Audio3
  44.             _MEMGET Left, Left.OFFSET + Create& - 2, Audio4
  45.             Audio = (Audio + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  46.             E& = E& - 2
  47.         LOOP
  48.  
  49.         E& = Create&
  50.         Vol = 1
  51.         DO UNTIL E& <= Create& - OverSampling
  52.             Vol = Vol - VolDown
  53.             _MEMGET Right, Right.OFFSET + Create& - Echo&, Audio3
  54.             _MEMGET Right, Right.OFFSET + Create& - 2, Audio4
  55.             Audio2 = (Audio2 + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  56.             E& = E& - 2
  57.         LOOP
  58.     END IF
  59.  
  60.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio 'left channel
  61.     _MEMPUT NewSound, NewSound.OFFSET + NewAudio& + 2, Audio2 'right channel
  62.     NewAudio& = NewAudio& + 4
  63.     Create& = Create& + 2
  64.  
  65. PRINT "New sound created. Saving as Tracks-mix4.wav..."
  66. SAVESOUND16S NewSound, "Tracks-mix4.wav"
  67. PRINT "Sound saved, erasing RAM..."
  68. _MEMFREE Right
  69. _MEMFREE NewSound
  70.  
  71. PRINT "Playing mixed sound"
  72. _SNDPLAYFILE ("tracks-mix4.wav")
  73.  
  74.  
  75. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  76.     DIM o AS _INTEGER64, mo AS _MEM
  77.     mo = _MEM(o)
  78.     _MEMPUT mo, mo.OFFSET, OffsetVal
  79.     _MEMFREE mo
  80.     OFFSETasI64&& = o
  81.  
  82.  
  83. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  84.  
  85.     TYPE head16
  86.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  87.         size AS LONG '              4 bytes  (file size)
  88.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  89.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  90.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  91.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  92.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  93.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  94.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  95.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  96.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  97.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  98.         lenght AS LONG '            4 bytes  Data block size
  99.     END TYPE '                     44 bytes  total
  100.     DIM H16 AS head16
  101.     ch = FREEFILE
  102.  
  103.     H16.chunk = "RIFF"
  104.     H16.size = 44 + OFFSETasI64(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  105.  
  106.     H16.fomat = "WAVE"
  107.     H16.sub1 = "fmt "
  108.     H16.subchunksize = 16
  109.     H16.format = 1
  110.     H16.channels = 2
  111.     H16.rate = 44100
  112.     H16.ByteRate = 44100 * 2 * 16 / 8
  113.     H16.Block = 4
  114.     H16.Bits = 16
  115.     H16.subchunk2 = "data"
  116.     H16.lenght = OFFSETasI64(arr.SIZE)
  117.     IF _FILEEXISTS(file$) THEN KILL file$
  118.  
  119.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  120.     _MEMGET arr, arr.OFFSET, Audio$
  121.  
  122.     OPEN file$ FOR BINARY AS #ch
  123.     PUT #ch, , H16
  124.     PUT #ch, , Audio$
  125.     Audio$ = ""
  126.  
  127.     CLOSE ch
  128.  



FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #25 on: January 01, 2021, 09:57:43 am »
Wow! One morning in your hands and we got sound processing! That's awesome, I'll be testing it right now!!

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #26 on: January 01, 2021, 10:42:39 am »
Great job, @Petr! On a side note, thanks for FUNCTION OFFSETasI64&& - that's really useful too.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #27 on: January 01, 2021, 10:56:32 am »
Thank you, Fellippe. There are already many new possibilities. And do you know what's funny? Remember the beginnings of QB64 with graphics? When was the first save format BMP? Now it's just WAV... the resemblance, isn't it wonderful? I'm going to keep experimenting because I really very enjoy it! Really nice function, this _MEMSOUND!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #28 on: January 01, 2021, 11:38:32 pm »
Here comes the first QB64 oscilloscope. Here I am "measuring" the frequency of a 500-hz sine wave:

Code: QB64: [Select]
  1. CONST true = -1, false = 0
  2.  
  3. DIM theSound AS LONG, x0 AS LONG, i AS _OFFSET, j AS _OFFSET
  4. DIM a%, c~&, k&, trackerHeight AS INTEGER
  5. DIM y0 AS LONG, y1 AS LONG
  6. DIM mouseDown AS _BYTE, f$, mouseDownOn AS INTEGER
  7. DIM sleft AS _MEM, sright AS _MEM
  8. DIM stereo AS _BYTE
  9. DIM stereoScreen AS LONG, monoScreen AS LONG
  10.  
  11. DIM BarFrequency AS INTEGER
  12. DIM BarWavelength AS INTEGER
  13. DIM BarPhase AS INTEGER
  14. DIM SomeText AS STRING
  15. BarFrequency = 441
  16. BarPhase = 0
  17. BarWavelength = INT(44100 / BarFrequency)
  18.  
  19. stereoScreen = _NEWIMAGE(882, 400, 32)
  20. monoScreen = _NEWIMAGE(882, 200, 32)
  21. SCREEN monoScreen
  22.  
  23. _TITLE "QB64 Sound Player + Oscilloscope"
  24.  
  25.     f$ = COMMAND$
  26.     start:
  27.     INPUT "File to load: ", f$
  28.  
  29. PRINT "Loading '"; f$; "'..."
  30. theSound = _SNDOPEN(f$)
  31. IF theSound = 0 THEN PRINT "Load failed.": END
  32.  
  33. loaded:
  34. sleft = _MEMSOUND(theSound, 1)
  35. sright = _MEMSOUND(theSound, 2)
  36.  
  37. IF sright.SIZE > 0 THEN
  38.     SCREEN stereoScreen
  39.     stereo = true
  40.     y0 = _HEIGHT / 4
  41.     y1 = _HEIGHT - _HEIGHT / 4
  42.     SCREEN monoScreen
  43.     y0 = _HEIGHT / 2
  44.  
  45. trackerHeight = 50
  46. _SNDPLAY theSound
  47. _SNDPAUSE theSound
  48.  
  49.         IF (_KEYDOWN(100305) OR _KEYDOWN(100306)) THEN
  50.             'BarPhase = BarPhase + SGN(_MOUSEWHEEL)
  51.             BarFrequency = BarFrequency + SGN(_MOUSEWHEEL)
  52.             BarWavelength = INT(44100 / BarFrequency)
  53.         ELSE
  54.             BarFrequency = BarFrequency + 20 * SGN(_MOUSEWHEEL)
  55.             BarWavelength = INT(44100 / BarFrequency)
  56.         END IF
  57.     WEND
  58.  
  59.         IF mouseDown = false THEN
  60.             mouseDown = true
  61.             IF _MOUSEY < _HEIGHT - trackerHeight THEN
  62.                 mouseDownOn = 1 'plot area
  63.             ELSE
  64.                 mouseDownOn = 2 'track area
  65.             END IF
  66.         ELSE
  67.             IF mouseDownOn = 2 AND _SNDPLAYING(theSound) = 0 THEN
  68.                 _SNDSETPOS theSound, map(_MOUSEX, 0, _WIDTH, 0, _SNDLEN(theSound))
  69.             END IF
  70.         END IF
  71.         IF mouseDown = false THEN
  72.             mouseDown = true
  73.             BarPhase = _MOUSEX
  74.         ELSE
  75.         END IF
  76.     ELSE
  77.         IF mouseDown THEN
  78.             'toggle play
  79.             IF mouseDownOn = 1 THEN
  80.                 toggleSoundState theSound
  81.             ELSEIF mouseDownOn = 2 THEN
  82.                 _SNDSETPOS theSound, map(_MOUSEX, 0, _WIDTH, 0, _SNDLEN(theSound))
  83.             END IF
  84.             mouseDown = false
  85.             mouseDownOn = 0
  86.         END IF
  87.     END IF
  88.  
  89.     k& = _KEYHIT
  90.     IF k& = 32 THEN toggleSoundState theSound
  91.  
  92.     DIM alpha AS INTEGER
  93.     alpha = 50 'IF _SNDPLAYING(theSound) THEN alpha = 40 ELSE alpha = 20
  94.     LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(0, alpha), BF
  95.     GOSUB render
  96.     IF _SNDPLAYING(theSound) = 0 THEN _PRINTSTRING (_WIDTH / 2 - 16, _HEIGHT / 2 - _FONTHEIGHT), CHR$(221) + CHR$(222)
  97.  
  98.     _DISPLAY
  99.     _LIMIT 60
  100.  
  101. render:
  102. o = INT((_SNDGETPOS(theSound)) * _SNDRATE)
  103. WHILE o MOD 2 <> 0: o = o + 1: WEND
  104. i = sleft.OFFSET + o
  105. IF stereo THEN j = sright.OFFSET + o
  106. FOR x0 = 0 TO _WIDTH
  107.     _MEMGET sleft, i, a%
  108.     IF a% < 0 THEN
  109.         c~& = _RGB32(67, 150, 33, map(a%, 0, -32767, 80, 255))
  110.     ELSE
  111.         c~& = _RGB32(67, 150, 33, map(a%, 0, 32767, 80, 255))
  112.     END IF
  113.     LINE (x0, y0)-STEP(0, map(a%, -32768, 32767, -_HEIGHT / 4, _HEIGHT / 4)), c~&, B 'F
  114.  
  115.     IF stereo THEN
  116.         _MEMGET sright, j, a%
  117.         IF a% < 0 THEN
  118.             c~& = _RGB32(67, 150, 33, map(a%, 0, -32767, 80, 255))
  119.         ELSE
  120.             c~& = _RGB32(67, 150, 33, map(a%, 0, 32767, 80, 255))
  121.         END IF
  122.         LINE (x0, y1)-STEP(0, map(a%, -32768, 32767, -_HEIGHT / 4, _HEIGHT / 4)), c~&, B 'F
  123.     END IF
  124.  
  125.     IF (x0 MOD BarWavelength) = 0 THEN
  126.         LINE (x0 + BarPhase, 0)-(x0 + BarPhase, _HEIGHT), _RGB32(0, 100, 100, 100)
  127.     END IF
  128.  
  129.     i = i + 2
  130.     IF stereo THEN j = j + 2
  131.     IF i + 2 >= sleft.OFFSET + sleft.SIZE THEN EXIT FOR
  132.  
  133. 'tracker:
  134. LINE (0, _HEIGHT - trackerHeight / 3)-STEP(map(_SNDGETPOS(theSound), 0, _SNDLEN(theSound), 0, _WIDTH), -trackerHeight / 3), _RGB32(255, 180), BF
  135. IF _MOUSEY > _HEIGHT - trackerHeight THEN
  136.     LINE (0, _HEIGHT - trackerHeight)-STEP(_WIDTH, trackerHeight), _RGB32(255, 30), BF
  137.  
  138. COLOR _RGB32(200, 200, 200, 255)
  139. LOCATE 1, 1: PRINT "Measured frequency:"; BarFrequency
  140. SomeText = "       MWheel = Coarse Freq.": LOCATE 1, _WIDTH / 8 - LEN(SomeText): PRINT SomeText
  141. SomeText = "CTRL + MWheel = Fine Freq.  ": LOCATE 2, _WIDTH / 8 - LEN(SomeText): PRINT SomeText
  142. SomeText = "  Right-Click = Phase       ": LOCATE 3, _WIDTH / 8 - LEN(SomeText): PRINT SomeText
  143.  
  144. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  145.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  146.  
  147. SUB toggleSoundState (theSound AS LONG)
  148.     IF _SNDPLAYING(theSound) THEN
  149.         _SNDPAUSE theSound
  150.     ELSE
  151.         DIM i AS INTEGER
  152.         FOR i = -20 TO 20
  153.             LINE (_WIDTH / 2 + 20, _HEIGHT / 2 - 5)-STEP(-40, i)
  154.         NEXT
  155.         _SNDLOOP theSound
  156.     END IF
  157.  
You're not done when it works, you're done when it's right.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #29 on: January 02, 2021, 04:48:28 am »
Hi  @STxAxTIC I have a question about this. Let's say I want to measure the frequency of sound.

My theory is this: Suppose I choose the number of samples 441 to analyze. I count the number of zero crossings (or just decreasing and increasing in amplitude?) In these 441 samples. Because the sampling frequency for 1 second is 44100, this is a time interval of 100 milliseconds (in 441 samples). For example, if I count 12 changes in the amplitude direction, the resulting frequency is f = 12 / 0.01 = 1200 Hz. I will perform another frequency analysis on samples 442 - 883. Is it correct?

  [ You are not allowed to view this attachment ]