Posts Tagged ‘while’

Split a long mp3 audio file into 3 min files

Wednesday, July 29th, 2015

After some frustration trying to get mp3splt to work, I caved in and wrote a script to split apart a large audio file into many 3min chunks. Save this in mp3split.sh:

#!/bin/bash
big="$1"
duration_stamp=$(ffmpeg -i "$big" 2>&1 | grep Duration | sed 's/^.*Duration: *\([^ ,]*\),.*/\1/g')
title=$(ffmpeg -i "$big" 2>&1  | grep "title *:" | sed 's/^.*title *: *\(.*\)/\1/g')
# get minutes as a raw integer number (rounded up)
prefix=$(basename "$big" .mp3)
echo $duration_stamp
mins=$(echo "$duration_stamp" | sed 's/\([0-9]*\):\([0-9]*\):\([0-9]*\)\.\([0-9]*\)/\1*60+\2+\3\/60+\4\/60\/100/g' | bc -l | python -c "import math; print int(math.ceil(float(raw_input())))")
ss="0"
count="1"
total_count=$(echo "$mins/3+1" | bc)
while [ "$ss" -lt "$mins" ]
do
  zcount=$(printf "%05d" $count)
  ss_hours=$(echo "$ss/60" | bc)
  ss_mins=$(echo "$ss%60" | bc)
  ss_stamp=$(printf "%02d:%02d:00" $ss_hours $ss_mins)
  ffmpeg -i "$big" -acodec copy -t 00:03:00 -ss $ss_stamp -metadata track="$count/$total_count" -metadata title="$title $zcount" "$prefix-$zcount.mp3" 
  ss=$[$ss+3]
  count=$[$count+1]
done

The execute mp3split.sh my-long-file.mp3. This will output a sequence of files:

my-long-file-00001.mp3
my-long-file-00002.mp3
my-long-file-00003.mp3
my-long-file-00004.mp3
...

Each will retain the meta data from the original file except the file number will be appended to the track name and the track number will be set accordingly (i.e. this will work well for splitting enormous audiobook files into file lists that play in the correct sequence on an iphone).

Note: mp3splt really seems like the right tool for this. It supposedly has fancy features like silence detection and presumably won’t reload the file for each new split.

Parsing optional input parameters/arguments in MATLAB function

Thursday, August 29th, 2013

Here’s some boilerplate code I use for parsing additional, optional input parameters when I write a matlab function. Usual I structure my matlab function prototypes as follows:

function C = function_name(A,B,varargin)

I comment this prototype with a message that’s very useful when issuing help function_name:

% FUNCTION_NAME This is a high-level description of what function_name takes
% as input, what it does and what it produces as output
% 
% C = function_name(A,B)
% C = function_name(A,B,'ParameterName',ParameterValue)
%
% Inputs:
%   A  num_cols by num_rows matrix of blah blah blah
%   B  num_cols by num_rows matrix of blah blah blah
%   Optional:
%     'ParameterName1' followed by an integer blah blah {1}
%     'ParameterName2' followed by one of 'foo','bar',{'oof'} blah blah
% Output:
%   C  num_cols by num_rows matrix of blah blah blah
%

I parse the optional inputs with a while loop and switch like this:

% defaults for optional parameters
parameter_value1 = 1;
parameter_value2 = 'oof';

% parse optional input parameters
v = 1;
while v < numel(varargin)
  switch varargin{v}
  case 'ParameterName1'
    assert(v+1<=numel(varargin));
    v = v+1;
    parameter_value1 = varargin{v};
  case 'ParameterName2'
    assert(v+1<=numel(varargin));
    v = v+1;
    parameter_value2 = varargin{v};
  otherwise
    error('Unsupported parameter: %s',varargin{v});
  end
  v = v+1;
end

Update: I should probably be using matlab’s built-in inputParser class, but it means that parameter names have to match variable names in my code. And variables are stored as fields in the inputParse instance: e.g. parser.Results.variable_name1. The advantage though is that it can easily handle input type validation.

Here’s an updated custom optional input parser. So far without validation, though it seems clear how to add support via function handles, e.g. @isnumeric, @islogical, @() customthing... .

  % default values
  variable_name1 = false;
  variable_name2 = [1,2,3];
  % Map of parameter names to variable names
  params_to_variables = containers.Map( ...
    {'ParamName1','ParamName2'}, ...
    {'variable_name1','variable_name2'});
  v = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace 
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end