In case you missed it, in a reply to another sort of unrelated post, here's a realtime sequencer/bassline/bassdrum synthesizer - requires FMOD ... demonstrates how to make simple realtime synthesis with filters and linear/logarithmic envelopes.
It's not terribly slow, but it is by NO means optimized - using the Sin() function, for example, is not something you'd normally do, unless you're as lazy as I am
Code: Select all
; FMOD Constants
#FSOUND_16BITS.l = $00000010
#FSOUND_SIGNED.l = $00000100
#FSOUND_MONO.l = $00000020
#FSOUND_FREE.l = -1
; Music/math constants and utility functions
#SampleRate = 44100
#Pi.f = 3.14159265
#Pi2.f = 6.2831853
Procedure.f NoteFreq(note.f)
ProcedureReturn Pow(2, (note+11)/12)*8.1757989
EndProcedure
#NumSteps = 8
Structure StepStruct
Freq.f
Drum.l
EndStructure
Dim Seq.StepStruct(#NumSteps)
StepNum.l = 0
NoteDur.l = #SampleRate/(130*4/60) ; 130 BPM, 4 steps per beat
NotePos.l = 0
Seq(0)\Freq = NoteFreq(36)
Seq(1)\Freq = NoteFreq(48)
Seq(2)\Freq = NoteFreq(42)
Seq(3)\Freq = NoteFreq(30)
Seq(4)\Freq = NoteFreq(48)
Seq(5)\Freq = NoteFreq(47)
Seq(6)\Freq = NoteFreq(46)
Seq(7)\Freq = NoteFreq(30)
DrumEnv.f = 1
DrumPos.f = 0.5
Seq(0)\Drum = 1
Seq(1)\Drum = 0
Seq(2)\Drum = 0
Seq(3)\Drum = 0
Seq(4)\Drum = 1
Seq(5)\Drum = 0
Seq(6)\Drum = 0
Seq(7)\Drum = 0
; Buffer Structure
#BufferSize.l = 4096*4 ; buffer size (increase if the sound breaks up!)
Structure BufferType
Sample.w[#BufferSize]
EndStructure
; Filter Structure
#Filter_HiCutoff = 1200
Structure FilterStruct
rlpf_f.f ; cutoff frequency
rlpf_r.f ; resonance amount
rlpf_c.f
rlpf_pos.f
rlpf_speed.f
EndStructure
DefType.FilterStruct Filter
Filter\rlpf_pos=0
Filter\rlpf_speed=0
Filter\rlpf_r=0.995
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c=2-2*Cos(2*pi*rlpf_f/#SampleRate)
; Callback
SinPos.f = 0
Procedure.b MyStreamCallback(*Stream.l, *Buff.BufferType, Len.l, Param.l)
Global SinPos, NotePos, NoteDur, StepNum, Seq, Filter, DrumPos, DrumEnv
For Index.l = 0 To (Len/2)-1
; Waveform
SinPos = SinPos + ((Seq(StepNum)\Freq)/#SampleRate)
If SinPos>1
SinPos - 1
EndIf
; Oscillator
Smp.f = Sin(SinPos * #Pi2)
; Shaping/distortion (sinus towards square)
Smp = Smp / (Abs(Smp)+0.01)
; Simple envelope
Smp = Smp * ((NoteDur-NotePos)/NoteDur)
; Filter
Filter\rlpf_speed = Filter\rlpf_speed + (Smp - Filter\rlpf_pos) * Filter\rlpf_c
Filter\rlpf_pos = Filter\rlpf_pos + Filter\rlpf_speed
Filter\rlpf_speed = Filter\rlpf_speed * Filter\rlpf_r
Smp = Filter\rlpf_pos * 0.1
Filter\rlpf_f = Filter\rlpf_f - 0.12
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
; Drum
If Seq(StepNum)\Drum=1
DrumPos = DrumPos + (130+DrumEnv*1500)/#SampleRate
DrumEnv = DrumEnv * 0.9992
Smp = Smp + ((NoteDur-NotePos)/NoteDur) * Sin(DrumPos)
EndIf
; Volume down
Smp = Smp * 0.7
; Clipping
If Smp>1
Smp=1
ElseIf SmpNoteDur
; Next Note
NotePos=0
StepNum+1
SinPos=0
If StepNum=#NumSteps
StepNum=0
EndIf
; Reset Filter Cutoff and recalculate coefficient
Filter\rlpf_f=#Filter_HiCutoff
Filter\rlpf_c = 2 - 2 * Cos(#Pi2 * Filter\rlpf_f / #SampleRate)
; Reset Drum
If Seq(StepNum)\Drum=1
DrumPos = 0.5
DrumEnv = 1
EndIf
EndIf
Next
ProcedureReturn 1 ; must return 1 to continue playing
EndProcedure
; Open a console, and play the stream until ENTER is pressed
OpenConsole()
PrintN("Simple Bassline Synthesizer/Sequencer example")
PrintN("Written by R. Schultz ([url]mailto:mp@mindplay.dk[/url])")
PrintN("Use freely, but give credit, and notify the author of any use!")
PrintN("")
PrintN("Initializing FMOD...")
FSOUND_Init(#SampleRate, 32, 0)
MyStream = FSOUND_Stream_Create(@MyStreamCallback(), #BufferSize*2, #FSOUND_16BITS | #FSOUND_SIGNED | #FSOUND_MONO, #SampleRate, 1)
If MyStream=0
PrintN("Stream creation failed!")
Else
FSOUND_Stream_Play(#FSOUND_FREE, MyStream)
PrintN("Playing Stream")
EndIf
Print("Press ENTER to quit")
Input()
FSOUND_Stream_Close(MyStream)
FSOUND_Close()
CloseConsole()
