Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Is it possible to make a _SNDNEW song this way?
#1
Here's an old program I made at the old forum before I knew PLAY could play more than one note at a time.  It used _SNDRAW to build notes and play them from the sound buffer.  Now that QB64PE has _SNDNEW,_MEMSOUND, etc. I wondered if this program can be used with those somehow.

Instead of playing with _SNDRAW like this, Is it possible to feed the data to a _SNDNEW memory instead so I could have the song with a handle for using it with _SNDPLAY controls?

I thought perhaps this music generator can be useful again for making background songs and play them using _SNDPLAY, and also still have PLAY & SOUND available too for sounds as well, like sound effects.

- Dav   

Code: (Select All)
'==============
'SNDRAWPLAY.BAS v2.0
'==============
'Attempting a PLAY-like song format using _SNDRAW
'Plays notes and allows more than one note to sound at the same time.
'Can play notes in the background.
'Coded By Dav, JAN/2021

'All 88 notes are available.
'Regular notes are lowercase (d4), Sharp notes are upper (D4).
'You can play a notes like this: f3 g3 a3 A3 cf d4 e4 f4
'Play a chord of notes by grouping inside (), like: (c4 e4 g4)

'Assign current note/rest length values like this...
'WN = Whole note, HN = Half note, DQ = Dotted quarter note
'QN = Quarter note, EN = Eighth note, SN = Sixteenth note

'Rests - nothing played, but time continues
'RN = Rest note.  Uses current note length value set.
'For example, to rest a quarter note, do this:
'QN RN

'Assign Tempos like this (always must be in 4 characters):
'T120  ... or T060  ...  or  T100

'Assign current meter (for whole length value to work)
'M3  (thats for 3/4)....  M4  (Thats for 4/4)

'========================================================

'=== Playing two octaves of all notes c3 to c5...
'Set tempo 120, meter 4/4, set sixteen note value
SPLAY "t160 m4 sn c3C3d3D3e3f3F3g3G3a3A3b3c4C4d4D4e4f4F4g4G4a4A4b4c5"

Do
    Color Rnd * 16
    Print "Testing all notes...c3 to c5..."
Loop While _SndRawLen
_SndRawDone


'=== Playing a background song.... Silent Night.,,,

s$ = "t100 m3" 'tempo 100, 3/4 meter
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'silent night
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'holy night
s$ = s$ + "hn(d5b4g4) qn(d5b4g4) wn(b4g4d4)" 'all is calm
s$ = s$ + "hn(c5e4g4) qn(c5e4g4) wn(g4e4c4)" 'all is bright
s$ = s$ + "hn(c4f4a4) qn(c4f4a4) dq(c5a4f4) en(b4g4e4) qn(a4f4d4)" 'round yon virgin
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'mother and child
s$ = s$ + "hn(c4f4a4) qn(c4f4a4) dq(c5a4f4) en(b4g4e4) qn(a4f4d4)" 'holy infant so
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'tender and mild
s$ = s$ + "hn(d5b4g4) qn(d5b4g4) dq(f5d5b4) en(d5b4g4) qn(b4g4f4)" 'sleep in heavenly
s$ = s$ + "hn(c5g4e4) qn(c5g4e4) hn(e5c5g4) qnrn" 'peace....
s$ = s$ + "qn(c5g4e4) qn(g4e4c4) qn(e4c4g3) dq(g4d4b3) en(f4d4b3) qn(d4b3f3)" 'sleep in heavenly
s$ = s$ + "wn(c4g3e3) rn"

SPLAY s$

Do
    Color Rnd * 16
    Print "Silent Night ";
    If InKey$ <> "" Then Exit Do
Loop While _SndRawLen
_SndRawDone

End




Sub SPLAY (Music$)

    rate = _SndRate

    'Set Defaults, just in case empty
    If Tempo = 0 Then Tempo = 60
    If Meter = 0 Then Meter = 3
    If NoteValue = 0 Then NoteValue = 1

    cur = 1

    Do

        'skip any spaces
        If Mid$(Music$, cur, 1) = " " Then cur = cur + 1

        'Check for tempo
        If UCase$(Mid$(Music$, cur, 1)) = "T" Then
            cur = cur + 1
            Tempo = Val(Mid$(Music$, cur, 3)): cur = cur + 3
        End If

        'Check for Meter
        If UCase$(Mid$(Music$, cur, 1)) = "M" Then
            cur = cur + 1
            Meter = Val(Mid$(Music$, cur, 1)): cur = cur + 1
        End If

        'Get notevalue
        Select Case UCase$(Mid$(Music$, cur, 2))
            Case Is = "DQ": cur = cur + 2: NoteValue = 1.5
            Case Is = "EN": cur = cur + 2: NoteValue = .5
            Case Is = "QN": cur = cur + 2: NoteValue = 1
            Case Is = "HN": cur = cur + 2: NoteValue = 2
            Case Is = "WN": cur = cur + 2
                If Meter = 3 Then NoteValue = 3 Else NoteValue = 4
            Case Is = "SN": cur = cur + 2: NoteValue = .25
        End Select

        'If regular note/rest found (not a group)
        Select Case Mid$(Music$, cur, 2)
            Case Is = "a0": note = 27.50: cur = cur + 2: GoSub LoadNote
            Case Is = "A0": note = 29.14: cur = cur + 2: GoSub LoadNote
            Case Is = "b0": note = 30.87: cur = cur + 2: GoSub LoadNote
            Case Is = "c1": note = 32.70: cur = cur + 2: GoSub LoadNote
            Case Is = "C1": note = 34.65: cur = cur + 2: GoSub LoadNote
            Case Is = "d1": note = 36.71: cur = cur + 2: GoSub LoadNote
            Case Is = "D1": note = 38.89: cur = cur + 2: GoSub LoadNote
            Case Is = "e1": note = 41.20: cur = cur + 2: GoSub LoadNote
            Case Is = "f1": note = 43.65: cur = cur + 2: GoSub LoadNote
            Case Is = "F1": note = 46.25: cur = cur + 2: GoSub LoadNote
            Case Is = "g1": note = 49.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G1": note = 51.91: cur = cur + 2: GoSub LoadNote
            Case Is = "a1": note = 55.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A1": note = 58.27: cur = cur + 2: GoSub LoadNote
            Case Is = "b1": note = 61.74: cur = cur + 2: GoSub LoadNote
            Case Is = "c2": note = 65.41: cur = cur + 2: GoSub LoadNote
            Case Is = "C2": note = 69.30: cur = cur + 2: GoSub LoadNote
            Case Is = "d2": note = 73.42: cur = cur + 2: GoSub LoadNote
            Case Is = "D2": note = 77.78: cur = cur + 2: GoSub LoadNote
            Case Is = "e2": note = 82.41: cur = cur + 2: GoSub LoadNote
            Case Is = "f2": note = 87.31: cur = cur + 2: GoSub LoadNote
            Case Is = "F2": note = 92.50: cur = cur + 2: GoSub LoadNote
            Case Is = "g2": note = 98.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G2": note = 103.83: cur = cur + 2: GoSub LoadNote
            Case Is = "a2": note = 110.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A2": note = 116.54: cur = cur + 2: GoSub LoadNote
            Case Is = "b2": note = 123.47: cur = cur + 2: GoSub LoadNote
            Case Is = "c3": note = 130.81: cur = cur + 2: GoSub LoadNote
            Case Is = "C3": note = 138.59: cur = cur + 2: GoSub LoadNote
            Case Is = "d3": note = 146.83: cur = cur + 2: GoSub LoadNote
            Case Is = "D3": note = 155.56: cur = cur + 2: GoSub LoadNote
            Case Is = "e3": note = 164.81: cur = cur + 2: GoSub LoadNote
            Case Is = "f3": note = 174.61: cur = cur + 2: GoSub LoadNote
            Case Is = "F3": note = 185.00: cur = cur + 2: GoSub LoadNote
            Case Is = "g3": note = 196.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G3": note = 207.65: cur = cur + 2: GoSub LoadNote
            Case Is = "a3": note = 220.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A3": note = 233.08: cur = cur + 2: GoSub LoadNote
            Case Is = "b3": note = 246.94: cur = cur + 2: GoSub LoadNote
            Case Is = "c4": note = 261.63: cur = cur + 2: GoSub LoadNote
            Case Is = "C4": note = 277.18: cur = cur + 2: GoSub LoadNote
            Case Is = "d4": note = 293.66: cur = cur + 2: GoSub LoadNote
            Case Is = "D4": note = 311.13: cur = cur + 2: GoSub LoadNote
            Case Is = "e4": note = 329.63: cur = cur + 2: GoSub LoadNote
            Case Is = "f4": note = 349.23: cur = cur + 2: GoSub LoadNote
            Case Is = "F4": note = 369.99: cur = cur + 2: GoSub LoadNote
            Case Is = "g4": note = 392.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G4": note = 415.30: cur = cur + 2: GoSub LoadNote
            Case Is = "a4": note = 440.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A4": note = 466.16: cur = cur + 2: GoSub LoadNote
            Case Is = "b4": note = 493.88: cur = cur + 2: GoSub LoadNote
            Case Is = "c5": note = 523.25: cur = cur + 2: GoSub LoadNote
            Case Is = "C5": note = 554.37: cur = cur + 2: GoSub LoadNote
            Case Is = "d5": note = 587.33: cur = cur + 2: GoSub LoadNote
            Case Is = "D5": note = 622.25: cur = cur + 2: GoSub LoadNote
            Case Is = "e5": note = 659.25: cur = cur + 2: GoSub LoadNote
            Case Is = "f5": note = 698.46: cur = cur + 2: GoSub LoadNote
            Case Is = "F5": note = 739.99: cur = cur + 2: GoSub LoadNote
            Case Is = "g5": note = 783.99: cur = cur + 2: GoSub LoadNote
            Case Is = "G5": note = 830.61: cur = cur + 2: GoSub LoadNote
            Case Is = "a5": note = 880.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A5": note = 932.33: cur = cur + 2: GoSub LoadNote
            Case Is = "b5": note = 987.77: cur = cur + 2: GoSub LoadNote
            Case Is = "c6": note = 1046.50: cur = cur + 2: GoSub LoadNote
            Case Is = "C6": note = 1108.73: cur = cur + 2: GoSub LoadNote
            Case Is = "d6": note = 1174.66: cur = cur + 2: GoSub LoadNote
            Case Is = "D6": note = 1244.51: cur = cur + 2: GoSub LoadNote
            Case Is = "e6": note = 1318.51: cur = cur + 2: GoSub LoadNote
            Case Is = "f6": note = 1396.91: cur = cur + 2: GoSub LoadNote
            Case Is = "F6": note = 1479.98: cur = cur + 2: GoSub LoadNote
            Case Is = "g6": note = 1567.98: cur = cur + 2: GoSub LoadNote
            Case Is = "G6": note = 1661.22: cur = cur + 2: GoSub LoadNote
            Case Is = "a6": note = 1760.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A6": note = 1864.66: cur = cur + 2: GoSub LoadNote
            Case Is = "b6": note = 1975.53: cur = cur + 2: GoSub LoadNote
            Case Is = "c7": note = 2093.00: cur = cur + 2: GoSub LoadNote
            Case Is = "C7": note = 2217.46: cur = cur + 2: GoSub LoadNote
            Case Is = "d7": note = 2349.32: cur = cur + 2: GoSub LoadNote
            Case Is = "D7": note = 2489.02: cur = cur + 2: GoSub LoadNote
            Case Is = "e7": note = 2637.02: cur = cur + 2: GoSub LoadNote
            Case Is = "f7": note = 2793.83: cur = cur + 2: GoSub LoadNote
            Case Is = "F7": note = 2959.96: cur = cur + 2: GoSub LoadNote
            Case Is = "g7": note = 3135.96: cur = cur + 2: GoSub LoadNote
            Case Is = "G7": note = 3322.44: cur = cur + 2: GoSub LoadNote
            Case Is = "a7": note = 3520.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A7": note = 3729.31: cur = cur + 2: GoSub LoadNote
            Case Is = "b7": note = 3951.07: cur = cur + 2: GoSub LoadNote
            Case Is = "c8": note = 4186.01: cur = cur + 2: GoSub LoadNote
            Case Is = "RN", "rn": note = 0: cur = cur + 2: GoSub LoadNote
        End Select

        'if group of notes found
        If Mid$(Music$, cur, 1) = "(" Then
            cur = cur + 1
            'Grab up until ')' found
            Group$ = ""
            Do
                a$ = Mid$(Music$, cur, 1): cur = cur + 1
                If a$ = ")" Then Exit Do
                If a$ <> " " Then Group$ = Group$ + a$
            Loop

            NumOfNotes = Len(Group$) / 2
            Length = (60 * NoteValue / Tempo)
            For L = 0 To Length * rate Step NumOfNotes

                For N = 1 To Len(Group$) Step 2
                    'fade = EXP(-L / rate * 8)
                    note$ = Mid$(Group$, N, 2)
                    If note$ = "a0" Then _SndRaw Sin((L / rate) * 27.50 * Atn(1) * 8) '* fade.
                    If note$ = "A0" Then _SndRaw Sin((L / rate) * 29.14 * Atn(1) * 8) '* fade.
                    If note$ = "b0" Then _SndRaw Sin((L / rate) * 30.87 * Atn(1) * 8) '* fade.
                    If note$ = "c1" Then _SndRaw Sin((L / rate) * 32.70 * Atn(1) * 8) '* fade.
                    If note$ = "C1" Then _SndRaw Sin((L / rate) * 34.65 * Atn(1) * 8) '* fade.
                    If note$ = "d1" Then _SndRaw Sin((L / rate) * 36.71 * Atn(1) * 8) '* fade.
                    If note$ = "D1" Then _SndRaw Sin((L / rate) * 38.89 * Atn(1) * 8) '* fade.
                    If note$ = "e1" Then _SndRaw Sin((L / rate) * 41.20 * Atn(1) * 8) '* fade.
                    If note$ = "f1" Then _SndRaw Sin((L / rate) * 43.65 * Atn(1) * 8) '* fade.
                    If note$ = "F1" Then _SndRaw Sin((L / rate) * 46.25 * Atn(1) * 8) '* fade.
                    If note$ = "g1" Then _SndRaw Sin((L / rate) * 49.00 * Atn(1) * 8) '* fade.
                    If note$ = "G1" Then _SndRaw Sin((L / rate) * 51.91 * Atn(1) * 8) '* fade.
                    If note$ = "a1" Then _SndRaw Sin((L / rate) * 55.00 * Atn(1) * 8) '* fade.
                    If note$ = "A1" Then _SndRaw Sin((L / rate) * 58.27 * Atn(1) * 8) '* fade.
                    If note$ = "b1" Then _SndRaw Sin((L / rate) * 61.74 * Atn(1) * 8) '* fade.
                    If note$ = "c2" Then _SndRaw Sin((L / rate) * 65.41 * Atn(1) * 8) '* fade.
                    If note$ = "C2" Then _SndRaw Sin((L / rate) * 69.30 * Atn(1) * 8) '* fade.
                    If note$ = "d2" Then _SndRaw Sin((L / rate) * 73.42 * Atn(1) * 8) '* fade.
                    If note$ = "D2" Then _SndRaw Sin((L / rate) * 77.78 * Atn(1) * 8) '* fade.
                    If note$ = "e2" Then _SndRaw Sin((L / rate) * 82.41 * Atn(1) * 8) '* fade.
                    If note$ = "f2" Then _SndRaw Sin((L / rate) * 87.31 * Atn(1) * 8) '* fade.
                    If note$ = "F2" Then _SndRaw Sin((L / rate) * 92.50 * Atn(1) * 8) '* fade.
                    If note$ = "g2" Then _SndRaw Sin((L / rate) * 98.00 * Atn(1) * 8) '* fade.
                    If note$ = "G2" Then _SndRaw Sin((L / rate) * 103.83 * Atn(1) * 8) '* fade.
                    If note$ = "a2" Then _SndRaw Sin((L / rate) * 110.00 * Atn(1) * 8) '* fade.
                    If note$ = "A2" Then _SndRaw Sin((L / rate) * 116.54 * Atn(1) * 8) '* fade.
                    If note$ = "b2" Then _SndRaw Sin((L / rate) * 123.47 * Atn(1) * 8) '* fade.
                    If note$ = "c3" Then _SndRaw Sin((L / rate) * 130.81 * Atn(1) * 8) '* fade.
                    If note$ = "C3" Then _SndRaw Sin((L / rate) * 138.59 * Atn(1) * 8) '* fade.
                    If note$ = "d3" Then _SndRaw Sin((L / rate) * 146.83 * Atn(1) * 8) '* fade.
                    If note$ = "D3" Then _SndRaw Sin((L / rate) * 155.56 * Atn(1) * 8) '* fade.
                    If note$ = "e3" Then _SndRaw Sin((L / rate) * 164.81 * Atn(1) * 8) '* fade.
                    If note$ = "f3" Then _SndRaw Sin((L / rate) * 174.61 * Atn(1) * 8) '* fade.
                    If note$ = "F3" Then _SndRaw Sin((L / rate) * 185.00 * Atn(1) * 8) '* fade.
                    If note$ = "g3" Then _SndRaw Sin((L / rate) * 196.00 * Atn(1) * 8) '* fade.
                    If note$ = "G3" Then _SndRaw Sin((L / rate) * 207.65 * Atn(1) * 8) '* fade.
                    If note$ = "a3" Then _SndRaw Sin((L / rate) * 220.00 * Atn(1) * 8) '* fade.
                    If note$ = "A3" Then _SndRaw Sin((L / rate) * 233.08 * Atn(1) * 8) '* fade.
                    If note$ = "b3" Then _SndRaw Sin((L / rate) * 246.94 * Atn(1) * 8) '* fade.
                    If note$ = "c4" Then _SndRaw Sin((L / rate) * 261.63 * Atn(1) * 8) '* fade.
                    If note$ = "C4" Then _SndRaw Sin((L / rate) * 277.18 * Atn(1) * 8) '* fade.
                    If note$ = "d4" Then _SndRaw Sin((L / rate) * 293.66 * Atn(1) * 8) '* fade.
                    If note$ = "D4" Then _SndRaw Sin((L / rate) * 311.13 * Atn(1) * 8) '* fade.
                    If note$ = "e4" Then _SndRaw Sin((L / rate) * 329.63 * Atn(1) * 8) '* fade.
                    If note$ = "f4" Then _SndRaw Sin((L / rate) * 349.23 * Atn(1) * 8) '* fade.
                    If note$ = "F4" Then _SndRaw Sin((L / rate) * 369.99 * Atn(1) * 8) '* fade.
                    If note$ = "g4" Then _SndRaw Sin((L / rate) * 392.00 * Atn(1) * 8) '* fade.
                    If note$ = "G4" Then _SndRaw Sin((L / rate) * 415.30 * Atn(1) * 8) '* fade.
                    If note$ = "a4" Then _SndRaw Sin((L / rate) * 440.00 * Atn(1) * 8) '* fade.
                    If note$ = "A4" Then _SndRaw Sin((L / rate) * 466.16 * Atn(1) * 8) '* fade.
                    If note$ = "b4" Then _SndRaw Sin((L / rate) * 493.88 * Atn(1) * 8) '* fade.
                    If note$ = "c5" Then _SndRaw Sin((L / rate) * 523.25 * Atn(1) * 8) '* fade.
                    If note$ = "C5" Then _SndRaw Sin((L / rate) * 554.37 * Atn(1) * 8) '* fade.
                    If note$ = "d5" Then _SndRaw Sin((L / rate) * 587.33 * Atn(1) * 8) '* fade.
                    If note$ = "D5" Then _SndRaw Sin((L / rate) * 622.25 * Atn(1) * 8) '* fade.
                    If note$ = "e5" Then _SndRaw Sin((L / rate) * 659.25 * Atn(1) * 8) '* fade.
                    If note$ = "f5" Then _SndRaw Sin((L / rate) * 698.46 * Atn(1) * 8) '* fade.
                    If note$ = "F5" Then _SndRaw Sin((L / rate) * 739.99 * Atn(1) * 8) '* fade.
                    If note$ = "g5" Then _SndRaw Sin((L / rate) * 783.99 * Atn(1) * 8) '* fade.
                    If note$ = "G5" Then _SndRaw Sin((L / rate) * 830.61 * Atn(1) * 8) '* fade.
                    If note$ = "a5" Then _SndRaw Sin((L / rate) * 880.00 * Atn(1) * 8) '* fade.
                    If note$ = "A5" Then _SndRaw Sin((L / rate) * 932.33 * Atn(1) * 8) '* fade.
                    If note$ = "b5" Then _SndRaw Sin((L / rate) * 987.77 * Atn(1) * 8) '* fade.
                    If note$ = "c6" Then _SndRaw Sin((L / rate) * 1046.50 * Atn(1) * 8) '* fade.
                    If note$ = "C6" Then _SndRaw Sin((L / rate) * 1108.73 * Atn(1) * 8) '* fade.
                    If note$ = "d6" Then _SndRaw Sin((L / rate) * 1174.66 * Atn(1) * 8) '* fade.
                    If note$ = "D6" Then _SndRaw Sin((L / rate) * 1244.51 * Atn(1) * 8) '* fade.
                    If note$ = "e6" Then _SndRaw Sin((L / rate) * 1318.51 * Atn(1) * 8) '* fade.
                    If note$ = "f6" Then _SndRaw Sin((L / rate) * 1396.91 * Atn(1) * 8) '* fade.
                    If note$ = "F6" Then _SndRaw Sin((L / rate) * 1479.98 * Atn(1) * 8) '* fade.
                    If note$ = "g6" Then _SndRaw Sin((L / rate) * 1567.98 * Atn(1) * 8) '* fade.
                    If note$ = "G6" Then _SndRaw Sin((L / rate) * 1661.22 * Atn(1) * 8) '* fade.
                    If note$ = "a6" Then _SndRaw Sin((L / rate) * 1760.00 * Atn(1) * 8) '* fade.
                    If note$ = "A6" Then _SndRaw Sin((L / rate) * 1864.66 * Atn(1) * 8) '* fade.
                    If note$ = "b6" Then _SndRaw Sin((L / rate) * 1975.53 * Atn(1) * 8) '* fade.
                    If note$ = "c7" Then _SndRaw Sin((L / rate) * 2093.00 * Atn(1) * 8) '* fade.
                    If note$ = "C7" Then _SndRaw Sin((L / rate) * 2217.46 * Atn(1) * 8) '* fade.
                    If note$ = "d7" Then _SndRaw Sin((L / rate) * 2349.32 * Atn(1) * 8) '* fade.
                    If note$ = "D7" Then _SndRaw Sin((L / rate) * 2489.02 * Atn(1) * 8) '* fade.
                    If note$ = "e7" Then _SndRaw Sin((L / rate) * 2637.02 * Atn(1) * 8) '* fade.
                    If note$ = "f7" Then _SndRaw Sin((L / rate) * 2793.83 * Atn(1) * 8) '* fade.
                    If note$ = "F7" Then _SndRaw Sin((L / rate) * 2959.96 * Atn(1) * 8) '* fade.
                    If note$ = "g7" Then _SndRaw Sin((L / rate) * 3135.96 * Atn(1) * 8) '* fade.
                    If note$ = "G7" Then _SndRaw Sin((L / rate) * 3322.44 * Atn(1) * 8) '* fade.
                    If note$ = "a7" Then _SndRaw Sin((L / rate) * 3520.00 * Atn(1) * 8) '* fade.
                    If note$ = "A7" Then _SndRaw Sin((L / rate) * 3729.31 * Atn(1) * 8) '* fade.
                    If note$ = "b7" Then _SndRaw Sin((L / rate) * 3951.07 * Atn(1) * 8) '* fade.
                    If note$ = "c8" Then _SndRaw Sin((L / rate) * 4186.01 * Atn(1) * 8) '* fade.
                Next

            Next

        End If

        If cur >= Len(Music$) Then Exit Do

        'IF INKEY$ <> "" THEN EXIT SUB

    Loop

    Exit Sub

    '=========================================================
    LoadNote:
    '========
    Length = (60 * NoteValue / Tempo)
    For L = 0 To Length * rate
        'fade = Exp(-L / rate * 8)
        If note = 0 Then
            _SndRaw 0
        Else
            _SndRaw Sin((L / rate) * note * Atn(1) * 8) '* fade
        End If
    Next
    Return

End Sub


Find my programs here in Dav's QB64 Corner
Reply
#2
I think you just inspired an idea to make _SNDNEW feed to an array handle. I mean essentially we have this with fonts, the ability to load several font libraries and keep them in memory; so this may be possible.

As a side note, did you ever consider cutting down some code by changing your style in SELECT CASE as in...

Code: (Select All)

        Select Case Mid$(Music$, cur, 2)

            Case Is = "a0": note = 27.50: cur = cur + 2: GoSub LoadNote

            Case Is = "A0": note = 29.14: cur = cur + 2: GoSub LoadNote

            Case Is = "b0": note = 30.87: cur = cur + 2: GoSub LoadNote

            Case Is = "c1": note = 32.70: cur = cur + 2: GoSub LoadNote

            Case Is = "C1": note = 34.65: cur = cur + 2: GoSub LoadNote

        End Select

to...

Code: (Select All)
act = 1 ' <------------------ 
        Select Case Mid$(Music$, cur, 2)

            Case Is = "a0": note = 27.50

            Case Is = "A0": note = 29.14

            Case Is = "b0": note = 30.87

            Case Is = "c1": note = 32.70

            Case Is = "C1": note = 34.65
           
            Case Else: act = 0 ' <------------------

        End Select
If act Then cur = cur + 2: GoSub LoadNote: act = 0 ' <------------------

Hopefully that other 'Sam' will stop by with a definitive answer to your sound query.

Pete
Fake News + Phony Politicians = Real Problems

Reply
#3
Nice tip.  Nope, I never thought of doing that. 

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#4
I think I got this figured out using another method will help from the wiki.  Leaving for the mountains now, but when I get back I’ll try to have some code to share with a new method.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#5
Hi,

It should work. I mean - maybe. The problem will be with mixing audio samples, probably. Instead of calling _SNDRAW, you save the entire output as a set of numbers in an array of type SINGLE, then you try to play it with _SndRaw (to verify that the recording of sound samples in the array is correct) and then it should work: You create a music descriptor via SndNew and then into you insert the content of the Single field into it via _MemPut. I think this can work.


Reply
#6
Quote:Instead of playing with _SNDRAW like this, Is it possible to feed the data to a _SNDNEW memory instead so I could have the song with a handle for using it with _SNDPLAY controls?
It is! That's exactly the reason why we added _SNDNEW. Mixing two sounds into the buffer is just a matter of summing the samples of the sounds (assuming they are signed and of the same format).

Here is a crude example of _SNDNEW. GenerateSineWave() simply inserts the samples into the buffer created by _SNDNEW using ProcSoundInsertSampleFrame(). It also mixes a tiny bit of noise into the sine waveform.

Code: (Select All)
OPTION _EXPLICIT

'-------------------------------------------------------------------------------
TYPE ProcSoundType
    handle AS LONG
    buffer AS _MEM
    cursor AS _UNSIGNED _OFFSET
END TYPE
'-------------------------------------------------------------------------------

' Since the sound buffer size cannot be changed after it is created, we'll need to know the exact frames we need in advance
CONST FRAMES = 65536

DIM ps(1 TO 7) AS ProcSoundType, i AS LONG

FOR i = 1 TO 7
    ProcSoundCreate ps(i), FRAMES
NEXT i

GenerateSineWave ps(1), 262!
GenerateSineWave ps(2), 294!
GenerateSineWave ps(3), 330!
GenerateSineWave ps(4), 349!
GenerateSineWave ps(5), 392!
GenerateSineWave ps(6), 440!
GenerateSineWave ps(7), 494!

PRINT "Press 1 - 7"

DIM k AS LONG

DO
    k = _KEYHIT

    SELECT CASE k
        CASE 49
            _SNDPLAYCOPY ProcSoundGetHandle(ps(1))

        CASE 50
            _SNDPLAYCOPY ProcSoundGetHandle(ps(2))

        CASE 51
            _SNDPLAYCOPY ProcSoundGetHandle(ps(3))

        CASE 52
            _SNDPLAYCOPY ProcSoundGetHandle(ps(4))

        CASE 53
            _SNDPLAYCOPY ProcSoundGetHandle(ps(5))

        CASE 54
            _SNDPLAYCOPY ProcSoundGetHandle(ps(6))

        CASE 55
            _SNDPLAYCOPY ProcSoundGetHandle(ps(7))
    END SELECT

    _LIMIT 60
LOOP UNTIL k = 27

FOR i = 1 TO 7
    ProcSoundDelete ps(i)
NEXT i

END

SUB GenerateSineWave (ps AS ProcSoundType, frequency AS SINGLE)
    DIM angleDelta AS SINGLE: angleDelta = _PI(2!) * frequency / _SNDRATE
    DIM angle AS SINGLE

    ProcSoundSeek ps, 0

    DO UNTIL ProcSoundIsFull(ps)
        ProcSoundInsertSampleFrame ps, SIN(angle) + ((RND - RND) * 0.05!)
        angle = angle + angleDelta
    LOOP
END SUB

'-------------------------------------------------------------------------------
SUB ProcSoundDelete (ps AS ProcSoundType)
    IF ps.handle THEN
        _SNDCLOSE ps.handle
        ps.handle = 0
        ps.cursor = 0
    END IF
END SUB

SUB ProcSoundCreate (ps AS ProcSoundType, sampleFrames AS _UNSIGNED LONG)
    ProcSoundDelete ps
    ps.handle = _SNDNEW(sampleFrames, 1, 32) ' hardcoded to create mono 32-bit FP buffer
    ps.cursor = 0
    ps.buffer = _MEMSOUND(ps.handle)
END SUB

FUNCTION ProcSoundGetHandle& (ps AS ProcSoundType)
    ProcSoundGetHandle = ps.handle
END FUNCTION

FUNCTION ProcSoundIsFull%% (ps AS ProcSoundType)
    ProcSoundIsFull = ps.cursor >= ps.buffer.SIZE
END FUNCTION

FUNCTION ProcSoundGetFrames~%& (ps AS ProcSoundType)
    ProcSoundGetFrames = ps.buffer.SIZE \ ps.buffer.ELEMENTSIZE
END FUNCTION

SUB ProcSoundSeek (ps AS ProcSoundType, frame AS _UNSIGNED _OFFSET)
    ps.cursor = frame * ps.buffer.ELEMENTSIZE
END SUB

FUNCTION ProcSoundGetPosition~%& (ps AS ProcSoundType)
    ProcSoundGetPosition = ps.cursor \ ps.buffer.ELEMENTSIZE
END FUNCTION

SUB ProcSoundInsertSampleFrame (ps AS ProcSoundType, sample AS SINGLE)
    _MEMPUT ps.buffer, ps.buffer.OFFSET + ps.cursor, sample AS SINGLE
    ps.cursor = ps.cursor + ps.buffer.ELEMENTSIZE ' ELEMENTSIZE here is 4 since sizeof(single) = 4
END SUB
'-------------------------------------------------------------------------------
Reply
#7
Thanks Sam. That' a GOOD SOUND EXAMPLE!

Pete Big Grin
Fake News + Phony Politicians = Real Problems

Reply
#8
Hey, great example, @a470g!  That's something I will mess with!

Here's what I was working on, used the _SNDNEW wiki example as a base, tried to convert the old code to using it.  I haven't added grouped notes yet (), but it can build melodies into a sound file handle to call on already.

This code is clumsy, I just wanted to get something working at the moment.  Has the same note usage as the old code, except tempo is given a parameter.

- Dav

Code: (Select All)
'SNDNOTES.BAS - THIS IS A WORK IN PROGRESS
'Dav, SEP/2024

'Builds notes and makes a sound with a sound handle for _SND playback/control.
'lowercase letters are normal notes, uppercase means sharps.
'example c4 is a reguar c note.  C4  is a C#.

'tempo = tempo of song
'wn = whole note duration
'hn = half note duration
'qn = quarter note
'en = eigth not duration
'sn = sinxteenth note
'ts = thity-second note
'rn = rest note of current duration set

a$ = "enc4c4g4g4a4a4qng4enf4f4e4e4d4d4qnc4"
a$ = a$ + "eng4g4f4f4e4e4qnd4eng4g4f4f4e4e4qnd4"
a$ = a$ + "enc4c4g4g4a4a4qng4enf4f4e4e4d4d4qnc4"

song& = _SndCopy(SndNotes&(160, a$))

Do
    Color Int(Rnd * 16)
    Print "Press SPACE play song, ESC to end"
    key$ = InKey$
    If key$ = " " Then _SndPlayCopy (song&)
    _Limit 10
Loop Until key$ = Chr$(27)

_SndClose song&

End


Function SndNotes& (tempo, notes$)

    'first, remove any spaces from the string
    n2$ = ""
    For i = 1 To Len(notes$)
        a$ = Mid$(notes$, i, 1)
        If a$ <> " " Then n2$ = n2$ + a$
    Next
    notes$ = n2$


    ' Set default tempo to keep in bounds
    If tempo < 40 Then tempo = 40
    If tempo > 200 Then tempo = 200

    ' Set default duration based on the tempo
    defaultduration = 60 / tempo ' (in seconds)
    SAMPLE_CHANNELS = 1 ' Number of channels
    SAMPLE_BYTES = 4 ' Number of bytes per sample

    Dim sndblk As _MEM
    totalsamples = 0
    currentduration = defaultduration

    'tally up duration/samples needed first
    For i = 1 To Len(notes$) Step 2
        durstr$ = Mid$(notes$, i, 2)
        If durstr$ = "wn" Then
            currentduration = 4 * defaultduration 'whole note
        ElseIf durstr$ = "hn" Then
            currentduration = 2 * defaultduration 'half note
        ElseIf durstr$ = "qn" Then
            currentduration = defaultduration 'quarter note
        ElseIf durstr$ = "en" Then
            currentduration = defaultduration / 2 'eighth note
        ElseIf durstr$ = "sn" Then
            currentduration = defaultduration / 4 'sixteenth note
        ElseIf durstr$ = "ts" Then
            currentduration = defaultduration / 8 'thirty-second note
        ElseIf durstr$ = "rn" Then
            ' Rest - do't change totalsamples, just skip
            totalsamples = totalsamples + currentduration * _SndRate
        Else
            totalsamples = totalsamples + (currentduration * _SndRate)
        End If
    Next

    'create the sound memory
    h = _SndNew(totalsamples + 88, SAMPLE_CHANNELS, SAMPLE_BYTES * 8)
    If (h < 1) Then
        Print "Failed to create sound!"
        End
    End If

    sndblk = _MemSound(h, 0)
    If sndblk.SIZE = 0 Then
        _SndClose h
        Print "Failed to access sound data!"
    End If

    Dim t As _Integer64
    currentsample = 0

    For i = 1 To Len(notes$) Step 2 'increment by 2
        durstr$ = Mid$(notes$, i, 2) 'read 2 bytes
        If durstr$ = "wn" Then
            currentduration = 4 * defaultduration 'hole note
        ElseIf durstr$ = "hn" Then
            currentduration = 2 * defaultduration 'half note
        ElseIf durstr$ = "qn" Then
            currentduration = defaultduration 'quarter note
        ElseIf durstr$ = "en" Then
            currentduration = defaultduration / 2 'eighth note
        ElseIf durstr$ = "sn" Then
            currentduration = defaultduration / 4 'sixteenth note
        ElseIf durstr$ = "ts" Then
            currentduration = defaultduration / 8 'thirty-second note
        ElseIf durstr$ = "rn" Then
            'rest, don't add to sample, just skip
            'this does a pause for currentduration
            currentsample = currentsample + (currentduration * _SndRate)
        Else
            ' Must be a note
            freq = 0 'defaut safety
            If durstr$ = "a0" Then freq = 27.50
            If durstr$ = "A0" Then freq = 29.14
            If durstr$ = "b0" Then freq = 30.87
            If durstr$ = "c1" Then freq = 32.70
            If durstr$ = "C1" Then freq = 34.65
            If durstr$ = "d1" Then freq = 36.71
            If durstr$ = "D1" Then freq = 38.89
            If durstr$ = "e1" Then freq = 41.20
            If durstr$ = "f1" Then freq = 43.65
            If durstr$ = "F1" Then freq = 46.25
            If durstr$ = "g1" Then freq = 49.00
            If durstr$ = "G1" Then freq = 51.91
            If durstr$ = "a1" Then freq = 55.00
            If durstr$ = "A1" Then freq = 58.27
            If durstr$ = "b1" Then freq = 61.74
            If durstr$ = "c2" Then freq = 65.41
            If durstr$ = "C2" Then freq = 69.30
            If durstr$ = "d2" Then freq = 73.42
            If durstr$ = "D2" Then freq = 77.78
            If durstr$ = "e2" Then freq = 82.41
            If durstr$ = "f2" Then freq = 87.31
            If durstr$ = "F2" Then freq = 92.50
            If durstr$ = "g2" Then freq = 98.00
            If durstr$ = "G2" Then freq = 103.83
            If durstr$ = "a2" Then freq = 110.00
            If durstr$ = "A2" Then freq = 116.54
            If durstr$ = "b2" Then freq = 123.47
            If durstr$ = "c3" Then freq = 130.81
            If durstr$ = "C3" Then freq = 138.59
            If durstr$ = "d3" Then freq = 146.83
            If durstr$ = "D3" Then freq = 155.56
            If durstr$ = "e3" Then freq = 164.81
            If durstr$ = "f3" Then freq = 174.61
            If durstr$ = "F3" Then freq = 185.00
            If durstr$ = "g3" Then freq = 196.00
            If durstr$ = "G3" Then freq = 207.65
            If durstr$ = "a3" Then freq = 220.00
            If durstr$ = "A3" Then freq = 233.08
            If durstr$ = "b3" Then freq = 246.94
            If durstr$ = "c4" Then freq = 261.63
            If durstr$ = "C4" Then freq = 277.18
            If durstr$ = "d4" Then freq = 293.66
            If durstr$ = "D4" Then freq = 311.13
            If durstr$ = "e4" Then freq = 329.63
            If durstr$ = "f4" Then freq = 349.23
            If durstr$ = "F4" Then freq = 369.99
            If durstr$ = "g4" Then freq = 392.00
            If durstr$ = "G4" Then freq = 415.30
            If durstr$ = "a4" Then freq = 440.00
            If durstr$ = "A4" Then freq = 466.16
            If durstr$ = "b4" Then freq = 493.88
            If durstr$ = "c5" Then freq = 523.25
            If durstr$ = "C5" Then freq = 554.37
            If durstr$ = "d5" Then freq = 587.33
            If durstr$ = "D5" Then freq = 622.25
            If durstr$ = "e5" Then freq = 659.25
            If durstr$ = "f5" Then freq = 698.46
            If durstr$ = "F5" Then freq = 739.99
            If durstr$ = "g5" Then freq = 783.99
            If durstr$ = "G5" Then freq = 830.61
            If durstr$ = "a5" Then freq = 880.00
            If durstr$ = "A5" Then freq = 932.33
            If durstr$ = "b5" Then freq = 987.77
            If durstr$ = "c6" Then freq = 1046.50
            If durstr$ = "C6" Then freq = 1108.73
            If durstr$ = "d6" Then freq = 1174.66
            If durstr$ = "D6" Then freq = 1244.51
            If durstr$ = "e6" Then freq = 1318.51
            If durstr$ = "f6" Then freq = 1396.91
            If durstr$ = "F6" Then freq = 1479.98
            If durstr$ = "g6" Then freq = 1567.98
            If durstr$ = "G6" Then freq = 1661.22
            If durstr$ = "a6" Then freq = 1760.00
            If durstr$ = "A6" Then freq = 1864.66
            If durstr$ = "b6" Then freq = 1975.53
            If durstr$ = "c7" Then freq = 2093.00
            If durstr$ = "C7" Then freq = 2217.46
            If durstr$ = "d7" Then freq = 2349.32
            If durstr$ = "D7" Then freq = 2489.02
            If durstr$ = "e7" Then freq = 2637.02
            If durstr$ = "f7" Then freq = 2793.83
            If durstr$ = "F7" Then freq = 2959.96
            If durstr$ = "g7" Then freq = 3135.96
            If durstr$ = "G7" Then freq = 3322.44
            If durstr$ = "a7" Then freq = 3520.00
            If durstr$ = "A7" Then freq = 3729.31
            If durstr$ = "b7" Then freq = 3951.07
            If durstr$ = "c8" Then freq = 4186.01

            'attack/decay/sustain/release parameters
            attack = .01 '10 ms
            decay = .1 '100 ms
            sustain = .7 '70% of vol
            release = .1 '100 ms

            'make sample
            For t = 0 To (currentduration * _SndRate) - 1
                samplevalue = Sin(2 * _Pi * freq * t / _SndRate)

                ' Apply attack/decay/sustain/release values
                time = t / _SndRate
                If time < attack Then
                    samplevalue = samplevalue * (time / attack) 'attack
                ElseIf time < attack + decay Then
                    samplevalue = samplevalue * ((sustain - 1) * (time - attack) / decay + 1) 'decay
                ElseIf time < (currentduration - release) Then
                    samplevalue = samplevalue * sustain 'sustain
                Else
                    samplevalue = samplevalue * (sustain * (1 - (time - (currentduration - release)) / release)) 'release
                End If

                'put value into buffer
                _MemPut sndblk, sndblk.OFFSET + (currentsample * SAMPLE_BYTES * SAMPLE_CHANNELS), samplevalue As SINGLE
                currentsample = currentsample + 1
            Next

        End If
    Next

    SndNotes& = _SndCopy(h)
    _SndClose h

End Function

Find my programs here in Dav's QB64 Corner
Reply




Users browsing this thread: 1 Guest(s)