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

0 Members and 1 Guest are viewing this topic.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #30 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.  
« Last Edit: January 02, 2021, 07:32:37 am by Petr »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #31 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).

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #32 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:

 [ You are not allowed to view this attachment ]  



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.

 [ You are not allowed to view this attachment ]  



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



« Last Edit: January 02, 2021, 12:25:03 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #33 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.  
« Last Edit: January 02, 2021, 04:09:47 pm by Petr »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #34 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.  

  [ You are not allowed to view this attachment ]  
  [ You are not allowed to view this attachment ]  
  [ You are not allowed to view this attachment ]  
  [ You are not allowed to view this attachment ]  

« Last Edit: January 02, 2021, 06:48:17 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Craz1000

  • Forum Regular
  • Posts: 111
  • I'm OK
    • View Profile
    • Craz1000.net
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #35 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!
« Last Edit: January 02, 2021, 09:41:30 pm by Craz1000 »

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #36 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 

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #37 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.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #38 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.
« Last Edit: January 03, 2021, 06:15:51 am by Petr »

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #39 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.
« Last Edit: January 03, 2021, 08:19:32 pm by FellippeHeitor »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #40 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!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #41 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.  


  [ You are not allowed to view this attachment ]  
« Last Edit: January 04, 2021, 10:38:27 am by Petr »

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #42 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.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #43 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.

FellippeHeitor

  • Guest
Re: Upcoming feature (v1.5) - _MEMSOUND (Hi, Petr!)
« Reply #44 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.