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
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