Тема: AHK: Запись mp3 с подрезкой тишины
Понадобилось для одного проекта записывать звук с подрезкой тишины с начала и с конца.
Написал гуи для ffmpeg.
https://www.videohelp.com/software/ffmpeg
ffmpeg.exe нужно будет переименовать в ffmpeg_script.exe.
Скрипт создает temp.wav, который потом стирает.
Результат сохраняется в %A_Now%.mp3.
NoiseGate := -70
#SingleInstance force
OnExit, MP3RecordGuiClose
LOAD_DLL_Mf_Mfplat()
MFStartup(version := 2, MFSTARTUP_FULL := 0)
MFCreateAttributes(pMFAttributes, 1)
IMFAttributes_SetGUID(pMFAttributes, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE"), MF_GUID(GUID1, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID"))
MFEnumDeviceSources(pMFAttributes, pppSourceActivate, pcSourceActivate)
Loop % pcSourceActivate
{
IMFActivate := NumGet(pppSourceActivate + (A_Index - 1)*A_PtrSize)
name := IMFActivate_GetAllocatedString(IMFActivate, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME"))
if (A_Index = 1)
RecordingDevices .= name "||"
else
RecordingDevices .= name "|"
ObjRelease(IMFActivate)
}
DllCall("ole32\CoTaskMemFree", "ptr", pppSourceActivate)
ObjRelease(pMFAttributes)
MFShutdown()
UNLOAD_DLL_Mf_Mfplat()
Gui, MP3Record: +AlwaysOnTop -DpiScale
Gui, MP3Record: Add, Text, x12, RecordingDevice:
Gui, MP3Record: Add, DDL, vRecordingDevice x12 w250, % RecordingDevices
Gui, MP3Record: Add, Button, x12 y62 w120 h20 vRecord gMP3Record, Start Recording
Gui, MP3Record: Add, Text, x54 y86 w80 vMP3Time
Gui, MP3Record: Show
return
MP3Record:
GuiControlGet, RecordingDevice
if (CurrentState != "Record")
{
loop
{
Process, Exist, ffmpeg_script.exe
if ErrorLevel
{
Process, Close, ffmpeg_script.exe
Process, WaitClose, ffmpeg_script.exe
}
else
break
}
Run, ffmpeg_script.exe -f dshow -i audio="%RecordingDevice%" -acodec copy -y temp.wav, , hide, pid
loop
{
if DllCall("AttachConsole", "uint", pid)
break
sleep 10
}
hConIn := DllCall("CreateFile", "str", "CONIN$", "uint", 0xC0000000, "uint", 0x3, "uint", 0, "uint", 0x3, "uint", 0, "uint", 0, "ptr")
if (hConIn = -1)
{
msgbox error CreateFile %A_LastError%
ExitApp
}
VarSetCapacity(ir, 24, 0) ; ir := new INPUT_RECORD
NumPut(1, ir, 0, "UShort") ; ir.EventType := KEY_EVENT
NumPut(1, ir, 8, "UShort") ; ir.KeyEvent.wRepeatCount := 1
min := sec := 0
CurrentState := "Record"
GuiControl,, Record, Stop Recording
SetTimer, Count, 1000
}
else
{
CurrentState := ""
GuiControl,, Record, Start Recording
SetTimer, Count, Off
NumPut(Asc("q"), ir, 14, "UShort")
NumPut(true, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := true
if !DllCall("WriteConsoleInput", "ptr", hConIn, "ptr", &ir, "uint", 1, "uint*", 0)
{
msgbox error WriteConsoleInput one %A_LastError%
ExitApp
}
NumPut(false, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := false
if !DllCall("WriteConsoleInput", "ptr", hConIn, "ptr", &ir, "uint", 1, "uint*", 0)
{
msgbox error WriteConsoleInput two %A_LastError%
ExitApp
}
DllCall("CloseHandle", "ptr", hConIn)
hConIn := ""
DllCall("FreeConsole")
Process, WaitClose, ffmpeg_script.exe
MsgBox, 274340,, Save recorded mp3?
IfMsgBox Yes
{
Run, ffmpeg_script.exe -i temp.wav -ab 320k -acodec libmp3lame -y -af "silenceremove=start_periods=1:start_duration=0:start_threshold=%NoiseGate%dB`,areverse`,silenceremove=start_periods=1:start_duration=0:start_threshold=%NoiseGate%dB`,areverse" "%A_Now%.mp3", , hide
Process, WaitClose, ffmpeg_script.exe
}
GuiControl,, MP3Time
FileDelete, temp.wav
}
return
Count:
sec++
if (sec = 60)
{
min++
sec := 0
}
GuiControl, MP3Record:, MP3Time, % "0:" Format("{1:02}", min) ":" Format("{1:02}", sec)
return
MP3RecordGuiClose:
loop
{
Process, Exist, ffmpeg_script.exe
if ErrorLevel
{
Process, Close, ffmpeg_script.exe
Process, WaitClose, ffmpeg_script.exe
}
else
break
}
FileDelete, temp.wav
ExitApp
LOAD_DLL_Mf_Mfplat()
{
if !DllCall("GetModuleHandle","str","Mf")
DllCall("LoadLibrary","Str", "Mf.dll", "ptr")
if !DllCall("GetModuleHandle","str","Mfplat")
DllCall("LoadLibrary","Str", "Mfplat.dll", "ptr")
}
UNLOAD_DLL_Mf_Mfplat()
{
if hModule := DllCall("GetModuleHandle", "str", "Mf", "ptr")
DllCall("FreeLibrary", "ptr", hModule)
if hModule := DllCall("GetModuleHandle", "str", "Mfplat", "ptr")
DllCall("FreeLibrary", "ptr", hModule)
}
MFStartup(version, dwFlags)
{
hr := DllCall("Mfplat.dll\MFStartup", "uint", version, "uint", dwFlags)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
MFCreateAttributes(ByRef ppMFAttributes, cInitialSize)
{
hr := DllCall("Mfplat.dll\MFCreateAttributes", "ptr*", ppMFAttributes, "uint", cInitialSize)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
IMFAttributes_SetGUID(this, guidKey, guidValue)
{
hr := DllCall(NumGet(NumGet(this+0)+24*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr", guidValue)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
MFEnumDeviceSources(pAttributes, ByRef pppSourceActivate, ByRef pcSourceActivate)
{
hr := DllCall("Mf.dll\MFEnumDeviceSources", "ptr", pAttributes, "ptr*", pppSourceActivate, "uint*", pcSourceActivate)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
IMFActivate_GetAllocatedString(this, guidKey)
{
hr := DllCall(NumGet(NumGet(this+0)+13*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr*", ppwszValue, "uint*", pcchLength)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
AllocatedString := StrGet(ppwszValue, pcchLength, "UTF-16")
DllCall("ole32\CoTaskMemFree", "ptr", ppwszValue)
return AllocatedString
}
MF_GUID(ByRef GUID, name)
{
static init:=1, _:={}
if init
{
init:=0
_.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE := [0xc60ac5fe, 0x252a, 0x478f, 0xa0, 0xef, 0xbc, 0x8f, 0xa5, 0xf7, 0xca, 0xd3]
_.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID := [0x14dd9a1c, 0x7cff, 0x41be, 0xb1, 0xb9, 0xba, 0x1a, 0xc6, 0xec, 0xb5, 0x71]
_.MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME := [0x60d0e559, 0x52f8, 0x4fa2, 0xbb, 0xce, 0xac, 0xdb, 0x34, 0xa8, 0xec, 0x1]
}
if _.haskey(name)
{
p := _[name]
VarSetCapacity(GUID,16)
,NumPut(p.1+(p.2<<32)+(p.3<<48),GUID,0,"int64")
,NumPut(p.4+(p.5<<8)+(p.6<<16)+(p.7<<24)+(p.8<<32)+(p.9<<40)+(p.10<<48)+(p.11<<56),GUID,8,"int64")
return &GUID
}
else return name
}
_Error(val)
{
msgbox % val
ExitApp
}
MFShutdown()
{
hr := DllCall("Mfplat.dll\MFShutdown")
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
Пример записи звука с внешнего источника с автоостопом при возникновении тишины меньшей чем -70дб, длящейся более 2 секунд.
SilenceDuration := 2000
NoiseGate := -70
#SingleInstance force
OnExit, MP3RecordGuiClose
LOAD_DLL_Mf_Mfplat()
MFStartup(version := 2, MFSTARTUP_FULL := 0)
MFCreateAttributes(pMFAttributes, 1)
IMFAttributes_SetGUID(pMFAttributes, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE"), MF_GUID(GUID1, "MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID"))
MFEnumDeviceSources(pMFAttributes, pppSourceActivate, pcSourceActivate)
Loop % pcSourceActivate
{
IMFActivate := NumGet(pppSourceActivate + (A_Index - 1)*A_PtrSize)
name := IMFActivate_GetAllocatedString(IMFActivate, MF_GUID(GUID, "MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME"))
if (A_Index = 1)
RecordingDevices .= name "||"
else
RecordingDevices .= name "|"
ObjRelease(IMFActivate)
}
DllCall("ole32\CoTaskMemFree", "ptr", pppSourceActivate)
ObjRelease(pMFAttributes)
MFShutdown()
UNLOAD_DLL_Mf_Mfplat()
Gui, MP3Record: +AlwaysOnTop -DpiScale
Gui, MP3Record: Add, Text, x12, RecordingDevice:
Gui, MP3Record: Add, DDL, vRecordingDevice x12 w250, % RecordingDevices
Gui, MP3Record: Add, Button, x12 y62 w120 h20 vRecord gMP3Record, Start Recording
Gui, MP3Record: Add, Text, x54 y86 w80 vMP3Time
Gui, MP3Record: Show
return
MP3Record:
GuiControlGet, RecordingDevice
loop
{
Process, Exist, ffmpeg_script.exe
if ErrorLevel
{
Process, Close, ffmpeg_script.exe
Process, WaitClose, ffmpeg_script.exe
}
else
break
}
Run, ffmpeg_script.exe -f dshow -i audio="%RecordingDevice%" -af silencedetect=noise=%NoiseGate%dB:d=0.1 -y temp.wav, , hide, pid
loop
{
if DllCall("AttachConsole", "uint", pid)
break
sleep 10
}
min := sec := 0
GuiControl, Disable, Record
SetTimer, Count, 1000
hConOut := DllCall("CreateFile", "str", "CONOUT$", "uint", 0xC0000000, "uint", 0x3, "ptr", 0, "uint", 0x3, "uint", 0, "ptr", 0, "ptr")
if (hConOut = -1)
{
msgbox error CreateFile CONOUT %A_LastError%
ExitApp
}
loop
{
VarSetCapacity(ConsoleScreenBufferInfo, 24, 0)
if !DllCall("GetConsoleScreenBufferInfo", "ptr", hConOut, "ptr", &ConsoleScreenBufferInfo)
{
msgbox GetConsoleScreenBufferInfo failed - error %A_LastError%
ExitApp
}
ConWinHeight := NumGet(ConsoleScreenBufferInfo, 6, "Short") + 1
if (ConWinHeight = 0)
ConWinHeight := NumGet(ConsoleScreenBufferInfo, 20, "Short") + 1
if !ConWinWidth
ConWinWidth := NumGet(ConsoleScreenBufferInfo, 18, "Short") + 1
VarSetCapacity(ConsoleText, ConWinWidth*ConWinHeight*2, 0)
if !DllCall("ReadConsoleOutputCharacter", "ptr", hConOut, "str", ConsoleText, "uint", ConWinWidth*ConWinHeight, "uint", 0, "ptr*", numCharsRead)
{
msgbox ReadConsoleOutputCharacter failed - error %A_LastError%.
ExitApp
}
if !RecordingStart and InStr(ConsoleText, "time=00:")
RecordingStart := 1
if RecordingStart and !RecordingStartSound and (!InStr(ConsoleText, "silence_start:") or InStr(ConsoleText, "silence_end:"))
RecordingStartSound := 1
if RecordingStartSound
{
StrReplace(ConsoleText, "silence_start:", "silence_start:", silence_startCount)
StrReplace(ConsoleText, "silence_end:", "silence_end:", silence_endCount)
if (silence_startCount > silence_endCount)
{
if !SilenceTime
SilenceTime := A_TickCount
else if ((A_TickCount - SilenceTime) > SilenceDuration)
{
RecordingStart := RecordingStartSound := SilenceTime := ConWinWidth := ""
DllCall("CloseHandle", "ptr", hConOut)
break
}
}
else
SilenceTime := ""
}
sleep 10
}
hConIn := DllCall("CreateFile", "str", "CONIN$", "uint", 0xC0000000, "uint", 0x3, "ptr", 0, "uint", 0x3, "uint", 0, "ptr", 0, "ptr")
if (hConIn = -1)
{
msgbox error CreateFile CONIN %A_LastError%
ExitApp
}
VarSetCapacity(ir, 24, 0) ; ir := new INPUT_RECORD
NumPut(1, ir, 0, "UShort") ; ir.EventType := KEY_EVENT
NumPut(1, ir, 8, "UShort") ; ir.KeyEvent.wRepeatCount := 1
NumPut(Asc("q"), ir, 14, "UShort")
NumPut(true, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := true
if !DllCall("WriteConsoleInput", "ptr", hConIn, "ptr", &ir, "uint", 1, "uint*", 0)
{
msgbox error WriteConsoleInput one %A_LastError%
ExitApp
}
NumPut(false, ir, 4, "Int") ; ir.KeyEvent.bKeyDown := false
if !DllCall("WriteConsoleInput", "ptr", hConIn, "ptr", &ir, "uint", 1, "uint*", 0)
{
msgbox error WriteConsoleInput two %A_LastError%
ExitApp
}
DllCall("CloseHandle", "ptr", hConIn)
DllCall("FreeConsole")
SetTimer, Count, Off
GuiControl,, MP3Time
Process, WaitClose, ffmpeg_script.exe
Run, ffmpeg_script.exe -i temp.wav -ab 320k -acodec libmp3lame -y -af "silenceremove=start_periods=1:start_duration=0:start_threshold=%NoiseGate%dB`,areverse`,silenceremove=start_periods=1:start_duration=0:start_threshold=%NoiseGate%dB`,areverse" "%A_Now%.mp3", , hide
Process, WaitClose, ffmpeg_script.exe
FileDelete, temp.wav
msgbox done
GuiControl, Enable, Record
return
Count:
sec++
if (sec = 60)
{
min++
sec := 0
}
GuiControl, MP3Record:, MP3Time, % "0:" Format("{1:02}", min) ":" Format("{1:02}", sec)
return
MP3RecordGuiClose:
loop
{
Process, Exist, ffmpeg_script.exe
if ErrorLevel
{
Process, Close, ffmpeg_script.exe
Process, WaitClose, ffmpeg_script.exe
}
else
break
}
FileDelete, temp.wav
ExitApp
LOAD_DLL_Mf_Mfplat()
{
if !DllCall("GetModuleHandle","str","Mf")
DllCall("LoadLibrary","Str", "Mf.dll", "ptr")
if !DllCall("GetModuleHandle","str","Mfplat")
DllCall("LoadLibrary","Str", "Mfplat.dll", "ptr")
}
UNLOAD_DLL_Mf_Mfplat()
{
if hModule := DllCall("GetModuleHandle", "str", "Mf", "ptr")
DllCall("FreeLibrary", "ptr", hModule)
if hModule := DllCall("GetModuleHandle", "str", "Mfplat", "ptr")
DllCall("FreeLibrary", "ptr", hModule)
}
MFStartup(version, dwFlags)
{
hr := DllCall("Mfplat.dll\MFStartup", "uint", version, "uint", dwFlags)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
MFCreateAttributes(ByRef ppMFAttributes, cInitialSize)
{
hr := DllCall("Mfplat.dll\MFCreateAttributes", "ptr*", ppMFAttributes, "uint", cInitialSize)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
IMFAttributes_SetGUID(this, guidKey, guidValue)
{
hr := DllCall(NumGet(NumGet(this+0)+24*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr", guidValue)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
MFEnumDeviceSources(pAttributes, ByRef pppSourceActivate, ByRef pcSourceActivate)
{
hr := DllCall("Mf.dll\MFEnumDeviceSources", "ptr", pAttributes, "ptr*", pppSourceActivate, "uint*", pcSourceActivate)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}
IMFActivate_GetAllocatedString(this, guidKey)
{
hr := DllCall(NumGet(NumGet(this+0)+13*A_PtrSize), "ptr", this, "ptr", guidKey, "ptr*", ppwszValue, "uint*", pcchLength)
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
AllocatedString := StrGet(ppwszValue, pcchLength, "UTF-16")
DllCall("ole32\CoTaskMemFree", "ptr", ppwszValue)
return AllocatedString
}
MF_GUID(ByRef GUID, name)
{
static init:=1, _:={}
if init
{
init:=0
_.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE := [0xc60ac5fe, 0x252a, 0x478f, 0xa0, 0xef, 0xbc, 0x8f, 0xa5, 0xf7, 0xca, 0xd3]
_.MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID := [0x14dd9a1c, 0x7cff, 0x41be, 0xb1, 0xb9, 0xba, 0x1a, 0xc6, 0xec, 0xb5, 0x71]
_.MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME := [0x60d0e559, 0x52f8, 0x4fa2, 0xbb, 0xce, 0xac, 0xdb, 0x34, 0xa8, 0xec, 0x1]
}
if _.haskey(name)
{
p := _[name]
VarSetCapacity(GUID,16)
,NumPut(p.1+(p.2<<32)+(p.3<<48),GUID,0,"int64")
,NumPut(p.4+(p.5<<8)+(p.6<<16)+(p.7<<24)+(p.8<<32)+(p.9<<40)+(p.10<<48)+(p.11<<56),GUID,8,"int64")
return &GUID
}
else return name
}
_Error(val)
{
msgbox % val
ExitApp
}
MFShutdown()
{
hr := DllCall("Mfplat.dll\MFShutdown")
if hr or ErrorLevel
_Error(A_ThisFunc " error: " hr "`nErrorLevel: " ErrorLevel)
}