Sunday
Mar032013

Merge Many MP3 files into a single MP3 file with PowerShell and FFMPEG  

This a follow up from my post yesterday on using PowerShell and FFMPEG to trim many MP3 files at once. The second part of my task was to merge those MP3 files into one big MP3 file.

The script is below.

Important Note: For a reason I'm not clear on I had to run PowerShell as Administrator for FFMPEG to successfully create the merged MP3.


$ffmpeg_exe = "D:\ffmpeg\bin\ffmpeg.exe"

Function Folder_MP3_Merge
{
    Param(
        [Parameter(Mandatory=$true)]
        [String] $FromFolder,
        
        [Parameter(Mandatory=$true)]
        [String] $ToFile

    )

    Process
    {
        $count=0
        $fromitems = (Get-ChildItem $FromFolder -Filter "*.mp3" -recurse -File)
        Write-Verbose "`t$fromitem"
        $fromnames = @()
        foreach ($fromitem in $fromitems)
        {
            $basename = $fromitem.Name
            Write-Verbose "Item [$count]: $basename"          
            $from_fullname = $fromitem.FullName
            $fromnames += $from_fullname
            $count++
        }
        $fromnames_all = [string]::join('|', $fromnames )

        if (Test-Path $ToFile)
        {
            Remove-Item $ToFile
        }

        $cmdline =  "$ffmpeg_exe -i `"concat:$fromnames_all`" -acodec copy `"$ToFile`" "
        Write-Verbose "`t CMD: $cmdline"
        invoke-expression -command $cmdline


    }
}

 
Folder_MP3_Merge -FromFolder "D:\mymp3files" -ToFile "D:\single.mp3"  -Verbose

Saturday
Mar022013

Batch Trimming a Folder MP3 Files Recursively with PowerShell and FFMPEG  

Similar to my previous post in which I was using PowerShell and ImageMagick, these evening I needed to take a folder of large mp3 files and trim them (extract only the first minute of audio) and save the audio into another folder.

For my audio transformation I used FFMPEG –  which rules. All I needed to do is write the Script that called. The code is below and is been written to follow a general pattern that these kinds of batch operations take. Thus, you should be able to modify it easily to suit you needs.

 

$ffmpeg_exe = "D:\ffmpeg\bin\ffmpeg.exe"

Function Folder_to_Folder_MP3_Trim
{
    Param(
        [Parameter(Mandatory=$true)]
        [String] $FromFolder,
        
        [Parameter(Mandatory=$true)]
        [String] $ToFolder,

        [Parameter(Mandatory=$false)]
        [String] $FromInclude

    )

    Process
    {
        $count=0
        $fromitems = Get-ChildItem $FromFolder -include $FromInclude -recurse
        foreach ($fromitem in $fromitems)
        {
            $basename = $fromitem.Name
            Write-Verbose "Item [$count]: $basename"
            if ($fromitem.PsIsContainer -eq $true)
            {
                Write-Verbose "`TYPE: Directory"
            }
            else
            {
                Write-Verbose "`tTYPE: File"
            }
           
            $from_fullname = $fromitem.FullName
            Write-Verbose "`tFROM: $from_fullname"
            $to_fullname  = Join-Path $ToFolder $fromitem.FullName.Substring( $FromFolder.Length )
            Write-Verbose "`t  TO: $to_fullname"

 
            if ($fromitem.PsIsContainer -eq $true)
            {
                Write-Verbose "`TYPE: Directory"
            }
            else
            {
                Write-Verbose "`tTYPE: File"
            }


            $to_directory = Split-Path $to_fullname -Parent


            if ( !(Test-Path $to_directory))
            {
                Write-Verbose "`tDestination directory does not exist"
                New-Item $to_directory -ItemType Directory
            }

            if ( Test-Path $to_fullname)
            {
                Write-Verbose "`tDestination item exists"
                if ($fromitem.PsIsContainer -eq $true)
                {
                }
                else
                {
                    Write-Verbose "`tDeleting existing destination item"
                    Remove-Item $to_fullname
                }               
            }
            $count++

            $cmdline =  "$ffmpeg_exe -t 60 -i `"$from_fullname`" -acodec copy `"$to_fullname`" "
            Write-Verbose "`t CMD: $cmdline"
            invoke-expression -command $cmdline
        }    
        Write-Verbose "Handled $count items"
    }
}

 
Folder_to_Folder_MP3_Trim -FromFolder "D:\InputAudio" -ToFolder "D:\OutputAudio"  -Verbose

Saturday
Mar022013

Visio 2013 Unboxing  

Among the more boring unboxing experiences I've ever had.

 

First, it comes in a smaller package –  and suspiciously light. Below you can compare it to the Office Professional 2010 package

IMG_20130302_122827

 

Inside is a smaller box. As you can see I purchased it from the Microsoft Company Store.

IMG_20130302_122853

 

Opening up that white box reveals two cards.

IMG_20130302_122905

 

 

And here it is ….

IMG_20130302_122929

 

IMG_20130302_122939

Thrilling!

 

Sunday
Feb242013

Interlude: Crystal Timelapses + Deus Ex: HR  

A beautiful macro lens video using part of the Deus EX: HR Soundtrack. 

Crystal Timelapses from Mark Svoboda on Vimeo.

http://vimeo.com/58951491

Sunday
Feb172013

Reliable Path Navigation in PowerShell based on Script Location  

I've forgotten and re-learned this several times in the past month few months –  that's means it's time for a blog post.

Summary: I'm going to show how to make your scripts more resilient to common issues with your current directory.

Let's start with my scenario as shown below. I need my PowerShell script Deploy.PS1 one to copy MyProject.DLL somewhere else.

Snap00251

Our first attempt at this will be to use relative paths like this in Deploy.PS!

copy ..\Bin\Debug\MyProject.DLL D:\outputfolder

The weakness of this approach is that the “current directory” is sensitive to where your PowerShell host is started from. For example if you launch PowerShell.exe by default your location will look something like “C:\users\username”

Also, in the course of your PowerShell session, you may have changed your current directory to some other location.

We need a more reliable way of traversing from where the Deploy.PS1 script exists –  regardless of the current path.

Fortunately this is not very hard!

First, let's figure out the absolute filename for the script. We simply get this from the value of $myinvocation.mycommand.path

    $script_path = $myinvocation.mycommand.path

Now, we find the location of the “Scripts” folder

    $script_folder = Split-Path $script_path -Parent

We go up once more to get to “MyProject”

    $project_path = Split-Path $script_folder -Parent

Navigate down into “bin/Debug”

    $bindebug_path = Join-Path $project_path "bin/Debug"

And finally get the location of the DLL

    $localdll = Join-Path $bindebug_path "MyProject.dll"

Here's the complete script

$script_path = $myinvocation.mycommand.path
$script_folder = Split-Path $script_path -Parent
$project_path = Split-Path $script_folder -Parent
$bindebug_path = Join-Path $project_path "bin/Debug"
$localdll = Join-Path $bindebug_path "MyProject.dll"

So now we've seen three things in action:

  • How to find where the currently runing script is located –  by using the value of $myinvocation.mycommand.path
  • Given a path, how to to get the parent folder –  by using the Split-Path cmdlet
  • How to append paths –  by using the Join-Path cmdlet

If you want to condense this even further, you can get it done in one line:

$localdll = Join-Path $MyInvocation.MyCommand.Path "../../bin/Debug"