powershell script to convert flac to aac

Discussion in 'Scripting' started by ohenry, Mar 3, 2019.

  1. ohenry

    ohenry MDL Novice

    Aug 10, 2009
    I recently spent a little time learning the rudiments of powershell, and I put together a script to do something I often do, reencode files from flac format to m4a (aac). I was using a semi-batch file to do this previously, and this seems to actually be better. I say “semi-batch” as it is a .btm file, JPSoft TCC. This is the direct successor to 4DOS from back in the day, and highly recommended as a replacement for cmd.exe.

    So anyway this powershell script starts in the current working directory, and attempts to convert any files with extension flac to an aac file, vbr, high quality, with extension m4a. And it finds and converts any flac files in nested subdirectories as well.

    Known limitations:

    This script does not like file or directory names with square brackets “ [ ] “, so be warned.

    You will need to find and download “ffmpeg-hi10-heaac” (google is your friend). The normal ffmpeg does not include libfdk_aac which you need to do high quality vbr aac files.

    I have set the maximum number of simultaneous processes to 8, which seems to work quite well on my system, Intel i5 7600K with 24 gigabytes of memory. You will have to experiment to find the best number for your system.

    It is assumed that you have no cmd shells running when you start this script. I never do, because I use TCC (see above) instead of cmd.exe.

    $s = Get-Date
    $filelist = Get-ChildItem -Path .\ -Filter *.flac -Recurse
    $cmdlines = @()
    $p1 = " /c c:\bin\ffmpeg-hi10-heaac.exe -i ";
    $p2 = " -c:a libfdk_aac -vbr 5 -map_metadata 0 -vn -id3v2_version 3  ";
    $filelist | ForEach-Object {
        if ( $_.length -lt 1kb) {
            $ln = $_.Fullname
            echo "skipping $ln less than 1kb"
        } else {
            $infile = $_.FullName
            $opfile = $_.FullName -replace '\.flac','.m4a'
            if (Test-Path $opfile) {
                echo "skipping $opfile as it exists"
            } else {
                $cmdline = $p1 + '"' + $infile +'" ' + $p2 + '"' + $opfile + '"'
                $cmdlines += $cmdline
    if (-not $cmdlines) {exit}
    echo $cmdlines
    echo "================ after echo cmdlines ================"
    foreach ($item in $cmdlines) {
        echo $item
        Start-Process -FilePath "$env:comspec" -ArgumentList $item
        $cmds_running = Get-Process -name cmd
        [int]$cmdx = $cmds_running.count
        while ($cmdx -ge 8) {
            echo "$cmdx cmd shells, sleeping "
            Start-Sleep -Milliseconds 500
            $cmds_running = Get-Process -name cmd
            [int]$cmdx = $cmds_running.count
            echo "after sleep $cmdx cmd shells running"
    Wait-Process cmd
    $e = Get-Date
    $elapsed = ($e - $s).TotalSeconds
    echo "Time $elapsed"
    $x1 = dir -recurse *.m4a|measure-object
    [int]$got = $x1.count
    [int]$max2 = [int]$cmdlines.GetUpperBound(0) + 1
    echo "m4a files: $got  Expected: $max2 "