Writing Music Using Python and the pretty_midi Library

Creating MIDI (Musical Instrument Digital Interface) files programmatically allows musicians to build, manipulate, and customize music digitally. Python, a versatile and beginner-friendly programming language, provides a fantastic toolkit for working with MIDI files via the pretty_midi library. In this article, we’ll explore the fundamentals of Python, MIDI, and the pretty_midi library, and illustrate how to generate MIDI files in Python.

MIDI: A Brief Overview

MIDI is a protocol that allows musical instruments and computer software to communicate with each other. MIDI does not store actual sounds, but rather instructions to produce sounds. For example, instead of recording the sound of a piano playing a C note, MIDI would store the information that a C note was played at a certain time and for a certain duration.

MIDI Messages

The core of MIDI is made up of messages. These messages convey information like which note to play, how loud to play it (velocity), and how long to hold it. The most common MIDI message is the ‘Note On’ message, which indicates that a note should start playing.

The pretty_midi Library

The pretty_midi library provides a high-level interface to read, compose, and manipulate MIDI files in Python. With pretty_midi, one can easily create and modify notes, set instrument types, and generate MIDI files.

Installing the Library

Before diving into the code, ensure you’ve installed the pretty_midi library. You can do so using Python’s package manager, pip:

pip install pretty_midi

Creating a Simple MIDI File

Now, let’s dive into the fun part! Here’s a simple example of how to create a MIDI file with a single note:

import pretty_midi

# Create a new PrettyMIDI object
midi = pretty_midi.PrettyMIDI()

# Create an instrument instance for a cello
cello_program = pretty_midi.instrument_name_to_program('Cello')
cello = pretty_midi.Instrument(program=cello_program)

# Specify the note, its start and end times, and its velocity
note = pretty_midi.Note(velocity=64, pitch=pretty_midi.note_name_to_number('C4'), start=0, end=1)

# Add the note to the cello instrument
cello.notes.append(note)

# Add the cello instrument to the PrettyMIDI object
midi.instruments.append(cello)

# Write the PrettyMIDI object to a new MIDI file
midi.write('cello_C4.mid')

Breaking it down:
1. We create a new PrettyMIDI object.
2. We specify an instrument (in this case, a cello).
3. We define a note (C4) to play for 1 second.
4. We add the note to our instrument and then the instrument to our MIDI object.
5. Finally, we write the object to a MIDI file.

With just a few lines of code, you’ve composed a simple MIDI file!

Expanding on the Basics of MIDI Creation with Python and pretty_midi

Having covered the rudiments of generating a MIDI file in Python using the pretty_midi library, you might be wondering: what’s next? While the basic example given previously highlights the creation of a single note, there is an expansive world of opportunities available for those who wish to delve deeper.

Multiple Notes and Chords

While the initial example showcased the creation of a single note, you can easily expand this to create sequences of notes or even simultaneous notes (chords).

To create a sequence:

notes = [
    pretty_midi.Note(velocity=64, pitch=pretty_midi.note_name_to_number('C4'), start=0, end=1),
    pretty_midi.Note(velocity=64, pitch=pretty_midi.note_name_to_number('D4'), start=1, end=2)
]

for note in notes:
    cello.notes.append(note)

For chords, you can simply adjust the start and end times so that multiple notes overlap.

Multiple Instruments

The pretty_midi library provides a vast range of instruments. You can introduce diverse instruments and layer their sounds to create richer musical pieces.

piano_program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano')
piano = pretty_midi.Instrument(program=piano_program)

piano.notes.append(pretty_midi.Note(velocity=64, pitch=pretty_midi.note_name_to_number('E4'), start=0, end=1))

midi.instruments.append(piano)

Control Changes: Expressiveness in MIDI

MIDI isn’t just about notes; it also incorporates control changes that can alter aspects like volume, pan, and modulation. For example, to add a crescendo (gradual volume increase), you might introduce a control change that increases the volume over a specific duration.

cello.control_changes.append(pretty_midi.ControlChange(number=7, value=50, time=0))  # Start quieter
cello.control_changes.append(pretty_midi.ControlChange(number=7, value=100, time=1))  # Increase volume over 1 second

Time Signature, Key Signature, and Tempo Changes

The library supports changes in time signature, key signature, and tempo, enabling you to add rhythmic variations and shifts in pace and mood.

midi.time_signature_changes.append(pretty_midi.TimeSignature(numerator=3, denominator=4, time=0.0))
midi.key_signature_changes.append(pretty_midi.KeySignature(key_number=2, time=0.0))
midi.adjust_seconds_to_be_tempo_rescaled(120)  # Set tempo to 120 BPM

Experiment with Algorithmic Composition

With programming, you can create patterns, variations, and structures algorithmically. Consider creating a function that generates a random sequence of notes, or one that varies a melody based on specific rules.

Reading and Modifying Existing MIDI Files

You can also read existing MIDI files, modify their content, and write them back. This is especially useful for automating edits, extracting data, or experimenting with variations.

existing_midi = pretty_midi.PrettyMIDI('path_to_file.mid')
# Manipulate as desired
existing_midi.write('modified_file.mid')

Further Exploration

  1. Start Simple: Before diving into more complex compositions, ensure you’re comfortable with the basics. It’s easier to troubleshoot a few notes than an entire symphony.
  2. Documentation is Key: The pretty_midi library has extensive documentation. Familiarize yourself with its offerings to understand the full breadth of possibilities.
  3. Practice Regularly: Like learning a musical instrument, programming benefits from consistent practice. Regular coding will solidify your understanding and enhance your skills.
  4. Experiment and Explore: Don’t hesitate to try out new things. Want to add random instruments, generate unconventional rhythms, or experiment with scales? Go for it!
  5. Collaborate and Share: Engage with online communities, share your projects, and seek feedback. Collaboration often introduces fresh perspectives and ideas.

Remember, the integration of music and programming provides a vast canvas for creativity. The tools are now in your hands; it’s up to you to paint the musical landscape.

Conclusion

The world of programmatically creating and manipulating MIDI files is vast and filled with creative possibilities. With Python and the pretty_midi library, even those new to programming can jump in and start experimenting. Whether you’re looking to automate certain musical tasks, experiment with algorithmic composition, or simply learn more about the digital side of music, Python and pretty_midi provide an accessible and powerful toolkit.

Similar Posts