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
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <Bass.au3>
#include <BassConstants.au3>
Opt("GUIOnEventMode", 1)
[/autoit] [autoit][/autoit] [autoit]Global $iWidth = @DesktopWidth, $iHeight = @DesktopHeight
Global $aNoten[8 * 12][2]
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
Global $hStream = _BASS_StreamCreate(44100, 1, 0, $STREAMPROC_PUSH, 0)
_BASS_ChannelPlay($hStream, 0)
Global $tData = DllStructCreate("short[44100]")
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)
Global $hBitmapBk = _CreateBkBmp()
GUISetState()
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
While 1
Sleep(100)
WEnd
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
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)
$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)
EndIf
_GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)
_GDIPlus_FontDispose($hFont)
_GDIPlus_FontFamilyDispose($hFamily)
_GDIPlus_StringFormatDispose($hFormat)
EndFunc ;==>_Draw
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
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
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
Func _Exit()
_BASS_Stop()
_BASS_Free()
_GDIPlus_PenDispose($hPen)
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_GraphicsDispose($hGraphics)
_GDIPlus_Shutdown()
Exit
EndFunc ;==>_Exit
Achtung! lieber vorher die Lautsprecher etwas leiser machen