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: , , ,

2006-04-05

Timidity++ compiling for cygwin

Timidity++
As stated in another thread, Timidity++ is a cool program to play (and convert) midi files. As I'm using it to convert midi files to .wav files (and then burn them to cd), I love to have a similar possibility under windows.

cygwin compilation
So I set out to compile Timidity++ in cygwin:
download the source from http://timidity.sourceforge.net/ and run cygwin for following:
  • tar jxf TiMidity++-2.13.0.tar.bz2
  • cd TiMidity++-2.13.0
  • bash ./configure --enable-interface=ncurses,gtk --enable-network --enable-audio=w32
  • export PATH=$PATH:. && make
  • make install
Configure TiMidity++
To run timidity correctly, you need a timidity.cfg file. Put it in %SystemRoot% (probably c:\windows). You can find one at http://home.swipnet.se/~w-10694/docs/timidity.cfg. This file makes references to directories:
dir /usr/local/lib/timidity

Now you only have to get .pat files and put them in that directory. You can get a copy of eawpats12_full.rar in http://people.fruitsalad.org/lauri/stuff/eawpats12_full.rar, unrar it to /usr/local/lib/timidity (as configured in timidity.cfg).

running timidity
It works:
timidity -int fn039russians.mid

Or if for instance you wanna convert a midi to a wav (which is what I wanted initially)
timidity --output-mode=w --output-file=result.wav fn039russians.mid

But for that look in the thread midi to wav conversion

Labels: , , ,

2006-03-02

MIDI to WAV conversion

Situation:
I was having a couple of MIDI files that I wanted (needed) to put on music CD's. My way was to convert them first to wav or mp3 files, prior to putting them on CD using a program like Ahead Nero (you can find it if your writer was not providing it).

Tools:
TiMidity++ is a converter that converts some MIDI files into audio-files (like RIFF WAVE).

These Distributions came with an "enough" configured timidity-package out of the box:

  • SuSE 9.0 (YaST - Software - timidity)
  • Debian 3.1a (apt-get install freepats timidity timidity-interfaces-extra)

If you have a TiMidity installation that's well-configured (capable of playing a midi-file on your (linux-) system), you'll be able to use it to save wav files.

Short way:

timidity --output-mode=w --output-file=result.wav source.mid

Long way:
You can first check your player, if at least it produces correct audio (through the speakers of the system) by executing

timidity source.mid

If this doesn't produce correct (evt. musical) sound, you should check the configuration of your timidity, prior to continuing here.

Using this command-line instruction, you create the wav file of the a midi file.

timidity --output-mode=w --output-file=result.wav source.mid

I use to reduce size of the files:

timitidy --sampling-freq=16000 --output-mode=w --output-file=result.wav source.mid
If I want only one single voice (or mute some channels), I use:
timidity --mute=0,-4 --output-mode=w --output-file=result.wav source.mid
This previous example mutes all voices (0) and then de-mutes voice 4 (in my case almost always the bass-line).

Labels: , , ,