Natooz / MidiTok

MIDI / symbolic music tokenizers for Deep Learning models 🎶
https://miditok.readthedocs.io/
MIT License
649 stars 80 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 1 week ago

mister-magpie commented 1 month 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 1 month 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 1 month 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 2 weeks ago

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

github-actions[bot] commented 1 week ago

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