QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: FellippeHeitor on December 31, 2020, 10:42:44 am

Title: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 10:42:44 am
Hello @Petr and everyone else. Look at this:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(600, 200, 32)
  2. DIM bonus AS LONG, x AS LONG, x0 AS LONG, i AS _OFFSET, a%, c~&
  3. bonus = _SNDOPEN("sine.ogg")
  4. PRINT bonus
  5.  
  6. IF bonus THEN _SNDPLAY bonus
  7.  
  8. s = _MEMSOUND(bonus, 1)
  9.  
  10. i = s.OFFSET
  11.     _MEMGET s, i, a%
  12.     IF x MOD 2 = 0 THEN
  13.         x0 = x0 + 1
  14.         c~& = _RGB32(map(a%, -32768, 32767, 0, 255), 0, 255)
  15.         LINE (x0, _HEIGHT / 2)-STEP(0, map(a%, -32768, 32767, -_HEIGHT / 2, _HEIGHT / 2)), c~&, BF
  16.         IF x0 >= _WIDTH THEN x0 = 0: _DISPLAY: CLS
  17.     END IF
  18.     x = x + 1
  19.  
  20.     i = i + 3
  21.     LOCATE 1, 1: PRINT i, s.OFFSET + s.SIZE
  22.     IF i + 2 >= s.OFFSET + s.SIZE THEN EXIT DO
  23.  
  24. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  25.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  26.  

_MEMSOUND is supposed to give you access to raw sound data after a file is decoded by using _SNDOPEN - in the same fashion as _MEMIMAGE gives you raw access to an image's data after you use _LOADIMAGE.

The code above won't work with v1.4 and not even with the latest dev build, as it's still in a separate branch for development. But it will yield the following results:



Is that what you had in mind, @Petr?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 01:05:24 pm
Hi Fellippe,

That's absolutely great. Perfect. That's exactly what I've wanted for so long. If this feature really will be in the next version of QB64, I will be absolutely happy. It will greatly expand the possibilities for everyone. We will no longer be limited to graphics, in which we have really huge possibilities, but will be able to combine it.

 
MEMSOUND is a fullfiled wish for me!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 01:18:25 pm
I think quickly and find that the following is needed:
- Function that returns the number of channels in the audio track:

 - if the data format is RAW, then all audio data will probably be in INTEGER format (if the output RAW format is 16 bits) and the number of channels will determine whether every other INTEGER should be read for the left channel (ie bytes 1.2 for the left track, bytes 3.4 for the right track, bytes 5.6 for the left track .... and so on, or in the case of mono all bytes will belong to the left audio channel), or if this will be handled differently and the left audio channel will be read separately into its own MEM block and right audio channel also in own separated memory block?

That's actually all, because with information about the number of channels in the audio track and RAW audio data, we can add everything else, if the stored RAW format in memory will always be the same type (16 bit). There are also WAV files that contain audio data in the format _UNSIGNED _BYTE (8 bit) or 32 bit, these contain audio data in the SINGLE format. Of course, it can be converted between each other, so one uniform format is enough in memory.

One thing is also needed. Audio sampling frequency. Will it always be the same, or will a new function be needed to return the current state of the sampling frequency? (in RAW MEM block)?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 01:29:49 pm
Notice in the sample code above that I'm getting the memory block with _MEMSOUND(handle, channel) - if it's mono, I'm getting channel 1, if it's stereo, I can get channel 2. It'll return a memblock of size 0 if you try to read the right channel (channel 2) and it's a mono sound.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 01:36:30 pm
I see! It never occurred to me what the number one meant there! In that case, it is already solved! And even it can be loaded separately. This is absolutely perfect! Looks really very, very nice!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 01:38:06 pm
One thing is also needed. Audio sampling frequency. Will it always be the same, or will a new function be needed to return the current state of the sampling frequency? (in RAW MEM block)?

The data available after _SNDOPEN is used is the result of the decoding and resampling that OpenAL does automatically, which means the output will (i believe) always be in accordance with _SNDRATE (usually returns 44100) and 16 bits per sample.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 01:46:52 pm
Quote
The data available after _SNDOPEN is used is the result of the decoding and resampling that OpenAL does automatically, which means the output will (i believe) always be in accordance with _SNDRATE (usually returns 44100) and 16 bits per sample.

So in that case, I think it's on the right track! I look forward to it. This feature function is a big amazing news!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 04:17:24 pm
I can't wait for you to test it, @Petr. I don't know how comfortable you are with cloning the repository (or maybe you already have it cloned) - either way, let me know and I can provide instructions for you to get started with it, even though it still requires more thought before it goes live, even for the dev build.



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. stereoScreen = _NEWIMAGE(882, 400, 32)
  12. monoScreen = _NEWIMAGE(882, 200, 32)
  13. SCREEN monoScreen
  14.  
  15. _TITLE "QB64 Sound Player"
  16.  
  17.     f$ = COMMAND$
  18.     start:
  19.     INPUT "File to load: ", f$
  20.  
  21. PRINT "Loading '"; f$; "'..."
  22. theSound = _SNDOPEN(f$)
  23. IF theSound = 0 THEN PRINT "Load failed.": END
  24.  
  25. loaded:
  26. sleft = _MEMSOUND(theSound, 1)
  27. sright = _MEMSOUND(theSound, 2)
  28.  
  29. IF sright.SIZE > 0 THEN
  30.     SCREEN stereoScreen
  31.     stereo = true
  32.     y0 = _HEIGHT / 4
  33.     y1 = _HEIGHT - _HEIGHT / 4
  34.     SCREEN monoScreen
  35.     stereo = false
  36.     y0 = _HEIGHT / 2
  37.  
  38. trackerHeight = 50
  39. _SNDPLAY theSound
  40. _SNDPAUSE theSound
  41.  
  42.         IF mouseDown = false THEN
  43.             mouseDown = true
  44.             IF _MOUSEY < _HEIGHT - trackerHeight THEN
  45.                 mouseDownOn = 1 'plot area
  46.             ELSE
  47.                 mouseDownOn = 2 'track area
  48.             END IF
  49.         ELSE
  50.             IF mouseDownOn = 2 AND _SNDPLAYING(theSound) = 0 THEN
  51.                 _SNDSETPOS theSound, map(_MOUSEX, 0, _WIDTH, 0, _SNDLEN(theSound))
  52.             END IF
  53.         END IF
  54.     ELSE
  55.         IF mouseDown THEN
  56.             'toggle play
  57.             IF mouseDownOn = 1 THEN
  58.                 toggleSoundState theSound
  59.             ELSEIF mouseDownOn = 2 THEN
  60.                 _SNDSETPOS theSound, map(_MOUSEX, 0, _WIDTH, 0, _SNDLEN(theSound))
  61.             END IF
  62.             mouseDown = false
  63.             mouseDownOn = 0
  64.         END IF
  65.     END IF
  66.  
  67.     k& = _KEYHIT
  68.     IF k& = 32 THEN toggleSoundState theSound
  69.  
  70.             _SNDSTOP theSound
  71.             _SNDCLOSE theSound
  72.             theSound = 0
  73.             f$ = _DROPPEDFILE$(1)
  74.             _PRINTSTRING (_WIDTH / 2 - _PRINTWIDTH("Loading...") / 2, _HEIGHT / 2 - _FONTHEIGHT), "Loading..."
  75.             _DISPLAY
  76.             theSound = _SNDOPEN(f$)
  77.             IF theSound THEN
  78.                 _FINISHDROP
  79.                 GOTO loaded
  80.             ELSE
  81.                 PRINT "Load failed."
  82.                 END
  83.             END IF
  84.         END IF
  85.         _FINISHDROP
  86.     END IF
  87.  
  88.     DIM alpha AS INTEGER
  89.     alpha = 50 'IF _SNDPLAYING(theSound) THEN alpha = 40 ELSE alpha = 20
  90.     LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(0, alpha), BF
  91.     GOSUB render
  92.     IF _SNDPLAYING(theSound) = 0 THEN _PRINTSTRING (_WIDTH / 2 - 16, _HEIGHT / 2 - _FONTHEIGHT), CHR$(221) + CHR$(222)
  93.  
  94.     _DISPLAY
  95.     _LIMIT 60
  96.  
  97. render:
  98. o = INT((_SNDGETPOS(theSound)) * _SNDRATE)
  99. WHILE o MOD 2 <> 0: o = o + 1: WEND
  100. i = sleft.OFFSET + o
  101. IF stereo THEN j = sright.OFFSET + o
  102. FOR x0 = 0 TO _WIDTH
  103.     _MEMGET sleft, i, a%
  104.     IF a% < 0 THEN
  105.         c~& = _RGB32(67, 150, 33, map(a%, 0, -32767, 80, 255))
  106.     ELSE
  107.         c~& = _RGB32(67, 150, 33, map(a%, 0, 32767, 80, 255))
  108.     END IF
  109.     LINE (x0, y0)-STEP(0, map(a%, -32768, 32767, -_HEIGHT / 4, _HEIGHT / 4)), c~&, BF
  110.  
  111.     IF stereo THEN
  112.         _MEMGET sright, j, a%
  113.         IF a% < 0 THEN
  114.             c~& = _RGB32(67, 150, 33, map(a%, 0, -32767, 80, 255))
  115.         ELSE
  116.             c~& = _RGB32(67, 150, 33, map(a%, 0, 32767, 80, 255))
  117.         END IF
  118.         LINE (x0, y1)-STEP(0, map(a%, -32768, 32767, -_HEIGHT / 4, _HEIGHT / 4)), c~&, BF
  119.     END IF
  120.  
  121.     i = i + 2
  122.     IF stereo THEN j = j + 2
  123.     IF i + 2 >= sleft.OFFSET + sleft.SIZE THEN EXIT FOR
  124.  
  125. 'tracker:
  126. LINE (0, _HEIGHT - trackerHeight / 3)-STEP(map(_SNDGETPOS(theSound), 0, _SNDLEN(theSound), 0, _WIDTH), -trackerHeight / 3), _RGB32(255, 180), BF
  127. IF _MOUSEY > _HEIGHT - trackerHeight THEN
  128.     LINE (0, _HEIGHT - trackerHeight)-STEP(_WIDTH, trackerHeight), _RGB32(255, 30), BF
  129.  
  130.  
  131. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  132.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  133.  
  134. SUB toggleSoundState (theSound AS LONG)
  135.     IF _SNDPLAYING(theSound) THEN
  136.         _SNDPAUSE theSound
  137.     ELSE
  138.         DIM i AS INTEGER
  139.         FOR i = -20 TO 20
  140.             LINE (_WIDTH / 2 + 20, _HEIGHT / 2 - 5)-STEP(-40, i)
  141.         NEXT
  142.         _SNDLOOP theSound
  143.     END IF
  144.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 05:24:41 pm
I didn't know it was possible to download it from GitHub. I downloaded a version with the last update eight hours ago, now it's unpacking. The computer says it will unpack for an hour because the ZIP contains 31067 files. That means it will end sometime around midnight of my time. Then I run setup-win.bat and after finishing I will try it :)
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 05:26:05 pm
Hm, that might not be enough, unfortunately. Can you confirm you downloaded the memsound branch?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: SMcNeill on December 31, 2020, 05:29:03 pm
Hm, that might not be enough, unfortunately. Can you confirm you downloaded the memsound branch?

If it’s the development branch, you should be able to test out the quick insert feature I just ended up pushing.  I’m thinking it should be working as intended now, without any issues, but it’d be nice to hear how it performs for others as well. ;)
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 05:31:32 pm
Oops... An error has occurred ... I'm already downloading the correct version! Where did I look?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 05:34:25 pm
Oops... An error has occurred ... I'm already downloading the correct version! Where did I look?

Assuming you're using Windows:

Let me know how it goes.

PS: The 7Zip version will likely unpack faster, but I don't know if you have 7Zip.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 05:37:39 pm
I use internal decompressors in Total Commander to unpack, 7zip can also. I'm already unpacking it to disk.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: SMcNeill on December 31, 2020, 05:41:32 pm
Quick question:  Are you looking to implement a _NEWSOUND type command so we can _MEMPUT information to it directly?

For example:

I =  _NEWIMAGE(640,480,32)
M = _MEMIMAGE(I)
_MEMPUT M, M.OFFSET, image_data()

The above can take a memblock that we saved to disk, and upload it up into a new image handle, so we can then _PUTIMAGE it, or work with it the same as any other image.

Will we be able to do something like:

S = _NEWSOUND(123, 441000, 1) 123 seconds at 44100 sndrate, with 1 channel
DIM M AS _MEM
M = _MEMSOUND(S, 1)
CALL Load_Routine ‘Load sound data from disk
_MEMPUT M, M.OFFSET, Sound_Data()
SNDPLAY S
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 05:42:10 pm
Not in the works as of yet. Bear in mind we have _SNDRAW for sound generation.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on December 31, 2020, 06:03:54 pm
WORKS AS EXPECTED!

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

HAPPY NEW YEAR! NOW MIDNIGHT HERE!

Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 06:04:38 pm
Happy New Year! Can't wait to see what you'll come up with this ❤️
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor 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.

Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on December 31, 2020, 06:40:49 pm
This music is a bit familiar to me :) 

😉
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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.  

Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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.  


Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor 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!!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 01, 2021, 10:42:39 am
Great job, @Petr! On a side note, thanks for FUNCTION OFFSETasI64&& - that's really useful too.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: STxAxTIC 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.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr 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?

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 02, 2021, 07:31:22 am
Reply which find, must be in inversion to this program, i wrote:

Code: QB64: [Select]
  1. SOUND 300, 18 '18 is 1 second of time
  2. SOUND2 300, 18
  3.  
  4. SUB SOUND2 (frequency AS INTEGER, Nlenght AS SINGLE)
  5.     lenght = Nlenght * 1 / 18
  6.     samples = _SNDRATE * lenght
  7.     s = _PI / (_SNDRATE / frequency) * 2
  8.  
  9.     DO UNTIL plsam >= samples
  10.         _SNDRAW SIN(u), COS(u)
  11.         u = u + s
  12.         IF ABS(s) = _SNDRATE / frequency THEN s = s * -1
  13.         plsam = plsam + 1
  14.     LOOP
  15.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 02, 2021, 07:58:02 am
Damn, it's different. The frequency is determined by the zero crossing density - not how many times the wave passes through zero, but how far apart in time. The amplitude height determines the volume. I think. I have to verify this theory. Either it will be the density of the zero crossing, or the density of the change in the direction of the amplitude (how far apart the individual peaks are).
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: STxAxTIC on January 02, 2021, 12:16:57 pm
Good morning Petr,

An excellent question. It took me a few minutes to figure out how to get this working, but now I couldn't be happier. Hopefully this answers all of your questions...

Starting with what's given by Fellippe, we have a "sample rate" of 44100 samples per second. That is: every 1/44100 seconds, we are handed the instantaneous volume of the sound being played. By plotting the sound data horizontally, there is precisely one "piece of data" per pixel. This means that the so-called "speed of sound" is exactly 44100 pixels per second in this scheme.

Let me label the speed of sound on screen as C = 44100 pixels/sec.

Now for some terms. Suppose we are handed a very simple sine curve. No weird squiggles, no squares or sawtooth waves yet, just a sine.

The "period" ( T ) of the wave is the TIME taken, like in seconds, for the entire wave to repeat itself.
The "frequency" ( F ) of the wave, is one divided by the period. This is why we measure frequency in Hz, which are just inverse seconds.
The "wavelength" ( L ) of the wave, is the peak-to-peak span, measured in pixels.

Now the cool part: What ties the variables all together, is the following wave equation:

C = L * F

So that means we can measure L and calculate F.

Here is a full-blown example measurement of a 200-hz sine wave:

 [ This attachment cannot be displayed inline in 'Print Page' view ]  



Alright, so what about more complicated patterns?

Well, any complicated wave is actually the sum of simple waves, and each of those simple waves obeys the equation above. However, it's a little harder to discern what's happening by just looking at the sum of two of more waves. For an example, I chose to overlay a 400hz sine wave onto a 500hz sine wave, both having equal volumes. This gives rise to a "binaural beat" which you can actually hear at not 500hz or 400hz, but the difference of the two, aka. 100hz. I have measured the 100hz beat frequency in the image below.

 [ This attachment cannot be displayed inline in 'Print Page' view ]  



In conclusion: frequency can only be reliably understood using the construction(s) above. It's misguiding to try counting it from the number of times the graph crosses the the x-axis, or anything like that. It will only turn out correct by accident, and only for pure sine curves.

tldr:
(i) know what the speed of sound on screen is
(ii) measure the wavelength of the thing you're measuring
(iii) let the equation tell you the frequency



Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 02, 2021, 03:30:30 pm
Thanks for reply, STxAxTIC.

You don't even know (actually, you know, but I didn't know) how big you're right. Carve your words in stone. If I do it the way I intended, my bass frequency - the deep tones will completely overlap the tones of the higher frequencies. So the question is, but don't even bother to explain it to me, he's already tried it _Vince - but it came across my stupidity - how the hell to filter out the individual frequencies from each other. Each of the frequencies can start anywhere in time ... yeah, I know and some Furrier transforms, but as I wrote, I'm too stupid for that.

So here I add a program - a demonstration of how not to do it. How my bad program works:

You are somewhere in the audio position during playback, you get the position as INT (_SNGETPOS * _SNDRATE). From this point you go back in the _MEM field to the sample, which has the opposite polarity than the sample in the place where you started. You count the number of samples from your starting point. Then you do the same thing in opposite - again from the place in the field where the same starting position is, you go to the sample, which has the opposite polarity. During this, you also add the volumes (sizes) of these samples.
When you encounter a sample with the opposite polarity, you calculate the total volume of that sample as the sum of the volumes / number of all samples.
The numbers of samples are added (this will give you the duration of this sample - by calculating 1 / _SNDRATE * number of these samples)
Finally, a modified formula is used to calculate the frequency, because the described process actually detects only one half-period of the frequency.

Now I will deviate from frequency detection again and do something else again. :)

Code: QB64: [Select]
  1. 'Example how it not works and how not writing this...
  2.  
  3. INPUT "Insert sound file name:"; s$
  4. PRINT "Opening file..."
  5.  
  6. s = _SNDOPEN(s$)
  7. IF s = 0 THEN PRINT "Invalid sound file.": END
  8. DIM left AS _MEM, right AS _MEM, SampleL AS _UNSIGNED INTEGER, SampleR AS _UNSIGNED INTEGER
  9. DIM VolL AS SINGLE, VolR AS SINGLE, BytePos AS LONG
  10. left = _MEMSOUND(s, 1)
  11. right = _MEMSOUND(s, 2)
  12.  
  13. SCREEN _NEWIMAGE(800, 600, 32)
  14. DIM LeftBox(7) AS INTEGER
  15. DIM RightBox(7) AS INTEGER
  16. DIM LeftVol(7) AS SINGLE
  17. DIM RightVol(7) AS SINGLE
  18. LeftVol(0) = 0
  19.  
  20. FOR an = 20 TO 244 STEP 32
  21.     LeftBox(i) = an + 1
  22.     LINE (an, 300)-(an + 29, 550), , B
  23.     RightBox(i) = an + 497
  24.     LINE (an + 496, 300)-(an + 525, 550), , B
  25.     i = i + 1
  26. i = 0
  27.     IF _SNDGETPOS(s) > .2 THEN
  28.         BytePos = INT(_SNDGETPOS(s) * _SNDRATE)
  29.         _MEMGET left, left.OFFSET + BytePos, SampleL
  30.         L = SGN(SampleL)
  31.         _MEMGET right, right.OFFSET + BytePos, SampleR
  32.         R = SGN(SampleR)
  33.  
  34.         i = 0
  35.         DO UNTIL SGN(SampleL) <> L
  36.             i = i - 2
  37.             IF i < left.OFFSET THEN EXIT DO
  38.             _MEMGET left, left.OFFSET + BytePos + i, SampleL
  39.             LeftVol = LeftVol + SampleL
  40.         LOOP
  41.         j = 0
  42.         _MEMGET left, left.OFFSET + BytePos, SampleL
  43.  
  44.         DO UNTIL SGN(SampleL) <> L
  45.             j = j + 2
  46.             IF j > left.SIZE THEN EXIT DO
  47.             _MEMGET left, left.OFFSET + BytePos + j, SampleL
  48.             LeftVol = LeftVol + SampleL
  49.         LOOP
  50.         DeltaL = ABS(i / 2) + j / 2
  51.  
  52.         i = 0
  53.         DO UNTIL SGN(SampleR) <> R
  54.             i = i - 2
  55.             IF i < right.OFFSET THEN EXIT DO
  56.             _MEMGET right, right.OFFSET + BytePos + i, SampleR
  57.             RightVol = RightVol + SampleR
  58.         LOOP
  59.         j = 0
  60.         _MEMGET right, right.OFFSET + BytePos, SampleR
  61.         DO UNTIL SGN(SampleR) <> R
  62.             IF j > right.SIZE THEN EXIT DO
  63.             j = j + 2
  64.             _MEMGET right, right.OFFSET + BytePos + j, SampleR
  65.             RightVol = RightVol + SampleR
  66.         LOOP
  67.         DeltaR = ABS(i / 2) + j / 2
  68.     END IF
  69.  
  70.  
  71.     FrequencyL = 1 / 44100 * DeltaL ' Time - amplitude duration between 2 samples - Left channel
  72.     FrequencyR = 1 / 44100 * DeltaR ' Time - amplitude duration between 2 samples - Right channel
  73.  
  74.     FL = FrequencyL * _SNDRATE / 2 / _PI(2) 'Frequency Left
  75.     FR = FrequencyR * _SNDRATE / 2 / _PI(2) 'Frequency Right
  76.  
  77.  
  78.     IF LeftVol THEN VolL = LeftVol / DeltaL / 32767: LeftVol = 0 ' This, current amplitude size (volume level) - Left
  79.     IF RightVol THEN VolR = RightVol / DeltaR / 32767: RightVol = 0 '                                             Right
  80.     '   PRINT FL; VolL; FR; VolR, FrequencyL; FrequencyR
  81.  
  82.     SELECT CASE FL
  83.         CASE 0 TO 150: BoxL = 0
  84.         CASE 151 TO 350: BoxL = 1
  85.         CASE 300 TO 500: BoxL = 2
  86.         CASE 501 TO 1000: BoxL = 3
  87.         CASE 1001 TO 2200: BoxL = 4
  88.         CASE 2201 TO 5000: BoxL = 5
  89.         CASE 5001 TO 6000: BoxL = 6
  90.         CASE IS > 6001: BoxL = 7
  91.  
  92.  
  93.     END SELECT
  94.  
  95.     SELECT CASE FR
  96.         CASE 0 TO 150: BoxR = 0
  97.         CASE 151 TO 350: BoxR = 1
  98.         CASE 300 TO 500: BoxR = 2
  99.         CASE 501 TO 1000: BoxR = 3
  100.         CASE 1001 TO 2200: BoxR = 4
  101.         CASE 2201 TO 5000: BoxR = 5
  102.         CASE 5001 TO 6000: BoxR = 6
  103.         CASE IS > 6001: BoxR = 7
  104.  
  105.     END SELECT
  106.  
  107.     PCOPY 1, _DISPLAY
  108.     LeftVol(BoxL) = LeftVol(BoxL) + VolL
  109.     IF LeftVol(BoxL) > 1 THEN LeftVol(BoxL) = 1
  110.  
  111.     RightVol(BoxR) = RightVol(BoxR) + VolR
  112.     IF RightVol(BoxR) > 1 THEN RightVol(BoxR) = 1
  113.  
  114.     FOR d = 0 TO 7
  115.         LINE (LeftBox(d), 549)-(LeftBox(d) + 27, 550 - (149 * LeftVol(d))), Red, BF
  116.         IF RightVol(d) <= 1 THEN LINE (RightBox(d), 549)-(RightBox(d) + 27, 550 - (149 * RightVol(d))), Red, BF
  117.         LeftVol(d) = LeftVol(d) - .003
  118.         IF LeftVol(d) < 0 THEN LeftVol(d) = 0
  119.         RightVol(d) = RightVol(d) - .003
  120.         IF RightVol(d) < 0 THEN RightVol(d) = 0
  121.     NEXT d
  122.     _DISPLAY
  123.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: STxAxTIC on January 02, 2021, 05:51:36 pm
Hello again Petr,

I was successful in implementing a very crude, non-optimized, but correct discrete Fourier transform. It's very crude for now, as expected - but rather than deliver a highly polished result, I thought I would share the early stage of the whole thing working. Below are are few screenshots. The "measured" frequencies are plotted in red. For pure tones, we should expect to see only one bar at a time, which is indeed evident. For the last picture, I used the 400hz + 500hz binaural beat, which predicts TWO red bars. Luckily, they show up! So, the whole thing now works - it just needs optimization to look nice.

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

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Craz1000 on January 02, 2021, 09:39:47 pm
I have a game project that has been on hold for over 2 years because I needed a way to get an oscilloscope working. Yes!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Dav on January 02, 2021, 10:34:19 pm
This all sounds very interesting!   Could something like this be used to analyze a played pitch and see if it's in tune?  Like frequency 440 Hz is the note A.    I tune pianos on the side, wonder if it would be possible to make a piano tuning app in QB64?

- Dav 
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 03, 2021, 03:57:14 am
Hi everyone.

@STxAxTIC: I had to leave the forum yesterday, it was half past one in the morning when I finished and I don't think much of it at that time.
Thanks for the new example, I'll take a look right away.

@Dav : I think this option is already here, but you have to use the 32-bit version of the IDE in version 0.954 and the SFML library. I have verified that in this version it is really possible to use a microphone with the SFML library with the QB64. Of course, is there a possibility (and I haven't looked so far) that maybe @SpriggsySpriggs has developed a library that allows it in newer versions?

Before adding post to this thread by @STxAxTIC, I wrote a simple - and sometimes I think practical - thing - when someone does a music editor, so here's a simple example of how to mute the sound at the end of an audio track. Of course, this can be done anywhere with a easy modification.

Code: QB64: [Select]
  1. INPUT "Insert music file name:"; m$
  2. INPUT "How long retreat at the end of the track do you want to create? [sec]"; delay
  3.  
  4.     PRINT "Opening file..."
  5.     music = _SNDOPEN(m$)
  6.     DIM left AS _MEM
  7.     DIM right AS _MEM
  8.     DIM NewSound AS _MEM
  9.     DIM position AS _OFFSET, D AS DOUBLE
  10.     DIM Size AS _OFFSET, DT AS _OFFSET, audio AS INTEGER
  11.  
  12.     left = _MEMSOUND(music, 1)
  13.     right = _MEMSOUND(music, 2)
  14.  
  15.     position = left.SIZE - _SNDRATE * delay * 2 'INTEGER, so * 2
  16.     downturn = 1 / (_SNDRATE * delay)
  17.  
  18.     IF right.SIZE > 0 THEN Size = left.SIZE * 2 ELSE Size = left.SIZE
  19.     NewSound = _MEMNEW(Size)
  20.  
  21.     'create downturn on both tracks...
  22.     PRINT "Building downturn..."
  23.  
  24.     DT = left.SIZE - 2
  25.  
  26.     DO UNTIL DT <= position
  27.         _MEMGET left, left.OFFSET + DT, audio
  28.         audio = audio * D
  29.         _MEMPUT left, left.OFFSET + DT, audio
  30.         IF right.SIZE > 0 THEN
  31.             _MEMGET right, right.OFFSET + DT, audio
  32.             audio = audio * D
  33.             _MEMPUT right, right.OFFSET + DT, audio
  34.         END IF
  35.         D = D + downturn
  36.         DT = DT - 2
  37.     LOOP
  38.     PRINT "Creating new track..."
  39.     'create one stereo track
  40.     DT = 0
  41.     i = 0
  42.     DO UNTIL i = left.SIZE
  43.         _MEMGET left, left.OFFSET + i, audio
  44.         _MEMPUT NewSound, NewSound.OFFSET + DT, audio
  45.         IF right.SIZE > 0 THEN
  46.             DT = DT + 2
  47.             _MEMGET right, right.OFFSET + i, audio
  48.             _MEMPUT NewSound, NewSound.OFFSET + DT, audio
  49.         END IF
  50.         DT = DT + 2
  51.         i = i + 2
  52.     LOOP
  53.  
  54.     'save work
  55.     f$ = "downturn_test.wav"
  56.     SAVESOUND16S NewSound, f$
  57.     PRINT "New audio file saved as "; f$
  58.     PRINT "Skipping 5 seconds before applyed downturn and playing..."
  59.     _SNDCLOSE music
  60.     music = _SNDOPEN(f$)
  61.     _SNDSETPOS music, _SNDLEN(music) - delay - 5
  62.     _SNDPLAY music
  63.     PRINT "File "; m$; "not exist."
  64.     END
  65.  
  66. DO UNTIL _SNDPLAYING(music) = 0
  67. PRINT "Done"
  68. _SNDCLOSE music
  69. _MEMFREE right
  70. _MEMFREE NewSound
  71.  
  72.  
  73. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  74.     DIM o AS _INTEGER64, mo AS _MEM
  75.     mo = _MEM(o)
  76.     _MEMPUT mo, mo.OFFSET, OffsetVal
  77.     _MEMFREE mo
  78.     OFFSETasI64&& = o
  79.  
  80.  
  81. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  82.  
  83.     TYPE head16
  84.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  85.         size AS LONG '              4 bytes  (file size)
  86.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  87.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  88.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  89.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  90.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  91.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  92.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  93.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  94.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  95.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  96.         lenght AS LONG '            4 bytes  Data block size
  97.     END TYPE '                     44 bytes  total
  98.     DIM H16 AS head16
  99.     ch = FREEFILE
  100.  
  101.     H16.chunk = "RIFF"
  102.     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
  103.  
  104.     H16.fomat = "WAVE"
  105.     H16.sub1 = "fmt "
  106.     H16.subchunksize = 16
  107.     H16.format = 1
  108.     H16.channels = 2
  109.     H16.rate = 44100
  110.     H16.ByteRate = 44100 * 2 * 16 / 8
  111.     H16.Block = 4
  112.     H16.Bits = 16
  113.     H16.subchunk2 = "data"
  114.     H16.lenght = OFFSETasI64(arr.SIZE)
  115.     IF _FILEEXISTS(file$) THEN KILL file$
  116.  
  117.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  118.     _MEMGET arr, arr.OFFSET, Audio$
  119.  
  120.     OPEN file$ FOR BINARY AS #ch
  121.     PUT #ch, , H16
  122.     PUT #ch, , Audio$
  123.     Audio$ = ""
  124.  
  125.     CLOSE ch
  126.  
  127.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 03, 2021, 06:11:35 am
@STxAxTIC  Thank you again for your example. Extra thanks for ''' separators, its very useful for me for better orientation in source code.

I have a few questions. In the source code, line 140. Why is the Amplitudes (x0 + 1) = 100 * a% / 32767 sample a% multiplied by one hundred? I have found that this affects the height of the amplitude. Is it an increase in sensitivity because the Amplitudes field is of type DOUBLE?

On line 168, do I understand that correctly? Do you calculate the frequency for each amplitude on the screen? Definitely yes, well yeah!

Oh yeah! And because in line 140 you calculate the amplitude depending on the width of the screen, the width of the screen is used everywhere for the calculation. So if I determine from how many samples in the _MEM field I want to count, I will do the same, but I will use the number of samples instead of the screen width.

This rendering on line 171 - 173 is  always draw by one column, that's probably just for graphic effect, right?

The BarFrequency, BarWaveLenght are not used for calculation, they are just for visualization, as It look.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 03, 2021, 08:18:00 pm
_MEMSOUND has now made it to the development build, and there have been a few fixes since the alpha testing you guys started. @Petr make sure you get the latest update (_SNDCLOSE has been fixed, also reading the new .SOUND element of the _MEM udt has been fixed).

Anyone willing to test the cool samples above in this thread can now get the development build from https://www.qb64.org/portal/development-build/ and just compile them - keep us updated if all goes as expected.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 10:09:06 am
@FellippeHeitor   Hi, I came home from work a while ago, I'll get to it right away!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 10:33:21 am
First test and problem occur: Downloaded version is 32 bit, 488c4a1. Try this source code in attachment. In previous version, in which i test it, it do new audio track and then play it. BUT NOW, in this version it do new audio track as expected, return valid handle for sound (it open created wav audio file and handle for it is 2) but nothing is playing. If i try play this file with windows media player, it plays correctly. Because valid handle is returned, i try _SNDLEN, if track time is writed correctly and - it is. But play not.

eee :) source code...

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack + add echo
  2.  
  3. EchoLenght = 0.12 '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. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Audio2 AS INTEGER, Audio3 AS INTEGER, Audio4 AS INTEGER
  11. REDIM PlayableFiles(0) AS STRING
  12.  
  13.  
  14. 'INPUT "Insert audio file name:"; a1$
  15.  
  16.     FUNCTION load_dir& (s AS STRING)
  17.     FUNCTION has_next_entry& ()
  18.     SUB close_dir ()
  19.     SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  20.  
  21. REDIM Dir(0) AS STRING, File(0) AS STRING
  22. GetFileList _CWD$, Dir(), File()
  23.  
  24.  
  25. FOR s = LBOUND(file) TO UBOUND(file)
  26.     SELECT CASE UCASE$(RIGHT$(File(s), 3))
  27.         CASE "MP3", "OGG", "WAV"
  28.             PlayableFiles(i) = File(s)
  29.             i = i + 1
  30.             REDIM _PRESERVE PlayableFiles(i) AS STRING
  31.     END SELECT
  32.  
  33. PRINT "Files to play: "; i - 1
  34.  
  35.  
  36. FOR playit = 0 TO i - 1
  37.     a1$ = PlayableFiles(playit)
  38.     PRINT "Opening file "; playit + 1; "/"; i - 1; " - "; PlayableFiles(playit)
  39.     IF a THEN _SNDCLOSE a
  40.     a = _SNDOPEN(a1$)
  41.     IF a THEN PRINT "Audio file opened" ELSE PRINT "Audio file 1 opening error.": END
  42.     LENa = _CEIL(_SNDLEN(a)) + EchoLenght
  43.     PRINT "Audio file lenght:"; LENa
  44.     NewTrackTime = LENa
  45.  
  46.  
  47.  
  48.  
  49.     Left = _MEMSOUND(a, 1)
  50.     Right = _MEMSOUND(a, 2)
  51.  
  52.     NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  53.     NewSound = _MEMNEW(NewSoundSize&)
  54.  
  55.     PRINT "SndRate:"; _SNDRATE
  56.     PRINT "Track memory len:"; Left.SIZE
  57.     PRINT "Creating audio..."
  58.  
  59.     VolDown = 1 / OverSampling
  60.     Create& = 0
  61.     NewAudio& = 0
  62.     DO UNTIL Create& >= Left.SIZE - 2
  63.         _MEMGET Left, Left.OFFSET + Create&, Audio
  64.         _MEMGET Right, Right.OFFSET + Create&, Audio2
  65.  
  66.         IF Create& > Echo& THEN
  67.  
  68.             E& = Create&
  69.             Vol = 1
  70.             DO UNTIL E& <= Create& - OverSampling
  71.                 Vol = Vol - VolDown
  72.                 _MEMGET Left, Left.OFFSET + Create& - Echo&, Audio3
  73.                 _MEMGET Left, Left.OFFSET + Create& - 2, Audio4
  74.                 Audio = (Audio + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  75.                 E& = E& - 2
  76.             LOOP
  77.  
  78.             E& = Create&
  79.             Vol = 1
  80.             DO UNTIL E& <= Create& - OverSampling
  81.                 Vol = Vol - VolDown
  82.                 _MEMGET Right, Right.OFFSET + Create& - Echo&, Audio3
  83.                 _MEMGET Right, Right.OFFSET + Create& - 2, Audio4
  84.                 Audio2 = (Audio2 + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  85.                 E& = E& - 2
  86.             LOOP
  87.         END IF
  88.  
  89.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio 'left channel
  90.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio& + 2, Audio2 'right channel
  91.         NewAudio& = NewAudio& + 4
  92.         Create& = Create& + 2
  93.     LOOP
  94.  
  95.     PRINT "New sound created. Saving as Tracks-mix4.wav..."
  96.     SAVESOUND16S NewSound, "Tracks-mix4.wav"
  97.     PRINT "Sound saved, erasing RAM..."
  98.     _MEMFREE Left
  99.     _MEMFREE Right
  100.     _MEMFREE NewSound
  101.  
  102.     PRINT "Playing mixed sound"
  103.     snd = _SNDOPEN("tracks-mix4.wav")
  104.     _SNDPLAY snd
  105.     DO UNTIL _SNDPLAYING(snd) = 0
  106.         LOCATE 12
  107.         PRINT _SNDGETPOS(snd)
  108.     LOOP
  109.     CLS
  110.     _SNDCLOSE snd
  111.     KILL "tracks-mix4.wav"
  112.  
  113.  
  114.  
  115. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  116.     DIM o AS _INTEGER64, mo AS _MEM
  117.     mo = _MEM(o)
  118.     _MEMPUT mo, mo.OFFSET, OffsetVal
  119.     _MEMFREE mo
  120.     OFFSETasI64&& = o
  121.  
  122.  
  123. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  124.  
  125.     TYPE head16
  126.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  127.         size AS LONG '              4 bytes  (file size)
  128.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  129.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  130.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  131.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  132.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  133.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  134.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  135.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  136.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  137.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  138.         lenght AS LONG '            4 bytes  Data block size
  139.     END TYPE '                     44 bytes  total
  140.     DIM H16 AS head16
  141.     ch = FREEFILE
  142.  
  143.     H16.chunk = "RIFF"
  144.     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
  145.  
  146.     H16.fomat = "WAVE"
  147.     H16.sub1 = "fmt "
  148.     H16.subchunksize = 16
  149.     H16.format = 1
  150.     H16.channels = 2
  151.     H16.rate = 44100
  152.     H16.ByteRate = 44100 * 2 * 16 / 8
  153.     H16.Block = 4
  154.     H16.Bits = 16
  155.     H16.subchunk2 = "data"
  156.     H16.lenght = OFFSETasI64(arr.SIZE)
  157.     IF _FILEEXISTS(file$) THEN KILL file$
  158.  
  159.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  160.     _MEMGET arr, arr.OFFSET, Audio$
  161.  
  162.     OPEN file$ FOR BINARY AS #ch
  163.     PUT #ch, , H16
  164.     PUT #ch, , Audio$
  165.     Audio$ = ""
  166.  
  167.     CLOSE ch
  168.  
  169. SUB GetFileList (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
  170.     CONST IS_DIR = 1
  171.     CONST IS_FILE = 2
  172.     DIM flags AS LONG, file_size AS LONG
  173.  
  174.     REDIM _PRESERVE DirList(100), FileList(100)
  175.     DirCount = 0: FileCount = 0
  176.  
  177.     IF load_dir(SearchDirectory) THEN
  178.         DO
  179.             length = has_next_entry
  180.             IF length > -1 THEN
  181.                 nam$ = SPACE$(length)
  182.                 get_next_entry nam$, flags, file_size
  183.                 IF (flags AND IS_DIR) OR _DIREXISTS(SearchDirectory + nam$) THEN
  184.                     DirCount = DirCount + 1
  185.                     IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
  186.                     DirList(DirCount) = nam$
  187.                 ELSEIF (flags AND IS_FILE) OR _FILEEXISTS(SearchDirectory + nam$) THEN
  188.                     FileCount = FileCount + 1
  189.                     IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
  190.                     FileList(FileCount) = nam$
  191.                 END IF
  192.             END IF
  193.         LOOP UNTIL length = -1
  194.         close_dir
  195.     ELSE
  196.     END IF
  197.     REDIM _PRESERVE DirList(DirCount)
  198.     REDIM _PRESERVE FileList(FileCount)
  199.  
  200.  
  201.  


  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 10:38:48 am
Because you are opening sound files in sequence, and using the same variable to hold the handle, it's important to reset it to 0 before attempting to _SNDOPEN again. See if this fixes it:

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack + add echo
  2.  
  3. EchoLenght = 0.12 '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. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Audio2 AS INTEGER, Audio3 AS INTEGER, Audio4 AS INTEGER
  11. REDIM PlayableFiles(0) AS STRING
  12.  
  13.  
  14. 'INPUT "Insert audio file name:"; a1$
  15.  
  16.     FUNCTION load_dir& (s AS STRING)
  17.     FUNCTION has_next_entry& ()
  18.     SUB close_dir ()
  19.     SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  20.  
  21. REDIM Dir(0) AS STRING, File(0) AS STRING
  22. GetFileList _CWD$, Dir(), File()
  23.  
  24.  
  25. FOR s = LBOUND(file) TO UBOUND(file)
  26.     SELECT CASE UCASE$(RIGHT$(File(s), 3))
  27.         CASE "MP3", "OGG", "WAV"
  28.             PlayableFiles(i) = File(s)
  29.             i = i + 1
  30.             REDIM _PRESERVE PlayableFiles(i) AS STRING
  31.     END SELECT
  32.  
  33. PRINT "Files to play: "; i - 1
  34.  
  35.  
  36. FOR playit = 0 TO i - 1
  37.     a1$ = PlayableFiles(playit)
  38.     PRINT "Opening file "; playit + 1; "/"; i - 1; " - "; PlayableFiles(playit)
  39.     IF a THEN _SNDCLOSE a: a = 0
  40.     a = _SNDOPEN(a1$)
  41.     IF a THEN PRINT "Audio file opened" ELSE PRINT "Audio file 1 opening error.": END
  42.     LENa = _CEIL(_SNDLEN(a)) + EchoLenght
  43.     PRINT "Audio file lenght:"; LENa
  44.     NewTrackTime = LENa
  45.  
  46.  
  47.  
  48.  
  49.     Left = _MEMSOUND(a, 1)
  50.     Right = _MEMSOUND(a, 2)
  51.  
  52.     NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  53.     NewSound = _MEMNEW(NewSoundSize&)
  54.  
  55.     PRINT "SndRate:"; _SNDRATE
  56.     PRINT "Track memory len:"; Left.SIZE
  57.     PRINT "Creating audio..."
  58.  
  59.     VolDown = 1 / OverSampling
  60.     Create& = 0
  61.     NewAudio& = 0
  62.     DO UNTIL Create& >= Left.SIZE - 2
  63.         _MEMGET Left, Left.OFFSET + Create&, Audio
  64.         _MEMGET Right, Right.OFFSET + Create&, Audio2
  65.  
  66.         IF Create& > Echo& THEN
  67.  
  68.             E& = Create&
  69.             Vol = 1
  70.             DO UNTIL E& <= Create& - OverSampling
  71.                 Vol = Vol - VolDown
  72.                 _MEMGET Left, Left.OFFSET + Create& - Echo&, Audio3
  73.                 _MEMGET Left, Left.OFFSET + Create& - 2, Audio4
  74.                 Audio = (Audio + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  75.                 E& = E& - 2
  76.             LOOP
  77.  
  78.             E& = Create&
  79.             Vol = 1
  80.             DO UNTIL E& <= Create& - OverSampling
  81.                 Vol = Vol - VolDown
  82.                 _MEMGET Right, Right.OFFSET + Create& - Echo&, Audio3
  83.                 _MEMGET Right, Right.OFFSET + Create& - 2, Audio4
  84.                 Audio2 = (Audio2 + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  85.                 E& = E& - 2
  86.             LOOP
  87.         END IF
  88.  
  89.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio 'left channel
  90.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio& + 2, Audio2 'right channel
  91.         NewAudio& = NewAudio& + 4
  92.         Create& = Create& + 2
  93.     LOOP
  94.  
  95.     PRINT "New sound created. Saving as Tracks-mix4.wav..."
  96.     SAVESOUND16S NewSound, "Tracks-mix4.wav"
  97.     PRINT "Sound saved, erasing RAM..."
  98.     _MEMFREE Left
  99.     _MEMFREE Right
  100.     _MEMFREE NewSound
  101.  
  102.     PRINT "Playing mixed sound"
  103.     snd = _SNDOPEN("tracks-mix4.wav")
  104.     _SNDPLAY snd
  105.     DO UNTIL _SNDPLAYING(snd) = 0
  106.         LOCATE 12
  107.         PRINT _SNDGETPOS(snd)
  108.     LOOP
  109.     CLS
  110.     _SNDCLOSE snd
  111.     KILL "tracks-mix4.wav"
  112.  
  113.  
  114.  
  115. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  116.     DIM o AS _INTEGER64, mo AS _MEM
  117.     mo = _MEM(o)
  118.     _MEMPUT mo, mo.OFFSET, OffsetVal
  119.     _MEMFREE mo
  120.     OFFSETasI64&& = o
  121.  
  122.  
  123. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  124.  
  125.     TYPE head16
  126.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  127.         size AS LONG '              4 bytes  (file size)
  128.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  129.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  130.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  131.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  132.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  133.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  134.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  135.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  136.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  137.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  138.         lenght AS LONG '            4 bytes  Data block size
  139.     END TYPE '                     44 bytes  total
  140.     DIM H16 AS head16
  141.     ch = FREEFILE
  142.  
  143.     H16.chunk = "RIFF"
  144.     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
  145.  
  146.     H16.fomat = "WAVE"
  147.     H16.sub1 = "fmt "
  148.     H16.subchunksize = 16
  149.     H16.format = 1
  150.     H16.channels = 2
  151.     H16.rate = 44100
  152.     H16.ByteRate = 44100 * 2 * 16 / 8
  153.     H16.Block = 4
  154.     H16.Bits = 16
  155.     H16.subchunk2 = "data"
  156.     H16.lenght = OFFSETasI64(arr.SIZE)
  157.     IF _FILEEXISTS(file$) THEN KILL file$
  158.  
  159.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  160.     _MEMGET arr, arr.OFFSET, Audio$
  161.  
  162.     OPEN file$ FOR BINARY AS #ch
  163.     PUT #ch, , H16
  164.     PUT #ch, , Audio$
  165.     Audio$ = ""
  166.  
  167.     CLOSE ch
  168.  
  169. SUB GetFileList (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
  170.     CONST IS_DIR = 1
  171.     CONST IS_FILE = 2
  172.     DIM flags AS LONG, file_size AS LONG
  173.  
  174.     REDIM _PRESERVE DirList(100), FileList(100)
  175.     DirCount = 0: FileCount = 0
  176.  
  177.     IF load_dir(SearchDirectory) THEN
  178.         DO
  179.             length = has_next_entry
  180.             IF length > -1 THEN
  181.                 nam$ = SPACE$(length)
  182.                 get_next_entry nam$, flags, file_size
  183.                 IF (flags AND IS_DIR) OR _DIREXISTS(SearchDirectory + nam$) THEN
  184.                     DirCount = DirCount + 1
  185.                     IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
  186.                     DirList(DirCount) = nam$
  187.                 ELSEIF (flags AND IS_FILE) OR _FILEEXISTS(SearchDirectory + nam$) THEN
  188.                     FileCount = FileCount + 1
  189.                     IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
  190.                     FileList(FileCount) = nam$
  191.                 END IF
  192.             END IF
  193.         LOOP UNTIL length = -1
  194.         close_dir
  195.     ELSE
  196.     END IF
  197.     REDIM _PRESERVE DirList(DirCount)
  198.     REDIM _PRESERVE FileList(FileCount)
  199.  
  200.  
  201.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 10:43:55 am
NOT. I test also your new 64bit version now and there all works without any upgrades in my source code as expected. So bug is in 32 bit version only.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 10:45:27 am
I'll try to reproduce it on my end. Mind sending me the offending audio file?

Keep in mind I've been developing _MEMSOUND in a 32bit environment, btw.

Also, keep in mind the need to reset the handle variable before loading new data.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 10:55:32 am
My first version, named as qb64-memsound downloaded from github is 64bit. Which file you need? Created output WAV file or file on input (MP3)?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 10:57:50 am
I tried in my machine and it worked with some files, not with others - which leads me to believe it has to do with the file generated and how OpenAL is decoding it - in which case debugging it beyond my abilities, since it's a third-party library. Let me know if you find something else that could be the cause.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 10:59:16 am
Could you try playing the generated files with v1.4? I believe this has nothing to do with the new _MEMSOUND after all, since your issue is with regular _SNDPLAY.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 11:02:23 am
I'll try, but it will work. This cannot be a bug in OpenAl when the 64-bit version plays it. Even the 32-bit version reads correctly the length of the audio. But it won't start. 64 bit starts it. 32 bit sees the length of the music but does not start playing.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 11:08:46 am
This was wrong, I was too fast. Searching problems...
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 11:10:27 am
Something related to the audio library then, since none of that code has been touched recently.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 11:38:01 am
So..... IDIOT AM I. Again.  Bad writed head in WAV file was the problem.


in SAVESOUND16S replace this row:   H16.lenght = OFFSETasI64(arr.SIZE) - 2
We still using integers.... NOW 32 bit version works as expected!

BIG SORRY FOR THIS.   -2  miss

Please try it also. I have five IDEs open here and I'm quickly losing track.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 11:38:52 am
Hahaha, glad to hear all is solved.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 11:44:12 am
The big unknown is: Why the this bug is none problem for 64 bit version, but it is problem for 32 bit version? Just add -2 and is done...

I am also very glad, that it works and this nice function can be added!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 11:51:47 am
Fellippe, but still:

This code was work under 32 bit:

Code: QB64: [Select]
  1. 'Program create new WAV soundtrack + add echo
  2. 'if _fileexists("1d.mp3")
  3. '_SNDPLAYFILE ("1d.mp3")
  4. 'SLEEP
  5.  
  6. '_SNDPLAYFILE ("tracks-mix4.wav")
  7.  
  8. 'SLEEP
  9.  
  10. EchoLenght = 0.12 '0.06 seconds is echo duration
  11. OverSampling = 10 'number of echoes sample passes
  12.  
  13. Echo& = _SNDRATE * EchoLenght
  14.  
  15. DO UNTIL Echo& MOD 2 = 0
  16.     Echo& = Echo& + 1
  17. DIM Left AS _MEM, Right AS _MEM, NewSound AS _MEM, Audio AS INTEGER, Audio2 AS INTEGER, Audio3 AS INTEGER, Audio4 AS INTEGER
  18. REDIM PlayableFiles(0) AS STRING
  19.  
  20.  
  21. 'INPUT "Insert audio file name:"; a1$
  22.  
  23.     FUNCTION load_dir& (s AS STRING)
  24.     FUNCTION has_next_entry& ()
  25.     SUB close_dir ()
  26.     SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
  27.  
  28. REDIM Dir(0) AS STRING, File(0) AS STRING
  29. GetFileList _CWD$, Dir(), File()
  30.  
  31.  
  32. FOR s = LBOUND(file) TO UBOUND(file)
  33.     SELECT CASE UCASE$(RIGHT$(File(s), 3))
  34.         CASE "MP3", "OGG", "WAV"
  35.             PlayableFiles(i) = File(s)
  36.             i = i + 1
  37.             REDIM _PRESERVE PlayableFiles(i) AS STRING
  38.     END SELECT
  39.  
  40. PRINT "Files to play: "; i - 1
  41.  
  42.  
  43. FOR playit = 0 TO i - 1
  44.     a1$ = PlayableFiles(playit)
  45.     PRINT "Opening file "; playit + 1; "/"; i - 1; " - "; PlayableFiles(playit)
  46.     IF a THEN _SNDCLOSE a: a = 0
  47.     a = _SNDOPEN(a1$)
  48.     IF a THEN PRINT "Audio file opened" ELSE PRINT "Audio file 1 opening error.": END
  49.     LENa = _CEIL(_SNDLEN(a)) + EchoLenght
  50.     PRINT "Audio file lenght:"; LENa
  51.     NewTrackTime = LENa
  52.  
  53.  
  54.  
  55.  
  56.     Left = _MEMSOUND(a, 1)
  57.     Right = _MEMSOUND(a, 2)
  58.  
  59.     NewSoundSize& = _SNDRATE * NewTrackTime * 2 * 2 'use stereo  + use INTEGER
  60.     NewSound = _MEMNEW(NewSoundSize&)
  61.  
  62.     PRINT "SndRate:"; _SNDRATE
  63.     PRINT "Track memory len:"; Left.SIZE
  64.     PRINT "Creating audio..."
  65.  
  66.     VolDown = 1 / OverSampling
  67.     Create& = 0
  68.     NewAudio& = 0
  69.     DO UNTIL Create& >= Left.SIZE - 2
  70.         _MEMGET Left, Left.OFFSET + Create&, Audio
  71.         _MEMGET Right, Right.OFFSET + Create&, Audio2
  72.  
  73.         IF Create& > Echo& THEN
  74.  
  75.             E& = Create&
  76.             Vol = 1
  77.             DO UNTIL E& <= Create& - OverSampling
  78.                 Vol = Vol - VolDown
  79.                 _MEMGET Left, Left.OFFSET + Create& - Echo&, Audio3
  80.                 _MEMGET Left, Left.OFFSET + Create& - 2, Audio4
  81.                 Audio = (Audio + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  82.                 E& = E& - 2
  83.             LOOP
  84.  
  85.             E& = Create&
  86.             Vol = 1
  87.             DO UNTIL E& <= Create& - OverSampling
  88.                 Vol = Vol - VolDown
  89.                 _MEMGET Right, Right.OFFSET + Create& - Echo&, Audio3
  90.                 _MEMGET Right, Right.OFFSET + Create& - 2, Audio4
  91.                 Audio2 = (Audio2 + Audio3 * (Vol + .01) + Audio4 * Vol) \ 3
  92.                 E& = E& - 2
  93.             LOOP
  94.         END IF
  95.  
  96.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio&, Audio 'left channel
  97.         _MEMPUT NewSound, NewSound.OFFSET + NewAudio& + 2, Audio2 'right channel
  98.         NewAudio& = NewAudio& + 4
  99.         Create& = Create& + 2
  100.     LOOP
  101.  
  102.     PRINT "New sound created. Saving as Tracks-mix4.wav..."
  103.     SAVESOUND16S NewSound, "Tracks-mix4.wav"
  104.     PRINT "Sound saved, erasing RAM..."
  105.     _MEMFREE Left
  106.     _MEMFREE Right
  107.     _MEMFREE NewSound
  108.  
  109.     PRINT "Playing mixed sound"
  110.     _SNDCLOSE a
  111.     a = 0
  112.     snd2 = _SNDOPEN("tracks-mix4.wav")
  113.     PRINT _SNDLEN(snd2), snd2
  114.     SLEEP
  115.     _SNDPLAY snd2
  116.     DO UNTIL _SNDPLAYING(snd2) = 0
  117.         LOCATE 12
  118.         PRINT _SNDGETPOS(snd2), _SNDLEN(snd2)
  119.     LOOP
  120.     CLS
  121.     _SNDCLOSE snd2
  122.     '    KILL "tracks-mix4.wav"
  123.  
  124.  
  125.  
  126. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  127.     DIM o AS _INTEGER64, mo AS _MEM
  128.     mo = _MEM(o)
  129.     _MEMPUT mo, mo.OFFSET, OffsetVal
  130.     _MEMFREE mo
  131.     OFFSETasI64&& = o
  132.  
  133.  
  134. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  135.  
  136.     TYPE head16
  137.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  138.         size AS LONG '              4 bytes  (file size)
  139.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  140.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  141.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  142.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  143.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  144.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  145.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  146.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  147.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  148.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  149.         lenght AS LONG '            4 bytes  Data block size
  150.     END TYPE '                     44 bytes  total
  151.     DIM H16 AS head16
  152.     ch = FREEFILE
  153.  
  154.     H16.chunk = "RIFF"
  155.     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
  156.  
  157.     H16.fomat = "WAVE"
  158.     H16.sub1 = "fmt "
  159.     H16.subchunksize = 16
  160.     H16.format = 1
  161.     H16.channels = 2
  162.     H16.rate = 44100
  163.     H16.ByteRate = 44100 * 2 * 16 / 8
  164.     H16.Block = 4
  165.     H16.Bits = 16
  166.     H16.subchunk2 = "data"
  167.     H16.lenght = OFFSETasI64(arr.SIZE) - 2 '  <---------------------- THIS IS THE PROBLEM. Without -2 works in 64 bit, with -2 works under 32 bit.
  168.     IF _FILEEXISTS(file$) THEN KILL file$
  169.  
  170.     Audio$ = SPACE$(OFFSETasI64(arr.SIZE))
  171.     _MEMGET arr, arr.OFFSET, Audio$
  172.  
  173.     OPEN file$ FOR BINARY AS #ch
  174.     PUT #ch, , H16
  175.     PUT #ch, , Audio$
  176.     Audio$ = ""
  177.  
  178.     CLOSE ch
  179.  
  180. SUB GetFileList (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
  181.     CONST IS_DIR = 1
  182.     CONST IS_FILE = 2
  183.     DIM flags AS LONG, file_size AS LONG
  184.  
  185.     REDIM _PRESERVE DirList(100), FileList(100)
  186.     DirCount = 0: FileCount = 0
  187.  
  188.     IF load_dir(SearchDirectory) THEN
  189.         DO
  190.             length = has_next_entry
  191.             IF length > -1 THEN
  192.                 nam$ = SPACE$(length)
  193.                 get_next_entry nam$, flags, file_size
  194.                 IF (flags AND IS_DIR) OR _DIREXISTS(SearchDirectory + nam$) THEN
  195.                     DirCount = DirCount + 1
  196.                     IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
  197.                     DirList(DirCount) = nam$
  198.                 ELSEIF (flags AND IS_FILE) OR _FILEEXISTS(SearchDirectory + nam$) THEN
  199.                     FileCount = FileCount + 1
  200.                     IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
  201.                     FileList(FileCount) = nam$
  202.                 END IF
  203.             END IF
  204.         LOOP UNTIL length = -1
  205.         close_dir
  206.     ELSE
  207.     END IF
  208.     REDIM _PRESERVE DirList(DirCount)
  209.     REDIM _PRESERVE FileList(FileCount)
  210.  


now do the same bug in 64 bit version as in previous case previous code in 32 bit! So something in 32 bit ide is shifted by 2 bytes down in 32 bit ide or is something shifted by 2 byte up in 64 bit version?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 04, 2021, 11:53:20 am
Offset sizes are different depending on the platform. It could be that.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: SMcNeill on January 04, 2021, 01:15:52 pm
Code: QB64: [Select]
  1. m = _MEM(x)
  2. PRINT m.OFFSET
  3. PRINT ConvertOffset(m.OFFSET)
  4.  
  5.  
  6. FUNCTION ConvertOffset&& (value AS _OFFSET)
  7. DIM m AS _MEM 'Define a memblock
  8. m = _MEM(value) 'Point it to use value
  9. $IF 64BIT THEN
  10.     'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
  11.     _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
  12.     'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
  13.     _MEMGET m, m.OFFSET, temp& 'Like this
  14.     ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
  15. _MEMFREE m 'Free the memblock
  16.  
  17.  

See the difference in the offset convertor above, and yours.  I imagine there’s your issue (4 vs 8 bytes).
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 01:53:42 pm
Thank you, Steve. This solved all. Now all works under all versions.

You can test it with this new effect, named as "When you shoot a turntable"

Code: QB64: [Select]
  1. 'program create speed - up track and then play it
  2. INPUT "Insert sound file name:", snd$
  3. DIM Left AS _MEM
  4. DIM Right AS _MEM
  5. DIM NewTrack AS _MEM
  6. DIM SL AS LONG, SR AS LONG
  7.  
  8. snd = _SNDOPEN(snd$)
  9. Left = _MEMSOUND(snd, 1)
  10. Right = _MEMSOUND(snd, 2)
  11. IF Right.SIZE = 0 THEN PRINT "Program need stereo track!": END
  12. NewTrack = _MEMNEW(Left.SIZE * 2)
  13. R = 0
  14. DO UNTIL p& >= Left.SIZE - R
  15.     IF p& MOD 88200 = 0 THEN R = R + 2
  16.     IF p& + R > Left.SIZE THEN EXIT DO
  17.     SL = 0
  18.     SR = 0
  19.     FOR SLUC = 1 TO R
  20.         _MEMGET Left, Left.OFFSET + p& + R, S
  21.         SL = SL + S
  22.         _MEMGET Right, Right.OFFSET + p& + R, S
  23.         SR = SR + S
  24.     NEXT SLUC
  25.  
  26.     SL = SL \ R
  27.     SR = SR \ R
  28.     _MEMPUT NewTrack, NewTrack.OFFSET + i&, SL
  29.     _MEMPUT NewTrack, NewTrack.OFFSET + i& + 2, SR
  30.  
  31.     p& = p& + R
  32.     i& = i& + 4
  33.  
  34. SAVESOUND16S NewTrack, "eff2.wav"
  35. _SNDPLAYFILE ("eff2.wav")
  36.  
  37.  
  38. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  39.  
  40.     TYPE head16
  41.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  42.         size AS LONG '              4 bytes  (file size)
  43.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  44.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  45.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  46.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  47.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  48.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  49.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  50.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  51.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  52.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  53.         lenght AS LONG '            4 bytes  Data block size
  54.     END TYPE '                     44 bytes  total
  55.     DIM H16 AS head16
  56.     ch = FREEFILE
  57.  
  58.     H16.chunk = "RIFF"
  59.     H16.size = 44 + ConvertOffset&&(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  60.  
  61.     H16.fomat = "WAVE"
  62.     H16.sub1 = "fmt "
  63.     H16.subchunksize = 16
  64.     H16.format = 1
  65.     H16.channels = 2
  66.     H16.rate = 44100
  67.     H16.ByteRate = 44100 * 2 * 16 / 8
  68.     H16.Block = 4
  69.     H16.Bits = 16
  70.     H16.subchunk2 = "data"
  71.     '  $IF 32BIT THEN
  72.     '      H16.lenght = ConvertOffset&&(arr.SIZE) - 2
  73.     '  $ELSE
  74.     H16.lenght = ConvertOffset&&(arr.SIZE)
  75.     ' $END IF
  76.     IF _FILEEXISTS(file$) THEN KILL file$
  77.  
  78.     Audio$ = SPACE$(ConvertOffset&&(arr.SIZE))
  79.     _MEMGET arr, arr.OFFSET, Audio$
  80.  
  81.     OPEN file$ FOR BINARY AS #ch
  82.     PUT #ch, , H16
  83.     PUT #ch, , Audio$
  84.     Audio$ = ""
  85.  
  86.     CLOSE ch
  87.  
  88.  
  89.  
  90. FUNCTION ConvertOffset&& (value AS _OFFSET)
  91.     DIM m AS _MEM 'Define a memblock
  92.     m = _MEM(value) 'Point it to use value
  93.     $IF 64BIT THEN
  94.         'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
  95.         _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
  96.     $ELSE
  97.         'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
  98.         _MEMGET m, m.OFFSET, temp& 'Like this
  99.         ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
  100.     $END IF
  101.     _MEMFREE m 'Free the memblock
  102.  

a little better version:

Code: QB64: [Select]
  1. 'program create speed - up track and then play it
  2. INPUT "Insert sound file name:", snd$
  3. DIM Left AS _MEM
  4. DIM Right AS _MEM
  5. DIM NewTrack AS _MEM
  6. DIM SL AS LONG, SR AS LONG
  7.  
  8. snd = _SNDOPEN(snd$)
  9. Left = _MEMSOUND(snd, 1)
  10. Right = _MEMSOUND(snd, 2)
  11. IF Right.SIZE = 0 THEN PRINT "Program need stereo track!": END
  12. NewTrack = _MEMNEW(Left.SIZE)
  13. R = 0
  14. DO UNTIL p& >= Left.SIZE - R
  15.     IF i& \ 4 MOD 88200 = 0 THEN R = R + 2
  16.     IF p& + R > Left.SIZE THEN EXIT DO
  17.     SL = 0
  18.     SR = 0
  19.     FOR SLUC = 1 TO R
  20.         _MEMGET Left, Left.OFFSET + p& + R, S
  21.         SL = SL + S
  22.         _MEMGET Right, Right.OFFSET + p& + R, S
  23.         SR = SR + S
  24.     NEXT SLUC
  25.  
  26.     SL = SL \ R
  27.     SR = SR \ R
  28.     _MEMPUT NewTrack, NewTrack.OFFSET + i&, SL
  29.     _MEMPUT NewTrack, NewTrack.OFFSET + i& + 2, SR
  30.  
  31.     p& = p& + R
  32.     i& = i& + 4
  33.  
  34. 'DO UNTIL S = 0
  35.  
  36.  
  37. SAVESOUND16S NewTrack, "eff2.wav"
  38. _SNDPLAYFILE ("eff2.wav")
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  49.  
  50.     TYPE head16
  51.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  52.         size AS LONG '              4 bytes  (file size)
  53.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  54.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  55.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  56.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  57.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  58.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  59.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  60.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  61.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  62.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  63.         lenght AS LONG '            4 bytes  Data block size
  64.     END TYPE '                     44 bytes  total
  65.     DIM H16 AS head16
  66.     ch = FREEFILE
  67.  
  68.     H16.chunk = "RIFF"
  69.     H16.size = 44 + ConvertOffset&&(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  70.  
  71.     H16.fomat = "WAVE"
  72.     H16.sub1 = "fmt "
  73.     H16.subchunksize = 16
  74.     H16.format = 1
  75.     H16.channels = 2
  76.     H16.rate = 44100
  77.     H16.ByteRate = 44100 * 2 * 16 / 8
  78.     H16.Block = 4
  79.     H16.Bits = 16
  80.     H16.subchunk2 = "data"
  81.     '  $IF 32BIT THEN
  82.     '      H16.lenght = ConvertOffset&&(arr.SIZE) - 2
  83.     '  $ELSE
  84.     H16.lenght = ConvertOffset&&(arr.SIZE)
  85.     ' $END IF
  86.     IF _FILEEXISTS(file$) THEN KILL file$
  87.  
  88.     Audio$ = SPACE$(ConvertOffset&&(arr.SIZE))
  89.     _MEMGET arr, arr.OFFSET, Audio$
  90.  
  91.     OPEN file$ FOR BINARY AS #ch
  92.     PUT #ch, , H16
  93.     PUT #ch, , Audio$
  94.     Audio$ = ""
  95.  
  96.     CLOSE ch
  97.  
  98.  
  99.  
  100. FUNCTION ConvertOffset&& (value AS _OFFSET)
  101.     DIM m AS _MEM 'Define a memblock
  102.     m = _MEM(value) 'Point it to use value
  103.     $IF 64BIT THEN
  104.         'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
  105.         _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
  106.     $ELSE
  107.         'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
  108.         _MEMGET m, m.OFFSET, temp& 'Like this
  109.         ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
  110.     $END IF
  111.     _MEMFREE m 'Free the memblock
  112.  
  113.  
  114.  
  115.  
  116. FUNCTION OFFSETasI64&& (OffsetVal AS _OFFSET) 'convert OFFSET value to _INTEGER64 value -> 8 byte lenght to 8 byte lenght
  117.     DIM o AS _INTEGER64, mo AS _MEM
  118.     mo = _MEM(o)
  119.     _MEMPUT mo, mo.OFFSET, OffsetVal
  120.     _MEMFREE mo
  121.     OFFSETasI64&& = o
  122.  
  123.  

The reverse effect can be achieved by adding more samples between the existing samples (always the mathematical average of two adjacent samples), thus achieving a deceleration effect.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 04, 2021, 02:58:21 pm
But the previous version is too rough. So, here's a way to do it better. The music will gradually speed up. This is done by omitting samples. To make this transition smoother, the transition is always supplemented by one sample to the place where the samples were omitted.
The more samples you insert, the more you slow down the acceleration and smooth the transition.

Code: QB64: [Select]
  1. 'speed - up track and then play it
  2. INPUT "Insert sound file name:", snd$
  3. DIM Left AS _MEM
  4. DIM Right AS _MEM
  5. DIM NewTrack AS _MEM
  6.  
  7. snd = _SNDOPEN(snd$)
  8. Left = _MEMSOUND(snd, 1)
  9. Right = _MEMSOUND(snd, 2)
  10. IF Right.SIZE = 0 THEN PRINT "Program need stereo track!": END
  11. NewTrack = _MEMNEW(Left.SIZE * 2)
  12. R = 0
  13. DO UNTIL p& >= Left.SIZE
  14.     IF p& MOD 22050 = 0 THEN
  15.         skip& = skip& + 10: p& = p& + skip& 'speed up by 10 samples per half second.  This is linear, but it can be exponencial...
  16.         OSL = SL
  17.         OSR = SR
  18.         IF p& > Left.SIZE - 2 THEN EXIT DO
  19.         _MEMGET Left, Left.OFFSET + p&, SL
  20.         _MEMGET Right, Right.OFFSET + p&, SR
  21.         SL = (OSL + SL) \ 2
  22.         SR = (OSR + SR) \ 2
  23.         _MEMPUT NewTrack, NewTrack.OFFSET + i&, SL
  24.         _MEMPUT NewTrack, NewTrack.OFFSET + i& + 2, SR
  25.         i& = i& + 4
  26.     ELSE p& = p& + 2 'all this values must be dividible by two (integer)
  27.     END IF
  28.     IF p& > Left.SIZE - 2 THEN EXIT DO
  29.     _MEMGET Left, Left.OFFSET + p&, SL
  30.     _MEMGET Right, Right.OFFSET + p&, SR
  31.     _MEMPUT NewTrack, NewTrack.OFFSET + i&, SL
  32.     _MEMPUT NewTrack, NewTrack.OFFSET + i& + 2, SR
  33.     i& = i& + 4
  34.  
  35. SAVESOUND16S NewTrack, "eff2.wav"
  36. _SNDPLAYFILE ("eff2.wav")
  37.  
  38.  
  39. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  40.     TYPE head16
  41.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  42.         size AS LONG '              4 bytes  (file size)
  43.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  44.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  45.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  46.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  47.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  48.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  49.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  50.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  51.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  52.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  53.         lenght AS LONG '            4 bytes  Data block size
  54.     END TYPE '                     44 bytes  total
  55.     DIM H16 AS head16
  56.     ch = FREEFILE
  57.  
  58.     H16.chunk = "RIFF"
  59.     H16.size = 44 + ConvertOffset&&(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  60.  
  61.     H16.fomat = "WAVE"
  62.     H16.sub1 = "fmt "
  63.     H16.subchunksize = 16
  64.     H16.format = 1
  65.     H16.channels = 2
  66.     H16.rate = 44100
  67.     H16.ByteRate = 44100 * 2 * 16 / 8
  68.     H16.Block = 4
  69.     H16.Bits = 16
  70.     H16.subchunk2 = "data"
  71.     H16.lenght = ConvertOffset&&(arr.SIZE)
  72.     IF _FILEEXISTS(file$) THEN KILL file$
  73.     Audio$ = SPACE$(ConvertOffset&&(arr.SIZE))
  74.     _MEMGET arr, arr.OFFSET, Audio$
  75.     OPEN file$ FOR BINARY AS #ch
  76.     PUT #ch, , H16
  77.     PUT #ch, , Audio$
  78.     Audio$ = ""
  79.     CLOSE ch
  80.  
  81.  
  82.  
  83. FUNCTION ConvertOffset&& (value AS _OFFSET)
  84.     DIM m AS _MEM 'Define a memblock
  85.     m = _MEM(value) 'Point it to use value
  86.     $IF 64BIT THEN
  87.         'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
  88.         _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
  89.     $ELSE
  90.         'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
  91.         _MEMGET m, m.OFFSET, temp& 'Like this
  92.         ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
  93.     $END IF
  94.     _MEMFREE m 'Free the memblock
  95.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 05, 2021, 01:37:14 pm
Next example. Sound "ping - pong". Take two different songs (to make the effect stand out more) and have the sound sent from the right speaker to the left, with the second song going opposite. Sound position is changed continuously during playback. It's best to listening it on headphones.

Code: QB64: [Select]
  1. DIM left AS _MEM
  2. DIM Right AS _MEM
  3. DIM AudioL AS INTEGER
  4. DIM AudioR AS INTEGER
  5. DIM NewSound AS _MEM
  6. _TITLE "Sound ping - pong"
  7. INPUT "Insert music file name"; snd$
  8. INPUT "Insert music file name2"; snd2$
  9.  
  10.     snd = _SNDOPEN(snd$)
  11.     PRINT "File 1 opened"
  12.     snd2 = _SNDOPEN(snd2$)
  13.     PRINT "File 2 opened"
  14.  
  15.     left = _MEMSOUND(snd, 1)
  16.     Right = _MEMSOUND(snd2, 1)
  17.     IF Right.SIZE > left.SIZE THEN Size = left.SIZE ELSE Size = Right.SIZE
  18.     PRINT "Size: "; Size
  19.     NewSound = _MEMNEW(Size * 2)
  20.     DO UNTIL s& = Size
  21.         _MEMGET left, left.OFFSET + s&, AudioL
  22.         _MEMGET Right, Right.OFFSET + s&, AudioR
  23.         L = (AudioL * ABS(SIN(sinus)) + AudioR * ABS(COS(sinus2))) / 2
  24.         R = (AudioR * ABS(SIN(sinus2)) + AudioL * ABS(COS(sinus))) / 2
  25.         _MEMPUT NewSound, NewSound.OFFSET + t&, L
  26.         _MEMPUT NewSound, NewSound.OFFSET + t& + 2, R
  27.         sinus = sinus + .00001
  28.         sinus2 = sinus + _PI
  29.         s& = s& + 2
  30.         t& = t& + 4
  31.     LOOP
  32.     PRINT "Some file not exists."
  33.     END
  34. PRINT "Saving WAV"
  35. SAVESOUND16S NewSound, "TestEff3.wav"
  36. PRINT "Playing"
  37. _SNDPLAYFILE "TestEff3.wav"
  38. _MEMFREE Right
  39. _MEMFREE NewSound
  40.  
  41.  
  42.  
  43. SUB SAVESOUND16S (arr AS _MEM, file AS STRING)
  44.  
  45.     TYPE head16
  46.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  47.         size AS LONG '              4 bytes  (file size)
  48.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  49.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  50.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  51.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  52.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  53.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  54.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  55.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  56.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  57.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  58.         lenght AS LONG '            4 bytes  Data block size
  59.     END TYPE '                     44 bytes  total
  60.     DIM H16 AS head16
  61.     ch = FREEFILE
  62.  
  63.     H16.chunk = "RIFF"
  64.     H16.size = 44 + ConvertOffset&&(arr.SIZE) / _SNDRATE / 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  65.     H16.fomat = "WAVE"
  66.     H16.sub1 = "fmt "
  67.     H16.subchunksize = 16
  68.     H16.format = 1
  69.     H16.channels = 2
  70.     H16.rate = 44100
  71.     H16.ByteRate = 44100 * 2 * 16 / 8
  72.     H16.Block = 4
  73.     H16.Bits = 16
  74.     H16.subchunk2 = "data"
  75.     H16.lenght = ConvertOffset&&(arr.SIZE)
  76.     ' $END IF
  77.     IF _FILEEXISTS(file$) THEN KILL file$
  78.     Audio$ = SPACE$(ConvertOffset&&(arr.SIZE))
  79.     _MEMGET arr, arr.OFFSET, Audio$
  80.     OPEN file$ FOR BINARY AS #ch
  81.     PUT #ch, , H16
  82.     PUT #ch, , Audio$
  83.     Audio$ = ""
  84.     CLOSE ch
  85.  
  86.  
  87.  
  88. FUNCTION ConvertOffset&& (value AS _OFFSET)
  89.     DIM m AS _MEM 'Define a memblock
  90.     m = _MEM(value) 'Point it to use value
  91.     $IF 64BIT THEN
  92.         'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
  93.         _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
  94.     $ELSE
  95.         'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
  96.         _MEMGET m, m.OFFSET, temp& 'Like this
  97.         ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
  98.     $END IF
  99.     _MEMFREE m 'Free the memblock
  100.  
  101.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 14, 2021, 03:31:35 pm
I will return to the beginning of this thread with a few questions to @STxAxTIC

I implanted your frequency acquisition program. Finally. It seems to work perfectly. The only thing I need to clarify: The resulting frequency in your second example is given by the number of samples analyzed. It is so? Therefore, a small number of samples is sufficient to obtain low frequencies. In your example, these are pixels, my solution is _SNDGETPOS - 300 TO _SNDGETPOS + 300. This way I get 600 audio samples, that's enough to get low frequencies. But if I wanted a frequency of 20 KHz, I would need to analyze the whole second (44100 samples for precise detection). Am I getting it right, or am I completely out of it again?

Wait. What I'm writing is nonsense. After all, a high frequency can be interspersed several times, even in a small number of samples. So it will be possible to construct the frequency detection as an average in six hundred samples. This is an imperceptible moment to the ear (0.014 seconds) but is enough to detect the frequency. Then it can be argued that the average frequency in a 0.014 second sample has some value. This will be the right solution, right?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 15, 2021, 03:58:47 pm
Hi. Here is a little work with _MEMSOUND, the movement of the stars in the background is the output of the implanted program from @STxAxTIC

Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 15, 2021, 03:59:57 pm
Whooooooa that's so cool!
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: STxAxTIC on January 15, 2021, 04:11:27 pm
@Petr  - this is just great!

I ran into a few - what I will call "windowing" problems with the frequency measurement code, so I will shortly dust off my latest copy and show where I left off. There is still something to fix - but we're *almost* there on a solution for reliably getting frequencies... I'll return to this as soon as I can.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: _vince on January 15, 2021, 08:02:57 pm
This all sounds very interesting!   Could something like this be used to analyze a played pitch and see if it's in tune?  Like frequency 440 Hz is the note A.    I tune pianos on the side, wonder if it would be possible to make a piano tuning app in QB64?

- Dav

if you know the sampling frequency, ie
Code: QB64: [Select]
  1. 'defdbl a-z
  2.  
  3. CONST sw = 1024
  4. CONST sh = 600
  5.  
  6. 'pi = 2*asin(1)
  7. pi = 4*ATN(1)
  8.  
  9. DECLARE SUB rfft(xx_r(), xx_i(), x_r(), n)
  10.  
  11. DIM x_r(sw-1), x_i(sw-1)
  12. DIM xx_r(sw-1), xx_i(sw-1)
  13.  
  14. FOR i=0 TO sw-1
  15.         x_r(i) = 100*SIN(2*pi*(sw*2000/44000)*i/sw) + (100*RND - 50)
  16.  
  17.  
  18. 'screenres sw, sh, 32
  19. SCREEN _NEWIMAGE(sw, sh, 32)
  20.  
  21. 'plot signal
  22. PSET (0, sh/4 - x_r(0))
  23. FOR i=0 TO sw-1
  24.         LINE -(i, sh/4 - x_r(i)), _RGB(255,0,0)
  25. LINE (0, sh/4)-STEP(sw,0), _RGB(255,0,0),,&h5555
  26.  
  27. _PRINTSTRING (0, 0), "2000 Hz signal with RND noise sampled at 44 kHz in 1024 samples"
  28.  
  29.  
  30. rfft xx_r(), xx_i(), x_r(), sw
  31.  
  32. 'plot its fft
  33. PSET (0, 50+3*sh/4 - 0.005*SQR(xx_r(0)*xx_r(0) + xx_i(0)*xx_i(0)) ), _RGB(255,255,0)
  34. FOR i=0 TO sw/2
  35.         LINE -(i*2, 50+3*sh/4 - 0.005*SQR(xx_r(i)*xx_r(i) + xx_i(i)*xx_i(i)) ), _RGB(255,255,0)
  36. LINE (0, 50+3*sh/4)-STEP(sw,0), _RGB(255,255,0),,&h5555
  37.  
  38.  
  39. 'find peak
  40. max = 0
  41. m = 0
  42. FOR i=0 TO sw/2
  43.         d = 0.01*SQR(xx_r(i)*xx_r(i) + xx_i(i)*xx_i(i))
  44.         IF d > max THEN
  45.                 max = d
  46.                 m = i
  47.         END IF
  48.  
  49. _PRINTSTRING (0, sh/2), "m_peak ="+STR$(m)
  50. _PRINTSTRING (0, sh/2 + 16), "f_peak = m_peak * 44 kHz / 1024 samples = "+STR$(m*44000/1024)+" Hz"
  51.  
  52. 'apply frequency correction, only works for some signals
  53. DIM u_r AS DOUBLE, u_i AS DOUBLE
  54. DIM v_r AS DOUBLE, v_i AS DOUBLE
  55.  
  56. u_r = xx_r(m - 1) - xx_r(m + 1)
  57. u_i = xx_i(m - 1) - xx_i(m + 1)
  58. v_r = 2*xx_r(m) - xx_r(m - 1) - xx_r(m + 1)
  59. v_i = 2*xx_i(m) - xx_i(m - 1) - xx_i(m + 1)
  60. c = (u_r*v_r + u_i*v_i)/(v_r*v_r + v_i*v_i)
  61.  
  62. _PRINTSTRING (0, sh/2 + 2*16), "f_corrected = "+STR$((m+c)*44000/1024)+" Hz"
  63.  
  64.  
  65.  
  66. SUB rfft(xx_r(), xx_i(), x_r(), n)
  67.         DIM w_r AS DOUBLE, w_i AS DOUBLE, wm_r AS DOUBLE, wm_i AS DOUBLE
  68.         DIM u_r AS DOUBLE, u_i AS DOUBLE, v_r AS DOUBLE, v_i AS DOUBLE
  69.  
  70.         log2n = LOG(n/2)/LOG(2)
  71.  
  72.         FOR i=0 TO n/2 - 1
  73.                 rev = 0
  74.                 FOR j=0 TO log2n - 1
  75.                         IF i AND (2^j) THEN rev = rev + (2^(log2n - 1 - j))
  76.                 NEXT
  77.  
  78.                 xx_r(i) = x_r(2*rev)
  79.                 xx_i(i) = x_r(2*rev + 1)
  80.         NEXT
  81.  
  82.         FOR i=1 TO log2n
  83.                 m = 2^i
  84.                 wm_r = COS(-2*pi/m)
  85.                 wm_i = SIN(-2*pi/m)
  86.  
  87.                 FOR j=0 TO n/2 - 1 STEP m
  88.                         w_r = 1
  89.                         w_i = 0
  90.  
  91.                         FOR k=0 TO m/2 - 1
  92.                                 p = j + k
  93.                                 q = p + (m \ 2)
  94.  
  95.                                 u_r = w_r*xx_r(q) - w_i*xx_i(q)
  96.                                 u_i = w_r*xx_i(q) + w_i*xx_r(q)
  97.                                 v_r = xx_r(p)
  98.                                 v_i = xx_i(p)
  99.  
  100.                                 xx_r(p) = v_r + u_r
  101.                                 xx_i(p) = v_i + u_i
  102.                                 xx_r(q) = v_r - u_r
  103.                                 xx_i(q) = v_i - u_i
  104.  
  105.                                 u_r = w_r
  106.                                 u_i = w_i
  107.                                 w_r = u_r*wm_r - u_i*wm_i
  108.                                 w_i = u_r*wm_i + u_i*wm_r
  109.                         NEXT
  110.                 NEXT
  111.         NEXT
  112.  
  113.         xx_r(n/2) = xx_r(0)
  114.         xx_i(n/2) = xx_i(0)
  115.  
  116.         FOR i=1 TO n/2 - 1
  117.                 xx_r(n/2 + i) = xx_r(n/2 - i)
  118.                 xx_i(n/2 + i) = xx_i(n/2 - i)
  119.         NEXT
  120.  
  121.         DIM xpr AS DOUBLE, xpi AS DOUBLE
  122.         DIM xmr AS DOUBLE, xmi AS DOUBLE
  123.  
  124.         FOR i=0 TO n/2 - 1
  125.                 xpr = (xx_r(i) + xx_r(n/2 + i)) / 2
  126.                 xpi = (xx_i(i) + xx_i(n/2 + i)) / 2
  127.  
  128.                 xmr = (xx_r(i) - xx_r(n/2 + i)) / 2
  129.                 xmi = (xx_i(i) - xx_i(n/2 + i)) / 2
  130.  
  131.                 xx_r(i) = xpr + xpi*COS(2*pi*i/n) - xmr*SIN(2*pi*i/n)
  132.                 xx_i(i) = xmi - xpi*SIN(2*pi*i/n) - xmr*COS(2*pi*i/n)
  133.         NEXT
  134.  
  135.         'symmetry, complex conj
  136.         FOR i=0 TO n/2 - 1
  137.                 xx_r(n/2 + i) = xx_r(n/2 - 1 - i)
  138.                 xx_i(n/2 + i) =-xx_i(n/2 - 1 - i)
  139.         NEXT
  140.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 16, 2021, 03:29:11 am
Thank you @_vince ! I try apply it to real audio signal and then give here my outputs.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 16, 2021, 04:26:28 am
@_vince Please look to my modification your code, if it is modfified correctly? Use some MP3 file.

I am not sure on row 101 in this source code, if can it be with _CONTINUE, if m = 0.

Thank you.


Code: QB64: [Select]
  1. 'defdbl a-z
  2.  
  3. CONST sw = 1024
  4. CONST sh = 600
  5.  
  6.  
  7. '''
  8. DIM Left AS _MEM
  9. '''
  10.  
  11. 'pi = 2*asin(1)
  12. pi = 4 * ATN(1)
  13.  
  14. DECLARE SUB rfft(xx_r(), xx_i(), x_r(), n)
  15.  
  16. DIM x_r(sw - 1), x_i(sw - 1)
  17. DIM xx_r(sw - 1), xx_i(sw - 1)
  18.  
  19. '''
  20. AudioFile$ = "Track10.mp3"
  21. S = _SNDOPEN(AudioFile$)
  22. Left = _MEMSOUND(S, 1)
  23. '''
  24. SCREEN _NEWIMAGE(sw, sh, 32)
  25.  
  26.  
  27. '''
  28.     i = 0: j = 0
  29.     Position& = _SNDGETPOS(S) * _SNDRATE
  30.     IF Position& > 1024 AND Position& < Left.SIZE - 1024 THEN 'current (actual playing) sound frame is in middle - in position Position&
  31.         j& = Position& - 1022
  32.         DO UNTIL i = 1024
  33.  
  34.             x_r(i) = 100 * (_MEMGET(Left, Left.OFFSET + j&, INTEGER) / 32767)
  35.             i = i + 1
  36.             j& = j& + 2
  37.         LOOP
  38.         test& = j& - Position&
  39.  
  40.     END IF
  41.  
  42.     'FOR i = 0 TO sw - 1
  43.     'x_r(i) = 100 * SIN(2 * pi * (sw * 20000 / 44000) * i / sw) + (100 * RND - 50)
  44.     'NEXT
  45.  
  46.     i = 0
  47.     j = 0
  48.     '''
  49.  
  50.  
  51.  
  52.     'screenres sw, sh, 32
  53.     'SCREEN _NEWIMAGE(sw, sh, 32)
  54.  
  55.     'plot signal
  56.     CLS
  57.     PSET (0, sh / 4 - x_r(0))
  58.     FOR i = 0 TO sw - 1
  59.         LINE -(i, sh / 4 - x_r(i)), _RGB(255, 0, 0)
  60.     NEXT
  61.     LINE (0, sh / 4)-STEP(sw, 0), _RGB(255, 0, 0), , &H5555
  62.  
  63.     ' _PRINTSTRING (0, 0), "2000 Hz signal with RND noise sampled at 44 kHz in 1024 samples"
  64.  
  65.  
  66.     rfft xx_r(), xx_i(), x_r(), sw
  67.  
  68.     'plot its fft
  69.     PSET (0, 50 + 3 * sh / 4 - 0.005 * SQR(xx_r(0) * xx_r(0) + xx_i(0) * xx_i(0))), _RGB(255, 255, 0)
  70.     FOR i = 0 TO sw / 2
  71.         LINE -(i * 2, 50 + 3 * sh / 4 - 0.005 * SQR(xx_r(i) * xx_r(i) + xx_i(i) * xx_i(i))), _RGB(255, 255, 0)
  72.     NEXT
  73.     LINE (0, 50 + 3 * sh / 4)-STEP(sw, 0), _RGB(255, 255, 0), , &H5555
  74.  
  75.  
  76.     'find peak
  77.     DIM max AS DOUBLE, d AS DOUBLE
  78.     max = 0
  79.     m = 0
  80.     FOR i = 0 TO sw / 2
  81.         d = 0.01 * SQR(xx_r(i) * xx_r(i) + xx_i(i) * xx_i(i))
  82.         IF d > max THEN
  83.             max = d
  84.             m = i
  85.         END IF
  86.     NEXT
  87.  
  88.     _PRINTSTRING (0, sh / 2), "m_peak =" + STR$(m)
  89.     _PRINTSTRING (0, sh / 2 + 16), "f_peak = m_peak * 44 kHz / 1024 samples = " + STR$(m * 44000 / 1024) + " Hz"
  90.  
  91.     'apply frequency correction, only works for some signals
  92.     DIM c AS DOUBLE
  93.     DIM u_r AS DOUBLE, u_i AS DOUBLE
  94.     DIM v_r AS DOUBLE, v_i AS DOUBLE
  95.  
  96.     IF m = 0 THEN _CONTINUE 'm = 1
  97.     u_r = xx_r(m - 1) - xx_r(m + 1)
  98.     u_i = xx_i(m - 1) - xx_i(m + 1)
  99.     v_r = 2 * xx_r(m) - xx_r(m - 1) - xx_r(m + 1)
  100.     v_i = 2 * xx_i(m) - xx_i(m - 1) - xx_i(m + 1)
  101.     c = (u_r * v_r + u_i * v_i) / (v_r * v_r + v_i * v_i)
  102.  
  103.     _PRINTSTRING (0, sh / 2 + 2 * 16), "f_corrected = " + STR$((m + c) * 44000 / 1024) + " Hz"
  104.  
  105.     ' SLEEP
  106.     PRINT test&
  107.     _DISPLAY
  108.     _LIMIT 20
  109.  
  110.  
  111.  
  112. SUB rfft (xx_r(), xx_i(), x_r(), n)
  113.     DIM w_r AS DOUBLE, w_i AS DOUBLE, wm_r AS DOUBLE, wm_i AS DOUBLE
  114.     DIM u_r AS DOUBLE, u_i AS DOUBLE, v_r AS DOUBLE, v_i AS DOUBLE
  115.  
  116.     log2n = LOG(n / 2) / LOG(2)
  117.  
  118.     FOR i = 0 TO n / 2 - 1
  119.         rev = 0
  120.         FOR j = 0 TO log2n - 1
  121.             IF i AND (2 ^ j) THEN rev = rev + (2 ^ (log2n - 1 - j))
  122.         NEXT
  123.  
  124.         xx_r(i) = x_r(2 * rev)
  125.         xx_i(i) = x_r(2 * rev + 1)
  126.     NEXT
  127.  
  128.     FOR i = 1 TO log2n
  129.         m = 2 ^ i
  130.         wm_r = COS(-2 * pi / m)
  131.         wm_i = SIN(-2 * pi / m)
  132.  
  133.         FOR j = 0 TO n / 2 - 1 STEP m
  134.             w_r = 1
  135.             w_i = 0
  136.  
  137.             FOR k = 0 TO m / 2 - 1
  138.                 p = j + k
  139.                 q = p + (m \ 2)
  140.  
  141.                 u_r = w_r * xx_r(q) - w_i * xx_i(q)
  142.                 u_i = w_r * xx_i(q) + w_i * xx_r(q)
  143.                 v_r = xx_r(p)
  144.                 v_i = xx_i(p)
  145.  
  146.                 xx_r(p) = v_r + u_r
  147.                 xx_i(p) = v_i + u_i
  148.                 xx_r(q) = v_r - u_r
  149.                 xx_i(q) = v_i - u_i
  150.  
  151.                 u_r = w_r
  152.                 u_i = w_i
  153.                 w_r = u_r * wm_r - u_i * wm_i
  154.                 w_i = u_r * wm_i + u_i * wm_r
  155.             NEXT
  156.         NEXT
  157.     NEXT
  158.  
  159.     xx_r(n / 2) = xx_r(0)
  160.     xx_i(n / 2) = xx_i(0)
  161.  
  162.     FOR i = 1 TO n / 2 - 1
  163.         xx_r(n / 2 + i) = xx_r(n / 2 - i)
  164.         xx_i(n / 2 + i) = xx_i(n / 2 - i)
  165.     NEXT
  166.  
  167.     DIM xpr AS DOUBLE, xpi AS DOUBLE
  168.     DIM xmr AS DOUBLE, xmi AS DOUBLE
  169.  
  170.     FOR i = 0 TO n / 2 - 1
  171.         xpr = (xx_r(i) + xx_r(n / 2 + i)) / 2
  172.         xpi = (xx_i(i) + xx_i(n / 2 + i)) / 2
  173.  
  174.         xmr = (xx_r(i) - xx_r(n / 2 + i)) / 2
  175.         xmi = (xx_i(i) - xx_i(n / 2 + i)) / 2
  176.  
  177.         xx_r(i) = xpr + xpi * COS(2 * pi * i / n) - xmr * SIN(2 * pi * i / n)
  178.         xx_i(i) = xmi - xpi * SIN(2 * pi * i / n) - xmr * COS(2 * pi * i / n)
  179.     NEXT
  180.  
  181.     'symmetry, complex conj
  182.     FOR i = 0 TO n / 2 - 1
  183.         xx_r(n / 2 + i) = xx_r(n / 2 - 1 - i)
  184.         xx_i(n / 2 + i) = -xx_i(n / 2 - 1 - i)
  185.     NEXT
  186.  
  187.  
  188.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 16, 2021, 01:26:41 pm
@_vince  gave us a treasure. By no means do I understand what the hell SUB rfft is doing, but he's doing it damn well and incredibly fast. I sat down and played with it. Now it seems to work the way I wanted. I just had to take the results of the  _Vince program and categorize them. Now I'm going to try to turn this treasure into a SUB so that I just insert the _MEM field and get back a number indicating the frequency.

You can try it. The program includes a graphics analyzer. (on left depth, then next frequencies by the highest on right side). It seems that sometimes when there is a long deep frequency, it does not register a high frequency (cymbals) but it is highly likely that it is my fault.

@_vince, thank you. This took me a long time.

Code: QB64: [Select]
  1. 'defdbl a-z
  2.  
  3. CONST sw = 1024
  4. CONST sh = 600
  5.  
  6.  
  7. '''
  8. DIM Left AS _MEM
  9. DIM Right AS _MEM
  10. DIM Analyzer(8) AS SINGLE
  11. '''
  12.  
  13.  
  14. DIM u_r AS DOUBLE, u_i AS DOUBLE
  15. DIM v_r AS DOUBLE, v_i AS DOUBLE
  16.  
  17.  
  18. 'pi = 2*asin(1)
  19. pi = 4 * ATN(1)
  20.  
  21. DECLARE SUB rfft(xx_r(), xx_i(), x_r(), n)
  22.  
  23. DIM x_r(sw - 1), x_i(sw - 1)
  24. DIM xx_r(sw - 1), xx_i(sw - 1)
  25.  
  26. '''
  27. AudioFile$ = "01.mp3"
  28. S = _SNDOPEN(AudioFile$)
  29. Left = _MEMSOUND(S, 1)
  30. Right = _MEMSOUND(S, 2)
  31.  
  32. '''
  33. SCREEN _NEWIMAGE(sw, sh, 32)
  34.  
  35. TestT = TIMER
  36. '''
  37.     i = 0: j = 0 '                                             reset previous values
  38.     Position& = _SNDGETPOS(S) * _SNDRATE * 2 '                 *2, because sound data are in INTEGER format and INTEGER is always 2 byte long
  39.     IF Position& > 1024 AND Position& < Left.SIZE - 1024 THEN 'current (actual playing) sound frame is in middle - in position Position&
  40.         j& = Position& - 1022
  41.         DO UNTIL i >= 1024
  42.             x_r(i) = 100 * _MEMGET(Left, Left.OFFSET + j&, INTEGER) / 32767
  43.             i = i + 1
  44.             j& = j& + 2
  45.         LOOP
  46.         test& = j& - Position&
  47.     END IF
  48.  
  49.     'FOR i = 0 TO sw - 1
  50.     'x_r(i) = 100 * SIN(2 * pi * (sw * 20000 / 44000) * i / sw) + (100 * RND - 50)      '_Vince's signal generator in original source code
  51.     'NEXT
  52.  
  53.     i = 0
  54.     j& = 0
  55.     '''
  56.  
  57.  
  58.  
  59.     'screenres sw, sh, 32
  60.     'SCREEN _NEWIMAGE(sw, sh, 32)
  61.  
  62.     'plot signal
  63.     CLS
  64.     PSET (0, sh / 4 - x_r(0))
  65.     FOR i = 0 TO sw - 1
  66.         LINE -(i, sh / 4 - x_r(i)), _RGB(255, 0, 0)
  67.     NEXT
  68.     LINE (0, sh / 4)-STEP(sw, 0), _RGB(255, 0, 0), , &H5555
  69.  
  70.     ' _PRINTSTRING (0, 0), "2000 Hz signal with RND noise sampled at 44 kHz in 1024 samples"
  71.  
  72.  
  73.     rfft xx_r(), xx_i(), x_r(), sw
  74.  
  75.     'plot its fft
  76.     PSET (0, 50 + 3 * sh / 4 - 0.005 * SQR(xx_r(0) * xx_r(0) + xx_i(0) * xx_i(0))), _RGB(255, 255, 0)
  77.     FOR i = 0 TO sw / 2
  78.         LINE -(i * 2, 50 + 3 * sh / 4 - 0.005 * SQR(xx_r(i) * xx_r(i) + xx_i(i) * xx_i(i))), _RGB(255, 255, 0)
  79.     NEXT
  80.     LINE (0, 50 + 3 * sh / 4)-STEP(sw, 0), _RGB(255, 255, 0), , &H5555
  81.  
  82.  
  83.     'find peak
  84.     DIM max AS DOUBLE, d AS DOUBLE
  85.     max = 0
  86.     m = 0
  87.     FOR i = 0 TO sw / 2
  88.         d = 0.01 * SQR(xx_r(i) * xx_r(i) + xx_i(i) * xx_i(i))
  89.         IF d > max THEN
  90.             max = d
  91.             m = i
  92.         END IF
  93.     NEXT
  94.  
  95.     _PRINTSTRING (0, sh / 2), "m_peak =" + STR$(m)
  96.     _PRINTSTRING (0, sh / 2 + 16), "f_peak = m_peak * 44 kHz / 1024 samples = " + STR$(m * 44000 / 1024) + " Hz"
  97.  
  98.     'apply frequency correction, only works for some signals
  99.     '   DIM c AS DOUBLE
  100.     '  DIM u_r AS DOUBLE, u_i AS DOUBLE
  101.     ' DIM v_r AS DOUBLE, v_i AS DOUBLE
  102.  
  103.     IF m = 0 THEN _CONTINUE
  104.     u_r = xx_r(m - 1) - xx_r(m + 1)
  105.     u_i = xx_i(m - 1) - xx_i(m + 1)
  106.     v_r = 2 * xx_r(m) - xx_r(m - 1) - xx_r(m + 1)
  107.     v_i = 2 * xx_i(m) - xx_i(m - 1) - xx_i(m + 1)
  108.     c = (u_r * v_r + u_i * v_i) / (v_r * v_r + v_i * v_i)
  109.  
  110.     F = (m + c) * _SNDRATE / 1024 '                                                             1024 = number of samples
  111.     _PRINTSTRING (0, sh / 2 + 2 * 16), "f_corrected = " + STR$(F) '(m + c) * 44000 / 1024) + " Hz"
  112.  
  113.  
  114.     'If signal is contained in some range, add 30 pixels for Y coordinate (analyzer go up, its wroted as bottom - this value)
  115.     SELECT CASE F
  116.         CASE 20 TO 125: Analyzer(1) = Analyzer(1) + 30 'areas set by picture on google...
  117.         CASE 126 TO 300: Analyzer(2) = Analyzer(2) + 30
  118.         CASE 300 TO 500: Analyzer(3) = Analyzer(3) + 30
  119.         CASE 500 TO 1000: Analyzer(4) = Analyzer(4) + 30
  120.         CASE 1001 TO 2000: Analyzer(5) = Analyzer(5) + 30
  121.         CASE 2001 TO 4000: Analyzer(6) = Analyzer(6) + 30
  122.         CASE 4001 TO 8000: Analyzer(7) = Analyzer(7) + 30
  123.         CASE IS > 8001: Analyzer(8) = Analyzer(8) + 30
  124.     END SELECT
  125.  
  126.  
  127.  
  128.     'analyzer overflow control
  129.     FOR analyze = 1 TO 8 '                                    analyze 8 spectrums
  130.         IF Analyzer(analyze) > 150 THEN Analyzer(analyze) = 100
  131.     NEXT
  132.  
  133.     'draw analyzer
  134.     AnC = 0
  135.     FOR AnalyzatorX = 600 TO 670 STEP 10
  136.         AnC = AnC + 1
  137.         FreqHeight = Analyzer(AnC) '                          Y coordinate for drawing frequency analyzer, maximal size is 150 pixels
  138.         LINE (AnalyzatorX - 4, 400)-(AnalyzatorX + 4, 400 - FreqHeight), &HFFAD0000, BF
  139.         IF Analyzer(AnC) > 0 THEN Analyzer(AnC) = Analyzer(AnC) - 1 ' always, if analyzer contains some higher position than bottom, give one pixel out
  140.     NEXT
  141.  
  142.     PRINT Position&, _SNDGETPOS(S) * _SNDRATE
  143.     PRINT TIMER - TestT: TestT = TIMER
  144.     _DISPLAY
  145.     _LIMIT 200
  146.  
  147.  
  148.  
  149. SUB rfft (xx_r(), xx_i(), x_r(), n)
  150.     DIM w_r AS DOUBLE, w_i AS DOUBLE, wm_r AS DOUBLE, wm_i AS DOUBLE
  151.     DIM u_r AS DOUBLE, u_i AS DOUBLE, v_r AS DOUBLE, v_i AS DOUBLE
  152.  
  153.     log2n = LOG(n / 2) / LOG(2)
  154.  
  155.     FOR i = 0 TO n / 2 - 1
  156.         rev = 0
  157.         FOR j = 0 TO log2n - 1
  158.             IF i AND (2 ^ j) THEN rev = rev + (2 ^ (log2n - 1 - j))
  159.         NEXT
  160.  
  161.         xx_r(i) = x_r(2 * rev)
  162.         xx_i(i) = x_r(2 * rev + 1)
  163.     NEXT
  164.  
  165.     FOR i = 1 TO log2n
  166.         m = 2 ^ i
  167.         wm_r = COS(-2 * pi / m)
  168.         wm_i = SIN(-2 * pi / m)
  169.  
  170.         FOR j = 0 TO n / 2 - 1 STEP m
  171.             w_r = 1
  172.             w_i = 0
  173.  
  174.             FOR k = 0 TO m / 2 - 1
  175.                 p = j + k
  176.                 q = p + (m \ 2)
  177.  
  178.                 u_r = w_r * xx_r(q) - w_i * xx_i(q)
  179.                 u_i = w_r * xx_i(q) + w_i * xx_r(q)
  180.                 v_r = xx_r(p)
  181.                 v_i = xx_i(p)
  182.  
  183.                 xx_r(p) = v_r + u_r
  184.                 xx_i(p) = v_i + u_i
  185.                 xx_r(q) = v_r - u_r
  186.                 xx_i(q) = v_i - u_i
  187.  
  188.                 u_r = w_r
  189.                 u_i = w_i
  190.                 w_r = u_r * wm_r - u_i * wm_i
  191.                 w_i = u_r * wm_i + u_i * wm_r
  192.             NEXT
  193.         NEXT
  194.     NEXT
  195.  
  196.     xx_r(n / 2) = xx_r(0)
  197.     xx_i(n / 2) = xx_i(0)
  198.  
  199.     FOR i = 1 TO n / 2 - 1
  200.         xx_r(n / 2 + i) = xx_r(n / 2 - i)
  201.         xx_i(n / 2 + i) = xx_i(n / 2 - i)
  202.     NEXT
  203.  
  204.     DIM xpr AS DOUBLE, xpi AS DOUBLE
  205.     DIM xmr AS DOUBLE, xmi AS DOUBLE
  206.  
  207.     FOR i = 0 TO n / 2 - 1
  208.         xpr = (xx_r(i) + xx_r(n / 2 + i)) / 2
  209.         xpi = (xx_i(i) + xx_i(n / 2 + i)) / 2
  210.  
  211.         xmr = (xx_r(i) - xx_r(n / 2 + i)) / 2
  212.         xmi = (xx_i(i) - xx_i(n / 2 + i)) / 2
  213.  
  214.         xx_r(i) = xpr + xpi * COS(2 * pi * i / n) - xmr * SIN(2 * pi * i / n)
  215.         xx_i(i) = xmi - xpi * SIN(2 * pi * i / n) - xmr * COS(2 * pi * i / n)
  216.     NEXT
  217.  
  218.     'symmetry, complex conj
  219.     FOR i = 0 TO n / 2 - 1
  220.         xx_r(n / 2 + i) = xx_r(n / 2 - 1 - i)
  221.         xx_i(n / 2 + i) = -xx_i(n / 2 - 1 - i)
  222.     NEXT
  223.  
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: SMcNeill on January 28, 2021, 08:34:32 am
Quick thought:

Shouldn’t _MEMSOUND have a mem.TYPE associate with it?

http://www.qb64.org/wiki/MEM

mem.TYPE is an OFFSET, so it’s always a minimum of 32-bits in size.  _MEMSOUND could easily just take the 17th bit as an identifier.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on January 28, 2021, 09:19:19 am
It should. Thoughts?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: bplus on January 29, 2021, 02:28:58 pm
Nice one! @Petr 

I nominate you to do the Wiki demo example for this :)
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 29, 2021, 03:37:23 pm
@bplus

I really appreciate this offer, do you mean the source code for the video above? Or a newer one that uses the _Vince solution to gain frequency? I'll probably get there on Sunday or Monday. Tomorrow my daughter celebrates her birthday, so there will be no time tomorrow. So I'll send you the source code, because I don't have access to the wiki myself, you'll be able to paste it there.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: bplus on January 29, 2021, 03:46:13 pm
@bplus

I really appreciate this offer, do you mean the source code for the video above? Or a newer one that uses the _Vince solution to gain frequency? I'll probably get there on Sunday or Monday. Tomorrow my daughter celebrates her birthday, so there will be no time tomorrow. So I'll send you the source code, because I don't have access to the wiki myself, you'll be able to paste it there.

Oh I don't have access to Wiki either and I am sort of a generalist myself, but you seem expert in the arena of sound and all it's nuances. I think Wiki needs short and as little complicated as can get but still get the point of how to use the thing being demo'd, so _vince variation might go over the top in needs. You guys are already over my head so _vince thing might be just the thing, I don't know ;)

I could put demo in Infomatics Board if you say it's specially good.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on January 29, 2021, 04:13:23 pm
I understand. Just write the simplest program possible. Something light for visualization with descriptions in English. Good! I'll prepare it here.
But I don't feel like a sound expert myself. I'm just interested.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: bplus on January 29, 2021, 05:07:01 pm
I understand. Just write the simplest program possible. Something light for visualization with descriptions in English. Good! I'll prepare it here.
But I don't feel like a sound expert myself. I'm just interested.


Petr for Infomatics (the thing I have some permission for) simple is not so important than cool! If the thing with _vince stuff is way cooler than a simple demo then let's go for that. It would be cool to get something with _vince contributing too!

For Wiki, it is only MHO that simple is better by simple I mean short and sweet and by sweet I mean gets the point across elegantly, one very fine example of this is Wiki's Rotozoom. But I am not involved with Wiki project, so far everyone has been doing great by me for that! And thanks again to those who do contribute to that project.

Quote
I'm just interested.
Yes that can go a long way towards getting your head into the game and coming up with something clever.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: _vince on February 01, 2021, 08:00:06 pm
I'm glad you managed to get it working. That 'frequency correction' algorithm tends to work well for sharp tall peaks in noise and not so well for more complicated signals. Skimming this thread, it looks like you and static were reinventing the fourier transform, FFT is damn powerful and there's a lot more you can do with it.  I'd like to get on board one day and show more demos of audio DSP.  One day when I find the willpower and update QB64, etc
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on February 06, 2021, 02:08:41 pm
Hi @_vince

I apologize for the late reply first. Now it's just that I had to interrupt programming and finish important work at home (is not completed). I would have time for programming today, but - I don't know why - I've had a terrible headache since morning. I don't know why, there's no reason to. Of course, I want to do this, but I repeat that this is something that is currently at the maximum limit of my knowledge. So I cried here :) and now I'm going to do it again. It has to go.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 08, 2021, 03:49:54 am
I there a way to load _MEMSOUND to play ogg files with 6 channels of sound? I am working on this now.
Or is stereo the limit?

Russ
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: FellippeHeitor on February 08, 2021, 05:58:30 am
I think the library we use for audio in QB64 is capable of 5.1 output, but it hasn't been incorporated using that ability. I'll let you know if this becomes a thing.

What happens when you load a 6 channel file with _SNDOPEN?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 08, 2021, 12:24:30 pm
It does not load, mind you the file is saved at 192,00 hz, 6 channels and is the full album, so that may overlaod it, but I have 16 GB of RAM and the latest nightly of QB64.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 08, 2021, 12:57:39 pm
Some how andsome way I found this program for playing video files, but I get a black screen...the code is short and I can't seem to find the original post for it.

  [ This attachment cannot be displayed inline in 'Print Page' view ]

I try to play a big video, I believe its John Fogerty in concert from 1977 or around there somewhere.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Dav on February 08, 2021, 01:51:59 pm
That was my code,  I think its in the wiki too. I also updated it a little, but from what ive heard, it only works for some people on some systems.  Works for me in win7 on certain vedios formats, mpg and wmv for example, but not mp4.  I have a 32bit dll I put together to play videos, and I could post that if you want. Id have to dig it up, not sure what disk i put it on.

- Dav
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 08, 2021, 01:56:32 pm
That would be good Dave, do you have the latest version? I am slowly converting avis to mpg files, like some of the disney anime stuff, will post one if its works, and yes can you post that dll for me , I seem to need it, I get a black screen with sound.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Dav on February 08, 2021, 04:43:35 pm
I look for it.  Not on my current laptop, so it's on a backup disk somewhere.

- Dav
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 08, 2021, 08:13:34 pm
One thing I noticed in the current version is that you cannot have any spaces in the filenames for the wmv or mpg files to play, can someone fix this?
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: Petr on February 09, 2021, 04:05:07 pm
@rcamp48

Hi. I experiment with that too. Do you have sound when playing video? Using the source code as it is here, my video is about 20x faster. This can be solved by adding CHR $ (0) to some strings - it works better, but still very fast. And without sound. I tried a DivX - AVI file.
Title: Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
Post by: rcamp48 on February 10, 2021, 01:19:13 pm
Ya no problem , I get sound and video, but I am using VLC for video and Wavepad soon enough for audio with the program I modified.... i belive it is yours...