Moin,
Vor einiger Zeit habe ich eine lustige Seite zum Tönebasteln entdeckt: ByteBeat.
Diese Angelegenheit fand ich sehr schön, also habe ich ein kleines Skript gebastelt welches ähnliche Spielereien ermöglicht.
Es wird keine Javascriptsyntax unterstützt (wer hätte das gedacht), dafür aber alles was der AutoIt Interpreter zulässt
Würde mich freuen wenn einige Leute Spaß daran finden, und ggf. sogar ein kleines Lied komponieren können
AutoIt
; +++++ Wissenswertes +++++
; Funktionen:
; $x - Position innerhalb der WAV. Die funktion die man ins Feld eingibt f($x) berechnet die Amplitute (signed 16Bit Wert) zum Zeitpunkt des Samples
; | Bei z.B. 8000 kHz werden 8000 Werte pro Sekunde berechnet und der Lautsprecher entsprechend bewegt. Man kann ihm also 8000 Mal pro Sekunde
; | eine neue Position zwischen -(2^15-1) und 2^15-1 zuweisen. Töne ergeben sich durch wiederholtes neupositionieren. Frequenzen haben NICHTS mit der
; | Ampliture zu tun die die Funktion berechnet, sondern mit der Periodizität der Funktion.
; $z - Läuft von 0 (Beginn des Sounds) bis 1 (Ende des Sounds)
; $p - Kreiszahl PI (braucht man villeicht für irgendwas)
; Allgemein können alle buildIn AutoIt Funktionen benutzt werden, da Execute benutzt wird bitte ich darum keinen Unfug zu treiben. Man kann sich auch
; eigene Funktionen schreiben die benutzt werden können. z.B. _Sin($x, $Ton) gibt bei $Ton = 58 den Kammerton A ohne Abhängigkeit der Samplingrate.
; Capsize
; - Verhindert Knacken der Lautsprecher beim ein- und Ausschalten des Tons
; Gain (2^x)
; - Töne werden als Signed 16Bit Werte gespeichert. Ein Sinus z.B. geht nur von -1 bis 1.
; | Mit einem Gain von 15 geht er von 2^15-1 bis 2^15
; - Ist oft nutzlos, wenn Töne via Überlauf erzeugt werden, z.B.
; Farbe der Ladebalken:
; Hellblau - Musik wird abgespielt
; Lila - Musik wird generiert
; Orange - Grafischer Krimskrams wird erzeugt
; AMP = Amplitude = Lautstärke
; - Die Anzeige gibt einen Überblick über die Lautstärke des Sounds
; - Da nur ein Bruchteil der Samples analysiert wird ist die Anzeige nicht besonders genau.
; - Angezeigt werden 2 Kurven. Mittelwert + Stdandardabweichung und Mittelwert - Standardabweichung
; - Die Anzeige ist Logarithmisch
; 06.Mai.15
; SoundEdit von Mars@AutoIt.de
#include <GDIPlus.au3>
Opt('GUIOnEventMode', 1)
Global $bExit = False
Global $iW = 512, $iH = 330
Global $iGFXh = 155
Global $iLadebalkenH = 16
Global $iPlayTimer = 0, $iPlayTimerMax = 0
Global $hWav
Global $iSamplingRate
Global $iBkColGFX = 0xFFE0E0E0
Global $iBkColGUI = 0xFFEEEEEE
Global $hGUI = GUICreate('SoundEdit', $iW, $iH + $iGFXh + $iLadebalkenH)
GUISetBkColor(BitAND($iBkColGUI, 0xFFFFFF), $hGUI)
GUICtrlCreateEdit('Länge ( ms )', 10, 10, 110, 20, 2049)
GUICtrlCreateEdit('Samplingrate ( Hz )', 10, 50, 110, 20, 2049)
GUICtrlCreateEdit('Capsize ( % )', 10, 90, 110, 20, 2049)
GUICtrlCreateEdit('Gain ( 2^x )', 10, 130, 110, 20, 2049)
Global $hSli_Len = GUICtrlCreateSlider(120, 10, $iW - 210, 30), $iRead_Len
Global $hSli_Sam = GUICtrlCreateSlider(120, 50, $iW -210, 30), $iRead_Sam
Global $hSli_Cap = GUICtrlCreateSlider(120, 90, $iW - 210, 30), $iRead_Cap
Global $hSli_Gai = GUICtrlCreateSlider(120, 130, $iW - 210, 30), $iRead_Gai
Global $hLab_Len = GUICtrlCreateEdit('0', $iW - 90, 10, 80, 20, 2049)
Global $hLab_Sam = GUICtrlCreateEdit('0', $iW - 90, 50, 80, 20, 2049)
Global $hLab_Cap = GUICtrlCreateEdit('0', $iW - 90, 90, 80, 20, 2049)
Global $hLab_Gai = GUICtrlCreateEdit('0', $iW - 90, 130, 80, 20, 2049)
Global $hLab_Fun = GUICtrlCreateEdit('Mod(BitAnd(42,($x/2^10)),11)*$x', 10, 170, $iW - 20, 52, 1)
GUICtrlSetFont(-1, 9, 400, 0, 'Arial', 5)
Global $hLab_Snd = GUICtrlCreateEdit('', 10, 230, $iW - 20, 52, 2049)
GUICtrlSetFont(-1, 9, 400, 0, 'Arial', 5)
Global $hBtn_SS = GUICtrlCreateButton('Start',10, 290, 100, 30)
GUICtrlSetOnEvent(-1, '_EVENT_StartStop')
GUICtrlSetLimit($hSli_Len, 195, 0)
GUICtrlSetData($hSli_Len, 50)
GUICtrlSetLimit($hSli_Sam, 95, 0)
GUICtrlSetData($hSli_Sam, 35)
GUICtrlSetLimit($hSli_Cap, 50, 0)
GUICtrlSetData($hSli_Cap, 5)
GUICtrlSetLimit($hSli_Gai, 15, 0)
GUICtrlSetData($hSli_Gai, 8)
_GDIPlus_Startup()
Global $hGFX = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Global $hBMP = _GDIPlus_BitmapCreateFromGraphics($iW, $iGFXh + $iLadebalkenH, $hGFX)
Global $hBUF = _GDIPlus_ImageGetGraphicsContext($hBMP)
Global $hBRU_BkColGFX = _GDIPlus_BrushCreateSolid($iBkColGFX)
Global $hBRU_BkColGUI = _GDIPlus_BrushCreateSolid($iBkColGUI)
Global $hBRU_VAR = _GDIPlus_BrushCreateSolid(0xFF20FF20)
Global $hBRU_WHITE = _GDIPlus_BrushCreateSolid(0x40FFFFFF)
Global $hPEN_VAR = _GDIPlus_PenCreate(0xFF000000, 1)
Global $hPEN_BLACK = _GDIPlus_PenCreate(0x80FFFFFF, 1)
Global $hBRU_LINVAR = _GDIPlus_LineBrushCreate(0, $iGFXh, 0, $iGFXh+$iLadebalkenH, 0xFF000000, 0xFFE0E0E0)
_GDIPlus_GraphicsClear($hBUF, $iBkColGFX)
_GFX_Neuzeichnen()
GUIRegisterMsg(0xF, 'WM_PAINT')
OnAutoItExitRegister('_Freigeben')
GUISetState(@SW_SHOW, $hGUI)
GUISetOnEvent(-3, '_Exit', $hGUI)
While Sleep(10) And Not $bExit
_GUI_Slider($hSli_Gai, $hLab_Gai, CalcCap, $iRead_Gai)
_GUI_Slider($hSli_Len, $hLab_Len, CalcLen, $iRead_Len)
_GUI_Slider($hSli_Sam, $hLab_Sam, CalcSam, $iRead_Sam)
_GUI_Slider($hSli_Cap, $hLab_Cap, CalcCap, $iRead_Cap)
If Not $iPlayTimer = 0 Then
If TimerDiff($iPlayTimer) <= $iPlayTimerMax Then
_GFX_Ladebalken(TimerDiff($iPlayTimer)/$iPlayTimerMax, 0xFF41AFEB)
Else
_Play_Stop()
EndIf
EndIf
WEnd
Func _Play_Stop()
_WAV_Stop()
GUICtrlSetData($hBtn_SS, 'Start')
$iPlayTimerMax = 0
$iPlayTimer = 0
_GFX_Ladebalken(0)
EndFunc
Func _EVENT_StartStop()
$iPlayTimerMax = CalcLen($iRead_Len)
If Not $iPlayTimer = 0 Then
_Play_Stop()
Else
GUICtrlSetData($hBtn_SS, 'Stop')
RenderSnd()
_WAV_Play($hWav)
$iPlayTimer = TimerInit()
EndIf
EndFunc
Func RenderSnd()
Local $iLen = Int(CalcLen($iRead_Len))
Local $sFunc = GUICtrlRead($hLab_Fun)
Local $iCapSize = Int(CalcCap($iRead_Cap))
Local $iGain = 2^Int(CalcCap($iRead_Gai))
$iGain -= ($iGain = 2^15)*1
; Sollte (noch) global sein
$iSamplingRate = Int(CalcSam($iRead_Sam))
$hWav = _WAV_New($iLen)
Local $p = 3.1415926536
Local $l = $iLen/1000
Local $z
For $x = 1 To $hWav[2] Step 1
$z = $x/$l/$iSamplingRate
$hWav[0].WAVDATA(($x)) = Execute($sFunc) * $iGain
If IsInt($x/2000) Then _GFX_Ladebalken($x/$hWav[2], 0xFFB03EEB)
Next
_Wav_SmoothEdge($hWav, $iCapSize)
_GFX_Amp($hWav)
_GFX_FFT($hWav)
_GFX_Ladebalken(0)
WM_PAINT()
EndFunc
Func CalcCap($i)
Return $i
EndFunc
Func CalcLen($i)
Return Int(($i + 5)^1.75/10)*10
EndFunc
Func CalcSam($i)
Return Int($i * 500) + 500
EndFunc
Func _GFX_FFT(ByRef $hWav, $bEmpty = False) ; Boah, ich hab keinen Nerv hierfür
Local $W = $iW - 20 ; Wäre in AutoIt wahrscheinlich auch zu langsam. ASM Time...
Local $H = $iGFXh/2 - 20
_GDIPlus_GraphicsFillRect($hBUF, 0, $H+20, $W + 20, $H + 20, $hBRU_BkColGFX)
_GDIPlus_GraphicsDrawString($hBUF, 'FFT', 15, $H + 15 + 20)
_GDIPlus_PenSetColor($hPEN_VAR, 0xFF000000)
_GDIPlus_GraphicsDrawRect($hBUF, 8, $H + 28, $W + 4, $H + 4, $hPEN_VAR)
If $bEmpty Then Return
EndFunc
Func _GFX_Amp(ByRef $hWav, $bEmpty = False) ; Lautstärke -> Log(Abs Abweichung von der Ruhelage)
Local $W = $iW - 20, $H = $iGFXh/2 - 20
_GDIPlus_GraphicsFillRect($hBUF, 0, 0, $W + 20, $H + 20, $hBRU_BkColGFX)
_GDIPlus_GraphicsDrawString($hBUF, 'Amp', 15, 15)
_GDIPlus_PenSetColor($hPEN_VAR, 0xFF000000)
_GDIPlus_GraphicsDrawRect($hBUF, 8, 8, $W + 4, $H + 4, $hPEN_VAR)
If $bEmpty Then Return
; An jedem Punkt wird der Mittelwert der näheren Umgebung, sowie die Standardabweichung berechnet.
; Anschließend wird eine Kurve für m+s und eine fr m-s gezeichnet.
Local $iSteps = (Int(Log($hWav[2]) * 6) + 10), $iWidth = Int(($hWav[2]/$iSteps)^0.6), $iPos, $iMid, $iStdAbw, $aPoints1[$iSteps+1][2]=[[$iSteps]], $aPoints2[$iSteps+1][2]=[[$iSteps]]
$iWidth += IsInt($iWidth/2) ? 0 : 1 ; Muss gerade sein, da |x|x|x|m+-s|x|x|x
;~ ConsoleWrite('AMP: Steps: ' & $iSteps & ' iWidth: ' & $iWidth & ' Samples: ' & $hWav[2] & ' Cover: ' & $iSteps*$iWidth/$hWav[2]*100 & ' % ' & @CRLF)
For $i = 0 To $iSteps - 1 Step 1 ; Deckt nur einen Bruchteil der Daten ab und versucht ein möglichst gutes Bild zu geben.
_GFX_Ladebalken($i/($iSteps-1), 0xFFEB9A3E)
$iPos = Int(($i + 1/$iSteps) / $iSteps * $hWav[2])
$iMid = 0
$iStdAbw = 0
For $x = $iPos - $iWidth/2 To $iPos + $iWidth/2 Step 1
$iMid += Abs($hWav[0].WAVDATA(($x)))
Next
$iMid /= $iWidth
For $x = $iPos - $iWidth/2 To $iPos + $iWidth/2 Step 1
$iStdAbw += (Abs($hWav[0].WAVDATA(($x))) - $iMid)^2
Next
$iStdAbw = ($iStdAbw/$iWidth)^0.5
$aPoints1[$i+1][0] = 10 + $i/($iSteps-1) * $W
$aPoints1[$i+1][1] = 10 + $H - ((1+$iMid-$iStdAbw) <= 0 ? 0 : (Log(1+$iMid-$iStdAbw)/Log(32768))) * $H
$aPoints2[$i+1][0] = 10 + $i/($iSteps-1) * $W
$aPoints2[$i+1][1] = 10 + $H - ((1+$iMid+$iStdAbw) <= 0 ? 0 : (Log(1+$iMid+$iStdAbw)/Log(32768))) * $H
Next
_GDIPlus_GraphicsSetSmoothingMode($hBUF, 2)
_GDIPlus_PenSetColor($hPEN_VAR, 0xFFEE8020)
_GDIPlus_GraphicsDrawCurve2($hBUF, $aPoints1, 0, $hPEN_VAR)
_GDIPlus_PenSetColor($hPEN_VAR, 0xFFEE2080)
_GDIPlus_GraphicsDrawCurve2($hBUF, $aPoints2, 0, $hPEN_VAR)
_GDIPlus_GraphicsSetSmoothingMode($hBUF, 0)
_GFX_Ladebalken(0)
EndFunc
Func _GUI_Slider($hSli, $hLab, $xCalcFunc, ByRef $iRead)
If GUICtrlRead($hSli) <> $iRead Then
$iRead = GUICtrlRead($hSli)
GUICtrlSetData($hLab, $xCalcFunc($iRead))
EndIf
EndFunc
Func _GFX_Neuzeichnen()
Local $xTmp
_GFX_Ladebalken(0)
_GFX_Amp($xTmp, True)
_GFX_FFT($xTmp, True)
EndFunc
Func _WAV_Play(ByRef $hWav)
DllCall('winmm.dll', 'int', 'PlaySoundA', 'ptr', $hWav[1], 'int', 0, 'int', 5)
EndFunc
Func _WAV_Stop()
DllCall('winmm.dll', 'int', 'PlaySoundA', 'ptr', 0, 'int', 0, 'int', 0)
EndFunc
Func _WAV_New($iLen = 1000) ; Länge in Millisekunden
Local $hWav[5] = [DllStructCreate('char RIFF [4];uint FileSize;char WAVE [4];char fmt [4];uint fmt_len;word Format;word Channels;uint Samplerate;uint Bytes;word Block;word BitPerSample;char DATA [4];uint Len;short WAVDATA[' & Round($iLen / 1000, 3) * $iSamplingRate & ']')]
With $hWav[0]
.RIFF = 'RIFF'
.FileSize = 2 * Round($iLen / 1000, 3) * $iSamplingRate + 44 - 8
.WAVE = 'WAVE'
.fmt = 'fmt '
.fmt_len = 16
.Format = 1 ; PCM
.Channels = 1
.Samplerate = $iSamplingRate
.Bytes = $iSamplingRate * 2
.Block = 2
.BitPerSample = 16
.DATA = 'data'
.Len = 2 * Round($iLen / 1000, 3) * $iSamplingRate
EndWith
$hWav[1] = DllStructGetPtr($hWav[0])
$hWav[2] = Round($iLen / 1000, 3) * $iSamplingRate
$hWav[3] = DllStructGetPtr($hWav[0], 'WAVDATA')
$hWav[4] = 0
Return $hWav ; 0 -> DllStruct, 1 -> PTR, 2 -> Anzahl Samples, 3 -> PTR Wavdata, 4 -> RenderPos Wavdata
EndFunc
Func _Sin($x, $nNote) ; _Sin($x, 58) = Kammerton A
Return Sin($x/$iSamplingRate*2*3.14159*Freq($nNote))
EndFunc
Func Freq($nNote)
Return 55*2^(($nNote-22)/12)
EndFunc
Func _Wav_SmoothEdge(ByRef $hWav, $iCapSize)
For $x = 1 To $iCapSize*$iSamplingRate/100 Step 1
If IsInt($x/1000) Then _GFX_Ladebalken($x/($iCapSize*$iSamplingRate/100), 0xFFB03EEB)
$hWav[0].WAVDATA(($x)) = $hWav[0].WAVDATA(($x)) * ExpAnstieg($x - 1, $iCapSize*$iSamplingRate/100, 0.00005)
$hWav[0].WAVDATA(($hWav[2] - $x + 1)) = $hWav[0].WAVDATA(($hWav[2] - $x + 1)) * ExpAnstieg($x - 1, $iCapSize*$iSamplingRate/100, 0.00005)
Next
EndFunc
Func ExpAnstieg($iPos, $iW, $nDelta)
Local $c = Log(1 / $nDelta - 1)
Return 1 / (1 + (2.718282) ^ (-$iPos / (($iW - 1) / 2 / $c) + $c))
EndFunc
Func _GFX_Ladebalken($iProzent, $iCol = 0)
If $iProzent > 0 Then
_GDIPlus_LineBrushSetColors($hBRU_LINVAR, '0xFF' & Hex(Int(BitAND(BitShift($iCol,16), 0xFF) + 16),2) & Hex(Int(BitAND(BitShift($iCol,8), 0xFF) + 16),2) & Hex(Int(BitAND($iCol, 0xFF) + 16),2), '0xFF' & Hex(Int(BitAND(BitShift($iCol,16), 0xFF) - 16),2) & Hex(Int(BitAND(BitShift($iCol,8), 0xFF) - 16),2) & Hex(Int(BitAND($iCol, 0xFF) - 16),2))
_GDIPlus_GraphicsFillRect($hBUF, 0, $iGFXh, $iW, $iLadebalkenH, $hBRU_BkColGUI)
_GDIPlus_GraphicsFillRect($hBUF, 0, $iGFXh , $iW * $iProzent, $iLadebalkenH, $hBRU_LINVAR)
_GDIPlus_GraphicsDrawRect($hBUF, 0, $iGFXh, $iW * $iProzent, $iLadebalkenH - 1, $hPEN_BLACK)
_GDIPlus_GraphicsFillRect($hBUF, 0, $iGFXh, $iW * $iProzent, $iLadebalkenH/2, $hBRU_WHITE)
_GDIPlus_GraphicsDrawImageRectRect($hGFX, $hBMP, 0, $iGFXh, $iW, $iLadebalkenH, 0, $iH + $iGFXh, $iW, $iLadebalkenH)
Else
_GDIPlus_GraphicsFillRect($hBUF, 0, $iGFXh, $iW, $iLadebalkenH, $hBRU_BkColGUI)
_GDIPlus_GraphicsDrawImageRectRect($hGFX, $hBMP, 0, $iGFXh, $iW, $iLadebalkenH, 0, $iH + $iGFXh, $iW, $iLadebalkenH)
EndIf
EndFunc
Func _Freigeben()
_GDIPlus_BrushDispose($hBRU_BkColGUI)
_GDIPlus_PenDispose($hPEN_BLACK)
_GDIPlus_BrushDispose($hBRU_LINVAR)
_GDIPlus_PenDispose($hPEN_VAR)
_GDIPlus_BrushDispose($hBRU_WHITE)
_GDIPlus_BrushDispose($hBRU_BkColGFX)
_GDIPlus_BrushDispose($hBRU_VAR)
_GDIPlus_GraphicsDispose($hBUF)
_GDIPlus_BitmapDispose($hBMP)
_GDIPlus_GraphicsDispose($hGFX)
_GDIPlus_Shutdown()
EndFunc
Func WM_PAINT()
_GDIPlus_GraphicsDrawImage($hGFX, $hBMP, 0, $iH)
EndFunc
Func _Exit()
$bExit = True
EndFunc
Alles anzeigen
Hab den Editor jetzt intern etwas aufgeräumt und den Gain als neue Einstellung hinzugefügt. (In Bezug auf die Version die ich mal in der SB gepostet habe)
lg
M