MIDI Tools
MIDI generation, processing, looping, and alternative tuning systems.
Requirements
MIDI tools require the mido library for reading/writing MIDI files.
Polyrhythmic MIDI Generator
Polyrhythmic Patterns
midi.polyrhythmic_midi requires midoGenerate complex polyrhythmic MIDI patterns with multiple overlapping time signatures.
Concept
Polyrhythms occur when two or more rhythmic patterns with different subdivisions play simultaneously. Common examples include 3:2 (three against two), 4:3, 5:4, and more complex ratios. This module generates MIDI files with multiple tracks, each following its own rhythmic subdivision.
Example Usage
from audio_dsp.midi.polyrhythmic_midi import generate_polyrhythmic_midi
# Generate 3:2 polyrhythm
generate_polyrhythmic_midi(
output_file="polyrhythm_3_2.mid",
ratios=[3, 2],
bars=4,
bpm=120,
notes=[60, 64] # C4, E4
)
# Complex 5:4:3 polyrhythm
generate_polyrhythmic_midi(
output_file="complex_poly.mid",
ratios=[5, 4, 3],
bars=8,
bpm=100,
notes=[48, 55, 62] # C3, G3, D4
)
# African-style 12:8 feel
generate_polyrhythmic_midi(
output_file="african_12_8.mid",
ratios=[4, 3], # 4 against 3
bars=4,
bpm=110,
notes=[36, 42], # Kick and hi-hat
channel=10 # Drum channel
)
MIDI Looper
Loop & Process MIDI
midi.midi_looper requires midoLoop MIDI files with optional transformations like transposition, time-stretching, and velocity changes.
Example Usage
from audio_dsp.midi.midi_looper import MIDILooper
looper = MIDILooper()
# Load a MIDI file
looper.load("melody.mid")
# Create 4 loops with ascending transposition
looper.loop(
repetitions=4,
transpose_per_loop=2 # Up a whole step each loop
)
# Apply velocity curve
looper.apply_velocity_curve(
curve="crescendo",
min_vel=40,
max_vel=120
)
# Time stretch (half speed)
looper.time_stretch(factor=2.0)
# Save result
looper.save("looped_melody.mid")
# Quick loop with transformations
looper.load("bassline.mid")
looper.loop(
repetitions=8,
transpose_per_loop=0,
velocity_variation=10, # Random velocity +/- 10
timing_humanize=5 # Random timing +/- 5 ticks
)
looper.save("humanized_bassline.mid")
MIDI Retuning
Microtonal MIDI
midi.midi_retune requires midoRetune MIDI files to alternative tuning systems using pitch bend messages.
Supported Tunings
| Tuning | Description |
|---|---|
| just_intonation | Pure ratios based on harmonic series |
| pythagorean | Built on stacked perfect fifths (3:2) |
| meantone | Quarter-comma meantone temperament |
| werckmeister | Werckmeister III well-temperament |
| 19_edo | 19 equal divisions of octave |
| 31_edo | 31 equal divisions of octave |
| custom | User-defined cents offsets per note |
Example Usage
from audio_dsp.midi.midi_retune import retune_midi
# Retune to just intonation
retune_midi(
input_file="piano.mid",
output_file="piano_just.mid",
tuning="just_intonation",
root="C"
)
# Pythagorean tuning
retune_midi(
input_file="strings.mid",
output_file="strings_pythagorean.mid",
tuning="pythagorean"
)
# Custom tuning (cents offset from 12-TET)
custom_tuning = {
'C': 0,
'C#': -10,
'D': 4,
'D#': -6,
'E': -14,
'F': -2,
'F#': -12,
'G': 2,
'G#': -8,
'A': 0,
'A#': -4,
'B': -12
}
retune_midi(
input_file="melody.mid",
output_file="melody_custom.mid",
tuning="custom",
custom_cents=custom_tuning
)
Logarithmic Tunings
Exotic Tuning Systems
midi.logarithmic_tuningsGenerate frequency tables and MIDI mappings for non-standard equal temperaments.
EDO (Equal Division of Octave) Systems
| EDO | Step Size (cents) | Notable Intervals |
|---|---|---|
| 12-EDO | 100 | Standard Western (reference) |
| 19-EDO | 63.16 | Better major thirds, minor sevenths |
| 22-EDO | 54.55 | Excellent approximation of 7-limit intervals |
| 24-EDO | 50 | Quarter tones (Arabic music) |
| 31-EDO | 38.71 | Near-just major/minor thirds |
| 41-EDO | 29.27 | Excellent fifth and third approximations |
| 53-EDO | 22.64 | Very close to just intonation |
Example Usage
from audio_dsp.midi.logarithmic_tunings import (
generate_edo_frequencies,
create_midi_mapping,
cents_to_ratio
)
# Generate 19-EDO frequency table
freqs_19 = generate_edo_frequencies(
divisions=19,
base_freq=440, # A4
octaves=2
)
print(freqs_19)
# Create MIDI note mapping for 31-EDO
# Maps 31 notes per octave to MIDI note numbers
mapping_31 = create_midi_mapping(
divisions=31,
base_note=60 # Middle C
)
# Convert cents to frequency ratio
ratio = cents_to_ratio(386) # Just major third
print(f"Just major third ratio: {ratio:.4f}") # ~1.25
# Generate Bohlen-Pierce scale (tritave-based)
from audio_dsp.midi.logarithmic_tunings import generate_bp_frequencies
bp_freqs = generate_bp_frequencies(
base_freq=220,
steps=13 # 13 steps per tritave (3:1)
)
MIDI Tips
Working with MIDI
Basic MIDI Operations
import mido
# Create a new MIDI file
mid = mido.MidiFile()
track = mido.MidiTrack()
mid.tracks.append(track)
# Add tempo (500000 microseconds = 120 BPM)
track.append(mido.MetaMessage('set_tempo', tempo=500000))
# Add notes
track.append(mido.Message('note_on', note=60, velocity=64, time=0))
track.append(mido.Message('note_off', note=60, velocity=64, time=480))
# Save
mid.save('output.mid')
# Read existing MIDI
mid = mido.MidiFile('input.mid')
for track in mid.tracks:
for msg in track:
if msg.type == 'note_on':
print(f"Note: {msg.note}, Velocity: {msg.velocity}")
MIDI Note Reference
| Note | MIDI # | Frequency (Hz) |
|---|---|---|
| C2 | 36 | 65.41 |
| C3 | 48 | 130.81 |
| C4 (Middle C) | 60 | 261.63 |
| A4 (Concert A) | 69 | 440.00 |
| C5 | 72 | 523.25 |
| C6 | 84 | 1046.50 |