midisox - a SoX-like workalike, for handling MIDI files


 > midisox [global-options]   \
   [format-options] infile1 [[format-options] infile2] ...   \
   [format-options] outfile   \
   [effect [effect-options]] ...

 > sox chorus.wav chorus.wav mid8.wav chorus.wav out.wav
 > play out.wav
 > midisox chorus.mid chorus.mid mid8.mid chorus.mid out.mid
 > aplaymidi out.mid
 > midisox -M bass.mid pno.mid -v 1.1 horns.mid soar.mid verse.mid
 > midisox -M bass.mid pno.mid voice.mid - | aplaymidi -
 > midisox -M http://mid.com/drms.mid pno.mid voice.mid -d
 > muscript -midi chords | midisox -M - bass.mid -d
 > muscript -midi chords | midisox - -n stat
 > midisox -M "|midisox chords.mid - pitch -200" solo.mid out.mid
 > midisox impro.mid riff.mid trim 37.2 3.4
 > midisox --help ; midisox --help-effect=all


Midisox is a tool for working on MIDI files, with a calling interface modelled, as far as possible, on that of SoX, which is a well-established tool for working on audio files.

Midisox standardises all its files to a tick-rate of 1000 ticks/sec. This makes it possible to mix them together. But it does make it hard to load them into music-typesetting software afterwards and have the beats recognised. . .

Midisox assumes at various places that it is working on a General-Midi file: for example, the pitch effect will not try to transpose the drumkit on Channel 9.

Midisox is available in three versions, one in Python3, one in Perl and one in Lua.


-h, --help

Show version number and Helpful usage information


Show usage information on the specified effect (or "all").


Prompt before overwriting an existing file.

-m | -M | --combine concatenate|merge|mix|sequence

Select the input file combining method; -m means mix, -M merge. If the mix combining method is selected (with -m) then two or more input files must be given and will all be mixed together into one MIDI-track. A mixed file cannot be un-mixed.

If the merge combining method is selected (with -M), then the merged file contains all of the MIDI-tracks from all of the input files; un-merging is possible using multiple invocations of midisox with the mixer effect. The merging process attempts to avoid channel-conflicts by renumbering channels in the later files as necessary (however, a total of only fifteen MIDI-channels is available).

The default is sequence.


Displays the version number.


There is only one file-format-option available:

-v, --volume FACTOR

Adjusts the volume (specifically, the velocity parameter of all the notes) by a factor of FACTOR. A factor less than 1 decreases the volume; greater than 1 increases it.

Files can be either filenames, or
  meaning STDIN or STDOUT accordingly
"|program [options] ..."   specifies that the given program's stdout be used as an input file
http://wherever/whatever.mid   will fetch any valid URL as an input file
-d   meaning the "default" output-device, i.e. the MIDI will be fed into aplaymidi so you can hear it
-n   meaning a null output-device (useful with the stat effect)

EFFECTS:   compand, echo, fade, key, mixer, pad, pan, pitch, quantise, repeat, stat, tempo, trim, vol

compand   gradient   {channel:gradient}

Adjusts the velocity of all notes closer to (or away from) 100.   If the gradient parameter is 0 every note gets volume 100, if it is 1.0 there is no effect, if it is greater than 1.0 there is expansion, and if it is negative the loud notes become soft and the soft notes loud.   The default value is 0.5.   Individual channels can be given individual gradients.   The syntax of this effect is not the same as its SoX equivalent.

echo   gain-in   gain-out   <delay   decay>

Adds echoing to the audio.   Each delay decay pair gives the delay in milliseconds and the decay of that echo.   Gain-in and gain-out are ignored, they are there for compatibilty with SoX. The echo effect triples the number of channels in the MIDI, so doesn't work well if there are more than 5 channels initially.
E.g.:   echo 1 1 240 0.6 450 0.3

For a more elaborately configurable echo effect, see midiecho

fade   fade-in-length   [stop-time [fade-out-length]]

Adds a fade effect to the beginning, end, or both of the MIDI.   Fade-ins start from the beginning and ramp the volume (specifically, the velocity parameter of all the notes) from zero to full, over fade-in-length seconds.   Specify 0 seconds if no fade-in is wanted.

For fade-outs, the MIDI will be truncated at stop-time, and the volume will be ramped from full down to zero starting at fade-out-length seconds before the stop-time.   If fade-out-length is not specified, it defaults to the same value as fade-in-length.   No fade-out is performed if stop-time is not specified.   If the stop-time is specified as 0, it will be set to the end of the MIDI.   Times are specified in seconds: ss.frac

key   shift  { channel:shift }

Changes the key (i.e. pitch but not tempo). This is just an alias for the pitch effect.

mixer   < channel[:to_channel] >

Reduces the number of MIDI channels, by selecting just some of them and combining these (if necessary) into one track.   The channel parameters are the channel-numbers 0 ... 15, for example   mixer 9   selects just the drumkit.   If an optional to_channel is specified, the selected channel will be remapped to the to_channel; for example,   mixer 3:1   will select just channel 3 and renumber it to channel 1.
If a channel number begins with a minus (including -0 !) then that channel will be suppressed, and the others transmitted.
The syntax of this effect is not the same as its SoX equivalent.

pad { length[@position] }     or     pad   length_at_start   length_at_end

Pads the MIDI with silence, at the beginning, the end, or at specified points within the file.   Both length and position are specified in seconds.   length is the amount of silence to insert, and   position the position at which to insert it.   Any number of lengths and positions may be specified, provided that each specified position is not less that the previous one.   position is optional for the first and last lengths specified, and if omitted they correspond to the beginning and end respectively.   For example:   pad 2 2   adds two seconds of silence at each end, whilst   pad 2.5@180   inserts 2.5 seconds of silence 3 minutes into the MIDI.   If silence is wanted only at the end, specify a zero-length pad at the start.

pan   direction

Pans all the MIDI-channels from one side to another. The direction is a value from -1 to 1; -1 represents far-left and 1 represents far-right.

pitch   shift   { channel:shift }

Changes the pitch (i.e. key but not tempo).   shift gives the pitch-shift, as positive or negative "cents" (i.e. 100ths of a semitone). However, currently all pitch-shifts get rounded to the nearest 100 cents, i.e. to the nearest semitone.   Individual channels (0..15) can be given individual shifts.

quantise   length { channel:length }     or     quantize   length { channel:length }

Adjusts the beginnings of all the notes to be a multiple of length seconds since the previous note.   If the length is greater than 30 then it is considered to be in milliseconds.   Channels for which length is zero do not get quantised.   quantise and quantize are synonyms.   This is a MIDI-related effect, and is not present in Sox.

repeat   count

Repeat the entire MIDI count times.   Note that repeating one time doubles the length: the original MIDI plus the one repeat.

stat   [-freq]

Does a statistical check on the MIDI, and prints results on stderr.
This sox-compatible behaviour means if you want to grep the output, you redirect stderr, e.g.:
    midisox mix3.mid -n stat 2>&1 | grep patch_changes_by_track
    midisox mix3.mid -n stat 2>&1 | grep nticks

The MIDI is passed unmodified through the processing chain.
The -freq option calculates the input's MIDI-pitch-spectrum (60 = middle-C) and prints it to stderr before the rest of the stats.

tempo   factor

Changes the tempo (but not the pitch).   factor gives the ratio of new tempo to the old tempo. So if factor > 1.0, then the MIDI will be speeded up.

trim   start [length]

Outputs only the segment of the file starting at start seconds, and ending length seconds later, or at the end if length is not specified. To preserve instruments, however, the latest patch-setting event in each channel is preserved, even if it occurred before the start of the segment.

vol   increment   { channel:increment }

Adjusts the volume (velocity) of all notes by a fixed increment.   If increment is -15 every note has its velocity reduced by fifteen, if it is 0 there is no effect, if it is +10 the velocity is increased by ten.   Individual channels can be given individual adjustments.   The syntax of this effect is not the same as its SoX equivalent.


Python3   The current version of midisox is available by http at www.pjb.com.au/midi/free/midisox
To install midisox, save it to disc, move it into your $PATH, make it executable, and if necessary edit the first line to reflect where python3 is installed on your system. You will also need to install the MIDI.py and TermClui.py modules in your $PYTHONPATH.

Perl   The current version of midisox_pl is available by http at www.pjb.com.au/midi/free/midisox_pl
To install it, save it to disc, rename it midisox, move it into your $PATH, make it executable, and if necessary edit the first line to reflect where perl is installed on your system. You will also need to install the MIDI-Perl and Term::Clui and LWP::Simple CPAN modules.

Lua   The current version of midisox_lua is available by http at www.pjb.com.au/midi/free/midisox_lua
To install it, save it to disc, rename it midisox, move it into your $PATH, make it executable, and if necessary edit the first line to reflect where lua is installed on your system. You will also need to install the MIDI.lua module and the luaposix module (on debian: aptitude install liblua5.1-posix1). Fetching URLs as input files is believed to work either with the freepops-luacurl module (on debian: aptitude install liblua5.1-curl0), or with the luacurl module.   The Lua version runs considerably faster than the Python or Perl versions.

These files are all on github and can be downloaded by:
  git clone https://github.com/peterbillam/miditools


5.5, 20130507, All versions: in the quantise effect channels can be given individual lengths
5.4, 20130321, All versions: bug fixed in the quantise effect
5.3, 20120626, All versions: compand effect default_gradient is 0.5 not 0.0
5.2, 20111224, All versions: in the pitch effect channels can be given individual shifts
5.1, 20111219, All versions: the vol effect is introduced
5.0, 20111201, All versions: the compand effect and the quantise effect are introduced, and the mixer effect will accept negative channels
4.9, 20110922, All versions: fade with stop_time == 0 fades at end of file
4.8, 20110910, Lua version fixes reading from pipes
4.7, 20110710, Perl version opus2score() interprets note_on with vol=0 as a note_off and terminates unended notes at the end of the track
4.6, 20110111, Lua version fixes an emtpy-string-is-true bug in gm_on_already
4.5, 20101026, Lua version stat -freq works
4.4, 20101021, Lua version function wget() uses luacurl to get URLs
4.3, 20100926, Python3 version bug fixed appending to tuple in mixer()
4.2, 20100910, Python3 version fade effect handles absent params
4.1, 20100802, bug fixed in the Python3 midisox, in the mixer effect
4.0, 20100306, bug fixed in the pan effect
3.9, 20100203, the pitch effect as synonym for key
3.8, 20091128, fetches any valid URL as an input file
3.7, 20091127, "|cmd" pipe-style input files
3.6, 20091113, -d pseudo-output-file plays through aplaymidi
3.5, 20091112, pad shifts from 0 ticks, and stat output tidied
3.4, 20091107, the mixer effect does channel-remapping e.g. 3:1
3.3, 20091021, warns about mixing GM on and GM off or bank-select
3.2, 20091018, stat -freq detects the screen width
3.1, 20091018, does the pan effect
3.0, 20091018, stat effect gets the -freq option
2.9, 20091015, does the mixer effect
2.8, 20091014, echo channels are panned alternately right and left
2.7, 20091014, does the echo effect
2.6, 20091013, does the key effect
2.5, 20091013, midi2ms_score not opus2ms_score
2.4, 20091012, uses midi2ms_score
2.3, 20091011, fixed infinite loop in pad() at the end
2.2, 20091010, to_millisecs() must now be called on the opus
2.1, 20091010, stat effect sorted, and more complete
2.0, 20091010, vol_mul() improves defensiveness and clarity
1.9, 20091010, the fade effect fades-out correctly
1.8, 20091010, does the fade effect, and trim works with one arg
1.7, 20091009, will read from - (i.e. stdin)
1.6, 20091009, does the repeat effect
1.5, 20091008, does -h, --help and --help-effect=NAME
1.4, 20091007, does the pad effect
1.3, 20091007, does the tempo effect
1.2, 20091007, will write to - (i.e. stdout), and does trim
1.1, 20091006, does sequence, concatenate and stat
1.0, 20091003, first working version, does merge and mix


Peter J Billam www.pjb.com.au/comp/contact.html



search.cpan.org/perldoc?LWP::Simple (in the libwww-perl package)