wakillon Posted September 9, 2014 Posted September 9, 2014 (edited) I use a USB key or an FM transmitter in my car to listen mp3. Two problems have emerged: long silences or a different sound level between different tracks or between tracks and FM radio. Seeking a software that could solve automatically these problems, for multiple files, I returned empty-handed ! All i have found who could be interesting were some examples about remove silence on un4seen.com (the bass audio library website) After much research I managed to adapt it, here is the result : Mp3SilenceRemover can trim a bunch of mp3 files that have silence at the beginnings and ends, automatically. Script scans each file for when the sound starts and ends, by detecting a pre-determined silence threshold, then reencode them without silent parts found. Usefull if you want use mp3 files for a mix or avoid long silences between tracks. Multiple settings are available for preserving mp3 quality. Mp3Gain can be used for avoid a too big difference in sound level between 2 tracks. Main Id3 Tags can be preserved and the fade at end of the track too. Script use : bass.dll, bassenc.dll, bassext.dll, tags.dll, lame.exe and mp3gain.exe. The default settings I have choosen are the ones who give me the best results during my numerous tries. Free to you to adapt them to your needs, they are saved automatically. New mp3 files will be located in the same folder with "_SR1" at the end of the name. Buttons were made online with chimply.com the easy and free buttons generator ! No external files or includes needed, they are embbeded in script. source and executable are available in the Download Section Hope you like it ! Edited February 3, 2016 by wakillon Danyfirex and GreenCan 2 AutoIt 3.3.18.0 X86 - SciTE 5.5.7 - WIN 11 24H2 X64 - Other Examples Scripts
GreenCan Posted September 15, 2014 Posted September 15, 2014 Hi wakillon, As usual you make brilliant tiny apps. I like it very much. It's also very destructive if one doesn't pay attention , I think it would be niceif the proposed Bitrate in the drop down would match the one in the original file. GreenCan Contributions CheckUpdate - SelfUpdating script ------- Self updating script Dynamic input validation ------------------- Use a Input masks can make your life easier and Validation can be as simple MsgBox with CountDown ------------------- MsgBox with visual countdown Display Multiline text cells in ListView ---- Example of pop-up or ToolTip for multiline text items in ListView Presentation Manager ---------------------- Program to display and refresh different Border-less GUI's on a Display (large screen TV) USB Drive Tools ------------------------------ Tool to help you with your USB drive management Input Period udf ------------------------------ GUI for a period input Excel ColorPicker ---------------------------- Color pickup tool will allow you to select a color from the standard Excel color palette Excel Chart UDF ----------------------------- Collaboration project with water GetDateInString ------------------------------ Find date/time in a string using a date format notation like DD Mon YYYY hh:mm TaskListAllDetailed --------------------------- List All Scheduled Tasks Computer Info --------------------------------- A collection of information for helpdesk Shared memory Demo ----------------------- Demo: Two applications communicate with each other through means of a memory share (using Nomad function, 32bit only) Universal Date Format Conversion -------- Universal date converter from your PC local date format to any format Disable Windows DetailsPane -------------- Disable Windows Explorer Details Pane Oracle SQL Report Generator ------------- Oracle Report generator using SQL SQLite Report Generator ------------------- SQLite Report generator using SQL SQLite ListView and BLOB demo ---------- Demo: shows how binary (image) objects can be recognized natively in a database BLOB field DSN-Less Database connection demo --- Demo: ActiveX Data Objects DSN-Less Database access Animated animals ----------------------------- Fun: Moving animated objects Perforated image in GUI --------------------- Fun: Perforate your image with image objects UEZ's Perforator major update ------------- Fun: Pro version of Perforator by UEZ Visual Crop Tool (GUI) ----------------------- Easy to use Visual Image Crop tool Visual Image effect (GUI) -------------------- Visually apply effects on an image
UEZ Posted September 16, 2014 Posted September 16, 2014 The About function is my style What I don't like is that the silent remove encodes the MP3 again which means quality loss. mpTrim e.g. cuts the frames only without re-encoding. Maybe there is a cmdline tool with same ability which you can use. Br, UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
eukalyptus Posted September 16, 2014 Posted September 16, 2014 (edited) Maybe there is a cmdline tool with same ability which you can use. Or you trim the frames yourself: expandcollapse popup;#include <Array.au3> Global $hFile = FileOpen("Test.mp3", 16) Global $bMP3 = FileRead($hFile) FileClose($hFile) ;MP3: [..........................................] ; | | ; 2s 6s ; |_______________| ; 4s Global $bNew = _CutMP3($bMP3, 2000, 6000) $hFile = FileOpen("New.mp3", 18) FileWrite($hFile, $bNew) FileClose($hFile) Func _CutMP3(ByRef $bMP3, $iMSStart, $iMSEnd, $bID3v2 = True) $iMSStart /= 1000 $iMSEnd /= 1000 Local $iMP3Len = BinaryLen($bMP3) Local $tMP3 = DllStructCreate("char[" & $iMP3Len * 2 & "]; byte[2882];") Local $pMP3 = DllStructGetPtr($tMP3) DllStructSetData($tMP3, 1, StringTrimLeft($bMP3, 2)) Local $aHeader = _MP3_GetHeaders($bMP3) ;_ArrayDisplay($aHeader) Local $bNew = BinaryMid(0, 1, 0) If $bID3v2 And $aHeader[1][0] > 0 Then ;Id3v2Tag $bNew = BinaryMid($bMP3, 1, $aHeader[1][0]) ;ID3v2 EndIf Local $iFirstHeader = 1 Local $iXingVBRIFrames = __MP3_GetFrameCountXINGVBRI($pMP3 + $aHeader[1][0] * 2) If Not @error And $iXingVBRIFrames > 0 Then $iFirstHeader = 2 ;Skip XING / VBRI Frame Local $iMS = 0, $iFrameStart = $iFirstHeader For $i = $iFirstHeader To $aHeader[0][0] ;Skip $iMSStart Milliseconds $iMS += $aHeader[$i][5] / $aHeader[$i][2] If $iMS >= $iMSStart Then ExitLoop $iFrameStart = $i Next For $i = $iFrameStart To $aHeader[0][0] ;Add Frames $iMSStart to $iMSEnd $bNew &= BinaryMid($bMP3, $aHeader[$i][0], $aHeader[$i][4]) $iMS += $aHeader[$i][5] / $aHeader[$i][2] If $iMS > $iMSEnd Then ExitLoop Next Return $bNew EndFunc ;==>_CutMP3 Func _MP3_GetHeaders(Const ByRef $bMP3, $iMaxHeaders = -1, $iMaxErrors = 99, $bToolTip = True) ;by Eukalyptus AutoIt.de Local $iMP3Len = BinaryLen($bMP3) Local $tMP3 = DllStructCreate("char[" & $iMP3Len * 2 & "]; byte[2882];") Local $pMP3 = DllStructGetPtr($tMP3) DllStructSetData($tMP3, 1, StringTrimLeft($bMP3, 2)) Local $aHeader[128][6] = [[0, "BitRate", "SampleRate", "Chan", "FrameSize", "Samples"]] __MP3_GetHeaders($pMP3, $iMP3Len, $aHeader, $iMaxHeaders, $iMaxErrors, $bToolTip) Return $aHeader EndFunc ;==>_MP3_GetHeaders ;############################################################################################################ ;# Internal MP3 Functions ;############################################################################################################ Func __MP3_GetHeaders($pMP3, $iMP3Len, ByRef $aHeader, $iMaxHeaders = -1, $iMaxErrors = 99, $bToolTip = True) ;by Eukalyptus AutoIt.de $iMaxHeaders = Dec(Hex($iMaxHeaders, 8), 2) ;-1=4294967295 Local $iMP3Pos = 0, $iCnt = 1, $iTmpOff, $iError = 0 While $iCnt <= $iMaxHeaders $iTmpOff = $iMP3Pos If Not __MP3_GetFrameHeaderInfo($pMP3 + $iMP3Pos * 2, $iMP3Pos, $aHeader[$iCnt][1], $aHeader[$iCnt][2], $aHeader[$iCnt][3], $aHeader[$iCnt][4], $aHeader[$iCnt][5]) Then If $iMP3Pos >= $iMP3Len - 1440 Then $aHeader[$iCnt][0] = $iMP3Pos $iCnt += 1 ExitLoop ;End of file EndIf $iMP3Pos = $iTmpOff __MP3_SkipID3v2TAG($pMP3 + $iMP3Pos * 2, $iTmpOff) ;maybe ID3v2 inside MP3 Stream!? If $iTmpOff = $iMP3Pos Then ;no ID3v2 or no FrameHeader ahead $iError += 1 If $iError > $iMaxErrors Then ExitLoop $iMP3Pos += 26 ;try offset of MinFrameSize (8KBit, 22050Hz) Else $iMP3Pos = $iTmpOff; ID3v2 offset EndIf Else $aHeader[$iCnt][0] = $iMP3Pos - $aHeader[$iCnt][4] $iCnt += 1 If $iCnt >= UBound($aHeader) Then ReDim $aHeader[$iCnt * 2][6] If $bToolTip And Not Mod($iCnt, 1000) Then ToolTip(StringFormat("%.2f%%", $iMP3Pos * 100 / $iMP3Len)) EndIf WEnd If $bToolTip Then ToolTip("") $aHeader[0][0] = $iCnt - 1 ReDim $aHeader[$iCnt][6] Return $iError EndFunc ;==>__MP3_GetHeaders Func __MP3_GetFrameHeaderInfo($pMP3, ByRef $iMP3Pos, ByRef $iBitRate, ByRef $iSampleRate, ByRef $iChan, ByRef $iFrameSize, ByRef $iSamples) ;by Eukalyptus AutoIt.de ;[ Byte 1 ][ Byte 2 ][ Byte 3 ][ Byte 4 ] ;[1][1][1][1][1][1][1][1][1][1][1][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ] ;|_______________________________|| ||____|| ||__________|| ||_|| ||____|| ||_|| ||____| ; |____| |_| |____| |_| |____| |_| ; Sync Layer BitRate Pad Chan Copy Emph ; ID Protect Freq Prv ModEx Orig Local $aRegExp, $iRegExpOff, $iMod, $iHeader, $iID, $iBRate, $iBRM, $fBRF, $iPad Local $tMP3 = DllStructCreate("char[2882];", $pMP3) $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "FF[FE][23AB].{4}", 1) ;Match Header Mpeg(1/2/2.5) - Layer_III - ProtectionBit ON/OFF If @error Then Return SetError(1, 1, False) $iRegExpOff = @extended - 9 $iMod = Mod($iRegExpOff, 2) $iRegExpOff += $iMod $iMP3Pos += $iRegExpOff * 0.5 If Not $iMod Then ;Byte boundaries $iHeader = Dec($aRegExp[0], 1) $iID = BitAND(BitShift($iHeader, 19), 0x3) Switch $iID Case 0, 2 ;Mpeg2/2.5 $iSamples = 576 Case 3 ;Mpeg1 $iSamples = 1152 Case Else ; 1 = reserved Return SetError(1, 2, False) EndSwitch If BitAND(BitShift($iHeader, 17), 0x3) <> 1 Then Return SetError(1, 3, False) ; <> Layer III $iBRate = BitAND(BitShift($iHeader, 12), 0xF) Switch $iID Case 3 ;MPEG Version 1 $iBRM = Mod($iBRate + 2, 4) + 1 $fBRF = 2 ^ BitShift($iBRate + 2, 2) $iBitRate = 16 * $fBRF + 4 * $fBRF * $iBRM Case Else ;MPEG Version 2.5 + MPEG Version 2 $iBRM = Mod($iBRate - 1, 8) + 1 $fBRF = 2 ^ BitShift($iBRate - 1, 3) $iBitRate = 8 * $fBRF * $iBRM + 64 * ($fBRF - 1) EndSwitch Switch BitAND(BitShift($iHeader, 10), 0x3) Case 0 $iSampleRate = 11025 Case 1 $iSampleRate = 12000 Case 2 $iSampleRate = 8000 Case Else ; 3 = reserved Return SetError(1, 4, False) EndSwitch Switch $iID Case 2 $iSampleRate *= 2 ;Mpeg2 = 16000, 24000, 22050 Case 3 $iSampleRate *= 4 ;Mpeg1 = 32000, 48000, 44100 EndSwitch $iPad = BitAND(BitShift($iHeader, 9), 0x1) $iChan = (BitAND(BitShift($iHeader, 6), 0x3) <> 4) + 1 ;0,1=Stereo 2=DualMono 3=Mono $iFrameSize = Int((($iSamples / 0.008) * $iBitRate / $iSampleRate)) + $iPad $tMP3 = DllStructCreate("char[3];", $pMP3 + $iRegExpOff + $iFrameSize * 2) Switch DllStructGetData($tMP3, 1) Case "FFF", "FFE" $iMP3Pos += $iFrameSize Case Else Return SetError(1, 5, False) ;FrameSize offset does not match a FrameHeader - something went wrong EndSwitch Return True EndIf Return SetError(1, 6, False) EndFunc ;==>__MP3_GetFrameHeaderInfo Func __MP3_SkipID3v2TAG($pMP3, ByRef $iMP3Pos) ;by Eukalyptus AutoIt.de ;[49][44][33][xx][xx][yy][zz][zz][zz][zz] ;| ||______|| ||______________| ;|__________| |__| ; Version TagSize ; "ID3" Flags Local $iPos, $iHeader, $iFlags Local $tMP3 = DllStructCreate("char[2882];", $pMP3) Local $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "494433.{14}", 1) If @error Then Return SetError(0, 0, False) $iPos = @extended - 21 If Mod($iPos, 2) Then Return SetError(1, 0, False) ;TAG not at Byte-Boundaries $iPos *= 0.5 $iHeader = Dec(StringRight($aRegExp[0], 8)) If BitAND($iHeader, 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 8), 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 16), 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 24), 0xFF) > 0x7F Then Return SetError(1, 1, False);Size Bytes <= 7F! If BitAND(BitShift($iHeader, 40), 0xFF) = 0xFF Or BitAND(BitShift($iHeader, 48), 0xFF) = 0xFF Then Return SetError(1, 2, False);Version Bytes <> FF! $iFlags = Dec(StringLeft(StringTrimLeft($aRegExp[0], 10), 2)) $iPos += BitOR(BitAND($iHeader, 0x7F), BitShift(BitAND($iHeader, 0x7F00), 1), BitShift(BitAND($iHeader, 0x7F0000), 2), BitShift(BitAND($iHeader, 0x7F000000), 3)) + (10 * BitShift(BitAND($iFlags, 0x8), 3)) + 10 $tMP3 = DllStructCreate("char[3];", $pMP3 + $iPos * 2) Switch DllStructGetData($tMP3, 1) Case "FFF", "FFE" $iMP3Pos += $iPos Case Else Return SetError(1, 3, False) ;Pos does not match a FrameHeader - something went wrong EndSwitch Return True EndFunc ;==>__MP3_SkipID3v2TAG Func __MP3_GetFrameCountXINGVBRI($pMP3) ;by Eukalyptus AutoIt.de Local $tMP3 = DllStructCreate("char[2882];", $pMP3) ;[58][69][6E][67][xx][xx][xx][xx][yy][yy][yy][yy][zz][zz][zz][zz][tt][tt][tt][tt][tt][tt]... ;|______________|| ||______________||______________||__________________________ ; |______________| ; "Xing" Frames Bytes 100 [Bytes] TOC ; Flags: 0x1 0x2 0x4 Local $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "(58696E67)(.{8})(.{8})", 3) ;"Xing" If Not @error Then If BitAND(Dec($aRegExp[1]), 1) = 1 Then Return Dec($aRegExp[2]) Else ;[56][42][52][49][xx][xx][yy][yy][zz][zz][xx][xx][xx][xx][yy][yy][yy][yy][zz][zz][xx][xx][yy][yy][zz][zz][xx][xx][xx][xx][xx]... ;|______________|| ||______|| ||______________|| ||______|| ||______|| ||______________________ ; |______| |______| |______________| |______| |______| ; "VBRI" Delay Bytes TOC Count Size TOC [size*count) ; Version Quality Frames Scale Frames/Entry $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "(56425249)(.{4})(.{4})(.{4})(.{8})(.{8})", 3) ;"VBRI" If Not @error Then Return Dec($aRegExp[5]) EndIf Return 0 EndFunc ;==>__MP3_GetFrameCountXINGVBRI E Edited September 16, 2014 by eukalyptus UEZ 1 DirectSound UDF Direct2D UDF
UEZ Posted September 16, 2014 Posted September 16, 2014 As usual great stuff Eukalyptus:thumbsup:.Is there an easy way to analyse the beginning / end of the MP3 to get the silence duration?Br,UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
eukalyptus Posted September 16, 2014 Posted September 16, 2014 (edited) Without Bass.dll you can use my DirectSound UDF to decode the mp3.: http://autoit.de/index.php?page=Thread&postID=361564#post361564 And then look for the peaks. expandcollapse popup#include "DirectSound.au3" Global $hFile = FileOpen("Test.mp3", 16) Global $bMP3 = FileRead($hFile) FileClose($hFile) Local $aWav = _DSnd_MP3Decode($bMP3) _FindSilence($aWav) Func _FindSilence($aWav, $fThreshold = 0.05) Local $iWavLen = BinaryLen($aWav[0]) Local $iSamples = $iWavLen * 0.5 Local $tWav = DllStructCreate("byte[" & $iWavLen & "];") Local $tWavSmp = DllStructCreate("short[" & $iSamples & "];", DllStructGetPtr($tWav)) DllStructSetData($tWav, 1, $aWav[0]) Local $iThrHld = 32768 * $fThreshold Local $iStart = 0 For $i = 1 To $iSamples * 0.5 If Abs(DllStructGetData($tWavSmp, 1, $i)) >= $iThrHld Then ExitLoop $iStart = $i Next Local $iEnd = $iSamples For $i = $iSamples To $iSamples * 0.5 Step -1 $iEnd = $i If Abs(DllStructGetData($tWavSmp, 1, $i)) >= $iThrHld Then ExitLoop Next Local $fMSStart = $iStart / $aWav[1].SamplesPerSec / $aWav[1].Channels * 1000 Local $fMSEnd = $iEnd / $aWav[1].SamplesPerSec / $aWav[1].Channels * 1000 ConsoleWrite("> MSStart:" & $fMSStart & " MSEnd:" & $fMSEnd & @CRLF) EndFunc ;==>_FindSilence E Edit: faster, using ASM expandcollapse popup;#include "FASM.au3" #include "DirectSound.au3" #include <Memory.au3> Global Const $bASM_SilenceStart_32 = "0x538B5424088B4C240C668B5C2410668B026609C0790366F7D86639D87C0489C8EB0883C20283E9017FE45BC20C00" Global Const $bASM_SilenceStart_64 = "0x668B016609C0790366F7D8664439C07C0489D0EB094883C10283EA017FE2C3" Global Const $bASM_SilenceEnd_32 = "0x538B5424088B4C240C668B5C241001CA01CA83EA02668B026609C0790366F7D86639D87C0489C8EB0583E9017FE45BC20C00" Global Const $bASM_SilenceEnd_64 = "0x4801D14801D14883E902668B016609C0790366F7D8664439C07C0489D0EB0583EA017FE2C3" Global $hFile = FileOpen("Test.mp3", 16) Global $bMP3 = FileRead($hFile) FileClose($hFile) Global $aWav = _DSnd_MP3Decode($bMP3) Global $aCut = _FindSilence($aWav) Global $bNew = _CutMP3($bMP3, $aCut[0], $aCut[1]) $hFile = FileOpen("New.mp3", 18) FileWrite($hFile, $bNew) FileClose($hFile) Func _FindSilence($aWav, $fThreshold = 0.1) Local $pASM_Start, $_pASM_Start, $pASM_End, $_pASM_End Switch @AutoItX64 Case 0 $pASM_Start = __ASMCreate($bASM_SilenceStart_32, $_pASM_Start) $pASM_End = __ASMCreate($bASM_SilenceEnd_32, $_pASM_End) Case Else $pASM_Start = __ASMCreate($bASM_SilenceStart_64, $_pASM_Start) $pASM_End = __ASMCreate($bASM_SilenceEnd_64, $_pASM_End) EndSwitch Local $iWavLen = BinaryLen($aWav[0]) Local $iSamples = $iWavLen * 0.5 Local $tWav = DllStructCreate("byte[" & $iWavLen & "];") DllStructSetData($tWav, 1, $aWav[0]) Local $iThrHld = 32768 * $fThreshold Local $aResult = DllCallAddress("uint", $pASM_Start, "struct*", $tWav, "uint", $iSamples, "short", $iThrHld) Local $iStart = $iSamples - $aResult[0] Local $aResult = DllCallAddress("uint", $pASM_End, "struct*", $tWav, "uint", $iSamples, "short", $iThrHld) Local $iEnd = $aResult[0] Local $fMSStart = $iStart / $aWav[1].SamplesPerSec / $aWav[1].Channels * 1000 Local $fMSEnd = $iEnd / $aWav[1].SamplesPerSec / $aWav[1].Channels * 1000 _MemVirtualFree($_pASM_Start, 0, $MEM_RELEASE) _MemVirtualFree($_pASM_End, 0, $MEM_RELEASE) Local $aRet[2] $aRet[0] = $fMSStart $aRet[1] = $fMSEnd Return $aRet EndFunc ;==>_FindSilence Func _CutMP3(ByRef $bMP3, $iMSStart, $iMSEnd, $bID3v2 = True) $iMSStart /= 1000 $iMSEnd /= 1000 Local $iMP3Len = BinaryLen($bMP3) Local $tMP3 = DllStructCreate("char[" & $iMP3Len * 2 & "]; byte[2882];") Local $pMP3 = DllStructGetPtr($tMP3) DllStructSetData($tMP3, 1, StringTrimLeft($bMP3, 2)) Local $aHeader = _MP3_GetHeaders($bMP3) Local $bNew = BinaryMid(0, 1, 0) If $bID3v2 And $aHeader[1][0] > 0 Then ;Id3v2Tag $bNew = BinaryMid($bMP3, 1, $aHeader[1][0]) ;ID3v2 EndIf Local $iFirstHeader = 1 Local $iXingVBRIFrames = __MP3_GetFrameCountXINGVBRI($pMP3 + $aHeader[1][0] * 2) If Not @error And $iXingVBRIFrames > 0 Then $iFirstHeader = 2 ;Skip XING / VBRI Frame Local $iMS = 0, $iFrameStart = $iFirstHeader For $i = $iFirstHeader To $aHeader[0][0] ;Skip $iMSStart Milliseconds $iMS += $aHeader[$i][5] / $aHeader[$i][2] If $iMS >= $iMSStart Then ExitLoop $iFrameStart = $i Next Local $iFrameEnd For $i = $iFrameStart To $aHeader[0][0] ;Add Frames $iMSStart to $iMSEnd $iFrameEnd = $i $iMS += $aHeader[$i][5] / $aHeader[$i][2] If $iMS > $iMSEnd Then ExitLoop Next $tMP3 = DllStructCreate("byte[" & $iMP3Len * 2 & "];") $pMP3 = DllStructGetPtr($tMP3) DllStructSetData($tMP3, 1, $bMP3) Local $tNew = DllStructCreate("byte[" & $aHeader[$iFrameEnd][0] - $aHeader[$iFrameStart][0] & "]", $pMP3 + $aHeader[$iFrameStart][0]) $bNew &= DllStructGetData($tNew, 1) Return $bNew EndFunc ;==>_CutMP3 Func _MP3_GetHeaders(Const ByRef $bMP3, $iMaxHeaders = -1, $iMaxErrors = 99, $bToolTip = True) ;by Eukalyptus AutoIt.de Local $iMP3Len = BinaryLen($bMP3) Local $tMP3 = DllStructCreate("char[" & $iMP3Len * 2 & "]; byte[2882];") Local $pMP3 = DllStructGetPtr($tMP3) DllStructSetData($tMP3, 1, StringTrimLeft($bMP3, 2)) Local $aHeader[128][6] = [[0, "BitRate", "SampleRate", "Chan", "FrameSize", "Samples"]] __MP3_GetHeaders($pMP3, $iMP3Len, $aHeader, $iMaxHeaders, $iMaxErrors, $bToolTip) Return $aHeader EndFunc ;==>_MP3_GetHeaders ;############################################################################################################ ;# Internal MP3 Functions ;############################################################################################################ Func __MP3_GetHeaders($pMP3, $iMP3Len, ByRef $aHeader, $iMaxHeaders = -1, $iMaxErrors = 99, $bToolTip = True) ;by Eukalyptus AutoIt.de $iMaxHeaders = Dec(Hex($iMaxHeaders, 8), 2) ;-1=4294967295 Local $iMP3Pos = 0, $iCnt = 1, $iTmpOff, $iError = 0 While $iCnt <= $iMaxHeaders $iTmpOff = $iMP3Pos If Not __MP3_GetFrameHeaderInfo($pMP3 + $iMP3Pos * 2, $iMP3Pos, $aHeader[$iCnt][1], $aHeader[$iCnt][2], $aHeader[$iCnt][3], $aHeader[$iCnt][4], $aHeader[$iCnt][5]) Then If $iMP3Pos >= $iMP3Len - 1440 Then $aHeader[$iCnt][0] = $iMP3Pos $iCnt += 1 ExitLoop ;End of file EndIf $iMP3Pos = $iTmpOff __MP3_SkipID3v2TAG($pMP3 + $iMP3Pos * 2, $iTmpOff) ;maybe ID3v2 inside MP3 Stream!? If $iTmpOff = $iMP3Pos Then ;no ID3v2 or no FrameHeader ahead $iError += 1 If $iError > $iMaxErrors Then ExitLoop $iMP3Pos += 26 ;try offset of MinFrameSize (8KBit, 22050Hz) Else $iMP3Pos = $iTmpOff; ID3v2 offset EndIf Else $aHeader[$iCnt][0] = $iMP3Pos - $aHeader[$iCnt][4] $iCnt += 1 If $iCnt >= UBound($aHeader) Then ReDim $aHeader[$iCnt * 2][6] If $bToolTip And Not Mod($iCnt, 1000) Then ToolTip(StringFormat("%.2f%%", $iMP3Pos * 100 / $iMP3Len)) EndIf WEnd If $bToolTip Then ToolTip("") $aHeader[0][0] = $iCnt - 1 ReDim $aHeader[$iCnt][6] Return $iError EndFunc ;==>__MP3_GetHeaders Func __MP3_GetFrameHeaderInfo($pMP3, ByRef $iMP3Pos, ByRef $iBitRate, ByRef $iSampleRate, ByRef $iChan, ByRef $iFrameSize, ByRef $iSamples) ;by Eukalyptus AutoIt.de ;[ Byte 1 ][ Byte 2 ][ Byte 3 ][ Byte 4 ] ;[1][1][1][1][1][1][1][1][1][1][1][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ] ;|_______________________________|| ||____|| ||__________|| ||_|| ||____|| ||_|| ||____| ; |____| |_| |____| |_| |____| |_| ; Sync Layer BitRate Pad Chan Copy Emph ; ID Protect Freq Prv ModEx Orig Local $aRegExp, $iRegExpOff, $iMod, $iHeader, $iID, $iBRate, $iBRM, $fBRF, $iPad Local $tMP3 = DllStructCreate("char[2882];", $pMP3) $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "FF[FE][23AB].{4}", 1) ;Match Header Mpeg(1/2/2.5) - Layer_III - ProtectionBit ON/OFF If @error Then Return SetError(1, 1, False) $iRegExpOff = @extended - 9 $iMod = Mod($iRegExpOff, 2) $iRegExpOff += $iMod $iMP3Pos += $iRegExpOff * 0.5 If Not $iMod Then ;Byte boundaries $iHeader = Dec($aRegExp[0], 1) $iID = BitAND(BitShift($iHeader, 19), 0x3) Switch $iID Case 0, 2 ;Mpeg2/2.5 $iSamples = 576 Case 3 ;Mpeg1 $iSamples = 1152 Case Else ; 1 = reserved Return SetError(1, 2, False) EndSwitch If BitAND(BitShift($iHeader, 17), 0x3) <> 1 Then Return SetError(1, 3, False) ; <> Layer III $iBRate = BitAND(BitShift($iHeader, 12), 0xF) Switch $iID Case 3 ;MPEG Version 1 $iBRM = Mod($iBRate + 2, 4) + 1 $fBRF = 2 ^ BitShift($iBRate + 2, 2) $iBitRate = 16 * $fBRF + 4 * $fBRF * $iBRM Case Else ;MPEG Version 2.5 + MPEG Version 2 $iBRM = Mod($iBRate - 1, 8) + 1 $fBRF = 2 ^ BitShift($iBRate - 1, 3) $iBitRate = 8 * $fBRF * $iBRM + 64 * ($fBRF - 1) EndSwitch Switch BitAND(BitShift($iHeader, 10), 0x3) Case 0 $iSampleRate = 11025 Case 1 $iSampleRate = 12000 Case 2 $iSampleRate = 8000 Case Else ; 3 = reserved Return SetError(1, 4, False) EndSwitch Switch $iID Case 2 $iSampleRate *= 2 ;Mpeg2 = 16000, 24000, 22050 Case 3 $iSampleRate *= 4 ;Mpeg1 = 32000, 48000, 44100 EndSwitch $iPad = BitAND(BitShift($iHeader, 9), 0x1) $iChan = (BitAND(BitShift($iHeader, 6), 0x3) <> 4) + 1 ;0,1=Stereo 2=DualMono 3=Mono $iFrameSize = Int((($iSamples / 0.008) * $iBitRate / $iSampleRate)) + $iPad $tMP3 = DllStructCreate("char[3];", $pMP3 + $iRegExpOff + $iFrameSize * 2) Switch DllStructGetData($tMP3, 1) Case "FFF", "FFE" $iMP3Pos += $iFrameSize Case Else Return SetError(1, 5, False) ;FrameSize offset does not match a FrameHeader - something went wrong EndSwitch Return True EndIf Return SetError(1, 6, False) EndFunc ;==>__MP3_GetFrameHeaderInfo Func __MP3_SkipID3v2TAG($pMP3, ByRef $iMP3Pos) ;by Eukalyptus AutoIt.de ;[49][44][33][xx][xx][yy][zz][zz][zz][zz] ;| ||______|| ||______________| ;|__________| |__| ; Version TagSize ; "ID3" Flags Local $iPos, $iHeader, $iFlags Local $tMP3 = DllStructCreate("char[2882];", $pMP3) Local $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "494433.{14}", 1) If @error Then Return SetError(0, 0, False) $iPos = @extended - 21 If Mod($iPos, 2) Then Return SetError(1, 0, False) ;TAG not at Byte-Boundaries $iPos *= 0.5 $iHeader = Dec(StringRight($aRegExp[0], 8)) If BitAND($iHeader, 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 8), 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 16), 0xFF) > 0x7F Or BitAND(BitShift($iHeader, 24), 0xFF) > 0x7F Then Return SetError(1, 1, False);Size Bytes <= 7F! If BitAND(BitShift($iHeader, 40), 0xFF) = 0xFF Or BitAND(BitShift($iHeader, 48), 0xFF) = 0xFF Then Return SetError(1, 2, False);Version Bytes <> FF! $iFlags = Dec(StringLeft(StringTrimLeft($aRegExp[0], 10), 2)) $iPos += BitOR(BitAND($iHeader, 0x7F), BitShift(BitAND($iHeader, 0x7F00), 1), BitShift(BitAND($iHeader, 0x7F0000), 2), BitShift(BitAND($iHeader, 0x7F000000), 3)) + (10 * BitShift(BitAND($iFlags, 0x8), 3)) + 10 $tMP3 = DllStructCreate("char[3];", $pMP3 + $iPos * 2) Switch DllStructGetData($tMP3, 1) Case "FFF", "FFE" $iMP3Pos += $iPos Case Else Return SetError(1, 3, False) ;Pos does not match a FrameHeader - something went wrong EndSwitch Return True EndFunc ;==>__MP3_SkipID3v2TAG Func __MP3_GetFrameCountXINGVBRI($pMP3) ;by Eukalyptus AutoIt.de Local $tMP3 = DllStructCreate("char[2882];", $pMP3) ;[58][69][6E][67][xx][xx][xx][xx][yy][yy][yy][yy][zz][zz][zz][zz][tt][tt][tt][tt][tt][tt]... ;|______________|| ||______________||______________||__________________________ ; |______________| ; "Xing" Frames Bytes 100 [Bytes] TOC ; Flags: 0x1 0x2 0x4 Local $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "(58696E67)(.{8})(.{8})", 3) ;"Xing" If Not @error Then If BitAND(Dec($aRegExp[1]), 1) = 1 Then Return Dec($aRegExp[2]) Else ;[56][42][52][49][xx][xx][yy][yy][zz][zz][xx][xx][xx][xx][yy][yy][yy][yy][zz][zz][xx][xx][yy][yy][zz][zz][xx][xx][xx][xx][xx]... ;|______________|| ||______|| ||______________|| ||______|| ||______|| ||______________________ ; |______| |______| |______________| |______| |______| ; "VBRI" Delay Bytes TOC Count Size TOC [size*count) ; Version Quality Frames Scale Frames/Entry $aRegExp = StringRegExp(DllStructGetData($tMP3, 1), "(56425249)(.{4})(.{4})(.{4})(.{8})(.{8})", 3) ;"VBRI" If Not @error Then Return Dec($aRegExp[5]) EndIf Return 0 EndFunc ;==>__MP3_GetFrameCountXINGVBRI #ASM _ASM_SilenceStart_32 # use32 # push ebx # mov edx, [esp+8] # mov ecx, [esp+12] # mov bx, [esp+16] # _Loop: # mov ax, [edx] # or ax, ax # jns _AbsResult # neg ax # _AbsResult: # cmp ax, bx # jl _Cont # mov eax, ecx # jmp _Ret # _Cont: # add edx, 2 # sub ecx, 1 # jg _Loop # _Ret: # pop ebx # ret 12 #ASMEND #ASM _ASM_SilenceStart_64 # use64 # _Loop: # mov ax, [rcx] # or ax, ax # jns _AbsResult # neg ax # _AbsResult: # cmp ax, r8w # jl _Cont # mov eax, edx # jmp _Ret # _Cont: # add rcx, 2 # sub edx, 1 # jg _Loop # _Ret: # ret #ASMEND #ASM _ASM_SilenceEnd_32 # use32 # push ebx # mov edx, [esp+8] # mov ecx, [esp+12] # mov bx, [esp+16] # add edx, ecx # add edx, ecx # _Loop: # sub edx, 2 # mov ax, [edx] # or ax, ax # jns _AbsResult # neg ax # _AbsResult: # cmp ax, bx # jl _Cont # mov eax, ecx # jmp _Ret # _Cont: # sub ecx, 1 # jg _Loop # _Ret: # pop ebx # ret 12 #ASMEND #ASM _ASM_SilenceEnd_64 # use64 # add rcx, rdx # add rcx, rdx # _Loop: # sub rcx, 2 # mov ax, [rcx] # or ax, ax # jns _AbsResult # neg ax # _AbsResult: # cmp ax, r8w # jl _Cont # mov eax, edx # jmp _Ret # _Cont: # sub edx, 1 # jg _Loop # _Ret: # ret #ASMEND Func __ASMCreate(Const ByRef $bBinaryCode, ByRef $pPtr) Local $iSize = BinaryLen($bBinaryCode) $pPtr = _MemVirtualAlloc(0, $iSize + 16, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) Local $pStruct = Number($pPtr) $pStruct = $pStruct + 16 - Mod($pStruct, 16) Local $tStruct = DllStructCreate("byte[" & $iSize & "];", $pStruct) DllStructSetData($tStruct, 1, $bBinaryCode) Return $pStruct EndFunc ;==>__ASMCreate Edited September 16, 2014 by eukalyptus UEZ 1 DirectSound UDF Direct2D UDF
UEZ Posted September 16, 2014 Posted September 16, 2014 (edited) Great Eukalyptus!Edit: seems that some MP3s cannot be decoded by DS. Tested the new version and all tested MP3s were loaded properly to DS.Br,UEZ Edited September 16, 2014 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
wakillon Posted September 16, 2014 Author Posted September 16, 2014 Hi wakillon, As usual you make brilliant tiny apps. I like it very much. It's also very destructive if one doesn't pay attention , I think it would be niceif the proposed Bitrate in the drop down would match the one in the original file. GreenCan Ok, your suggestion will be added to the next version Thank you The About function is my style What I don't like is that the silent remove encodes the MP3 again which means quality loss. mpTrim e.g. cuts the frames only without re-encoding. Maybe there is a cmdline tool with same ability which you can use. Br, UEZ Where is the "fun" factor? I know mptrim but it is limited to 7 minutes of music ! I preferred to work with the great Bass UDF associated with lame ! Thank you alt="wink.png"> Without Bass.dll you can use my DirectSound UDF to decode the mp3.: http://autoit.de/index.php?page=Thread&postID=361564#post361564 And then look for the peaks. Your solutions are always amazing ! ASM seems fast, but I do not master this language at all ! From a big fan : Thanks to share this nice example. alt="wink.png"> AutoIt 3.3.18.0 X86 - SciTE 5.5.7 - WIN 11 24H2 X64 - Other Examples Scripts
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now