acid music thingie

Windows specific forum
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by mindplay.

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

:) :) :) ACIIIIIIIED :) :) :) ... heheh - enjoy!

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()
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by mindplay

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,
A lot of modern FPUs have instructions to calculate the sine (x86 does). If PB uses these then I'd say that piece of your code was fairly well optimised apart from the jump to the Sin() command :wink:


--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by mindplay.

Function call overhead, yes - but if it did use a CPU Sin instruction, it wouldn't compile into a function call, would it? :wink:
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by El_Choni.

AFAIK, PB translates Sin() directly to fsin, no function calls, so there's no 'misoptimization' when using it.

El_Choni
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by tinman.
Originally posted by mindplay

Function call overhead, yes - but if it did use a CPU Sin instruction, it wouldn't compile into a function call, would it? :wink:
If El_Choni is correct (and I have no reason to doubt him :) then PureBasic is cleverer than I thought. I did not realise it could "inline" functions (or perhaps Fred has put some special code in to handle commands which should be "inline" such as sin, cos, peek, poke, etc).


--
It's not minimalist - I'm increasing efficiency by reducing input effort.
(Win98first ed. + all updates, PB3.51)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by fred.

Yes, there is no extra call for mathematic functions and some other which perform much better directly inlined. Who said than PB isn't clever ? :).

Code: Select all

; a.f = Sin(0.15)
  MOV    dword [esp-4],1041865114
  FLD    dword [esp-4]
  FSIN
  FSTP   dword [v_a]


Fred - AlphaSND
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by mindplay.

Fred, how about peeks and pokes? do those translate into function calls, or into code as well?

On a completely different note, now that I have your attention Fred ... :) ... how about adding some sort of keyword to Procedures that allows you to make (small) procedures that get compiled "on the spot"? i.e. instead of being compiled as a function and function calls, the code gets repeatedly inserted into the code where the procedure is "called"? sort of like a macro ... ? ... like for example, let's say you have a little filter routine, such as the one I have here, and you need to use that in several places - when calculating realtime sounds, you'd normally have an overhead of 44100 function calls (!) for every filter (!!) - if it were possible to reduce that to zero by simply changing "Procedure" to "MetaProcedure" for example ("meta" since it's not technically a procedure anymore), this could give give PB an serious additional speed boost? :)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by fred.

It's planned and it will called 'Macro' :). About the Peek/Poke stuff, if you really want speed use a pointer associated to a structure. It's the fastest way. Peek/Poke aren't inlined.

Fred - AlphaSND
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

Cant get the source work... get everytime the message that "FSOUND_Init(#SampleRate, 32, 0)" isnt a function or something". Seems i need any PB/UserLib or...? If someone can help me, it would be very nice... thx!

greetz
MrVainSCL! aka Thorsten

PIII450, 256MB Ram, 80GB HD + 6,4 GB, RivaTNT, DirectX9.0, SB AWE64, Win2000 + all Updates...
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

> get everytime the message that "FSOUND_Init(#SampleRate, 32, 0)"
> isnt a function or something".

Same with me... :cry:
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Danilo.

You need to install http://home.t-online.de/home/ExpressTrack/PureFMOD.zip

cya,
...Danilo
(registered PureBasic user)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by MrVainSCL.

HI mindplay,
very nice example but it crash everytime when running.. (still playing the generated synth)

Danilo, thx for info and link to PureMOD

greetz
MrVainSCL! aka Thorsten

PIII450, 256MB Ram, 80GB HD + 6,4 GB, RivaTNT, DirectX9.0, SB AWE64, Win2000 + all Updates...
Post Reply