Natooz / MidiTok

MIDI / symbolic music tokenizers for Deep Learning models 🎶
https://miditok.readthedocs.io/
MIT License
698 stars 84 forks source link

REMI with rests does not produce Bar tokens if rest is at the end of a bar #189

Closed mister-magpie closed 3 months ago

mister-magpie commented 4 months ago

I noticed that when using the REMI tokenizer with rests the tokenizer skips the Bar_None token if the rest falls on the last position of a bar. The following note, however, will feature a Position_0 token so the new bar is correctly identified.

Here's an example with Frere Jacques melody

[ 
# bar 1
  'Bar_None', 'TimeSig_4/4', 'Position_0', 'Tempo_120.0', 'Pitch_72', 'Velocity_127', 'Duration_1.0.6', 'Position_12', 'Pitch_74', 'Velocity_127', 'Duration_1.0.6', 'Position_24', 'Pitch_76', 'Velocity_127', 'Duration_1.0.6', 'Position_36', 'Pitch_72', 'Velocity_127', 'Duration_1.0.6', 
# bar 2
  'Bar_None', 'TimeSig_4/4', 'Position_0', 'Pitch_72', 'Velocity_127', 'Duration_1.0.6', 'Position_12', 'Pitch_74', 'Velocity_127', 'Duration_1.0.6', 'Position_24', 'Pitch_76', 'Velocity_127', 'Duration_1.0.6', 'Position_36', 'Pitch_72', 'Velocity_127', 'Duration_1.0.6', 
# bar 3
  'Bar_None', 'TimeSig_4/4', 'Position_0', 'Pitch_76', 'Velocity_127', 'Duration_1.0.6', 'Position_12', 'Pitch_77', 'Velocity_127', 'Duration_1.0.6', 'Position_24', 'Pitch_79', 'Velocity_127', 'Duration_1.0.6', 'Rest_1.0.4', 
# bar 4
  'Position_0', 'Pitch_76', 'Velocity_127', 'Duration_1.0.6', 'Position_12', 'Pitch_77', 'Velocity_127', 'Duration_1.0.6', 'Position_24', 'Pitch_79', 'Velocity_127', 'Duration_1.0.6'
]
Natooz commented 4 months ago

Thank you for pointing it out

Indeed rests are kinda special in the way that they can "skip" bar tokens if they span across bars. This was done in order to allow rests that may last more than one bar.

In your example, the tokenizer should be able to decode the tokens while identifying the last bar as the rest token will be decoded accordingly. But I acknowledge that there may be a better way to deal with rests and bars in REMI. Other alternatives could include:

Among the two alternatives, I feel that the first is probably preferable while being simpler to implement (it would actually make the current code simpler). I am open to discussion. 🤷‍♂️

mister-magpie commented 4 months ago

Thanks, now it makes more sense. I think this property of the rest tokens should be described in the documentation. My expectation was that consecutive empty bars would all feature the Bar_None token and no note tokens.

As for my use case, I'm implementing a fill in the middle type of model and the collator works by considering a certain number of bars. My fix was forcing a Bar_None before each Position_0. I noticed that sometimes the gaps can be big but I guess those can be easily filtered from the dataset by checking the lenght of the longest rest

github-actions[bot] commented 3 months ago

This issue is stale because it has been open for 30 days with no activity.

github-actions[bot] commented 3 months ago

This issue was closed because it has been inactive for 14 days since being marked as stale.