Requirements

Install MIDI support: pip install audio_dsp[midi]

MIDI tools require the mido library for reading/writing MIDI files.

Polyrhythmic MIDI Generator

Polyrhythmic Patterns

midi.polyrhythmic_midi requires mido

Generate 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 mido

Loop 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 mido

Retune 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_tunings

Generate 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)
C23665.41
C348130.81
C4 (Middle C)60261.63
A4 (Concert A)69440.00
C572523.25
C6841046.50