Yikai-Liao / symusic

A cross platform note level midi decoding library with lightening speed, based on minimidi.
https://yikai-liao.github.io/symusic/
MIT License
108 stars 8 forks source link

Interface design for pianoroll representation #16

Closed lzqlzzq closed 5 months ago

lzqlzzq commented 6 months ago

We are designing interface for pianoroll representation. There are different existing interface designs:

I think the interface must satisfy:

Here are my considerations, do you have ideas? @Natooz @Yikai-Liao

lzqlzzq commented 6 months ago

And, how to handle overlapped notes?

Natooz commented 6 months ago

I think these are good directions! I agree that it is better to leave to the user the task to use the "MIDI-level" resampling methods.

filter_notes would be a function given by the user?

For overlapping notes, we can either:

Ideally, this could be given as an option to the user.

Also pypianoroll (and muspy?) has nice visualisation methods. Do you think it could be worth adding similar features in symusic?

Yikai-Liao commented 6 months ago

filter_notes will be added, which accepts a python function, like a lambda funciton. But just like using python lambda funciton in sort, don't expect it to be as fast as native c++ code.

For the pause token, do you mean this kind of things :

Note(start=0, duration=2, pitch=60) Note(start=2, duration=2, pitch=60)

  • without pause [1, 1, 1, 1]
  • with pause [1, 0, 1, 1]

Visualization part would be hard in cpp part. And I think it would better to reuse the code in pypianoroll (using matplotlib) to create such image. To be honest, we don't need to take care of the performance of visualization part.

Further, I think it would be better to add a install option for visualization like pip install symusic[visualizaiton] and pip install symusic[all]. Because many people just never use this part (visualization) and matloplib is large.

Natooz commented 6 months ago

You got it right for the pause ticks.

I agree with you for everything for the visualisation. It's indeed a part used only by a small proportion of users. (I was just asking out of curiosity, not recommending or asking for anything, thought you might be interested)

For filter_notes, maybe I'm missing something, but if the piano roll method receives a Score or Track object and this function, why not just letting the user filter the Score/Track himself with his own method before calling the piano roll method?

Yikai-Liao commented 6 months ago

filter_notes is for Score and Track (not for piano roll), it is implemented in some older versions and removed for some reasons that I have forgotten. It will be reimplemented in future versions.

lzqlzzq commented 6 months ago

I am implementing the pianoroll feature. Because the de-overlap operation is a little complicated and seems to be a useful tool even without the pianoroll, I plan to put it in ops.h. And, how to handle the following situation if a "pause" tick must be added?

Note(start=0, duration=1, pitch=60) Note(start=1, duration=2, pitch=60)

The first note cannot be ignored, and shifting the start of a note seems to change the semantics.

lzqlzzq commented 6 months ago

The only way I think is to raise a warning.

Yikai-Liao commented 6 months ago

I am implementing the pianoroll feature. Because the de-overlap operation is a little complicated and seems to be a useful tool even without the pianoroll, I plan to put it in ops.h. And, how to handle the following situation if a "pause" tick must be added?

Note(start=0, duration=1, pitch=60) Note(start=1, duration=2, pitch=60)

The first note cannot be ignored, and shifting the start of a note seems to change the semantics.

In my opinion, pause could only be used when ticks_per_quarter is large, which means the situation where duration=1 would be rare, and reduce the duration by 1 tick won't change the semantics too much.

When we need to use a "strong quantization" for creating pianoroll, the best way to deal with this kind of situation should be using onset pianoroll with frame pianoroll or offset pianoroll at the same time. For example, just put two kind of pianoroll in two distinct channels (this refers to the concept of channel in the images), and input them together into a model (e.g. CNN)

BTW, the example is actually not de-overlap, it is de-adjacentize (or de-adj for short)

This is the situation for de-overlap: Note(start=0, duration=2, pitch=60) Note(start=2, duration=2, pitch=60)