Moin,
schon lange hatte ich vor, einen Ersatz für das inzwischen etwas in die Jahre gekommene Razorlame zu basteln. Es ist alt und wird nicht mehr weiterentwickelt. Die Parameter für Lame sind auch nicht mehr aktuell, und außerdem stammt es aus einer Zeit, als die CPUs nur einen Kern hatten. Das Encoding größerer Mengen an .WAV-Dateien dauert länglich, während die CPU bei lausigen 25-30% vor sich hindümpelt und gar nicht richtig warm wird.
Außerdem ist hinterher immer etwas Nacharbeit mit mp3bookhelper erforderlich (ebenfalls schon etwas älter): ID3-Tags anhand der Dateinamen erstellen und anschließend die .mp3s in Unterordner einsortieren.
Das alles macht nun das Script in einem Rutsch - und es werden mehrere Lames gestartet, sofern mehrere .WAV-Files zu encoden sind (bei nur EINER Datei bringt das Script nullkommagarkeinen Geschwindigkeitsvorteil), damit die CPU auch "mal in Schweiß kommt".
Wenn das Script im selben Verzeichnis wie die Lame.exe liegt, ist alles gut. Ansonsten wird beim ersten Start danach gefragt, wo die Lame.exe ist.
Beim Beenden wird eine MultiCoreLame.ini geschrieben, damit man nicht jedesmal wieder bei Adam und Eva anfangen muß. Der Rest sollte anhand der Programmoberfläche und der dargestellten Hilfe selbsterklärend sein.
Anstatt es herauszukopieren, könnt Ihr das Script auch direkt hier herunterladen.
Spoiler anzeigen
#cs
[/autoit] [autoit][/autoit] [autoit]Name.............: MultiCoreLame
Version..........: 0.7.20140814
AutoItVersion....: 3.3.12.0
Author...........: Moon ( [email='multicorelame@foto-gama.net'][/email] )
Requirements.....: LAME.EXE, Windows XP... 8.1
Purpose..........: A Front-End for LAME, using multiple threads to be
a faster replacement for the old-fashioned Razorlame.
Also tags the mp3-files and structures them into sub-folders,
if the originating filename contains this information.
Licence..........: CC0 (Public Domain)
#ce
[/autoit] [autoit][/autoit] [autoit]Opt("MustDeclareVars",1)
[/autoit] [autoit][/autoit] [autoit]#include <GUIConstantsEx.au3> ; GUI Create, events
#include <ButtonConstants.au3> ; Button, Group, Radio, Checkbox
#include <EditConstants.au3> ; Edit, Input
#include <FileConstants.au3> ; File related
#cs
Do not include:
[/autoit] [autoit][/autoit] [autoit]#include <WindowsConstants.au3> ;Gui erweiterte Stile
#include <SliderConstants.au3> ;Slider
#include <ListviewConstants.au3> ;Listview
#include <AVIConstants.au3> ;AVI
#include <ComboConstants.au3> ;Combo
#include <Constants.au3> ;Tray, Run, StdIO,
#include <DateTimeConstants.au3> ;Date, MonthCal
#include <ListboxConstants.au3> ;List
#include <ProgressConstants.au3> ;Progress
#include <StaticConstants.au3> ;Label, Pic, Icon
#include <TabConstants.au3> ;Tab
#include <TreeviewConstants.au3> ;Treeview
#include <UpdownConstants.au3> ;Updown
#ce
[/autoit] [autoit][/autoit] [autoit]Global _ ; Window related variables
$HdlMainWindow , _ ; Main Window Handle (sic!)
$GUImsg , _ ; Messages from Windows...
$GUIheight , _ ; Height of the main window may vary, at least 270 pixel
$CIDlamegroup , _ ; Control IDentifier Group Lame settings...
$CIDcbr , _ ; Control IDentifier Radio selects CBR
$CIDvbr , _ ; Control IDentifier Radio selects VBR
$CIDvbrcbr , _ ; Control IDentifier Selection Menu Combo for VBR 0..9 or CBR 8..320
$CIDmono , _ ; Control IDentifier Checkbox for mono encoding
$CIDsystemgroup , _ ; Control IDentifier Group System settings...
$CIDThreadlabel , _ ; Control IDentifier Label number of Threads
$CIDThreads , _ ; Control IDentifier Selection Menu Combo for the number of threads to use
$CIDdelsrc , _ ; Control IDentifier Checkbox to delete source file after encoding
$CIDtagginggroup , _ ; Control IDentifier Group tagging and directory structure settings...
$CIDaddid3 , _ ; Control IDentifier Checkbox to use tagging or not
$CIDTagFormat , _ ; Control IDentifier Inputbox for tagging format, example "<Artist> - <Album> - <Title>"
$CIDrestruct , _ ; Control IDentifier Checkbox to use restructuring or not
$CIDrestructPattern , _ ; Control IDentifier Inputbox for structure format, example "<Artist>\<Album>\"
$CIDdstdir , _ ; Control IDentifier Button, select destination directory
$CIDFileOpen , _ ; Control IDentifier Button, select WAV File(s) and start encoding
$CIDsuccess , _ ; Control IDentifier Label for a successful encoding of x files in y seconds...
$CIDlamecommandlabel , _ ; Control IDentifier Label displays encoding settings, such as "lame -m m -V 0 (x4)"
$CIDhelpdisplay , _ ; Control IDentifier big Editbox displaying help before encoding starts
$CIDStopNew , _ ; Control IDentifier Button displayed during encoding, don't start more lames
$CIDKillAll ; Control IDentifier Button displayed during encoding, stop all encoders immediately
Global _ ; Initialized variables read and written from and to program's INI-file. Predefined for missing .ini
$bitrate = "192" , _ ; CBR bitrate
$vbrquality = "2" , _ ; VBR quality
$usevbr = True , _ ; default is VBR
$mono = False , _ ; default is stereo
$NumberOfThreads = 4 , _ ; starts 4 instances of Lame simultaneously
$MaxThreads = 20 , _ ; Maximum number of threads, read only, has to be written manually to INI
$delsrc = False , _ ; source WAV-file is NOT deleted by default
$addID3 = False , _ ; no ID3 tag is written by default
$restruct = False , _ ; no restructuring by default, only destination directory is used
$TagFormat = "" , _ ; nothing as ID3 tag...
$restructPattern = "" , _ ; nothing as restrucure pattern...
$LameLocation = "" , _ ; complete path to lame.exe, such as "d:\utilities\mp3encoder\lame.exe"
$dstdir = "" , _ ; destination directory for MP3-files
$LastSrcDir = @WindowsDir & "\" , _ ; Source directory for WAV-files
$WindowPos[4] = [10, 10, 0, 0] , _ ; Window position will be saved and next time placed there, width and height are ignored
$changed = True ; flag to indicate a change of the lame command, in order to update the lame command label
Global _ ; ID3 tagging values
$ID3Artist , _ ; These can only be used if the filename contains these informations!
$ID3Year , _ ; Also the information must be separated by unique limiters.
$ID3Album , _ ; The filename is fragmented by these unique limiters one by one.
$ID3Track , _ ; Example pattern: <Artist> - <Album> - <Year> - <Track#> - <Title>
$ID3Title , _ ; A valid filename for this pattern:
$ID3Comment ; Klaus Schulze - Shadowlands - 2013 - 03 - Licht und Schatten.wav
Global _ ; other stuff
$lamecommand = "-V 2 " , _ ; encoding settings, may be something like "-b 192 " or "-m m -V 6"
$SelectedFiles = "" ; returned by the file open dialog/button, example:
; "Z:\_Audio_Test|Calexico_(2006) Garden Ruin_01 Cruel.wav|Calexico_(2006) Garden Ruin_02
; Yours and Mine.wav|Calexico_(2006) Garden Ruin_03 Bisbee Blue.wav|Harald Grosskopf_(1980)
; Synthesist_01 So Weit, So Gut.wav|Harald Grosskopf_(1980) Synthesist_02 B.
; Aldrian.wav|Manuel Göttsching_(2005) Die Mulde_01 Schopferische Stille.wav|Manuel
; Göttsching_(2005) Die Mulde_02 Die Mulde.wav" (*** all in one line! ***)
Global _ ; help message displayed in big edit control
$HelpMessage = "Lame Einstellungen:" & @CRLF & _
" Nutze variable Bitrate für eine konstante Qualität, wobei '0' die beste Qualität bei größten Dateien liefert, während '9' die kleinsten Dateien" & @CRLF & _
" mit schlechtester Qualität erzeugt. Konstante Bitrate für eine schwankende Qualität, wobei größere Werte bessere Qualität bedeuten." & @CRLF & _
" Mono z.B. für Hörbücher. Genauer steht's in der Dokumentation zu LAME..." & @CRLF & _
"" & @CRLF & _
"System:" & @CRLF & _
" Anzahl Threads gibt an, wie viele Instanzen von Lame maximal gleichzeitig gestartet werden sollen, je mehr Threads laufen umso schneller sind" & @CRLF & _
" alle Dateien abgearbeitet. Allerdings läuft immer nur eine Instanz pro Quelldatei. Ein zu hoher Wert macht das System träge." & @CRLF & _
" Lösche Quelldatei gibt an, ob die Quelldatei (.WAV) nach der Erzeugung des MP3 gelöscht werden soll." & @CRLF & _
"" & @CRLF & _
"Tagging und Struktur:" & @CRLF & _
" Der ID3 Tag gibt an, wie die Metainformationen aus dem Dateinamen gebildet werden sollen und wie diese im Dateinamen getrennt sind." & @CRLF & _
" Unterstützt werden <Artist>, <Year>, <Album>, <Track#>, <Title> und <Comment>." & @CRLF & _
" Die Dateinamen müssen genau so aufgebaut sein wie in dem angegebenen Muster." & @CRLF & _
" Beispielmuster: <Artist>_(<Year>) <Album>_<Track#> <Title>" & @CRLF & _
" passende Dateinamen:" & @CRLF & _
" Element of Crime_(2005) Mittelpunkt der Welt_01 Delmenhorst.wav" & @CRLF & _
" Loney, Dear_(2009) Dear John_07 Summers.wav" & @CRLF & _
" Struktur gibt an, ob und wie die erzeugten MP3-Dateien unterhalb des Zielverzeichnisses einsortiert werden sollen. Ist kein Zielverzeichnis" & @CRLF & _
" ausgewählt, gilt das Quellverzeichnis als solches. Als Beispiel nehmen wir das Zielverzeichnis E:\neue Musik\" & @CRLF & _
" Beispielmuster: <Artist>\<Year> <Album>\" & @CRLF & _
" Die Dateien von oben würden dann so in den Verzeichnissen " & @CRLF & _
" E:\neue Musik\Element of Crime\2005 Mittelpunkt der Welt\Element of Crime_(2005) Mittelpunkt der Welt_01 Delmenhorst.mp3" & @CRLF & _
" E:\neue Musik\Loney, Dear\2009 Dear John\Loney, Dear_(2009) Dear John_07 Summers.mp3" & @CRLF & _
" zu liegen kommen." & @CRLF & _
"" & @CRLF & _
"Auf geht's..."
; begin Program ****************************************************************************************************************
LoadIniValues () ; Load user's default values
CreateGUI () ; Construct Graphical User Interface
GUISetState(@SW_SHOW, $HdlMainWindow) ; Fire up GUI...
$CIDsuccess = 0 ; Nothing done so far...
Do
$GUImsg = GUIGetMsg()
If $GUImsg <> 0 Then
Switch $GUImsg
Case $CIDvbr ; user switches Radio to use Variable Bitrate Encoding
GUICtrlDelete( $CIDvbrcbr ) ; delete and re-built control for VBR
$usevbr = True
$CIDvbrcbr = GUICtrlCreateCombo ( "", 150, 25, 70, 135)
GUICtrlSetData ( $CIDvbrcbr, "|0|1|2|3|4|5|6|7|8|9|", $vbrquality)
$changed = True ; re-display lame command
Case $CIDcbr ; user switches Radio to use Constant Bitrate Encoding
GUICtrlDelete( $CIDvbrcbr ) ; delete and re-built control for CBR
$usevbr = False
$CIDvbrcbr = GUICtrlCreateCombo ( "", 150, 25, 70, 135)
GUICtrlSetData ( $CIDvbrcbr, "|8|16|24|32|40|48|56|64|96|112|128|160|192|224|256|320|", $bitrate)
$changed = True
Case $CIDmono ; user switches mono on or off
$mono = NOT $mono
$changed = True
Case $CIDvbrcbr ; user selects either vbr-qualitylevel or a constant bitrate
If $usevbr Then
$vbrquality = GUICtrlRead ( $CIDvbrcbr )
Else
$bitrate = GUICtrlRead ( $CIDvbrcbr )
EndIf
$changed = True
Case $CIDThreads ; changing the number of simultaneously running lames
$NumberOfThreads = Int ( GUICtrlRead ( $CIDThreads ))
$changed = True
Case $CIDdstdir ; select destination directory for mp3-files
$dstdir = FileSelectFolder ( "Zielverzeichnis auswählen", $dstdir, 4)
If $dstdir = "" Then
GUICtrlSetData ( $CIDdstdir, "Zielverzeichnis: (keins gewählt)" )
Else
If StringRight ( $dstdir, 1) <> "\" Then $dstdir = $dstdir & "\"
GUICtrlSetData ( $CIDdstdir, "Zielverzeichnis: " & $dstdir )
EndIf
Case $CIDdelsrc ; change of delete source file
$delsrc = NOT $delsrc
Case $CIDaddID3 ; change of using ID3 tags
$addID3 = NOT $addID3
If $addID3 Then ; enable both the format input box and the restruct checkbox:
GUICtrlSetState ( $CIDTagFormat, $GUI_ENABLE )
GUICtrlSetState ( $CIDrestruct, $GUI_ENABLE )
If $restruct Then ; in case of restruct, check it and enable input box for directory structure:
GUICtrlSetState ( $CIDrestruct, $GUI_CHECKED )
GUICtrlSetState ( $CIDrestructPattern, $GUI_ENABLE )
Else ; no restructuring, uncheck it and disable input box for directory structure:
GUICtrlSetState ( $CIDrestruct, $GUI_UNCHECKED )
GUICtrlSetState ( $CIDrestructPattern, $GUI_DISABLE )
EndIf ; $restruct
Else ; no ID3 should be added, so disable tag format input box,
GUICtrlSetState ( $CIDTagFormat, $GUI_DISABLE )
GUICtrlSetState ( $CIDrestruct, $GUI_UNCHECKED ) ; uncheck restructure checkbox
GUICtrlSetState ( $CIDrestruct, $GUI_DISABLE ) ; disable restructure checkbox and
GUICtrlSetState ( $CIDrestructPattern, $GUI_DISABLE ) ; disable input box for directory structure
EndIf ; $addID3
Case $CIDrestruct ; change of using subfolders
$restruct = NOT $restruct
If $restruct Then ; enable input box
GUICtrlSetState ( $CIDrestructPattern, $GUI_ENABLE )
Else ; no subfolders should be used, disable input box:
GUICtrlSetState ( $CIDrestructPattern, $GUI_DISABLE )
EndIf ; $restruct
Case $CIDTagFormat ; user enters a tag format pattern:
$TagFormat = GUICtrlRead ( $CIDTagFormat )
Case $CIDrestructPattern ; user enters a subfolder pattern:
$restructPattern = GUICtrlRead ( $CIDrestructPattern ) ; a check for valid pattern is not done so far!
Case $CIDFileOpen ; user wants to select source .wav-files and start encoding:
$SelectedFiles = FileOpenDialog(" Datei(en) auswählen", $LastSrcDir, "Wave-Dateien (*.wav)", 7 )
If @error <> 0 Then ; user decided to abort file selection:
MsgBox(0,"Dateiauswahldialog abgebrochen", "Keine Dateien gewählt.")
$SelectedFiles = ""
Else ; user has given some files to work on...
If $CIDsuccess <> 0 Then GUICtrlDelete ( $CIDsuccess ) ; if program has done work already, remove the
; label placed by EncoderWork before
$CIDsuccess = EncoderWork($SelectedFiles, $lamecommand, $dstdir, $NumberOfThreads) ; here we go for it!
EndIf ; @error <> 0
EndSwitch
If $changed Then ; lame command or number of threads have been changed
$lamecommand = BuildLameCommand() ; re-build lame command and show it
GuiCtrlSetData ( $CIDlamecommandlabel, "lame " & $lamecommand & " (" & String($NumberOfThreads) & " Threads) using L.A.M.E. encoding engine" )
$changed = False
EndIf ; $changed
EndIf ; $GUImsg <> 0
Until $GUImsg = $GUI_EVENT_CLOSE ; User has finished and wants to quit...
SaveIniValues() ; Save user's default values for the next time
GUIDelete( $HdlMainWindow ) ; Remove GUI
Exit ; END.
; end Program ******************************************************************************************************************
[/autoit] [autoit][/autoit] [autoit]Func ID3parse ( $Form, $FileName )
; generate a proper command line addition for lame to add id3-tags
; $Form looks like: <Artist>_<Album>-<Track#> <Title>
; $Filename is the name of the source file ending in .wav, like "Metric_Fantasies-09 Blindness.wav"
LOCAL $pref ; prefix for lame
; Begin ID3parse
$ID3Artist = "" ; clean up...
$ID3Year = ""
$ID3Album = ""
$ID3Track = ""
$ID3Title = ""
$ID3Comment = ""
$Filename = StringReplace ( $Filename, ".wav", "<wav>", -1, 2) ; easy splitting
If $Form = "" Then
Return "" ; no Form given... -> nothing to return
Else
$pref = "--ignore-tag-errors --add-id3v2 " ; indicate lame to add id3v2 tags and ignore errors
$pref = $pref & ID3stacking ( "", $Form, $Filename ) ; get information from Form and Filename...
EndIf ; $Form = ""
Return $pref
EndFunc ; ID3parse ( $Form, $FileName )
Func ID3stacking ( $Carrier, $Form, $Filename ) ; - recursive -
; $Carrier contains all previous extraced information, $Form & $Filename as above ( ID3parse )
; 1st entry is ID3stacking ( '', '<Artist>_<Album>-<Track#> <Title>', 'Metric_Fantasies-09 Blindness<wav>')
; construct main ID3 info from Form and Filename, as "--ta Metric --tl Fantasies --tn 09 --tt Blindness "
; last char will be a space, because next parameter (source file.wav) for lame follows (later).
LOCAL _
$SelectTag, _ ; What do we process? Artist, Year, Album, Track#, Title or Comment?
$Limiter ; What is between the tags?
; begin ID3stacking
If StringLeft ( $Form, 1 ) = "<" Then ; a tagname follows
$Form = StringTrimLeft ( $Form, 1 ) ; isolate the tagname... Artist>_<Album>-<Track#> <Title>
$SelectTag = LeftOf ( ">", $Form ) ; Got it in $SelectTag: Artist
$Form = RightOf ( ">", $Form ) ; we don't need this part of the form anymore, but keep the rest:
; _<Album>-<Track#> <Title>
If $Form <> "" Then ; Something to do...
$Limiter = LeftOf ( "<", $Form ) ; Got the limiter before the next tag: _
$Form = RightOf ( $Limiter, $Form ) ; Keep the rest of the form: <Album>-<Track#> <Title>
Else ; $Form is empty
$Limiter = "<wav>" ; <wav> is no valid tag, all our filenames given from ID3parse end as <wav>
EndIf ; $Form <> ""
Switch $SelectTag ; Extract selected information from Filename and assign properly
Case "Artist"
$Carrier = $Carrier & "--ta " ; indicate lame what we want...
$ID3Artist = LeftOf ( $Limiter, $Filename ) ; This is not needed for adding ID3 tags, but in order to...
Case "Year"
$Carrier = $Carrier & "--ty "
$ID3Year = LeftOf ( $Limiter, $Filename ) ; ...restructure the destination file in subfolders we...
Case "Album"
$Carrier = $Carrier & "--tl "
$ID3Album = LeftOf ( $Limiter, $Filename ) ; ...keep these infos.
Case "Title"
$Carrier = $Carrier & "--tt "
$ID3Title = LeftOf ( $Limiter, $Filename )
Case "Track#"
$Carrier = $Carrier & "--tn "
$ID3Track = LeftOf ( $Limiter, $Filename )
Case "Comment"
$Carrier = $Carrier & "--tc "
$ID3Comment = LeftOf ( $Limiter, $Filename )
EndSwitch ; $SelectTag
; Now we put this together with the actual characters from the filename, pretty enclosed in double quotes and...
$Carrier = $Carrier & Chr(34) & LeftOf ( $Limiter, $Filename ) & Chr(34) & " " ; with a space at the end
; $Carrier now looks like '--ta "Metric" '
; cut off this from the filename and continue with the rest: "Fantasies-09 Blindness<wav>":
$Filename = RightOf ( $Limiter, $Filename)
; if more than <wav> is remaining in filename and our pattern has workload left, do it again with our so far
; digged cargo - $Filename is more than "<wav>" and $Form is more than or equal to "<Year>":
If (StringLen ( $Filename ) > 5) And (StringLen( $Form ) > 5) Then $Carrier = ID3stacking ( $Carrier, $Form, $Filename )
; 2nd level: ID3stacking ('--ta "Metric" ', '<Album>-<Track#> <Title>', 'Fantasies-09 Blindness<wav>')
; 3rd level: ID3stacking ('--ta "Metric" --tl "Fantasies" ', '<Track#> <Title>', '09 Blindness<wav>')
; 4th level: ID3stacking ('--ta "Metric" --tl "Fantasies" --tn "09" ', '<Title>', 'Blindness<wav>')
; 5th level: ID3stacking ('--ta "Metric" --tl "Fantasies" --tn "09" --tt "Blindness" ', '', '<wav>')
; finish
EndIf ; StringLeft ( $Form, 1 ) = "<"
Return $Carrier ; Got it for now...
EndFunc ; ID3stacking ( $Carrier, $Form, $Filename ) - recursive -
Func EncoderWork ( $SelFiles, $lamepar, $dst, $Threads)
; Start some threads and heat up the CPU...
LOCAL _
$iFile , _ ; index to next source file to process in $FileListArray, starting at 2
$ActiveThreads , _ ; Number of working lames
$iProcess , _ ; index to process number we look at in the main loop
$FileListArray , _ ; will contain all filenames to process, [0] is the quantity + 1, [1] is the path
$Worktime , _ ; TimerInit / TimerDiff used to tell the user how incredible FAST it's all done...
$RunCommand , _ ; String with lame and all command-line parameters for it
$deletedFiles , _ ; counting deleted source files
$workedFiles , _ ; counting encoded (finished) files
$Procs[$Threads][4] ; for each lame running, this array contains process data:
; [n][0] - PID returned by Run().
; Used to (a) check if it is still running and
; (b) to kill it in case of user abort
; [n][1] - Index to source file in $FileListArray
; [n][2] - ControlID of the displayed label during lifetime of PID
; [n][3] - Full path and filename of the destination file created by lame - in case of
; hard user abortion we need to delete this file because it's incomplete.
; begin EncoderWork
$Worktime = TimerInit() ; want to know how long it takes...
GUICtrlSetState ( $CIDFileOpen, $GUI_DISABLE )
GUICtrlSetState ( $CIDvbrcbr, $GUI_DISABLE )
GUICtrlSetState ( $CIDcbr, $GUI_DISABLE )
GUICtrlSetState ( $CIDvbr, $GUI_DISABLE )
GUICtrlSetState ( $CIDmono, $GUI_DISABLE )
GUICtrlSetState ( $CIDThreads, $GUI_DISABLE ) ; at first disable all controls during heavy work...
GUICtrlSetState ( $CIDdelsrc, $GUI_DISABLE )
GUICtrlSetState ( $CIDdstdir, $GUI_DISABLE )
GUICtrlSetState ( $CIDaddid3, $GUI_DISABLE )
GUICtrlSetState ( $CIDTagFormat, $GUI_DISABLE )
GUICtrlSetState ( $CIDrestruct, $GUI_DISABLE )
GUICtrlSetState ( $CIDrestructPattern, $GUI_DISABLE )
GUICtrlDelete ( $CIDhelpdisplay ) ; help not needed anymore, but the GUIplace of this (large) control
; is used for labels of filenames of running lames
; New button to stop after finishing the current running threads:
$CIDStopNew = GUICtrlCreateButton ( "Keine weiteren starten", 10, $GUIheight - 60, 380, 30 )
; New button to hard stop all threads immediately:
$CIDKillAll = GUICtrlCreateButton ( "Alles sofort stoppen!", 410, $GUIheight - 60, 380, 30 )
GUICtrlSetBkColor ( $CIDKillAll, 0xE08080) ; make this one a little red...
$deletedFiles = 0 ; no files deleted so far...
$workedFiles = 0 ; nothing finished so far...
; check if there is only one file to work on like "Y:\Audio\Dingsda.wav" and make it look like "Y:\Audio|Dingsda.wav":
If StringInStr ( $SelFiles,"|") = 0 Then $SelFiles = StringReplace ( $SelFiles, "\", "|", -1)
$FileListArray = StringSplit( $SelFiles, "|") ; all files are now in array elements,
$FileListArray[1] = $FileListArray[1] & "\" ; $FileListArray[1] - containing the path - needs a backslash
$ActiveThreads = 0 ; no lame started so far...
$iFile = 2 ; index points to $FileListArray[2], where we have the first filename
For $iProcess = 0 To $Threads - 1 ; initialize the Processarray
$Procs[$iProcess][0] = 0 ; no PID
$Procs[$iProcess][1] = 0 ; no fileindex
$Procs[$iProcess][2] = 0 ; no label displayed so far (not really needed to be initialized)
$Procs[$iProcess][3] = "" ; no destination file so far (not really needed to beinitialized)
Next ; $iProcess
If $dst = "" Then $dst = $FileListArray[1] ; User has not selected a destination directory, so it is our source dir.
$iProcess = 0 ; Process index starts from 0
; *** Now all preparation is done, here we start to fire up lame instances until all files are encoded ***
Do ; Loop runs through the processarray 0 - 1 - 2 - 3 - 0 - 1 - 2...
; (in case of 4 threads) until all files are processed
$GUImsg = GUIGetMsg () ; Check if the user wants to stop
If $GUImsg <> 0 Then
Switch $GUImsg
Case $CIDStopNew ; do not start any new lame process
$iFile = $FileListArray[0] + 1 ; mock all is done, although it's a lie
GUICtrlSetData ( $CIDStopNew, "Beende nur noch die laufenden...") ; change the button message...
Case $CIDKillAll ; hard stop of all running lames!
GUICtrlSetData ( $CIDKillAll, "Terminiere laufende Prozesse...") ; change the button message...
For $iProcess = 0 To $Threads - 1 ; check all processes
If ProcessExists ( $Procs[$iProcess][0] ) = $Procs[$iProcess][0] Then ; this one is still running
ProcessClose ( $Procs[$iProcess][0] ) ; kill it!
$Procs[$iProcess][1] = -1 ; and mark
EndIf ; ProcessExists ( $Procs[$iProcess][0] ) = $Procs[$iProcess][0]
GUICtrlDelete ( $Procs[$iProcess][2] ) ; delete label of process
Next ; $iProcess
GUICtrlSetData ( $CIDKillAll, "Lösche unfertige Dateien...") ; user is waiting...
Sleep($Threads * 250) ; wait while Windows still kills lames
For $iProcess = 0 To $Threads - 1 ; now check the previously marked processes
; If it has been marked, delete the incomplete file:
If $Procs[$iProcess][1] = -1 Then FileDelete ( $Procs[$iProcess][3])
Next ; $iProcess
ExitLoop ( 1 ) ; all is clean now, leave Do-loop running through processarray
EndSwitch ; $GUImsg
EndIf ; $GUImsg
; check for free process, still files left AND number of running threads
If ($Procs[$iProcess][0] = 0) And ($iFile <= $FileListArray[0]) And ( $ActiveThreads < $Threads) Then
; begin to start a new lame...
$RunCommand = $LameLocation & " " & $lamepar & " " & ID3parse( $TagFormat, $FileListArray[$iFile] ) & _
Chr(34) & $FileListArray[1] & $FileListArray[$iFile] & chr(34)
; so far, we have x:\wherelame\lame.exe -V 1 [--ta "Metric"... ]"Metric_Fantasies-09 Blindness.wav"
; As a result of calling ID3parse, $ID3Artist, $ID3Album, $ID3... are set in case of using tagging
$Procs[$iProcess][3] = $dst ; at least the destination file is placed in destination directory
; in case of using subfolders we now add these to destination:
If $restruct Then $Procs[$iProcess][3] = $Procs[$iProcess][3] & GetNewStruct( $dst )
; finally we add the filename ending up in .mp3 instead of .wav
$Procs[$iProcess][3] = $Procs[$iProcess][3] & StringReplace ( $FileListArray[$iFile], ".wav", ".mp3", -1, 2)
; add this to our command line enclosed in double quotes
$RunCommand = $RunCommand & " " & Chr(34) & $Procs[$iProcess][3] & Chr(34)
$Procs[$iProcess][0] = Run ( $RunCommand,"",@SW_HIDE) ; lame starts working here!
$Procs[$iProcess][1] = $iFile ; save source file index
$Procs[$iProcess][2] = GUICtrlCreateLabel($FileListArray[$iFile], _ ; display a label for the user's eyes
10 + (BitAND($iProcess, 1) * 400), _ ; x-pos in GUI
160 + 10 * $iProcess - 10 * BitAND($iProcess, 1), _ ; y-pos in GUI
390, 15)
$ActiveThreads += 1 ; one more lame running
$iFile += 1 ; next file please
Else ; busy or nothing left to do
Sleep(10)
EndIf ;($Procs[$iProcess][0] = 0) And ($iFile <= $FileListArray[0]) And ( $ActiveThreads < $Threads)
; now for the opposite lane: look for the actual $iProcess if it's finished and was active last time:
If ($Procs[$iProcess][0] <> 0) And (ProcessExists ( $Procs[$iProcess][0] ) = 0) Then
$workedFiles += 1 ; one more file done
$Procs[$iProcess][0] = 0 ; PID done, free it
If $delsrc Then ; user does not need the source file anymore
If FileDelete ( $FileListArray[1] & $FileListArray[$Procs[$iProcess][1]] ) Then $deletedFiles += 1
; one more source file deleted
EndIf ; $delsrc
GUICtrlDelete ( $Procs[$iProcess][2] ) ; remove label displaying filename
$ActiveThreads -= 1 ; a thread is free
EndIf ; (ProcessExists ( $Procs[$iProcess][0] ) = 0) And ($Procs[$iProcess][0] <> 0)
$iProcess += 1 ; next time in Do-loop look at the next process
If $iProcess >= $Threads Then $iProcess = 0 ; in case of overflow, restart at 0
Until ($ActiveThreads = 0) And ($iFile > $FileListArray[0]) ; all threads finisehd and all files processed
$LastSrcDir = $FileListArray[1] ; save this for the next time
GUICtrlSetState ( $CIDFileOpen, $GUI_ENABLE ) ; re-enable GUI - system is not busy anymore
GUICtrlSetState ( $CIDvbrcbr, $GUI_ENABLE )
GUICtrlSetState ( $CIDcbr, $GUI_ENABLE )
GUICtrlSetState ( $CIDvbr, $GUI_ENABLE )
GUICtrlSetState ( $CIDmono, $GUI_ENABLE )
GUICtrlSetState ( $CIDThreads, $GUI_ENABLE )
GUICtrlSetState ( $CIDdstdir, $GUI_ENABLE )
GUICtrlSetState ( $CIDdelsrc, $GUI_ENABLE )
GUICtrlSetState ( $CIDaddid3, $GUI_ENABLE )
If $addID3 Then
GUICtrlSetState ( $CIDTagFormat, $GUI_ENABLE )
GUICtrlSetState ( $CIDrestruct, $GUI_ENABLE )
If $restruct Then GUICtrlSetState ( $CIDrestructPattern, $GUI_ENABLE )
EndIf ; $addID3
GUICtrlDelete ( $CIDStopNew ) ; remove stop button - nothing to stop anymore
GUICtrlDelete ( $CIDKillAll ) ; remove kill button - nothing to kill anymore
; re-display help message
$CIDhelpdisplay = GUICtrlCreateEdit ( $HelpMessage, 30, 150, 740, $GUIheight - 180, BitOr ($ES_READONLY, $ES_AUTOVSCROLL))
GUICtrlSetBkColor ( $CIDhelpdisplay, 0xD0D0D0 )
$Worktime = TimerDiff ($Worktime) ; finished here
$Worktime = Round ($Worktime / 1000, 1) ; display time and number of processed files
Return GUICtrlCreateLabel ("Fertig nach " & String($Worktime) & " s mit " & String($workedFiles) & _
" (gelöscht: " & String($deletedFiles) & ") Dateien.", 400, $GUIheight - 20, 300, 20)
; give back just the controlID of the label - it has to be removed in case of another run
EndFunc ; EncoderWork ( $SelFiles, $lamepar, $dst, $Threads)
Func CreateGUI()
LOCAL _
$i , _
$ThreadComboMenu = "|"
; begin CreateGUI
For $i = 1 To $MaxThreads ; Make a suitable number of threads menu
$ThreadComboMenu = $ThreadComboMenu & String ( $i ) & "|" ; Example "|1|2|3|4|5|6|7|8|" in case of max 8 threads.
Next ; $i
If $NumberOfThreads > $MaxThreads Then $NumberOfThreads = $MaxThreads
$GUIheight = 220 + ( Round ( $MaxThreads / 2 ) * 20 )
If $GUIheight < 270 Then $GUIheight = 270
$HdlMainWindow = GUICreate ( "MultiCoreLame", 800, $GUIheight, $WindowPos[0], $WindowPos[1] )
$CIDlamegroup = GUICtrlCreateGroup ( "Lame Einstellungen", 5, 5, 225, 90 )
$CIDvbr = GUICtrlCreateRadio ( "variable Bitrate", 20, 27, 100, 20 )
$CIDcbr = GUICtrlCreateRadio ( "konstante Bitrate", 20, 57, 100, 20 )
$CIDvbrcbr = GUICtrlCreateCombo ( "", 150, 25, 70, 135 )
If $usevbr Then
GUICtrlSetState ( $CIDvbr, $GUI_CHECKED )
GUICtrlSetData ( $CIDvbrcbr, "|0|1|2|3|4|5|6|7|8|9|", $vbrquality)
Else
GUICtrlSetState ( $CIDcbr, $GUI_CHECKED )
GUICtrlSetData ( $CIDvbrcbr, "|8|16|24|32|40|48|56|64|96|112|128|160|192|224|256|320|", $bitrate )
EndIf ; $usevbr
$CIDmono = GUICtrlCreateCheckbox ( "Mono", 150, 57, 60, 20 )
If $mono Then GUICtrlSetState ( $CIDmono, $GUI_CHECKED )
$CIDsystemgroup = GUICtrlCreateGroup ( "System", 240, 5, 185, 90 )
$CIDThreadlabel = GUICtrlCreateLabel ( "Anzahl Threads:", 250, 27, 80, 20 )
$CIDThreads = GUICtrlCreateCombo ( "", 340, 25, 70, 20 )
GUICtrlSetData ( $CIDThreads, $ThreadComboMenu, String($NumberOfThreads) )
$CIDdelsrc = GUICtrlCreateCheckbox ( "Lösche Quelldatei", 250, 57, 120, 20 )
If $delsrc Then GUICtrlSetState ( $CIDdelsrc, $GUI_CHECKED )
$CIDtagginggroup = GUICtrlCreateGroup ( "Tagging und Struktur", 435, 5, 360, 90 )
$CIDaddid3 = GUICtrlCreateCheckbox ( "ID3 Tag:", 445, 27, 80, 20 )
$CIDTagFormat = GUICtrlCreateInput ( $TagFormat, 520, 27, 260, 20 )
$CIDrestruct = GUICtrlCreateCheckbox ("Struktur:", 445, 57, 80, 20 )
$CIDrestructPattern = GUICtrlCreateInput ( $restructPattern, 520, 57, 260, 20 )
If $addID3 Then
GUICtrlSetState ( $CIDaddID3, $GUI_CHECKED )
Else
GUICtrlSetState ( $CIDTagFormat, $GUI_DISABLE )
GUICtrlSetState ( $CIDrestruct, $GUI_DISABLE )
$restruct = False
EndIf ; Not $addID3
If $restruct Then
GUICtrlSetState ( $CIDrestruct, $GUI_CHECKED )
Else
GUICtrlSetState ( $CIDrestruct, $GUI_UNCHECKED )
GUICtrlSetState ( $CIDrestructpattern, $GUI_DISABLE )
EndIf ; Not $restruct
GUICtrlCreateGroup ( "", -99, -99, 1, 1)
[/autoit] [autoit][/autoit] [autoit]If $dstdir = "" Then
$CIDdstdir = GUICtrlCreateButton ( "Zielverzeichnis: (keins gewählt)", 10, 110, 380, 30 )
Else
$CIDdstdir = GUICtrlCreateButton ( "Zielverzeichnis: " & $dstdir, 10, 110, 380, 30)
EndIf
$CIDFileOpen = GUICtrlCreateButton ( "Dateien auswählen und starten", 410, 110, 380, 30)
$CIDhelpdisplay = GUICtrlCreateEdit ( $HelpMessage, 30, 150, 740, $GUIheight - 180, _
BitOr ($ES_READONLY, $ES_AUTOVSCROLL))
GUICtrlSetBkColor ( $CIDhelpdisplay, 0xD0D0D0 )
$lamecommand = BuildLameCommand()
$CIDlamecommandlabel= GUICtrlCreateLabel ( "", 10, $GUIheight - 20, 380, 18, $BS_CENTER)
; GUICtrlSetBkColor ( $CIDlamecommandlabel, 0xFFEEEE)
EndFunc ; CreateGUI()
Func LoadIniValues()
LOCAL _
$iniFilename = @ScriptDir & "\" & "MultiCoreLame.ini"
; begin LoadIniValues
If FileExists ( $iniFilename ) Then
$bitrate = IniRead ( $iniFilename, "LameParameters", "Bitrate", "192" )
$usevbr = StringToBool ( IniRead ( $iniFilename, "LameParameters", "VBR", "True" ))
$vbrquality = IniRead ( $iniFilename, "LameParameters", "VBRquality", "2" )
$mono = StringToBool ( IniRead ( $iniFilename, "LameParameters", "ModeMono", "False" ))
$LameLocation = IniRead ( $iniFilename, "System", "Encoder", "" )
$NumberOfThreads= Int ( IniRead ( $iniFilename, "System", "Threads", "4" ))
$MaxThreads = Int ( IniRead ( $iniFilename, "System", "MaxThreads", "20" ))
$dstdir = IniRead ( $iniFilename, "System", "DestinationDirectory", "" )
$LastSrcDir = IniRead ( $iniFilename, "System", "LastSourceDirectory", _
@WindowsDir & "\" )
$delsrc = StringToBool ( IniRead ( $iniFilename, "System", "DeleteSourceFile", "False" ))
$WindowPos[0] = Int ( IniRead ( $iniFilename, "System", "WindowPosX", 10))
$WindowPos[1] = Int ( IniRead ( $iniFilename, "System", "WindowPosY", 10))
$addID3 = StringToBool ( IniRead ( $iniFilename, "Tagging", "addID3", "False" ))
$TagFormat = IniRead ( $iniFilename, "Tagging", "Format", "" )
$restruct = StringToBool ( IniRead ( $iniFilename, "Tagging", "Restructure", "False" ))
$restructPattern= IniRead ( $iniFilename, "Tagging", "RestructPattern", "" )
EndIf ; FileExists ( $iniFilename )
; if inifile does not exist, it doesn't matter - BUT:
; Need to know where lame.exe is:
If $LameLocation = "" Then
If FileExists ( @ScriptDir & "\" & "lame.exe" ) Then ; fine, found it just there
$LameLocation = @ScriptDir & "\" & "lame.exe"
Else ; ask user for lame.exe location:
$LameLocation = FileOpenDialog ("Zeige mir die Lame.Exe", @ScriptDir & "\", "Lame.exe (lame.exe)", _
BitOr ( $FD_FILEMUSTEXIST , $FD_PATHMUSTEXIST ) )
If @error = 1 Then ; File selection failed
MsgBox(0,"Fataler Fehler", "Tut mir leid, ohne LAME.EXE kann ich nicht arbeiten")
Exit ; without lame.exe this script is senseless - we're off
EndIf
EndIf ; FileExists ( @ScriptDir & "\" & "lame.exe" )
EndIf ; $LameLocation = ""
EndFunc ; LoadIniValues()
#cs
[/autoit] [autoit][/autoit] [autoit]********************* primitives following *********************
[/autoit] [autoit][/autoit] [autoit]#ce
[/autoit] [autoit][/autoit] [autoit]Func GetNewStruct ( $dst )
LOCAL $path
; begin GetNewStruct
$path = $RestructPattern
$path = StringReplace ( $path, "<Artist>", $ID3Artist )
$path = StringReplace ( $path, "<Album>", $ID3Album )
$path = StringReplace ( $path, "<Year>", $ID3Year )
$path = StringReplace ( $path, "<Track#>", $ID3Track )
$path = StringReplace ( $path, "<Title>", $ID3Title )
$path = StringReplace ( $path, "<Comment>", $ID3Comment )
$path = StringReplace ( $path, "\\", "\" )
If StringRight ( $path, 1 ) <> "\" Then $path = $path & "\"
If Not FileExists ( $dst & $path ) Then DirCreate ( $dst & $path )
Return $path
EndFunc ; GetNewStruct ( $dst )
Func SaveIniValues()
LOCAL $iniFilename = @ScriptDir & "\" & "MultiCoreLame.ini"
; begin SaveIniValues
$WindowPos = WinGetPos ( $HdlMainWindow )
If $dstdir = "" Then $dstdir = $LastSrcDir
IniWrite ( $iniFilename, "LameParameters", "Bitrate", $bitrate )
IniWrite ( $iniFilename, "LameParameters", "VBR", $usevbr)
IniWrite ( $iniFilename, "LameParameters", "VBRquality", $vbrquality)
IniWrite ( $iniFilename, "LameParameters", "ModeMono", $mono)
IniWrite ( $iniFilename, "System", "Encoder", $LameLocation)
IniWrite ( $iniFilename, "System", "Threads", String( $NumberOfThreads ))
IniWrite ( $iniFilename, "System", "DestinationDirectory", $dstdir)
IniWrite ( $iniFilename, "System", "LastSourceDirectory", $LastSrcDir)
IniWrite ( $iniFilename, "System", "DeleteSourceFile", $delsrc)
IniWrite ( $iniFilename, "System", "WindowPosX", String( $WindowPos[0] ))
IniWrite ( $iniFilename, "System", "WindowPosY", String( $WindowPos[1] ))
IniWrite ( $iniFilename, "Tagging", "addID3", $addID3 )
IniWrite ( $iniFilename, "Tagging", "Format", $TagFormat )
IniWrite ( $iniFilename, "Tagging", "Restructure", $restruct )
IniWrite ( $iniFilename, "Tagging", "RestructPattern", $restructPattern )
EndFunc ; SaveIniValues()
Func BuildLameCommand()
LOCAL $commandstring
; begin BuildLameCommand
If $mono Then
$commandstring = "-m m "
Else
$commandstring = ""
EndIf
If $usevbr Then
$commandstring = $commandstring & "-V " & String ( $vbrquality ) & " "
Else
$commandstring = $commandstring & "-b " & String ( $bitrate ) & " "
EndIf
Return $commandstring
EndFunc ; BuildLameCommand()
Func StringToBool($check)
If ($check = "True") Or ($check = "true") Or ($check = "TRUE") Then
Return True
Else
Return False
EndIf
EndFunc ; StringToBool($check)
Func LeftOf ( $sub, $instr)
LOCAL $p
$p = StringInStr ( $instr, $sub )
If $p > 1 Then
Return StringLeft ( $instr, $p - 1 )
Else
Return ""
EndIf
EndFunc ; LeftOf ( $sub, $instr)
Func RightOf ( $sub, $instr)
LOCAL $p
$p = StringInStr ( $instr, $sub )
If ($p > 0) And ($p < StringLen ( $instr )) Then
Return StringRight ( $instr, StringLen ( $instr ) - ($p + (StringLen ( $sub ) - 1)))
Else
Return ""
EndIf
EndFunc ; RightOf ( $sub, $instr)
#cs
[/autoit] [autoit][/autoit] [autoit]********************* end primitives *********************
[/autoit] [autoit][/autoit] [autoit]#ce
[/autoit] [autoit][/autoit] [autoit]#cs
[/autoit] [autoit][/autoit] [autoit]********************* Debug *******************************
[/autoit] [autoit][/autoit] [autoit]Func WriteLog ( $msg )
FileWriteLine ( @ScriptDir & "\" & "MultiCoreLame.log", @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & @MSEC & ": <" & $msg & ">" )
EndFunc ; WriteLog ( $msg )
#ce
[/autoit]Die geschriebene .INI-Datei, die im selben Verzeichnis wie das Script zu liegen kommt, sieht dann ungefähr so aus:
Spoiler anzeigen
[LameParameters]
Bitrate=320
VBR=True
VBRquality=0
ModeMono=False
[System]
Encoder=U:\PortableApps\Lame\huddeltuddelknuddelbaer\lame.exe
Threads=6
MaxThreads=16
DestinationDirectory=E:\mp3\
LastSourceDirectory=Z:\_Audio_Test\
DeleteSourceFile=False
WindowPosX=4727
WindowPosY=323
[Tagging]
Format=<Artist>_(<Year>) <Album>_<Track#> <Title>
addID3=True
Restructure=True
RestructPattern=<Artist>\<Year> <Album>\
Alles anzeigen
Die bitte NICHT hier wechkopieren, weil der Kram auf Eurem System nicht paßt, es ist hier nur zur Ansicht!
Jaja, ich weiß:
* Es gibt schon drölfhausent Fantastilliarden Frontends für Lame. (Ja, aber die gefielen mir nicht so recht)
* Foobar2000 kann das auch, mit der Nutzung aller Prozessorkerne. (Ja, aber bei genügend Threads ist mein Script schneller )
* Das Script könnte unter bestimmten Umständen vielleicht fehlerhaft arbeiten. (Ja, gerne nehme ich Hinweise entgegen. So'n Ding ist halt "nie" fertig)
* Es haben sich schon welche totformatiert. (ich wollt's grad' übersichtlich halten)
* Es haben sich schon welche totkommentiert. (ist klar, der wahre AutoIt-Profi liest so'n bischen Code morgens mit halbem Auge noch vor dem ersten Kaffee runter und hat schon 42 Bugs gefunden, davon 23 tödliche... - ich bin aber kein solcher Nerd und wenn ich "das Ding" ein halbes Jahr nicht angesehen habe, verstehe ich mein eigenes Gefummel da nicht mehr... außerdem KÖNNTE es vielleicht sein, daß ein Neuling (zu denen ich mich zähle) es so etwas einfacher hat, den fremden Quelltext zu verstehen und womöglich etwas abzugucken.
Nun setze ich mich ganz bewußt Eurer vernichtenden Kritik aus, um (vielleicht) noch die groben Böcke (?) um die Ohren gehauen zu bekommen...
Gruß Moon