Skip to main content

Lightweight, pure-python utility for generating scales of midi notes. Includes support for microtunings via asclpy

Project description

midi-utils

midi-utils is a lightweight, pure-Python utility for working with MIDI notes, scales, chords, arpeggios, and alternative tuning systems. It provides tools for music theory operations, data sonification, and microtonal composition.

Features

  • Scale Generation - Generate MIDI note scales in various modes (major, minor, pentatonic, etc.)
  • Chord Construction - Build chords with inversions and extensions
  • Arpeggiation - Create complex arpeggio patterns with multiple styles
  • Tuning Systems - Support for 150+ alternative tuning systems via asclpy
  • MIDI/Frequency Conversion - Convert between note names, MIDI numbers, and frequencies
  • ADSR Envelopes - Generate amplitude envelopes for audio synthesis
  • Data Sonification - Map arbitrary data ranges to musical scales

Installation

pip install midi-utils

Quick Start

from midi_utils import midi_scale, midi_chord, midi_arp

# Generate a C major scale
scale = midi_scale('C', 'MAJOR', 'C3', 'C5')
# >>> [60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83, 84]

# Create a C minor chord
chord = midi_chord('C3', 'MIN')
# >>> [60, 63, 67]

# Arpeggiate the chord
arp = list(midi_arp(chord, octaves=[0, 1], duration=1000, styles=['updown']))
# >>> [{'note': 60, 'duration': 166.67, ...}, {'note': 63, ...}, ...]

Module Overview

midi_scale - Scale Generation

Generate scales in any key and mode over a specified MIDI range.

from midi_utils import midi_scale, SCALES

# Major scale from C3 to E5
midi_scale('C', 'MAJOR', 'C3', 'E5')
# >>> [60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83, 84, 86, 88]

# Natural minor scale
midi_scale('A', 'MINOR', 'A2', 'A4')
# >>> [45, 47, 48, 50, 52, 53, 55, 57, 59, 60, 62, 64, 65, 67, 69]

# Pentatonic scale with MIDI numbers
midi_scale(60, 'PENTATONIC', 48, 72)
# >>> [48, 50, 52, 55, 57, 60, 62, 64, 67, 69, 72]

# See all available scales
print(list(SCALES.keys()))

map_to_midi_scale - Data Sonification

Map values from any range to notes in a musical scale.

from midi_utils import midi_scale, map_to_midi_scale

# Map RGB values (0-255) to a C minor scale
c_min_scale = midi_scale('C', 'MINOR', 'C3', 'C5')
map_to_midi_scale(155, c_min_scale, 0, 255)
# >>> 77

# Map temperature readings to a scale
temps = [32, 45, 68, 82, 95]
notes = [map_to_midi_scale(t, c_min_scale, 30, 100) for t in temps]
# >>> [60, 63, 72, 79, 84]

midi_chord - Chord Construction

Build chords with inversions and voicing options.

from midi_utils import midi_chord, CHORDS

# Basic major chord
midi_chord('C3', 'MAJ')
# >>> [60, 64, 67]

# Dominant 7th chord
midi_chord('G3', 'DOM7')
# >>> [67, 71, 74, 77]

# First inversion
midi_chord('C3', 'MAJ', inversion=1)
# >>> [64, 67, 72]

# Stack up (add octaves above)
midi_chord('C3', 'MIN', stack_up=1)
# >>> [60, 63, 67, 72, 75, 79]

# See all available chords
print(list(CHORDS.keys()))

midi_arp - Arpeggiation

Create complex arpeggio patterns from chord sequences.

from midi_utils import midi_chord, midi_arp

chord = midi_chord('C3', 'MAJ')

# Simple arpeggio
arp = list(midi_arp(chord, duration=1000, styles=['up']))

# Each note is a dict with timing info
arp[0]
# >>> {'note': 60, 'duration': 333.33, 'start_time': 0.0, 'velocity': 100}

# Multiple octaves with various styles
arp = list(midi_arp(
    chord,
    octaves=[0, 1, 2],
    duration=2000,
    styles=['updown', 'thumb_up', 'middle_up'],
    beat_bpm=120,
    beat_count=1/16
))

# Available styles: 'up', 'down', 'updown', 'downup', 'thumb_up', 'thumb_down',
# 'middle_up', 'middle_down', 'pinky_up', 'pinky_down', 'random_shuffle', etc.

ADSR - Envelope Generation

Generate amplitude envelopes for audio synthesis.

from midi_utils import ADSR

# Create an ADSR envelope
envelope = ADSR(
    attack=0.1,    # 10% of samples for attack
    decay=0.2,     # 20% for decay
    sustain=0.7,   # Sustain level (70% of max)
    release=0.3,   # 30% for release
    samples=1000   # Total samples
)

# Get amplitude values
amplitudes = list(envelope)
# >>> [0.0, 0.02, 0.04, ..., 0.7, 0.7, ..., 0.35, 0.0]

# Or iterate for real-time use
for amp in ADSR(attack=0.2, decay=0.3, sustain=0.6, release=0.2):
    # Apply amplitude to audio sample
    pass

Utility Functions

MIDI/Note Conversions

from midi_utils import note_to_midi, midi_to_note, note_to_freq, midi_to_freq

# Note name to MIDI number
note_to_midi('A4')
# >>> 69

# MIDI number to note name
midi_to_note(60)
# >>> 'C3'

# Note name to frequency
note_to_freq('A4')
# >>> 440.0

# MIDI to frequency (standard 12-TET)
midi_to_freq(69)
# >>> 440.0

# MIDI to frequency with alternative tuning
midi_to_freq(69, tuning='19_edo')  # 19-tone equal temperament
# >>> 264.02...

# See available tunings
import asclpy
print(asclpy.list_tunings()[:10])
# >>> ['11_edo', '12_tet_edo', '13_edo', '19_edo', '22_edo', ...]

Tuning Systems

The midi_to_freq() function now supports 150+ alternative tuning systems via asclpy:

from midi_utils import midi_to_freq

# Standard 12-TET (default, backwards compatible)
midi_to_freq(60)  # C4
# >>> 261.63

# 19-tone equal temperament
midi_to_freq(60, tuning='19_edo')
# >>> 190.13

# 31-tone equal temperament
midi_to_freq(60, tuning='31_edo')
# >>> 265.99

# Historical temperaments
midi_to_freq(60, tuning='pythagorean_c')
# >>> 260.74

# Arabic Maqam tunings
midi_to_freq(60, tuning='rast_1')
# >>> 261.63

# See all tunings with details
import asclpy
asclpy.cli.list()  # Or: asclpy list (command-line)

Other Utilities

from midi_utils import midi_to_octave, freq_to_octave, sharp_to_flat

# Transpose MIDI note by octaves
midi_to_octave(60, 1)   # Up one octave
# >>> 72

# Transpose frequency by octaves
freq_to_octave(440.0, 1)  # Up one octave
# >>> 880.0

# Convert sharps to flats
sharp_to_flat('C#4')
# >>> 'DB4'

Constants

Access comprehensive mappings and lookup tables:

from midi_utils import (
    NOTE_TO_MIDI,      # Note name → MIDI number
    MIDI_TO_NOTE,      # MIDI number → Note name
    NOTE_TO_FREQ,      # Note name → Frequency
    MIDI_TO_FREQ,      # MIDI number → Frequency
    ROOT_TO_MIDI,      # Root name → MIDI class (0-11)
    CHORDS,            # Chord name → Interval pattern
    SCALES,            # Scale name → Interval pattern
    NOTE_EQUIVALENTS   # Sharp → Flat equivalents
)

# Example: Get frequency of C4
NOTE_TO_FREQ['C3']
# >>> 261.63

# Get intervals for major scale
SCALES['MAJOR']
# >>> [0, 2, 4, 5, 7, 9, 11]

Development

Setup

git clone git@gitlab.com:gltd/midi-utils.git
cd midi-utils
uv sync --dev  # Install all dependencies including dev tools

This project uses uv for fast, reliable Python package management.

Running Tests

# Run all tests
uv run pytest

# Run with verbose output
uv run pytest -vv

# Run specific test file
uv run pytest tests/test_midi_to_freq_tuning.py

# Or use make
make test

Linting and Formatting

# Run linter and formatter
make lint

# Or manually
uv run ruff check --fix midi_utils/ tests/
uv run ruff format midi_utils/ tests/

Project Structure

midi-utils/
├── midi_utils/
│   ├── __init__.py      # Public API exports   ├── scale.py         # Scale generation   ├── chord.py         # Chord construction   ├── arp.py           # Arpeggiation patterns   ├── utils.py         # Conversion utilities   ├── adsr.py          # Envelope generator   └── constants.py     # Scales, chords, note mappings
├── tests/               # Test suite
├── pyproject.toml       # Package configuration
└── README.md

License

MIT License - see LICENSE file for details.

Related Projects

  • asclpy - Ableton Scala tuning file parser with 150+ tuning systems

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

midi_utils-1.3.3.tar.gz (41.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

midi_utils-1.3.3-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

Details for the file midi_utils-1.3.3.tar.gz.

File metadata

  • Download URL: midi_utils-1.3.3.tar.gz
  • Upload date:
  • Size: 41.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for midi_utils-1.3.3.tar.gz
Algorithm Hash digest
SHA256 5a0249f288d14250ba6ce7262438941b2318e12638a445f386e585bb2d5edc6a
MD5 af5e66839a2c8cce8acd0f2ca1490281
BLAKE2b-256 1c30105f29ddabd0cce96641fbf6e9b53d9a0b0906f1fb997a81733282198be0

See more details on using hashes here.

File details

Details for the file midi_utils-1.3.3-py3-none-any.whl.

File metadata

  • Download URL: midi_utils-1.3.3-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for midi_utils-1.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 cc37e7f94615ec770bebbcb58b25eff52d9c06154c676ed5e8bde4e46ad2f78a
MD5 b63ecb44fcad52a9f233dd65b591cb8b
BLAKE2b-256 55ecba214eab2a431241035da1b1cf8f4857f6a58dbf242f9cd6e4eb4ff0da32

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page