Skip to content

Command line tool for converting polyphonic MIDI phrases to TidalCycles syntax

License

Notifications You must be signed in to change notification settings

TylerMclaughlin/midi_to_tidalcycles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

midi to tidalcycles

Command-line tools for converting polyphonic MIDI files to TidalCycles code expressions.

(Extreme) example of a >4 minute piano improvisation converted to TidalCycles code with pitch, note velocity, and legato data preserved. Here is the TidalCycles code generated from the recorded MIDI: Alt text

And using this code, TidalCycles can generate MIDI. If you don't add any transforming functions, the original MIDI data should be reconstructed. Here is the reconstructed MIDI data produced by the above autogenerated TidalCycles code (zoomed in to show velocities and note length): Alt text

Requirements

Description

Use this tool to take a MIDI file generated by a DAW or instrument and convert it to a TidalCycles expression.

python midi_to_tidalcycles.py [OPTIONS] [MIDIFILE...]

Polyphonic MIDI phrases will be converted to a TidalCycles stack. Optional arguments allow for adding # amp patterns (similar to midi velocity which is between 1 and 127 but ranging between 0.0 and 1.0 in TidalCycles syntax), adding # legato patterns, simplifying the generated expression, and controlling rhythmic quantization. Multiple separate MIDI files can be translated to TidalCycles in one command.

For an intro to sending MIDI signals from TidalCycles to your synthesizers and drum machines, check out Kindohm's youtube tutorial.

Example usage

python midi_to_tidalcycles.py -al ../test_examples/insen_quarter-eighth-notes_duophonic_125bpm.mid

prints

../test_examples/insen_quarter-eighth-notes_duophonic_125bpm.mid
inferred polyphony is 2
slow (8.0/4) $ stack [
    n "f5 ~ ~ ~ cs5 ~ ~ ~ c5 ~ ~ ~ gs4 ~ c5 ~ cs5 ~ c5 ~ gs4 ~ g4 ~ ~ ~ ~ ~ ~ ~ ~ ~"
    # amp "0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0"
    # legato "4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0",
    n "c6 ~ ~ ~ gs5 ~ ~ ~ g5 ~ ~ ~ f5 ~ g5 ~ gs5 ~ g5 ~ f5 ~ ds5 ~ ~ ~ ~ ~ ~ ~ ~ ~"
    # amp "0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.79 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0"
    # legato "4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0"
]

to standard out. This "stack" expression is intended to be copied and pasted into TidalCycles. Prepend something like d1 $ slow 8 $ and append # s "midi" # midichan 0 to this stack to start sending your MIDI signal from TidalCycles.

Options

-q, --resolution        specify number of quanta per quarter note
-l, --legato            print legato pattern
-a, --amp               print amplitude pattern
-c, --consolidate       simplify repeating values using mini-notation 
-e, --events            print MIDI event information
-d, --debug             print MIDI event information, voice numbers, and quanta numbers for debugging
-s, --shape             print MIDI shape (number of quanta and polyphonic voices)
-H, --hide              hide inferred polyphony and midi file info (useful for automatic copying of tidalcycles code) 

More examples

Basic use

python midi_to_tidalcycles.py ../test_examples/simple_legato_monophonic.mid

inferred polyphony is 1
slow (1.5/4) $ n "c5 d5 ds5 ~ f5 d5"

Adding amplitude (MIDI note velocity) to a duophonic file

python midi_to_tidalcycles.py -a ../test_examples/simple_legato_duophonic.mid

../test_examples/simple_legato_duophonic.mid
inferred polyphony is 2
slow (1.5/4) $ stack [
    n "c5 d5 ds6 ds5 f5 d5"
    # amp "0.79 0.79 0.39 0.79 0.79 0.79",
    n "c6 d6 ~ ~ f6 d6"
    # amp "0.39 0.39 0.0 0.0 0.39 0.39"
]

Adding amplitude, legato, and changing the resolution (notes per quarternote, or degree of quantization)

python midi_to_tidalcycles.py -al -q 16 ../test_examples/simple_legato_duophonic.mid

../test_examples/simple_legato_duophonic.mid
inferred polyphony is 2
slow (1.5/4) $ stack [
    n "c5 ~ ~ ~ d5 ~ ~ ~ ds6 ~ ~ ~ ds5 ~ ~ ~ f5 ~ ~ ~ d5 ~ ~ ~"
    # amp "0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.39 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0 0.79 0.0 0.0 0.0"
    # legato "4.0 0.0 0.0 0.0 8.0 0.0 0.0 0.0 8.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0",
    n "c6 ~ ~ ~ d6 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ f6 ~ ~ ~ d6 ~ ~ ~"
    # amp "0.39 0.0 0.0 0.0 0.39 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.39 0.0 0.0 0.0 0.39 0.0 0.0 0.0"
    # legato "4.0 4.0 0.0 0.0 4.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0"
]

Simplifying the generated TidalCycles code by consolidating repeating neighboring values (recommmended).

The '-c' or '--consolidate' flag simplifies the resulting TidalCycles expression by combining adjacent repeating values using the '!' mini-notation. The following shows how the above example is simplified with consolidation.

python midi_to_tidalcycles.py -alc -q 16 ../test_examples/simple_legato_duophonic.mid

../test_examples/simple_legato_duophonic.mid
inferred polyphony is 2
slow (1.5/4) $ stack [
    n "c5 ~!3 d5 ~!3 ds6 ~!3 ds5 ~!3 f5 ~!3 d5 ~!3"
    # amp "0.79 0.0!3 0.79 0.0!3 0.39 0.0!3 0.79 0.0!3 0.79 0.0!3 0.79 0.0!3"
    # legato "4.0 0.0!3 8.0 0.0!3 8.0 0.0!3 4.0 0.0!3 4.0 0.0!7",
    n "c6 ~!3 d6 ~!11 f6 ~!3 d6 ~!3"
    # amp "0.39 0.0!3 0.39 0.0!11 0.39 0.0!3 0.39 0.0!3"
    # legato "4.0!2 0.0!2 4.0 0.0!11 4.0 0.0!3 4.0 0.0!3"
]

You can see how the neighboring rests are grouped together now. Consolidation really shines with more complex examples!

Multiple MIDI files at once

python midi_to_tidalcycles.py -al ../test_examples/jazz-chords_played-live_quadraphonic_125bpm.mid ../test_examples/simple_legato_monophonic.mid

inferred polyphony is 4
slow (8.0/4) $ stack [
    n "e4 ~ ~ ~ gs4 ~ ~ ~ a4 ~ ~ ~ gs4 ~ ~ ~ g4 ~ ~ ~ gs4 ~ ~ ~ a4 ~ ~ ~ b4 ~ ~ ~"
    # amp "0.47 0.0 0.0 0.0 0.43 0.0 0.0 0.0 0.47 0.0 0.0 0.0 0.42 0.0 0.0 0.0 0.12 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.2 0.0 0.0 0.0 0.51 0.0 0.0 0.0"
    # legato "2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 3.0 0.0 0.0 0.0",
    n "c4 ~ ~ ~ f4 ~ ~ ~ e4 ~ ~ ~ b4 ~ ~ ~ a4 ~ ~ ~ d5 ~ ~ ~ g5 ~ ~ ~ c5 ~ ~ ~"
    # amp "0.43 0.0 0.0 0.0 0.39 0.0 0.0 0.0 0.49 0.0 0.0 0.0 0.46 0.0 0.0 0.0 0.46 0.0 0.0 0.0 0.54 0.0 0.0 0.0 0.46 0.0 0.0 0.0 0.57 0.0 0.0 0.0"
    # legato "2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 3.0 0.0 0.0 0.0",
    n "g4 ~ ~ ~ d4 ~ ~ ~ g4 ~ ~ ~ d5 ~ ~ ~ e5 ~ ~ ~ f5 ~ ~ ~ c5 ~ ~ ~ e5 ~ ~ ~"
    # amp "0.5 0.0 0.0 0.0 0.46 0.0 0.0 0.0 0.48 0.0 0.0 0.0 0.48 0.0 0.0 0.0 0.31 0.0 0.0 0.0 0.55 0.0 0.0 0.0 0.37 0.0 0.0 0.0 0.61 0.0 0.0 0.0"
    # legato "2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 3.0 0.0 0.0 0.0",
    n "a4 ~ ~ ~ b4 ~ ~ ~ c5 ~ ~ ~ f4 ~ ~ ~ c5 ~ ~ ~ b4 ~ ~ ~ e5 ~ ~ ~ ~ g5 ~ ~"
    # amp "0.47 0.0 0.0 0.0 0.39 0.0 0.0 0.0 0.43 0.0 0.0 0.0 0.48 0.0 0.0 0.0 0.47 0.0 0.0 0.0 0.52 0.0 0.0 0.0 0.49 0.0 0.0 0.0 0.0 0.42 0.0 0.0"
    # legato "2.0 0.0 0.0 0.0 3.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0"
]
../test_examples/simple_legato_monophonic.mid
inferred polyphony is 1
slow (1.5/4)  $ stack [
    n "c5 d5 ds5 ~ f5 d5"
    # amp "0.79 0.79 0.79 0.0 0.79 0.79"
    # legato "1.0 1.0 2.0 0.0 1.0 1.0"
]

Additional functionality

Extracting chords from MIDI

This functionality allows you to extract a 'library' of chords/voicings from a MIDI passage. The output format is tailored for use in the select TidalCycles function (http://tidalcycles.org/docs/reference/conditions/#select). This command extracts only the chords and ignores the rhythm, sustain, and velocity data of the MIDI file.

Duplicate chords found in the MIDI file are discarded if the -u flag is given.

The optional command-line string variable provided after the MIDI file specifies the name of the produced library.

This example:

python src/extract_chords.py test_examples/jazz-chords_played-live_quadraphonic_125bpm.mid my_jazz_chord_library

produces the following copyable TidalCycles code:

-- 8 chords
let my_jazz_chord_library p = select p [n "[-8, -12, -5, -3]", n "[-4, -7, -10, -1]", n "[-3, -8, -5, 0]", n "[-4, -1, 2, -7]", n "[-5, -3, 4, 0]", n "[-4, 2, 5, -1]", n "[-3, 7, 0, 4]", n "[-1, 0, 4, 7]"]

where p, the input to select, is a float between 0 and 1 (or a pattern of floats!).

Extracting melodic sequences

This functionality extracts only the notes (and their velocities) in the order in which they are played in the MIDI file. The output format is two monophonic patterns: one for notes and one for amps (MIDI velocity between 0 and 1).

Why output a pattern of notes and a pattern of amplitudes? Patterns are a flexible starting point for composition.
They are a convenient input to the variants of the nTake and ampTake functions I wrote (below). In addition to accepting patterns instead of a list, these variant functions also allow you to control the total number of notes or amplitudes to take. This can be used to limit the amount of "cross-rhythm chaos" that can happen when using a struct function with N notes and nTake with M != N notes, for example.

let patternToList pat = map value $ sortOn whole $ queryArc pat (Arc 0 1)                                       
    nT name amt p = nTake name (take amt (cycle (patternToList p)))                                             
    aT name amt p = ampTake name (take amt (cycle (patternToList p)))                                           

This example command

python src/extract_melody.py test_examples/simple_legato_monophonic.mid

autogenerates the following copyable TidalCycles code:

nT "notez" 5 "0 2 3 5 2"
# aT "ampz" 5 "0.79 0.79 0.79 0.79 0.79"

About

Command line tool for converting polyphonic MIDI phrases to TidalCycles syntax

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages