How to produce Python controlled audio output from music made with Music21

This post was generated from a question I asked and answered here on Stack Overflow.

# Generates and Plays 2 Music21 Scores "on the fly".
# see way below for source notes

from music21 import *

# we create the music21 Bottom Part, and do this explicitly, one object at a time.

n1 = note.Note('e4')
n1.duration.type = 'whole'
n2 = note.Note('d4')
n2.duration.type = 'whole'
m1 = stream.Measure()
m2 = stream.Measure()
partLower = stream.Part()

# For the music21 Upper Part, we automate the note creation procedure

data1 = [('g4', 'quarter'), ('a4', 'quarter'), ('b4', 'quarter'), ('c#5', 'quarter')]
data2 = [('d5', 'whole')]
data = [data1, data2]
partUpper = stream.Part()

def makeUpperPart(data):
    for mData in data:
        m = stream.Measure()
        for pitchName, durType in mData:
            n = note.Note(pitchName)
            n.duration.type = durType

# Now, we can add both Part objects into a music21 Score object.  

sCadence = stream.Score()
sCadence.insert(0, partUpper)
sCadence.insert(0, partLower)

# Now, let's play the MIDI of the sCadence Score 
# [from memory, ie no file  write necessary] using pygame

import cStringIO

sCadence_mf = sCadence.midiFile
sCadence_mStr = sCadence_mf.writestr()
sCadence_mStrFile = cStringIO.StringIO(sCadence_mStr)

import pygame

freq = 44100    # audio CD quality
bitsize = -16   # unsigned 16 bit
channels = 2    # 1 is mono, 2 is stereo
buffer = 1024    # number of samples
pygame.mixer.init(freq, bitsize, channels, buffer)

# optional volume 0 to 1.0

def play_music(music_file):
    stream music with module in blocking manner
    this will stream the sound from disk while playing
    clock = pygame.time.Clock()
        print "Music file %s loaded!" % music_file
    except pygame.error:
        print "File %s not found! (%s)" % (music_file, pygame.get_error())
        # check if playback has finished

# play the midi file we just saved


# now let's make a new music21 Score by reversing the upperPart notes
data2 = [('d5', 'whole')]
data = [data1, data2]
partUpper = stream.Part()
sCadence2 = stream.Score()
sCadence2.insert(0, partUpper)
sCadence2.insert(0, partLower)

# now let's play the new Score
sCadence2_mf = sCadence2.midiFile
sCadence2_mStr = sCadence2_mf.writestr()
sCadence2_mStrFile = cStringIO.StringIO(sCadence2_mStr)

## There are 3 sources for this mashup:

# 1. Source for the Music21 Score Creation

# 2.  Source for the Music21 MidiFile Class Behaviour

# 3.  Source for the pygame player:

3 thoughts on “How to produce Python controlled audio output from music made with Music21

  1. Thanks for the great post and ideas! We’ll be incorporating something like this in a music21 midi.realtime module, but we will still require pygame since our main expertise is not in realtime playback. But to really see music21’s abilities here you might want to see if microtonal playback is available, since it’s something music21 does well for writing midi files and almost no other system can do this. Try setting a note’s .pitch.accidental attribute to pitch.Accidental(‘half-flat’) and see if it works! Please feel free to post this to the music21list (Google Groups). People will be interested!

  2. Pingback: Nice Comments about my code from MIT’s Music21 creator, Michael Scott Cuthbert « Joe Codeswell – Notes to Myself and Others

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s