Author Topic: Random Melodies and Chords (first complete and second rewrite - Bug Question)  (Read 6918 times)

0 Members and 1 Guest are viewing this topic.

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
I have wrote a Program that Generates Melodies and Chords (in F-Major Intervals).
Most of the variable names come from Geman, but I translated the Prints to english.
How you like this? (Modifications are always welcome)

Code: QB64: [Select]
  1. Dim tonmat(30) As Integer
  2. Dim diff(30) As Integer
  3. Dim m(28) As String:
  4. m(1) = "V50O1C": m(2) = "V50O1D": m(3) = "V50O1E": m(4) = "V40O1F": m(5) = "V40O1G": m(6) = "V40O1A": m(7) = "V40O1B"
  5. m(8) = "V30O2C": m(9) = "V30O2D": m(10) = "V30O2E": m(11) = "V20O2F": m(12) = "V20O2G": m(13) = "V20O2A": m(14) = "V20O2B"
  6. m(15) = "V20O3C": m(16) = "V20O3D": m(17) = "V10O3E": m(18) = "V10O3F": m(19) = "V10O3G": m(20) = "V10O3A": m(21) = "V10O3B"
  7. Dim lm(7) As Integer
  8. lm(1) = 1: lm(2) = 2: lm(3) = 4: lm(4) = 8: lm(5) = 16: lm(6) = 32: lm(7) = 64
  9.  
  10. Print "<<<***---Welcome to Melodies and Chords v0.0.4beta by chlorophyll-zz---***>>>"
  11. Print "Values: Default in brackets,"
  12. Print "For default press Enter."
  13. Print "Were starting ;-)"
  14. start:
  15. Input "Automatic or Manual Mode? a/m (a)"; auto
  16. If auto <> "m" Then auto = "a"
  17. If auto = "a" Then Print "Automatic Mode" Else Print "Manual Mode"
  18. If auto = "m" Then
  19.     Input "Lowest Basetone? (C1 to B2) 1-14(1)"; minton: If minton < 1 Or minton > 14 Then minton = 1
  20.     Print
  21.     Input "Highest Basetone? (C1 to B2) 1-14(14)"; maxton: If maxton < 1 Or maxton > 14 Then maxton = 14
  22.     Print
  23. If auto = "a" Then
  24.     minton = 1
  25.     maxton = 14
  26. Print "Basetone from "; Mid$(m(minton), 5, 3); " to "; Mid$(m(maxton), 5, 3)
  27. If auto = "m" Then
  28.     Print "Maximum Duration of Tones? 1/ 1-2-4-8-16"
  29.     Input "                              1 2 3 4  5  1-6 (2) "; minlang
  30.     Print
  31.     If minlang < 1 Or minlang > 5 Then minlang = 2
  32.  
  33.     Print "Minimum Duration of Tones? 1/ 1-2-4-8-16"
  34.     Input "                              1 2 3 4  5  1-6 (4) "; maxlang
  35.     Print
  36.     If maxlang < 1 Or maxlang > 5 Then maxlang = 4
  37. If auto = "a" Then
  38.     minlang = 2
  39.     maxlang = 4
  40. Print "Duration 1/" + LTrim$(Str$(lm(minlang))) + " to 1/"; LTrim$(Str$(lm(maxlang)))
  41. If auto = "m" Then
  42.     Dim aws As String
  43.     Input "How much Chords Possibility in %? 0-100(25)"; aws: If aws = "" Or Val(aws) > 100 Then aws = "25"
  44.     Print
  45.     proz = Val(aws)
  46. If auto = "a" Then proz = 25
  47. Print LTrim$(Str$(proz)) + "% Chords Possibility"
  48. If auto = "m" Then
  49.     Input "1. Interval from Basetone? 1-7? (C-E=2) (2)"; intmin: If intmin < 1 Or intmin > 7 Then intmin = 2
  50.     Print
  51.     Input "2. Interval from Basetone? 1-7? (C-G=4) (4)"; intmax: If intmax < 1 Or intmax > 7 Then intmax = 4
  52.     Print
  53. If auto = "a" Then
  54.     intmin = 2
  55.     intmax = 4
  56. Print "1. Interval"; intmin; "Tones from Basetone, 2. Interval"; intmax; "Tones from Basetone"
  57.  
  58. debug = 0
  59.     anfang = anfang + 1
  60.     If anfang = 1 Then
  61.         For i = 20 To 1 Step -1
  62.             tonmat(i) = CInt(Rnd * (maxton - minton)) + minton
  63.             If debug = 1 Then Print ; Str$(i) + ". Tone:" + Str$(tonmat(i)) + ",";
  64.             diff(i) = tonmat(i) - tonmat(i + 1)
  65.             If debug = 1 Then Print "Difference " + Str$(i); ". "; diff(i)
  66.         Next i
  67.  
  68.     End If
  69.  
  70.     t = CInt(Rnd * (maxton - minton)) + minton
  71.     If debug = 1 And (t < 1 Or t > 28) Then Print "Tone below 1 or over 28 t="; t: Input t
  72.     n = m(t)
  73.  
  74.     l = CInt(Rnd * (maxlang - minlang)) + minlang
  75.     If debug = 1 And (l < 1 Or l > 7) Then Print "Duration below 1 or over 7 l="; l: Input l
  76.  
  77.  
  78.     lt = lm(l)
  79.  
  80.     rn = Rnd
  81.     If rn < (proz / 100) Then
  82.         akk = 1
  83.         n = n + "," + m(t + intmin) + "," + m(t + intmax)
  84.     End If
  85.  
  86.     If akk = 1 And l >= minlang + 1 And Rnd * .66 >= (proz / 100) Then
  87.         lt = lm(minlang)
  88.     End If
  89.     akk = 0
  90.  
  91.     If rn > (proz / 100) Then n = m(t)
  92.  
  93.     tone = "L" + LTrim$(Str$(lt)) + n
  94.  
  95.     z = z + 1
  96.     If z = 1 Then
  97.         Print "<<<*-For Restart press n-*>>>"
  98.         Print
  99.     End If
  100.     If z = 21 Then z = 0
  101.  
  102.     Print "Duration: 1/" + LTrim$(Str$(lt)) + Chr$(9) + "Note(s): ";
  103.     If Len(n) > 6 Then Print ; Mid$(n, 5, 2) + ", " + Mid$(n, 12, 2) + ", "; Mid$(n, 19, 2)
  104.     If Len(n) = 6 Then Print ; Mid$(n, 5, 2)
  105.     'V25O1C,V25O1G,V25A1
  106.     Print
  107.     Play tone
  108.  
  109.  
  110.  
  111.     For i = 20 To 1 Step -1
  112.         tonmat(i) = tonmat(i - 1)
  113.         If i = 1 Then tonmat(i) = t
  114.         If debug = 1 Then Print ; Str$(i) + ". Tone:" + Str$(tonmat(i)) + ",";
  115.         diff(i) = tonmat(i) - tonmat(i + 1)
  116.         If debug = 1 Then Print "Difference " + Str$(i); ". "; diff(i)
  117.     Next i
  118.  
  119.     If debug = 1 Then Sleep
  120.  
  121.     x = _KeyHit
  122.     If x Then
  123.         If x = -110 Then
  124.             x = 0
  125.             GoTo start:
  126.         End If
  127.     End If
  128.  

I have also rewrote the Program to have FM-Synth, because a tester suggested that.
First the Program did run as expected but then I edited something I forgot, and the Chords are now sounding garbled.
I think something is wrong about _SNDRAW or _SNDRAWLEN .
Could you have a quick look? Thank you in advance.

Code: QB64: [Select]
  1. Dim fm(88) As Double
  2. Dim tn(88) As String
  3.  
  4. Print "Welcone to Random Tones and Chords Generator v0.1b"
  5. Input "Please specify Chord possibility in % (25)"; uaw$
  6. If uaw$ = "" Or Val(uaw$) < 0 Or Val(uaw$) > 100 Then
  7.     aw = 25
  8. Else aw = Val(uaw$)
  9. Print "Chords possibility:"; aw; "%"
  10. bpm = 120
  11. 'interval 1 and 2 (semitones)
  12. int1 = 2
  13. int2 = 7
  14. 'interval possibility percent
  15. 'aw = 25
  16. 'tone minimum and maximum
  17. tmin = 35
  18. tmax = 47
  19. 'lengths min and max
  20. lmin = 2
  21. lmax = 4
  22. 'fill the tone names
  23. For i = 1 To 88
  24.     f = ((2 ^ ((i - 49) / 12)) * 440)
  25.     fm(i) = f
  26.     Select Case i Mod 12
  27.         Case 1: tn(i) = "A"
  28.         Case 2: tn(i) = "A#"
  29.         Case 3: tn(i) = "B"
  30.         Case 4: tn(i) = "C"
  31.         Case 5: tn(i) = "C#"
  32.         Case 6: tn(i) = "D"
  33.         Case 7: tn(i) = "D#"
  34.         Case 8: tn(i) = "E"
  35.         Case 9: tn(i) = "F"
  36.         Case 10: tn(i) = "F#"
  37.         Case 11: tn(i) = "G"
  38.         Case 0: tn(i) = "G#"
  39.     End Select
  40.     'Select Case Int(i / 12)
  41.     '    Case 0: tn(i) = tn(i) + "0"
  42.  
  43.     'End Select
  44.     'DEBUG
  45.     'Print f; tn(i)
  46.     'If i > 24 Then Sleep
  47.  
  48. 'delete all sharp tones
  49. For i = 1 To 88
  50.     If Mid$(tn(i), 2, 1) = "#" Then
  51.         tn(i) = tn(i - 1)
  52.         fm(i) = fm(i - 1)
  53.     End If
  54. 'DEBUG fm(49)="A"
  55. 'Print fm(49)
  56.  
  57. 'fill the lengths
  58. For i = 1 To 7
  59.     lm(i) = 2 ^ i / 2
  60.     'DEBUG
  61.     'Print lm(i)
  62.  
  63.  
  64.     'tones between tmin and tmax
  65.     i = CInt((Rnd * (tmax - tmin)) + tmin)
  66.  
  67.     lr = lm(CInt(Rnd * (lmax - lmin)) + lmin) 'Length out of the lenght fields between 2 and 4
  68.     l = 1 / lr * 60 / bpm * 4 'Lenght is parts of a second from the length fields multiplied by bpm
  69.  
  70.     If Rnd < aw / 100 Then
  71.         akk = 1
  72.     Else akk = 0
  73.     End If
  74.     t = 0
  75.     akk = 1
  76.     If akk = 1 Then
  77.         Print "Length 1/"; LTrim$(Str$(lr)); " Tone:"; tn(i); "+"; tn(i + 4); "+"; tn(i + 7)
  78.     Else Print "Length 1/"; LTrim$(Str$(lr)); " Tone:"; tn(i)
  79.     End If
  80.     Do
  81.         'queue some sound
  82.         Do While t < l 'you may wish to adjust this
  83.             sample = Sin(t * fm(i) * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  84.             sample = sample * Exp(-t * l) 'fade out eliminates clicks after sound
  85.             _SndRaw sample
  86.             t = t + 1 / _SndRate 'sound card sample frequency determines time
  87.  
  88.             If akk = 1 Then
  89.                 sample2 = Sin(t * fm(i + int1) * Atn(1) * 8)
  90.                 sample2 = sample2 * Exp(-t * l)
  91.                 _SndRaw sample2
  92.                 sample3 = Sin(t * fm(i + int2) * Atn(1) * 8)
  93.                 sample3 = sample3 * Exp(-t * l)
  94.                 _SndRaw sample3
  95.                 t = t + 2 / _SndRate
  96.             End If
  97.  
  98.  
  99.         Loop
  100.  
  101.  
  102.     Loop While t < l 'play for l seconds
  103.  
  104.     Do While _SndRawLen > 0 'Finish any left over queued sound!
  105.     Loop
  106.  
  107.     in = InKey$
  108. Loop While in = ""
  109.  
« Last Edit: September 17, 2021, 12:25:01 pm by chlorophyll-zz »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Hi welcome @chlorophyll-zz

Are you talking about slight buzz I am getting on chords or do I have too many crumbs in/on my speakers?

Sorry don't know much about sound Petr pretty good and Dav, speaking of whom have you checked this out?
https://www.qb64.org/forum/index.php?topic=2563.0
 

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
Are you talking about slight buzz I am getting on chords or do I have too many crumbs in/on my speakers?
Yes, the Buzz is the problem.

I looked in the Program you suggested, and that Program uses a slightly different method, _SNDPLAY, to play the sound of the Drum-Machine.
My Program uses _SNDRAW to generate the sound waves sample by sample, which it does obviously wrong in some way.

« Last Edit: September 17, 2021, 01:22:54 pm by chlorophyll-zz »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Here's a good reference, Fellippe's tut on sound, there is something new to QB64 about capturing wave patterns:
https://www.qb64.org/forum/index.php?topic=3919.0

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
Here's a good reference, Fellippe's tut on sound, there is something new to QB64 about capturing wave patterns:
https://www.qb64.org/forum/index.php?topic=3919.0
Thank you. I saw the Video a few days ago and that was the reason I discovered FM Synth Sample generation with _SNDRAW.
For the Video part with _SNDRAW, he basically covers the Example code from _SNDRAW in the Wiki,
which I also modified to get the samples. I think I will have to investigate further what it takes to generate a chord,
because I think I have made somehow a wrong assumption that I could just play the _SNDRAW samples after another to generate the Chords.

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
I think I discovered a bug. Even with a slighly modified example code from _SNDRAW Wiki, the buzz is there:
The Problem is not present with 2 Samples, but appears after 3 Samples and persists with any new Sample that you play after another.

Code: QB64: [Select]
  1. t = 0
  2. tmp$ = "Sample = ##.#####   Time = ##.#####"
  3. Locate 1, 60: Print "Rate:"; _SndRate
  4.     'queue some sound
  5.     Do While _SndRawLen < 3 'you may wish to adjust this
  6.         sample = Sin(t * 440 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  7.         sample = sample * Exp(-t * 3) 'fade out eliminates clicks after sound
  8.         _SndRaw sample
  9.         t = t + 1 / _SndRate 'sound card sample frequency determines time
  10.         sample = Sin(t * 220 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  11.         sample = sample * Exp(-t * 3) 'fade out eliminates clicks after sound
  12.         _SndRaw sample
  13.         t = t + 1 / _SndRate
  14.         sample = Sin(t * 220 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  15.         sample = sample * Exp(-t * 3) 'fade out eliminates clicks after sound
  16.         _SndRaw sample
  17.         t = t + 1 / _SndRate
  18.  
  19.     Loop
  20.  
  21.     'do other stuff, but it may interrupt sound
  22.     Locate 1, 1: Print Using tmp$; sample; t
  23. Loop While t < 3.0 'play for 3 seconds
  24.  
  25. Do While _SndRawLen > 0 'Finish any left over queued sound!
  26.  
  27.  

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
I have edited the code, so it only play two tones in a chord (now without buzz).
I suggest 100% Chords possibility for maximal comfort, thats why I made it default ;-)

Code: QB64: [Select]
  1. Dim fm(88) As Double
  2. Dim tn(88) As String
  3.  
  4. Print "Welcone to Random Tones and Chords Generator v0.1b"
  5. Input "Please specify Chord possibility in % (25)"; uaw$
  6. If uaw$ = "" Or Val(uaw$) < 0 Or Val(uaw$) > 100 Then
  7.     aw = 100
  8. Else aw = Val(uaw$)
  9. Print "Chords possibility:"; aw; "%"
  10. bpm = 120
  11. 'interval 1 and 2 (semitones)
  12. int1 = 4
  13. int2 = 7
  14. 'interval possibility percent
  15. 'aw = 25
  16. 'tone minimum and maximum
  17. tmin = 35
  18. tmax = 47
  19. 'lengths min and max
  20. lmin = 2
  21. lmax = 4
  22. 'fill the tone names
  23. For i = 1 To 88
  24.     f = ((2 ^ ((i - 49) / 12)) * 440)
  25.     fm(i) = CInt(f)
  26.     Select Case i Mod 12
  27.         Case 1: tn(i) = "A"
  28.         Case 2: tn(i) = "A#"
  29.         Case 3: tn(i) = "B"
  30.         Case 4: tn(i) = "C"
  31.         Case 5: tn(i) = "C#"
  32.         Case 6: tn(i) = "D"
  33.         Case 7: tn(i) = "D#"
  34.         Case 8: tn(i) = "E"
  35.         Case 9: tn(i) = "F"
  36.         Case 10: tn(i) = "F#"
  37.         Case 11: tn(i) = "G"
  38.         Case 0: tn(i) = "G#"
  39.     End Select
  40.     'Select Case Int(i / 12)
  41.     '    Case 0: tn(i) = tn(i) + "0"
  42.  
  43.     'End Select
  44.     'DEBUG
  45.     'Print f; tn(i)
  46.     'If i > 24 Then Sleep
  47.  
  48. 'delete all sharp tones
  49. For i = 1 To 88
  50.     If Mid$(tn(i), 2, 1) = "#" Then
  51.         tn(i) = tn(i - 1)
  52.         fm(i) = fm(i - 1)
  53.     End If
  54. 'DEBUG fm(49)="A"
  55. 'Print fm(49)
  56.  
  57. 'fill the lengths
  58. For i = 1 To 7
  59.     lm(i) = 2 ^ i / 2
  60.     'DEBUG
  61.     'Print lm(i)
  62.  
  63.  
  64.     'tones between tmin and tmax
  65.     i = CInt((Rnd * (tmax - tmin)) + tmin)
  66.  
  67.     lr = lm(CInt(Rnd * (lmax - lmin)) + lmin) 'Length out of the lenght fields between 2 and 4
  68.     l = 1 / lr * 60 / bpm * 4 'Lenght is parts of a second from the length fields multiplied by bpm
  69.  
  70.     If Rnd < aw / 100 Then
  71.         akk = 1
  72.     Else akk = 0
  73.     End If
  74.     t = 1 / _SndRate
  75.     If akk = 1 Then
  76.         Print "Length 1/"; LTrim$(Str$(lr)); " Tone:"; tn(i); "+"; tn(i + int1) '; "+"; tn(i + 7)
  77.     Else Print "Length 1/"; LTrim$(Str$(lr)); " Tone:"; tn(i)
  78.     End If
  79.     Do
  80.         'queue some sound
  81.         Do While t < l 'you may wish to adjust this
  82.             sample = Sin(t * fm(i) * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  83.             sample = sample * Exp(-t * l) 'fade out eliminates clicks after sound
  84.             _SndRaw sample
  85.             t = t + 1 / _SndRate 'sound card sample frequency determines time
  86.  
  87.             If akk = 1 Then
  88.                 sample2 = Sin(t * fm(i + int1) * Atn(1) * 8)
  89.                 sample2 = sample2 * Exp(-t * l)
  90.                 _SndRaw sample2
  91.                 t = t + 1 / _SndRate
  92.                 'sample = Sin(t * fm(i + int2) * Atn(1) * 8)
  93.                 'sample = sample3 * Exp(-t * l)
  94.                 '_SndRaw sample
  95.                 't = t + 1 / _SndRate
  96.             End If
  97.  
  98.         Loop
  99.  
  100.  
  101.     Loop While t < l 'play for l seconds
  102.  
  103.     Do While _SndRawLen > 0 'Finish any left over queued sound!
  104.     Loop
  105.  
  106.  
  107.     in = InKey$
  108. Loop While in = ""
  109.  
  110.  
« Last Edit: September 17, 2021, 02:34:35 pm by chlorophyll-zz »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Hi. Try, if this is repaired or is still broken:

Code: QB64: [Select]
  1. DIM fm(88) AS DOUBLE
  2. DIM tn(88) AS STRING
  3.  
  4. PRINT "Welcone to Random Tones and Chords Generator v0.1b"
  5. INPUT "Please specify Chord possibility in % (25)"; uaw$
  6. IF uaw$ = "" OR VAL(uaw$) < 0 OR VAL(uaw$) > 100 THEN
  7.     aw = 25
  8. ELSE aw = VAL(uaw$)
  9. PRINT "Chords possibility:"; aw; "%"
  10. bpm = 120
  11. 'interval 1 and 2 (semitones)
  12. int1 = 2
  13. int2 = 7
  14. 'interval possibility percent
  15. 'aw = 25
  16. 'tone minimum and maximum
  17. tmin = 35
  18. tmax = 47
  19. 'lengths min and max
  20. lmin = 2
  21. lmax = 4
  22. 'fill the tone names
  23. FOR i = 1 TO 88
  24.     f = ((2 ^ ((i - 49) / 12)) * 440)
  25.     fm(i) = f
  26.     SELECT CASE i MOD 12
  27.         CASE 1: tn(i) = "A"
  28.         CASE 2: tn(i) = "A#"
  29.         CASE 3: tn(i) = "B"
  30.         CASE 4: tn(i) = "C"
  31.         CASE 5: tn(i) = "C#"
  32.         CASE 6: tn(i) = "D"
  33.         CASE 7: tn(i) = "D#"
  34.         CASE 8: tn(i) = "E"
  35.         CASE 9: tn(i) = "F"
  36.         CASE 10: tn(i) = "F#"
  37.         CASE 11: tn(i) = "G"
  38.         CASE 0: tn(i) = "G#"
  39.     END SELECT
  40.     'Select Case Int(i / 12)
  41.     '    Case 0: tn(i) = tn(i) + "0"
  42.  
  43.     'End Select
  44.     'DEBUG
  45.     'Print f; tn(i)
  46.     'If i > 24 Then Sleep
  47.  
  48. 'delete all sharp tones
  49. FOR i = 1 TO 88
  50.     IF MID$(tn(i), 2, 1) = "#" THEN
  51.         tn(i) = tn(i - 1)
  52.         fm(i) = fm(i - 1)
  53.     END IF
  54. 'DEBUG fm(49)="A"
  55. 'Print fm(49)
  56.  
  57. 'fill the lengths
  58. FOR i = 1 TO 7
  59.     lm(i) = 2 ^ i / 2
  60.     'DEBUG
  61.     'Print lm(i)
  62.  
  63.  
  64.     'tones between tmin and tmax
  65.     i = CINT((RND * (tmax - tmin)) + tmin)
  66.  
  67.     lr = lm(CINT(RND * (lmax - lmin)) + lmin) 'Length out of the lenght fields between 2 and 4
  68.     l = 1 / lr * 60 / bpm * 4 'Lenght is parts of a second from the length fields multiplied by bpm
  69.  
  70.     IF RND < aw / 100 THEN
  71.         akk = 1
  72.     ELSE akk = 0
  73.     END IF
  74.     t = 0
  75.     akk = 1
  76.     IF akk = 1 THEN
  77.         PRINT "Length 1/"; LTRIM$(STR$(lr)); " Tone:"; tn(i); "+"; tn(i + 4); "+"; tn(i + 7)
  78.     ELSE PRINT "Length 1/"; LTRIM$(STR$(lr)); " Tone:"; tn(i)
  79.     END IF
  80.     DO
  81.         'queue some sound
  82.         DO WHILE t < l 'you may wish to adjust this
  83.             sample = SIN(t * fm(i) * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  84.             sample = sample * EXP(-t * l) 'fade out eliminates clicks after sound
  85.             '_SNDRAW sample
  86.             t = t + 1 / _SNDRATE 'sound card sample frequency determines time
  87.  
  88.             IF akk = 1 THEN
  89.                 sample2 = SIN(t * fm(i + int1) * ATN(1) * 8)
  90.                 sample2 = sample2 * EXP(-t * l)
  91.                 '   _SNDRAW sample2
  92.                 sample = (sample + sample2) / 2
  93.  
  94.                 sample3 = SIN(t * fm(i + int2) * ATN(1) * 8)
  95.                 sample3 = sample3 * EXP(-t * l)
  96.                 '   _SNDRAW sample3
  97.  
  98.                 sample = (sample + sample3) / 2
  99.  
  100.                 t = t + 2 / _SNDRATE
  101.             END IF
  102.  
  103.             _SNDRAW sample
  104.  
  105.         LOOP
  106.  
  107.  
  108.     LOOP WHILE t < l 'play for l seconds
  109.  
  110.     DO WHILE _SNDRAWLEN < 0 'Finish any left over queued sound!
  111.     LOOP
  112.  
  113.     in = INKEY$
  114. LOOP WHILE in = ""
  115.  
  116.  
  117.  


Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Very nice work, this all! Good job! I like it!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
I also encountered problems with slowing down or distorting the sound if I called the _SNDRAW command multiple times in a row. In order for the audio data to be transmitted as I intended, I first mix it using a mathematical average, and only finally, when the data stream is ready, I pass it all at once to the _SNDRAW command. This is the most reliable way to achieve the expected result.

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
Re: Random Melodies and Chords (first complete and second rewrite - Bug Question)
« Reply #10 on: September 17, 2021, 03:21:14 pm »
Hi. Try, if this is repaired or is still broken:

The tones are now double the frequency and half the duration as they should.
But the Buzz is gone.

I edited your edits in to the example code. Is this right?
I think the t is only added 1/_SNDRATE because only one sample gets played.

This produces one tone, I think of 440 Hz.

Code: QB64: [Select]
  1. t = 0
  2. tmp$ = "Sample = ##.#####   Time = ##.#####"
  3. Locate 1, 60: Print "Rate:"; _SndRate
  4.     'queue some sound
  5.     Do While _SndRawLen < 3 'you may wish to adjust this
  6.         sample1 = Sin(t * 440 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  7.         sample1 = sample1 * Exp(-t * 3) 'fade out eliminates clicks after sound
  8.         '_SndRaw sample
  9.         t = t + 1 / _SndRate 'sound card sample frequency determines time
  10.  
  11.         sample2 = Sin(t * 110 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  12.         sample2 = sample2 * Exp(-t * 3) 'fade out eliminates clicks after sound
  13.         '_SndRaw sample
  14.         't = t + 1 / _SndRate
  15.  
  16.         sample1 = (sample1 + sample2) / 2
  17.  
  18.         sample3 = Sin(t * 220 * Atn(1) * 8) '440Hz sine wave (t * 440 * 2Ï€)
  19.         sample3 = sample3 * Exp(-t * 3) 'fade out eliminates clicks after sound
  20.  
  21.         sample1 = (sample1 + sample3) / 2
  22.  
  23.         't = t + 1 / _SndRate
  24.         _SndRaw sample1
  25.     Loop
  26.  
  27.  
  28.     'do other stuff, but it may interrupt sound
  29.     Locate 1, 1: Print Using tmp$; sample; t
  30. Loop While t < 3.0 'play for 3 seconds
  31.  
  32. Do While _SndRawLen > 0 'Finish any left over queued sound!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Random Melodies and Chords (first complete and second rewrite - Bug Question)
« Reply #11 on: September 17, 2021, 04:11:16 pm »
You are very right. So I'm trying everything here now. Well, I think I've found a solution. Also, thanks to that, I finally understood what the _SNDRAWOPEN command was doing, which I had quietly trodden around in the past and couldn't understand. And now your clear code makes perfect sense to him. This ensures that the individual sounds do not mix. This program should work properly, it shows what I tried. I think that's what you're looking for.

Code: QB64: [Select]
  1. t = 0
  2. tmp$ = "Sample = ##.#####   Time = ##.#####"
  3. LOCATE 1, 60: PRINT "Rate:"; _SNDRATE
  4.  
  5.  
  6.     'queue some sound
  7.     DO UNTIL t >= 3 'you may wish to adjust this
  8.         sample1 = SIN(t * 440 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  9.         sample1 = sample1 * EXP(-t * 3) 'fade out eliminates clicks after sound
  10.         '_SndRaw sample
  11.         ' t = t + 1 / _SNDRATE 'sound card sample frequency determines time
  12.  
  13.         sample2 = SIN(t * 110 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  14.         sample2 = sample2 * EXP(-t * 3) 'fade out eliminates clicks after sound
  15.         '_SndRaw sample
  16.         ' t = t + 1 / _SndRate
  17.  
  18.         '  sample1 = (sample1 + sample2) / 2
  19.  
  20.         sample3 = SIN(t * 220 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  21.         sample3 = sample3 * EXP(-t * 3) 'fade out eliminates clicks after sound
  22.  
  23.         ' sample1 = (sample1 + sample3) / 2
  24.  
  25.         t = t + 1 / _SNDRATE
  26.         _SNDRAW sample1, , S1
  27.         _SNDRAWDONE
  28.         _SNDRAW sample2, , S2
  29.         _SNDRAWDONE
  30.         _SNDRAW sample3, , S3
  31.         _SNDRAWDONE
  32.  
  33.         '   _SNDRAW sample1
  34.         '   _SNDRAW sample2
  35.         '   _SNDRAW sample3
  36.  
  37.         LOCATE 1, 1: PRINT USING tmp$; sample; t
  38.  
  39.  
  40.     LOOP
  41.  
  42.     _SNDCLOSE S1
  43.     _SNDCLOSE S2
  44.     _SNDCLOSE S3
  45.  
  46.     'do other stuff, but it may interrupt sound
  47.     LOCATE 1, 1: PRINT USING tmp$; sample; t
  48. LOOP WHILE t < 3.0 'play for 3 seconds
  49.  
  50. DO WHILE _SNDRAWLEN > 0 'Finish any left over queued sound!
  51.  
  52.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Random Melodies and Chords (first complete and second rewrite - Bug Question)
« Reply #12 on: September 17, 2021, 05:30:22 pm »
Did that fix the melodies?

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
Re: Random Melodies and Chords (first complete and second rewrite - Bug Question)
« Reply #13 on: September 18, 2021, 12:14:57 am »
Well, I think I've found a solution.
I cant test right now, but this looks very promising. I will test and work your example code in my Program and write back to you. Later ;-)

Offline chlorophyll-zz

  • Newbie
  • Posts: 15
    • View Profile
Re: Random Melodies and Chords (first complete and second rewrite - Bug Question)
« Reply #14 on: September 19, 2021, 01:24:15 am »
Well, I think I've found a solution.

...

Code: QB64: [Select]
  1. t = 0
  2. tmp$ = "Sample = ##.#####   Time = ##.#####"
  3. LOCATE 1, 60: PRINT "Rate:"; _SNDRATE
  4.  
  5.  
  6.     'queue some sound
  7.     DO UNTIL t >= 3 'you may wish to adjust this
  8.         sample1 = SIN(t * 440 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  9.         sample1 = sample1 * EXP(-t * 3) 'fade out eliminates clicks after sound
  10.         '_SndRaw sample
  11.         ' t = t + 1 / _SNDRATE 'sound card sample frequency determines time
  12.  
  13.         sample2 = SIN(t * 110 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  14.         sample2 = sample2 * EXP(-t * 3) 'fade out eliminates clicks after sound
  15.         '_SndRaw sample
  16.         ' t = t + 1 / _SndRate
  17.  
  18.         '  sample1 = (sample1 + sample2) / 2
  19.  
  20.         sample3 = SIN(t * 220 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  21.         sample3 = sample3 * EXP(-t * 3) 'fade out eliminates clicks after sound
  22.  
  23.         ' sample1 = (sample1 + sample3) / 2
  24.  
  25.         t = t + 1 / _SNDRATE
  26.         _SNDRAW sample1, , S1
  27.         _SNDRAWDONE
  28.         _SNDRAW sample2, , S2
  29.         _SNDRAWDONE
  30.         _SNDRAW sample3, , S3
  31.         _SNDRAWDONE
  32.  
  33.         '   _SNDRAW sample1
  34.         '   _SNDRAW sample2
  35.         '   _SNDRAW sample3
  36.  
  37.         LOCATE 1, 1: PRINT USING tmp$; sample; t
  38.  
  39.  
  40.     LOOP
  41.  
  42.     _SNDCLOSE S1
  43.     _SNDCLOSE S2
  44.     _SNDCLOSE S3
  45.  
  46.     'do other stuff, but it may interrupt sound
  47.     LOCATE 1, 1: PRINT USING tmp$; sample; t
  48. LOOP WHILE t < 3.0 'play for 3 seconds
  49.  
  50. DO WHILE _SNDRAWLEN > 0 'Finish any left over queued sound!
  51.  
  52.  

This produces only the last Sample (3) of 220Hz, a bit distorted, unfortunately.
You can hear that yourself when you compare the sound of your code 
to the first and second _sndraw commented out.:

Code: QB64: [Select]
  1. t = 0
  2. tmp$ = "Sample = ##.#####   Time = ##.#####"
  3. LOCATE 1, 60: PRINT "Rate:"; _SNDRATE
  4.  
  5.  
  6.     'queue some sound
  7.     DO UNTIL t >= 3 'you may wish to adjust this
  8.         sample1 = SIN(t * 440 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  9.         sample1 = sample1 * EXP(-t * 3) 'fade out eliminates clicks after sound
  10.         '_SndRaw sample
  11.         ' t = t + 1 / _SNDRATE 'sound card sample frequency determines time
  12.  
  13.         sample2 = SIN(t * 110 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  14.         sample2 = sample2 * EXP(-t * 3) 'fade out eliminates clicks after sound
  15.         '_SndRaw sample
  16.         ' t = t + 1 / _SndRate
  17.  
  18.         '  sample1 = (sample1 + sample2) / 2
  19.  
  20.         sample3 = SIN(t * 220 * ATN(1) * 8) '440Hz sine wave (t * 440 * 2?)
  21.         sample3 = sample3 * EXP(-t * 3) 'fade out eliminates clicks after sound
  22.  
  23.         ' sample1 = (sample1 + sample3) / 2
  24.  
  25.         t = t + 1 / _SNDRATE
  26.         '_SNDRAW sample1, , S1
  27.         '_SNDRAWDONE
  28.         '_SNDRAW sample2, , S2
  29.         '_SNDRAWDONE
  30.         _SNDRAW sample3, , S3
  31.         _SNDRAWDONE
  32.  
  33.         '   _SNDRAW sample1
  34.         '   _SNDRAW sample2
  35.         '   _SNDRAW sample3
  36.  
  37.         LOCATE 1, 1: PRINT USING tmp$; sample; t
  38.  
  39.  
  40.     LOOP
  41.  
  42.     _SNDCLOSE S1
  43.     _SNDCLOSE S2
  44.     _SNDCLOSE S3
  45.  
  46.     'do other stuff, but it may interrupt sound
  47.     LOCATE 1, 1: PRINT USING tmp$; sample; t
  48. LOOP WHILE t < 3.0 'play for 3 seconds
  49.  
  50. DO WHILE _SNDRAWLEN > 0 'Finish any left over queued sound!
  51.  
  52.  
« Last Edit: September 19, 2021, 01:31:25 am by chlorophyll-zz »