2006-04-13

Creating separate .wav files for different voices in a midi file.

This script will generate .wav files for separate tracks of a midi-file.

Timidity++ is used for this. Timidity should first be configured to be able to play midi files (to be certain your configuration has a working sound-configuration (like using eawpats).

The script uses cat, echo, mkdir, sed and timidity (all but timidity should not be a problem in any posix system).

The script is to be fed with an action-file with lines containing
midi-file-name followed by space-separated voice-directory-names.
e.g. execute
towav.sh --no_all --action config.towav

with config.towav holding:

mymidi/file1.mid solo piano1 piano2 nothing nothing drum
file2.mid sop1 sop2 alt1 alt2 ten bar bas
...


for more info, read the code OR execute
towav.sh --help

Here's the script (I call it towav.sh)

#!/bin/bash
# Filename: towav.sh
# Author: Dieter Demerre
# Revision: $Revision:$
# Project: midi to wav
# Copyright: GPL (http://www.gnu.org/licenses/licenses.html)
# History:
#
# Description:
# The file script will produce single-voice .wav files (from midi files)
#
# Requirements:
# scripts expects cat, echo, mkdir, sed and timidity to be reachable in the path.
#

PROGRAMNAME="MIDI to VOICE WAV"
PROGRAMVERSION="Rel. 1.0 2006-04-13"
# INITIALIZATION SECTION
# This section is NOT in function, to pre-generate global variables.
actionfile=""
traceoption=""
createdirs=0
overwrite=0
createall=1
targetdir="."
usefilevoice=0

CAT="cat"
ECHO="echo"
MKDIR="mkdir -p"
SED="sed"
TIMIDITY="timidity"

# CODE SECTION
# To view or adapt actuall execution, go to end of file to see
# main function call (and just above, the implementation)
function printUsage
{
${CAT} <<END_OF_USAGE

Usage:
------
towav <option>+

where <option> being amongst
------
--action <file>
REQUIRED OPTION
Will read filenames to convert (and corresponding voice-names) from <file>
<file> should have lines with space-separated tokens:
e.g.
<filename1> <voice1> <voice2>
<filename2> <voice1>

--complete
Will create "complete" voice-files. This is, when a track starts with "silence" this silence is also put
in the .wav file. Omit this option to have voice-track start at first note instead.
This option is very usefull if you try to mix the voices afterwards (like with soxmix).

--createdirs
Will try to create required directories.

--help
Will output this display.

--no_all
will prevent the production of a .wav file with ALL voices.

--overwrite
will cause existing (.wav) files to be overwritten.

--targetdir <dir>
<dir> is main output-directory in which directories wherein the output-files are to be created.

--use_filevoice
will create file/voice.wav files i.s.o voice/file.wav

END_OF_USAGE
}

function test_dir
{
# Usage:
# test_dir <dir>
# with <dir> directory to be created if allowed
if [ $# -ne 1 ]; then ${ECHO} "${FUNCNAME} with invalid nr of arguments $#" >&2; exit; fi
if [ ! -d "${1}" -a ! -z "${createdirs}" -a 0 -ne ${createdirs} ]; then
${MKDIR} "${1}"
fi
}

function compose_voicefilename
{
# Usage:
# compose_voicefilename <base> <voice>
if [ $# -ne 2 ]; then ${ECHO} "${FUNCNAME} with invalid nr of arguments $#" >&2; exit; fi
if [ ${usefilevoice} -ne 0 ]; then
dir=${targetdir}/${1};
voicefile=${dir}/${2}.wav;
else
dir=${targetdir}/${2};
voicefile=${dir}/${1}.wav;
fi
}

function allmidi2wav
{
# Usage:
# allmidi2wav <midi-file> <voice>+
# with <voice>+ in order they are in midi-file.
#
if [ $# -lt 2 ]; then ${ECHO} "${FUNCNAME} with invalid nr of arguments $#" >&2; exit; fi
midi_file=$1;
base=`basename ${midi_file}|${SED} 's/\.mid$//;s/\.midi$//;'`
if [ ! -f ${midi_file} ]; then
${ECHO} "Could not find input midi-file ${midi_file}" >&2
else
voicenr=1;
shift 1;
while [ $# -gt 0 ]; do
voice=${1};
compose_voicefilename ${base} ${voice}
options="${traceoption} --mute=0,-${voicenr} "
midi_to_wav ${midi_file} ${voicefile} "${options}"
shift 1;
voicenr=$[ $voicenr + 1 ]
done
if [ ${createall} -ne "0" ]; then
compose_voicefilename ${base} "all"
options=" "
midi_to_wav ${midi_file} ${voicefile} "${options}"
fi
fi
}

function midi_to_wav
{
# Usage:
# midi_to_wav <inputfile> <outputfile> <convertoptions>
local inputfile=$1;
if [ ! -s "${inputfile}" ]; then
${ECHO} "Could not find input-file ${inputfile}." >&2;
return
fi
local outputfile=$2;
dir=`dirname ${outputfile}`
test_dir ${dir}
if [ ! -d ${dir} ]; then
${ECHO} "could not find directory ${dir}." >&2;
elif [ ${overwrite} -eq 0 -a -s ${outputfile} ]; then
${ECHO} "Found already existing ${outputfile}."
else
local options=$3;
${TIMIDITY} ${options} --output-mode=w --output-file=${outputfile} ${inputfile}
fi
}

function EvaluateArguments
{
while [ ${#} -gt 0 ]; do
case "${1}" in
--action)
shift
if [ ${#} -gt 0 -a -f ${1} ]; then
actionfile=${1}
${ECHO} "Will perform actions from ${actionfile}"
else
${ECHO} "Could not find action file"
actionfile=""
fi
;;
--complete)
${ECHO} "Will produce silence-preceded voice-files"
traceoption="--trace"
;;
--createdirs)
${ECHO} "Will try to create required directories"
createdirs=1
;;
--help)
actionfile=""
return
;;
--no_all)
${ECHO} "Will not generate file for all voices"
createall=0
;;
--overwrite)
${ECHO} "Will overwrite existing files"
overwrite=1
;;
--targetdir)
shift
if [ ${#} -gt 0 ]; then
targetdir=${1}
${ECHO} "Will create voice-parts in directory ${targetdir}"
else
${ECHO} "Could not find target directory" >&2
targetdir=""
fi
;;
--use_filevoice)
${ECHO} "Will produce file/voice.wav files i.s.o voice/file.wav"
usefilevoice=1
;;
*)
${ECHO} "Unknown option $1" >&2
;;
esac
shift
done
}

function ExecuteActions
{
if [ -z "${actionfile}" -o ! -f "${actionfile}" ]; then
${ECHO} "no action ${actionfile} file specified or found" >&2
printUsage
else
${ECHO} "Now evaluating ${actionfile}"
3<${actionfile}
read -a line <&3
while [ ! -z "${line}" ]; do
if [ ! -f ${line[0]} ]; then
${ECHO} "input midi file ${line[0]} was not found" >&2
else
allmidi2wav ${line[*]}
fi
read -a line <&3
done
fi
}

function main
{
${ECHO} ${PROGRAMNAME}
${ECHO} ${PROGRAMVERSION}
${ECHO} "----------------------------"
EvaluateArguments $@
test_dir ${targetdir}
if [ ! -d ${targetdir} ]; then
${ECHO} "could not find target directory ${targetdir}" >&2
else
ExecuteActions
fi
}

main $@

Labels: , , ,

0 Comments:

Post a Comment

<< Home