I want to write my own DSP (Digital Signal Processing) - Unit for FMOD.
right only numbers > 0 ... but can you play a sine without numbers < 0?
Code: Select all
Declare MAKELONG(low, high)
Declare HIWORD(Value)
Declare LOWORD(Value)
Declare Unload()
Declare Stop()
Declare.l Lowpass(ptOriginalbuffer.l, ptNewbuffer.l, Length.l, Param.l)
Declare FFT()
Global Volume.l
Global Quit.l
Global Play.l
Global Stream_ID.l
Global LowPassID.l
Global FFTFrequenz.l
Global Wert.l
Volume = 25
Wert = 2000
Quit = #False
Play = #False
Pause.l = #False
FFT_ID.l = #Null
Stream_ID = #Null
LowPassID = #Null
FFTUnit_ID.l = #Null
LowpassUnit_ID.l = #Null
Temp.s = ""
FFTFrequenz = 30
Soundfile.s = ""
Structure fftarray
Value.f[512]
EndStructure
If OpenWindow(1,0,0,520,350,#PB_Window_SystemMenu|#PB_Window_ScreenCentered, "FMOD FFT-Spectrum Visualization") <> #False
If FSOUND_SetBufferSize(125) <> #False
If FSOUND_Init(44100, 32, 0) <> #False
If CreateMenu(1, WindowID(1)) <> #False And CreateGadgetList(WindowID(1)) <> #False
MenuItem(1, "Open")
MenuItem(2, "Play")
MenuItem(3, "Stop")
MenuItem(4, "Pause")
OpenSubMenu("Spectrum Analyzer")
OpenSubMenu("Frequenz")
MenuItem(5, "10 Hz")
MenuItem(6, "30 Hz")
MenuItem(7, "50 Hz")
MenuItem(8, "70 Hz")
MenuItem(9, "90 Hz")
CloseSubMenu()
CloseSubMenu()
SetMenuItemState(1, 6, #True)
CreateImage(1, 513, 201)
TrackBarGadget(1, 4, 215, 513, 20, 0, 255)
TrackBarGadget(2, 4, 245, 513, 20, 0, 5000)
TrackBarGadget(3, 4, 275, 513, 20, 1, 2000)
SetGadgetState(1, Volume)
SetGadgetState(3, 2000)
FFT_ID = CreateThread(@FFT(), #Null)
If FFT_ID <> 0
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_EventMenu
Select EventMenuID()
Case 1 ;(Open)
Stop()
Temp = OpenFileRequester("", "c:\music\club\", "Music (*.mp3, *.wav, *.mp2, *.ogg, *.raw)|*.mp3;*.wav;*.mp2;*.ogg;*.raw|*.*|*.*", #Null, #Null)
If Temp <> ""
Soundfile = Temp
EndIf
Case 2 ;(Play)
Stream_ID = FSOUND_Stream_OpenFile(Soundfile, 0, 0) ;open the soundfile
If Stream_ID <> 0
FFTUnit_ID = FSOUND_DSP_GetFFTUnit()
FSOUND_DSP_SetActive(FFTUnit_ID, #True) ;activate the FastFourierTransformation-DSP-Unit
LowpassUnit_ID = FSOUND_DSP_Create(@Lowpass(), FSOUND_DSP_GetPriority(FFTUnit_ID) - 1, #Null)
FSOUND_DSP_SetActive(LowpassUnit_ID, #True)
FSOUND_Stream_Play(1, Stream_ID) ;play the stream on channel 1
Play = #True
;Lautstärke setzen
FSOUND_SetVolume(1, GetGadgetState(1))
EndIf
Case 3 ;(Stop)
Stop()
Case 4 ;(Pause)
If Pause <> #True
FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream
Play = #False
Pause = #True
FSOUND_DSP_SetActive(FFTUnit_ID, #False)
FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
FSOUND_DSP_Free(LowpassUnit_ID)
Else
If Stream_ID <> 0
Pause = #False
FFTUnit_ID = FSOUND_DSP_GetFFTUnit()
FSOUND_DSP_SetActive(FFTUnit_ID, #True) ;activate the FastFourierTransformation-DSP-Unit
LowpassUnit_ID = FSOUND_DSP_Create(@Lowpass(), FSOUND_DSP_GetPriority(FFTUnit_ID) - 1, #Null)
FSOUND_DSP_SetActive(LowpassUnit_ID, #True)
FSOUND_Stream_Play(1, Stream_ID) ;play the stream on channel 1
Play = #True
;Lautstärke setzen
FSOUND_SetVolume(1, GetGadgetState(1))
;Position setzen
FSOUND_Stream_SetPosition(Stream_ID, Int((FSOUND_Stream_GetLength(Stream_ID) / 5000) * GetGadgetState(2)))
EndIf
EndIf
Case 5
FFTFrequenz = 10
SetMenuItemState(1, 5 ,#True)
SetMenuItemState(1, 6 ,#False)
SetMenuItemState(1, 7 ,#False)
SetMenuItemState(1, 8 ,#False)
SetMenuItemState(1, 9 ,#False)
Case 6
FFTFrequenz = 30
SetMenuItemState(1, 5 ,#False)
SetMenuItemState(1, 6 ,#True)
SetMenuItemState(1, 7 ,#False)
SetMenuItemState(1, 8 ,#False)
SetMenuItemState(1, 9 ,#False)
Case 7
FFTFrequenz = 50
SetMenuItemState(1, 5 ,#False)
SetMenuItemState(1, 6 ,#False)
SetMenuItemState(1, 7 ,#True)
SetMenuItemState(1, 8 ,#False)
SetMenuItemState(1, 9 ,#False)
Case 8
FFTFrequenz = 70
SetMenuItemState(1, 5 ,#False)
SetMenuItemState(1, 6 ,#False)
SetMenuItemState(1, 7 ,#False)
SetMenuItemState(1, 8 ,#True)
SetMenuItemState(1, 9 ,#False)
Case 9
FFTFrequenz = 90
SetMenuItemState(1, 5 ,#False)
SetMenuItemState(1, 6 ,#False)
SetMenuItemState(1, 7 ,#False)
SetMenuItemState(1, 8 ,#False)
SetMenuItemState(1, 9 ,#True)
EndSelect
Case #PB_Event_Gadget
Select EventGadgetID()
Case 1
If Play <> #False
;Lautstärke setzen
FSOUND_SetVolume(1, GetGadgetState(1))
EndIf
Case 2
If Play <> #False
;Position ändern
FSOUND_Stream_SetPosition(Stream_ID, Int((FSOUND_Stream_GetLength(Stream_ID) / 5000) * GetGadgetState(2)))
EndIf
Case 3
Wert = GetGadgetState(3)
EndSelect
Case #PB_Event_CloseWindow
Unload()
Case #WM_QUIT
Unload()
EndSelect
Until Quit <> #False
EndIf
EndIf
EndIf
EndIf
EndIf
End
Procedure FFT()
Protected TimeStart.l
Protected Time.l
Protected hfft.fftarray
Protected x.l
Protected y.l
Protected Value.f
Protected Color.l
Protected Periodendauer.l
Repeat
If Play <> #False And FSOUND_DSP_GetActive(FSOUND_DSP_GetFFTUnit()) <> 0
TimeStart = GetTickCount_()
Periodendauer = Int((1 / FFTFrequenz) * 1000)
CopyMemory(FSOUND_DSP_GetSpectrum(), hfft, 4*512)
UseImage(1)
StartDrawing(ImageOutput())
For i = 0 To 511 Step 4
Value = 199 - Pow(0.0000001, hfft\Value[i]) * 199
;Jeder der 512 Frequenzen kann sich von 0 bis 200 erstrecken
;Jeder "Block" ist 5 Pixel hoch, deshalb in 5er Schritten
For y = 0 To 200 Step 5
;Die Farbe für jeden 5er Schritt berechnen
;Formel by Froggerprogger
Color = (255 - y) * $000100 + y * $000001
;Wenn der aktuelle "Block" aktiv ist
If Value > y
;Den Block mit der dynamischen Farbe füllen
Box(i + 1, 200 - y, 3, 6, Color)
;ist der "Block" leer, ...
ElseIf actfftvalue < y
;... muss er mit grauer Farbe gefüllt werden
Box(i + 1, 205 - y, 3, y - 200, RGB($B0,$CF,$F4))
y = 200
EndIf
;Next block
Next y
;Next Frequenz
Next i
StopDrawing()
UseWindow(1)
StartDrawing(WindowOutput())
DrawImage(UseImage(1), 4, 10)
StopDrawing()
;Positionen berechnen
SetGadgetState(2, Int((FSOUND_Stream_GetPosition(Stream_ID) / FSOUND_Stream_GetLength(Stream_ID)) * 5000))
If FSOUND_Stream_GetPosition(Stream_ID) = FSOUND_Stream_GetLength(Stream_ID)
FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream
Play = 0
FSOUND_DSP_Free(LowpassUnit_ID)
FSOUND_DSP_Free(FFTUnit_ID)
SetGadgetState(2, 1)
EndIf
Time = Int(Periodendauer - (GetTickCount_() - TimeStart))
If Time > 0 And Time < Periodendauer
Delay(Time)
EndIf
Else
;Wenn keine Musik aktiv ist
UseImage(1)
StartDrawing(ImageOutput())
Box(0, 0, 512, 200)
For i = 0 To 511 Step 4
Box(i + 1, 0, 3, 201, RGB($B0,$CF,$F4))
Next i
StopDrawing()
UseWindow(1)
StartDrawing(WindowOutput())
DrawImage(UseImage(1), 4, 10)
StopDrawing()
Delay(50)
EndIf
Until Quit = #True
EndProcedure
Procedure.l Lowpass(ptOriginalbuffer.l, ptNewbuffer.l, Length.l, Param.l)
Protected ptNewbuffer
Protected ptOriginalbuffer
Protected Length
Protected Param
Protected Counter.l
Protected Left.l
Protected Right.l
Dim Daten.l(Length)
CopyMemory(ptNewbuffer, @Daten(), 4 * Length)
For Counter = 0 To Length - 1
Debug Daten(Counter)
Next Counter
ProcedureReturn @Daten()
EndProcedure
Procedure Stop()
Shared Stream_ID, Volume, Play, FFTUnit_ID, LowpassUnit_ID
;Fadeout
For i = Volume To 0 Step -1 ;a small fast fade-out to prevent a clipping-sound
FSOUND_SetVolume(1, i)
Delay(5)
Next
FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream
Play = #False
FSOUND_DSP_SetActive(FFTUnit_ID, #False)
FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
FSOUND_DSP_Free(LowpassUnit_ID)
SetGadgetState(2, 1)
EndProcedure
Procedure Unload()
Quit = #True
WaitThread(FFT_ID)
FSOUND_Stream_Stop(Stream_ID) ;stop playing the stream
FSOUND_DSP_SetActive(FFTUnit_ID, #False) ;set the FFT-DSP-Unit inactive
FSOUND_DSP_SetActive(LowpassUnit_ID, #False)
FSOUND_DSP_Free(LowpassUnit_ID)
FSOUND_Close() ;shut down FSOUND
EndProcedure
Procedure LOWORD(Value)
ProcedureReturn Value & $FFFF
EndProcedure
Procedure HIWORD(Value)
ProcedureReturn (Value >> 16) & $FFFF
EndProcedure
Procedure MAKELONG(low, high)
ProcedureReturn low | (high<<16)
EndProcedure
thing, the lowpass callback are in english...
The first TrackBarGadget are the volume and the 2. are the position
at the song. The 3. for some testing ... and later for the cutoff frequency