Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

music21.midi.realtime.play does not play ties correctly on OS X Sierra #266

Closed
AlexisGoodfellow opened this issue Dec 7, 2017 · 7 comments · Fixed by #565
Closed

music21.midi.realtime.play does not play ties correctly on OS X Sierra #266

AlexisGoodfellow opened this issue Dec 7, 2017 · 7 comments · Fixed by #565

Comments

@AlexisGoodfellow
Copy link

AlexisGoodfellow commented Dec 7, 2017

First things first: This project is absolutely incredible. A couple of other developers and I have been building an application for the past couple months using music21 as the primary backend technology, and I cannot thank all of you enough for the enormous amount of work you all have put into this massive project.

That said, I came across an issue recently that is a bit problematic for our particular use case. We've been using music21.midi.realtime.play in order to play back pieces that our users compose, and we ran into a strange problem involving playback of notes connected with ties. This simple python program is enough to replicate the issue:

import music21

# Create the stream
s = music21.stream.Stream()
# Make two notes with a tie between them
note1 = music21.note.Note("C#4", 1.0)
note1.tie = music21.tie.Tie("start")
note2 = music21.note.Note("C#4", 2.0)
note2.tie = music21.tie.Tie("stop")
# Insert the notes in the stream
s.insert(0.0, note1)
s.insert(1.0, note2)
# Attempt to playback the stream
music21.midi.realtime.StreamPlayer(s).play() # 2 notes play instead of 1
# Check the score in a GUI to make sure the tie is present
s.show()

Correct me if I'm wrong, but I'm pretty sure the whole point of ties is to ensure a note keeps sounding beyond what a single note head can notate. Fortunately, it appears that Musescore and other GUI applications display the tie correctly, which means that the tie is indeed interpretable. However, this does not appear to be the case on playback - where only 1 continuous note should sound, 2 are played.

I've only poked a little bit into the music21 source code - there's quite a lot of it - but this seems like something that should be doable with a little tooling around. One potential workaround could be storing semantic note duration (as it appears on the page) and playback note duration (as one would hear the piece when played) as separate values. I imagine this could get a little hairy when trying to create ties across separate Stream objects, though. I don't know how feasible it is in all cases, but it may be something to consider implementing.

It also may very well be that this issue is local to my machine environment, and if so it's definitely a low priority bug that we can probably hack around. But if it's not unique to my architecture, it seems like something that could probably be investigated and improved upon.

Thanks again for all your hard work! :)

Edit: If it helps, we're using the most recent version of music21, version 4.1.0.

@mscuthbert
Copy link
Member

Hi! Thanks for the kind words. The "realtime" module is more of a proof of concept than anything too formal, but it'd be nice to get this right. Does the piece play properly if you use .show('midi')? Just trying to narrow down the possible fault points.

@mscuthbert
Copy link
Member

Oh, and probably worth it to use the prerelease v5.0a1 -- lots of good improvements there; nothing in .midi.realtime, but tons of bugs squashed; one of which might affect this. install with pip3 install --upgrade --pre music21 or something like that.

@AlexisGoodfellow
Copy link
Author

AlexisGoodfellow commented Dec 12, 2017

I totally understand wanting to narrow down problem areas, so I just ran that same code snippet against both the upgraded and non-upgraded versions of music21. My findings were the same regardless of version number.

music21.realtime.StreamPlayer(s).play() produces two separate tones instead of one continuous tone.

music21.show() displays the tie in the GUI editor.

music21.show('midi') (with QuickTime installed) also plays two notes instead of one. It produces the same results as music21.realtime.StreamPlayer(s).play().

My gut suspicion is that something strange is happening at the music21-to-midi conversion step; the notes are converted successfully, but the tie gets lost in translation. After all, converting a half note produces only one tone over two qLs, so it's not like the playback engine is incapable of producing a note with a duration of two qLs. It just happens to play back the two tied quarter notes as two independent quarter notes instead of a single half note.

Do you have any even vague ideas about what could be causing this? I may have some time to poke around music21's source code on my own after finals season is over, but having a general idea where to investigate first would be helpful in limiting the scope of where to look for problems!

@mscuthbert
Copy link
Member

Thanks! This is a great start. Does the problem go away if you run s.stripTies().show(). And does it change if you use stream.Measure() instead of stream.Stream() or if you put a time signature of 3/4? Thanks!!!

@ajirving
Copy link
Contributor

I can reproduce this issue. It looks to me like the problem is in the stripTies method which is called by the Midi conversion with argument retainContainers=True. Since the notes aren't contained in measures this is failing to delete the 2nd note although it is correctly setting the duration of the first one. Creating the above example with the notes in a measure it appears to behave correctly. There is a comment in the code that it needs updating to use a more general recursion when removing notes, as well as the above example it would also fail if the notes were contained in voices within the measure. Is the retainContainers argument really necessary for the Midi output? Turning it off might avoid these issues but I haven't tested to see what other problems it might cause.

@jacobtylerwalls
Copy link
Member

jacobtylerwalls commented Jun 20, 2020

Helpful lead, @ajirving. stripTies() confesses it assumes the containers are measures.

# note: this assumes the container is Measure

Seems we should check if measures are contained in the stream before setting retainContainers=True otherwise, use the default (False).

Any interest in pursuing this, @ajirving @AlexisGoodfellow ?

@jacobtylerwalls
Copy link
Member

This actually goes deeper than MIDI. You can reproduce this with just stripTies(retainContainers=True) so long as your notes are not contained in Measure objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants