FFT Bass.dll kleiner Lehrgang

  • Hi

    Den meisten ist nicht ganz klar, wie die einzelnen Frequenzbänder im Zusammenhang mit der Tonhöhe stehen.
    Diese Bänder decken alle einen gleich großen Frequenzbereich ab, allerdings entspricht eine Oktave einer Frequenzverdoppelung weshalb die "Länge" einer Oktave immer größer wird.

    Da wir aber linear denken, ist es besser die Oktaven immer gleich groß darzustellen.
    Dazu muß man jedoch die Frequenzbänder logarithmisch anordnen.

    Ich habe versucht das mit diesem Script etwas zu verdeutlichen:

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <Bass.au3>
    #include <BassConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    Global $iWidth = @DesktopWidth, $iHeight = @DesktopHeight
    Global $aNoten[8 * 12][2]

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $pi = ATan(1) * 4

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_STARTUP(@ScriptDir & '\BASS.dll')
    _BASS_Init(0, -1, 44100, 0, '')
    If @error Then
    MsgBox(0, 'Error', 'Sound konnte nicht Initialisiert werden!')
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Global $hStream = _BASS_StreamCreate(44100, 1, 0, $STREAMPROC_PUSH, 0)
    _BASS_ChannelPlay($hStream, 0)
    Global $tData = DllStructCreate("short[44100]")

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGui = GUICreate("FFT", $iWidth, $iHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    GUISetBkColor(0x000000)
    If @OSVersion = "WIN_XP" Then WinSetTrans($hGui, "", 0xFF)
    _GDIPlus_Startup()
    Global $hBrush = _GDIPlus_BrushCreateSolid(0xFF555555)
    Global $hBrushColor = _GDIPlus_BrushCreateSolid(0xFFFFBB00)
    Global $hPen = _GDIPlus_PenCreate(0xFF555555)
    Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui)
    _GDIPlus_GraphicsClear($hGraphics, 0xFF000000)
    Global $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphics)
    Global $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    Global $hBitmapBk = _CreateBkBmp()
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    Global $fftstruct = DllStructCreate('float[256]')

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 88
    _PlayFreq($hStream, $aNoten[$i][1], 150)
    _Draw($i)
    Sleep(160)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(100)
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _PlayFreq($hStream, $nFreq = 440, $iMS = 1000)
    Local $iSec = Floor($iMS / 1000)
    $iMS = Mod($iMS, 1000) / 1000
    For $i = 1 To 44100
    DllStructSetData($tData, 1, 32767 * Sin($i * $pi * 2 / (44100 / $nFreq)), $i)
    Next
    For $i = 0 To $iSec
    Switch $i
    Case $iSec
    _BASS_StreamPutData($hStream, DllStructGetPtr($tData), Round(44100 * 2 * $iMS))
    Case Else
    _BASS_StreamPutData($hStream, DllStructGetPtr($tData), (44100 * 2))
    EndSwitch
    Next
    EndFunc ;==>_PlayFreq

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Draw($iIndex = -1)
    Local $iDist = ($iWidth - 20) / 128, $iX, $iW
    _GDIPlus_GraphicsDrawImage($hContext, $hBitmapBk, 0, 0)
    _BASS_ChannelGetData($hStream, DllStructGetPtr($fftstruct), $BASS_DATA_FFT256)
    For $i = 1 To 128
    $nLevel = DllStructGetData($fftstruct, 1, $i) * 100
    If $nLevel > 20 Then
    _GDIPlus_GraphicsFillRect($hContext, $i * $iDist, 150 - $nLevel, $iDist, $nLevel, $hBrush)
    $iX = ((Log($i) / Log(10) * 20) * ($iWidth - 20)) / (Log(128) / Log(10) * 20)
    $iW = (((Log($i + 1) / Log(10) * 20) * ($iWidth - 20)) / (Log(128) / Log(10) * 20)) - $iX
    _GDIPlus_GraphicsFillRect($hContext, $iX + 10, 450 - $nLevel, $iW, $nLevel, $hBrush)
    EndIf
    Next
    Local $hFormat = _GDIPlus_StringFormatCreate(0x0004)
    Local $hFamily = _GDIPlus_FontFamilyCreate("Arial")
    Local $hFont = _GDIPlus_FontCreate($hFamily, 8, 1)
    Local $tLayout, $aInfo
    If $iIndex >= 0 Then
    $iX = ($aNoten[$iIndex][1] * ($iWidth - 20)) / 22050
    $iY = Mod($iIndex, 12)
    $tLayout = _GDIPlus_RectFCreate($iX + 10, $iY * 10 + 150, 0, 0)
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $aNoten[$iIndex][0], $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, $aNoten[$iIndex][0], $hFont, $aInfo[0], $hFormat, $hBrushColor)

    [/autoit] [autoit][/autoit] [autoit]

    $iX = ($iIndex * ($iWidth - 20)) / (89)
    $iY = Mod($iIndex, 12)
    $tLayout = _GDIPlus_RectFCreate($iX + 10, $iY * 10 + 450, 0, 0)
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $aNoten[$iIndex][0], $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, $aNoten[$iIndex][0], $hFont, $aInfo[0], $hFormat, $hBrushColor)

    [/autoit] [autoit][/autoit] [autoit]

    EndIf
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_StringFormatDispose($hFormat)
    EndFunc ;==>_Draw

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateBkBmp()
    Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphics)
    Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsClear($hContext, 0xFF000000)
    Local $hFormat = _GDIPlus_StringFormatCreate(0x0004)
    Local $hFamily = _GDIPlus_FontFamilyCreate("Arial")
    Local $hFont = _GDIPlus_FontCreate($hFamily, 8, 1)
    Local $tLayout, $aInfo

    [/autoit] [autoit][/autoit] [autoit]

    Local $nFreq = 61.7354126570155*2
    Local $aNotenName[12] = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "H"]
    Local $iCnt = 0
    For $i = 0 To 7
    For $j In $aNotenName
    $nFreq = $nFreq * 2 ^ (1 / 12)
    $aNoten[$iCnt][0] = $j
    $aNoten[$iCnt][1] = Round($nFreq, 2)
    $iCnt += 1
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Local $iDist = ($iWidth - 20) / 128, $iX, $iW
    For $i = 1 To 128
    If Mod($i, 12) = 1 Then
    $tLayout = _GDIPlus_RectFCreate($i * $iDist, 30, 0, 0)
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, Round($i * (44100 / 256), 1) & "Hz", $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, Round($i * (44100 / 256), 1) & "Hz", $hFont, $aInfo[0], $hFormat, $hBrush)
    EndIf
    _GDIPlus_GraphicsDrawRect($hContext, $i * $iDist, 50, $iDist, 100, $hPen)
    $iX = ((Log($i) / Log(10) * 20) * ($iWidth - 20)) / (Log(128) / Log(10) * 20)
    $iW = (((Log($i + 1) / Log(10) * 20) * ($iWidth - 20)) / (Log(128) / Log(10) * 20)) - $iX
    _GDIPlus_GraphicsDrawRect($hContext, $iX + 10, 350, $iW, 100, $hPen)
    Next
    For $i = 0 To 88
    $iX = ($aNoten[$i][1] * ($iWidth - 20)) / 22050
    $iY = Mod($i, 12)
    $tLayout = _GDIPlus_RectFCreate($iX + 10, $iY * 10 + 150, 0, 0)
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $aNoten[$i][0], $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, $aNoten[$i][0], $hFont, $aInfo[0], $hFormat, $hBrush)
    $iX = ($i * ($iWidth - 20)) / (89)
    $iY = Mod($i, 12)
    $tLayout = _GDIPlus_RectFCreate($iX + 10, $iY * 10 + 450, 0, 0)
    Switch $iY
    Case 0
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $aNoten[$i][0] & " = " & Round($aNoten[$i][1], 1) & "Hz", $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, $aNoten[$i][0] & " = " & Round($aNoten[$i][1], 1) & "Hz", $hFont, $aInfo[0], $hFormat, $hBrush)
    Case Else
    $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $aNoten[$i][0], $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hContext, $aNoten[$i][0], $hFont, $aInfo[0], $hFormat, $hBrush)
    EndSwitch
    Next
    _GDIPlus_GraphicsDispose($hContext)
    Return $hBitmap
    EndFunc ;==>_CreateBkBmp

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    _BASS_Stop()
    _BASS_Free()
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]

    Achtung! lieber vorher die Lautsprecher etwas leiser machen :D

  • Sehr interessant, leider hängt das Ganze von den Boxen ab! Meine "Schlepptop" Boxen taugen nichts :thumbdown: und ich kann gerade so bis 16k Hz hören!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯