Is it possible to make a _SNDNEW song this way? - Dav - 09-07-2024
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
RE: Is it possible to make a _SNDNEW song this way? - Pete - 09-07-2024
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
RE: Is it possible to make a _SNDNEW song this way? - Dav - 09-07-2024
Nice tip. Nope, I never thought of doing that.
- Dav
RE: Is it possible to make a _SNDNEW song this way? - Dav - 09-07-2024
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
RE: Is it possible to make a _SNDNEW song this way? - Petr - 09-07-2024
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.
RE: Is it possible to make a _SNDNEW song this way? - a740g - 09-07-2024
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
'-------------------------------------------------------------------------------
RE: Is it possible to make a _SNDNEW song this way? - Pete - 09-07-2024
Thanks Sam. That' a GOOD SOUND EXAMPLE!
Pete
RE: Is it possible to make a _SNDNEW song this way? - Dav - 09-07-2024
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
|