Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Is it possible to make a _SNDNEW song this way?
#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


Messages In This Thread
RE: Is it possible to make a _SNDNEW song this way? - by Dav - 09-07-2024, 11:45 PM



Users browsing this thread: 2 Guest(s)