Search code examples
pythoniopygamemidibytesio

Using pygame to play a MIDI file from stream


What I want to do is the following: Create a MIDI file, but only in memory, and feed it into pygame.mixer.music.load(). Here is what I've been trying (I'm using MidiFile from here):

import pygame.mixer
import MidiFile3
import io

pygame.mixer.init()

midi = MidiFile3.MIDIFile(1) # midi file with one track
midi.addTrackName(0,0,"Track 1") #Track Name on track 0, position 0
midi.addTempo(0,0,120) #Tempo to 120 bpm on track 0, position 0

for i in range(8):
    midi.addNote(0,0,60,i,1,100) #add 8 c1-notes to the track

bytestream = io.BytesIO()
midi.writeFile(bytestream)
pygame.mixer.music.load(bytestream.getvalue())

Here I get the error message

pygame.error: File path 'MThd' contains null characters

When I do

bytestream = open('file.mid','wb')
midi.writeFile(bytestream)
bytestream.close()
pygame.mixer.music.load('file.mid')

it works as expected.

Of course, I know there is a difference between string containing a file name and a byte-string containing what the file contains. But I found this Post on Daniweb which uses bytestreams and the example works for me.

I just can't figure out how to get my example to work.


Solution

  • I fixed the issue as follows:

    bytestream = io.BytesIO()
    midi.writeFile(bytestream)
    temp = io.BytesIO(bytestream.getvalue())
    pygame.mixer.music.load(temp)
    

    As it seems, the writeFile() operation somehow makes the BytesIO object invalid to the pygame.mixer.music.load() method. By using the constructor of BytesIO again with the correctly created bytestream we magically get a valid bytestream we can pass to pygame.mixer.music.load().