cuthbertLab / music21

music21 is a Toolkit for Computational Musicology
https://www.music21.org/
Other
2.13k stars 402 forks source link

MIDI export - no pitch shift in cents being exported #1602

Open lgmventura opened 1 year ago

lgmventura commented 1 year ago

music21 version

8.1.0

Problem summary

Not exporting pitch shift in cents within a MidiEvent. It is possible to set a class variable called centShift, but it has no effect when saving the MIDI file. This is different from the pitch bend, which is a MIDI channel message, affecting all notes from the channel simultaneously.

Steps to reproduce Adapting the test function testBasicExport to include cents:

def testBasicExport(self):
        from music21 import midi
        mt = midi.MidiTrack(1)
        # duration, pitch, cent, velocity
        data = [[1024, 60, -80, 90],
                [1024, 60, 40, 70],
                [1024, 60, 0, 120],
                [1024, 60, 90, 80]]
        timeNow = 0
        tLast = 0
        for d, p, c, v in data:
            dt = midi.DeltaTime(mt)
            dt.time = timeNow - tLast
            # add to track events
            mt.events.append(dt)

            me = midi.MidiEvent(mt)
            me.type = midi.ChannelVoiceMessages.NOTE_ON
            me.channel = 1
            me.pitch = p
            me.centShift = c
            me.velocity = v
            mt.events.append(me)

            # add note off / velocity zero message
            dt = midi.DeltaTime(mt)
            dt.time = d
            # add to track events
            mt.events.append(dt)

            me = midi.MidiEvent(mt)
            me.type = midi.ChannelVoiceMessages.NOTE_ON
            me.channel = 1
            me.pitch = p
            me.centShift = c
            me.velocity = 0
            mt.events.append(me)

            tLast = timeNow + d  # have delta to note off
            timeNow += d  # next time

        # add end of track
        dt = midi.DeltaTime(mt)
        mt.events.append(dt)

        me = midi.MidiEvent(mt)
        me.type = midi.MetaEvents.END_OF_TRACK
        me.channel = 1
        me.data = b''  # must set data to empty bytes
        mt.events.append(me)

        # for e in mt.events:
        #     print(e)

        mf = midi.MidiFile()
        mf.ticksPerQuarterNote = 1024  # cannot use: 10080
        mf.tracks.append(mt)

        fileLikeOpen = io.BytesIO()
        # mf.open('/src/music21/music21/midi/out.mid', 'wb')
        mf.openFileLike(fileLikeOpen)
        mf.write()
        mf.close()

Expected vs. actual behavior

I expected the midi note_on event in the MIDI file to have a microtonal offset in pitch. Current behaviour: no pitch shift in cents being exported.

More information

OS: Ubuntu 22.04 Playback with VLC + fluid plugin.

mscuthbert commented 1 year ago

At the time we made the system, no playback devices were supporting pitch shift -- this is why we went with pitch bend. Microtonal shifts would have been much easier. Are Windows/Mac software now supporting it in playback? Note that Ubuntu is not a free-tier supported system.

If this happens (which I'm not committing to), we would need to do it as a keyword argument to .write('midi', microtonesAsPitchShift=True) with a different output system, since obviously we cannot output both microtone shifts and pitch bends, and many users will still have devices that only support pitch bend.

lgmventura commented 1 year ago

@mscuthbert What do you mean with "Ubuntu is not a free-tier supported system."?

mscuthbert commented 1 year ago

@mscuthbert What do you mean with "Ubuntu is not a free-tier supported system."?

Fixes for Ubuntu are only implemented by the core team if support is paid for. They will be merged if well-documented and well-tested. But in general, music21 only should be counted on by devs to work on Windows and MacOS. I like it when it works elsewhere (I use it on Ubuntu daily) but it's too hard to debug every possible configuration there. See the FAQ.