Still trying to make sense of Tempo, Sync, and MIDI loop issue
-
@Christoph-Hart
TH.setOnBeatChange()
always fires at the DAW tempo no matter when yousetHostBpm()
at different tempo.The TH
syncMode
doesn't seem to affect this -
@Christoph-Hart I prepared a snippet so we can test a few things in order to get the MIDI issues (or my bad implementation) sorted once for all.
HiseSnippet 4007.3oc6as7aibjdu4LSOqIsmYsw5f.jSUzgMTqF2hujFN1vq3qlhT7o3C8xwwoX2EIaw9AU2MEEm.mXDDffbIHmx48XtFfbH2VCjK4+fbZMLRNkSw+Gj7UU2jraJRFNZ7L6jMRXNv9qpup988n9dTcO0MMjHVVFlbAB1ZxPBWfOfu4Dc69Y6iUz4JliKvSoDjpXHSZQrr4xLYH1xhHyEHvCOjNm.AeDG6ue3fLXUrtDYNINtSLTjHkUzTrmSsdpRJpp4wvJpn4Y1IRUTxPOqgpwH.OOjOB2Prz.bORULcZOfmKviEkUrMLaZisIVbAdTFC4IM6aLV2Y9mnXozQkPeHJWSXgbHm2PUlhXJUtr8UTkqOUts3fEs9bsvCczBeLeEEYkYzmqM9P1.n4b3UeD3A9g2C8AundgWDOvaIP5AdfzOYpggAIU7DhoqgoRwbEQNTh5CHYGYZRzsaRtZDwmA4GNvcnVlfp0K8xFFCE0w.7j8Rlt5cfo1bHw+.Ad3FKqQWqrxQEq7JpDpbGX5CvroxHXyygswbA9a4iFIlfdq8KkLaiSMJIHT4XwKtLsffvYBBoEpKnoznYqhwt.nHbXZgKExIHbdiLRB4xzQ3xRoULZ2umP2CuTna2qSW.VfBWb9E2Pfwk0ykQP87LB4OJSwDoqWHZuVEDpmsnvYEZq97CE5EWqNvaKUXs2YmLBbTH53U9WyuaYkNlXyI6ld3PUEIrshgNp4ngCMLs28PCSr9glFFWSrPL6EUQasaArt7Dj6.61vPZ.Jm4HM2eNkgLXKEIujPQhlFkwRBcrsoERRE0GaaAhN0pSOL0TomN1djI.rGWcjVFLngAi128af+9x+yCpZno.iyNt6ZI+vT4H5KiLEmfw0z16wYGuDeNBsHZCMlS37Tbd7cejiu6Gw2TxTYn87QnF22muntMwrKF7P8585LWtG73eFeVCXF51BZ3Aj7lvCy3HbxHQdFZ+HQ19yBAyxxPkHHoRvlgABg18WDJ3wsEAGhZUa9ogBFJ3mf7bZAIaPrz+irQpf7fv1H69DDQWtVW14BD4ZXSeFpyHaDtKrgrwUwV1HcCaBxnaWjhtkMAKiLIViTsUz6ATPXjs4HcvEfHirbO7IDJHB0puhEB9GccjvVDzXB7SSzDiQng.jPcMMzPVT0MSB0wpYUolcCSvJq.+fMKXKnqPk5nvi6SzonAYAQmgsy1fMjF.RBkGFycQRPrTKx1NZ.KhcM8LDrMDOSuGYlVnqhIYpV.9MHlcfIQw8uDUjBZJ3oFBHJ5A+urTFppFiAEgzHKaPjrodGLEogt5DG87MNBHPg7LTepNhQuP5rkPsDqTuFBrlinGiDlgAEaTOCCYp9nCdJHNkpClpuXJBpN1hnRj.KvyXqJUuQsNVz.XfFFx7.1LrjsEUkkK8otPThIGrM7DHkE5ZhoEFMVwtORzEvNKnyBMeI7JnBqTmQIm1zQPY.UCRnZ4nTLIpLOFXwnncWX8.mRcYl4kx.asck4hNt.v9qhFaXpBhYQDVCMxhIkKXVbWRFK5fhelWIJr9HsNfmB3izAhRL00BFGYCARrnlPiQTc6NJVUIigPIa6W5vNVD7vglFXo9GD5WraH3uc2EkiHohMYABsBAozAGpqwlrCftYqPeNhUlgPOh87zZg2xaFssfCxKkYZTDXA7PQ.a4KesSLfcgXsvITLxRQanJAM.NGsqkNFLCI1MwLUQnEVZA3HMDKjvxrEdqDOOtPbCIbCQKbyrYEizqgPubYFqUWlzHVzp0EFYIF6kQxs2EsOoYdySJJeckwVQjJFMMVKchRciEuVNYsXwa1EeBtcrKutlTxDw2+XsqpE6LqiTvkOpx3DILpztS+IkjzJbi3XQy71p4Dq2Qdv9Wp2svHoBIK9R0iTGe8jhUqJku0UQ5XTo2NQtvtbV7KDqMnyNIfDHZG0dxM1I6E+zgsZmcf4.Qqi5jytcxAwa1bX7ZpWaL45N8ZazzrboX06rW81IpTD2hzreD6jEIMNKm9Y6aeo9QsrZmrvkow4DSL9P0pYG1d+yj5oKHl15E8JE+Jr1Xs3Mxb1I4GmPyN49RGUnIAj0xmEUqsR5ytoc1SMibnP77BOu2Y5sJWpXk8doXgLku4vnYRKTljuR1L5k5YojTb3UwLyeRkKJYdQDoW.6RuRpihuemKqcZ9585mnU790ZnHeEoyY6DwnW8m2sPb0qupj7NENKI9HkwxMKU2pVhbGU+Bq3sNo3ESHwilrw3FUZBFGHab8KGalYvKKYXOrggkzgFurbhBVMjNLVbH9YjWbLdu72bYhJx6WbupMGHc0ocss6PRzKudYkB62qtbx81e+iqbt7omGI+HyLipT9pzGlLZqZsacSybWMnL1JeknSTO4zFmCpg7WryKNMdhR6jvzXXiz2DytsTghjjIR2IwNYsincV7gVGlt3kR3h0t33BCN8DipYJuSma1QP+boLZ0nm.B44LPqBfaundOEcHWGDAvl.oqzsnEZPqmPk333OmAVfiR5c.1llIENvk0.npCODdqoSv+YMZHiL15nUxl6D7yEMr0Z4xcB94pOjuEBvxphfx8pXdg4s0RDTfrEv+WrFQElRjs19YgPK+u0yIDQ5K8sqz.4qeScmwZ1y0xWz6Hewti7E+NxWh6He6sLMZEVlQPkB0fWTGRypbMTm.6Am7v0fjlLBSSLOiPcSRWh4z44gz7T3.IZ+rSmCc6MI8fr3NsEQM00LUfiXelaxrh5PsGvIueNT1UHfaHEqSeRGZpHGFp2C.WTAZYnzAAWbeEvUSe5V2DFhM8ULyvzkvatH5NQgZKiJrh5blk6J3fMV0RgTzUgHBntPkmrdOnZb2iCTsuogZXoop9mApYUXEB8mEJnRWTX2mBBOF715.vJLaoDTfRYtoV24qE.ifAGMTlFGhNKZvmfecnu9yB0EJSKbGVMESYeaTGp.4BnrXUUZakguMVYB2hhjucghcKnxLo9nv2FyTgIXvfT4gVncjOMnaDSX2KXXYmYnV3OIJC6AC1AhhNv4mA8vTzkwzzXkTW4Snpsvauvp.xtqgIqmhBWk8AVp0ZdtMBbFC1nkZohBCLSY9EQ+RJmN3z0mALLyjgUaJlCqYtYMOuZVTkZ4DWhnLMF3F6oEz4LzzKUJ7ri7ewzkZIdZeoC7m6WMctqzsZAbMSVpWN84KQLbyn8pIE2pcsvQXAB9ZVKoqKu4xwrePLW82pV8ko4cRm9JB4aE0Y8HdVN6Unk8ggYHNiX5VnrERW8PQ2Pld6JwMnYmYDn7sn7MezvzeVj5R7Lz7VQ.gaZa+CMgFsBGd5XnCPa8KQag9TzVasMZGzL1ombBEDfW6lhnBhMDmsbnV0P4KVMG5zBhUgf8hHQ3gZ4Y+ro3wsEqlUDUrIpgX5rEDygRCCS8jXSnp3YsP0pJN6zOqSVJQmtYCCtsRrdwFPHC82YrSa7jwd5DEZsxjHQfrdxauDy9BEBs4l+EhTCl7EVpkahW994XpmZaYC5y3ZOmxxrtdFNLH8L9YHFzd48osX2Xh2noLgZQj6Ij7RjzPaxedTwUMrI0zcRz.biVbntcW5XtpFVY3KYX58yYtNFcaI2qAjNQt.Ox+UsxuYW0pjyAZOSzPmVLSsgD8UcW3btQA33B7dtnBlpM6R7dp6k3kYjssgNG8NGee9YUUyw.M.t.rqA7Uh4nSYd9sJtIKPH9okI+ZxerE4eyDfY7G+0j+Dul7u2qI+QVB+sKxt3ct.AbcI.2jgDSaEpGXfbjqUjHNWtaP9bDqAPh.t.OYVlCf7F40byrM8a5lZxbD7mjZrhrc+4ihS0mnzqumaiNWJBqNb5M+TlfMceGPlXYEiCMMFMzq+fM4Fa5NSCyxhJS0PuRXMpGrlZzadr9T9rsgL+UVBbehe31TUQlX5ZRmVCmGz9q9y8f1u8ONkl22ZW0TZXOBlQJnUigMUdouSSVi51UAlEOemgZb9k1T+o2RZKlxQDdBOsNXAjyqHPlzEOR0INsWkmE9ZRQcnOMHUxzWRzlXZ9H9ExBrJCD3YsAFnaCikZxbjrOjmkiesdSOwExkwcHpLD+d7reGcU1laATN8k.TrpROcM1N8XdURWaWLUkm8VFnJEmWzvhWtsE6RkYEiXsx7qSewFbDHmCd1aqbyLIdhHOWD4T7HhoFtnHd9qygENWOsP7Eq1RrQ0zkeUQZLOH8aMeafTnvv6DRi6UmN4sARq2PL+WAJ1WUjlv6Iw+h2ZHETrupHcOuV++x27H8C3Y8RybVeUwp2jk.ZdqblJc1VEOQzGRCsRjFj2sA1UATN6TJVULnwtvlSbpAcovxu3fLuk3btKFeLOsKLt0mBYcH1sAVuQjm7FFwz14WFhu8qM+C4qXHORk9l489EnP+rabG.5ev2qNm1autkh8DeepF+X8YoroP7i3qSuctkiwGrDLR+hWdCfQ2OlmmvK1sKQxdN.eDe9ydy7k63c6+8b192m+TvXydcmta9fAq5yn56+6+U+6a5mQ0vM9ynpljMf.22UjEIp2Udgwh4ww4WmiXOR2+zcHEyKIpzA8rqE0qO2ThdmYp5XceKF7ruUphxzigoB8u8ebfy0r2j.RibMKIPX8+Mp7CGTejpE4T5QOOq626gbLujKfMkoW6nO+tGttunrn+tyWTVfM8qx4m4RcNhhtzuNm+f.7nUbmIzanoBvJtGgdyLzgpxtZivai9C+bT78oWRyzI.EyZXRDoewMytn5UekK+3tz+N0M1bmZY++Cj0wmq6O0Ai+D9zEx0rga1F1uQh5WSTAA1u6ZECcig8MzU7cruAw1ToWOhunIKULRaaCMTkcj40D+wAkvS7R86e4G+ctS167bnTl.PyK4BP7iYO+c+CoXK2LBW+OlpIzRluut1y+1FDUB1ZNJh72jRTxf9pStip80+cYFfeCcMdBuiPhXogd2qZjmNEeNVg28.3GvyL+uqp+9o7tNiuyp.eJu6Yi2UUgqsf3G9+aJHd8IXfp+PuS2VyuOOTEZLDyTh9sisrgwH52ZbELj9hderPsOMgx7kHz2klNQkVqQfGPqJv44HSegLMI5xrG9ug+bGLJ84.tCFc5faTGLV5qpClu427y+WdmoClC1jNXNO0R5f4iSsjNXfFN13NX99i+m+t66f4cjNXh8icGLIey0ASx66f49NX9sQGLeymG5+5N1ACW1E5f4e8uZS5f4e5u69NXtuCl66f49NXtuCl66f4GuNXdarGZXISiuRxoJJZxl2iQAjac1+ufCxWg9LZ12lFOeDgHbZPkxekjD0e8SfhgVNOwtC7D+NvSh6.O6cG3Y+6.OO+NvSx0xCsIkzirMzb74AB0Ec9OWdfY+GeOvC49erQklTK
Here are the questions that @gorangrooves and I need to resolve or understand to conduct the current project:
-
MIDI Player doesn't loop at the endOfTrack event, but after the last note off instead resulting in a truncated sequence.
This is the case wether you play from startInternalClock or click play in the MP (when not synced to the master clock of course) -
setOnBeatChange doesn't fire at the first beat
-> Is this intended? -
setOnBeatChange doesn't follow a custom tempo (setHostBpm) but only the external one, hence the HACK TEMPO solution.
-> Is it good or bad? -
When Internal sync is selected, the playing speed still reacts to DAW tempo change.
Vice versa with External, the speed reacts to custom tempo.
-> Is this intended?
-> Are the sync modes only related to play/stop and not the tempo? -
In the real world, I am using setOnBeatChange to play the next sequence (number of bars in the seq times a counter+isNewBar)
-> Is this a good approach?
EDIT: fix tempo hack in snippet
-
-
MIDI Player doesn't loop at the endOfTrack event, but after the last note off instead resulting in a truncated sequence.
I'm such an idiot it isn't even funny anymore. The end of track event was in there all along, I just deleted it :) It's fixed now ...
setOnBeatChange doesn't fire at the first beat
Yup, use the start / stop callback for that (or if you don't want to duplicate the logic, just call your onBeatFunction in the onStart callback manually).
When Internal sync is selected, the playing speed still reacts to DAW tempo change.
Yeah that was kind of messy (it checks whether you've called Engine.setHostBpm()). I've refactored some code relating to this and added a new function to the TransportHandler that will link the bpm to which mode is currently active. So if this is enabled, it will use the internal BPM if the sync mode is Internal and the host bpm if the sync mode is external (if you set the internal bpm to -1 it will always use the host bpm and if the host bpm can't be detected it will use the internal bpm).
In the real world, I am using setOnBeatChange to play the next sequence (number of bars in the seq times a counter+isNewBar)
No, the accuracy of the beat change callback might not be enough. Use the onGridChange callback, this will get you a sample accurate position with a timestamp within the current buffer.
-
@Christoph-Hart said in Still trying to make sense of Tempo, Sync, and MIDI loop issue:
I'm such an idiot it isn't even funny anymore. The end of track event was in there all along, I just deleted it :) It's fixed now ...
Amazing! Thanks!
Yup, use the start / stop callback for that (or if you don't want to duplicate the logic, just call your onBeatFunction in the onStart callback manually).
Well, the idiot is me...
Yeah that was kind of messy (it checks whether you've called Engine.setHostBpm()). I've refactored some code relating to this and added a new function to the TransportHandler that will link the bpm to which mode is currently active. So if this is enabled, it will use the internal BPM if the sync mode is Internal and the host bpm if the sync mode is external (if you set the internal bpm to -1 it will always use the host bpm and if the host bpm can't be detected it will use the internal bpm).
Nice! I'm checking this ASAP
But this confirms how setHostBpm term is confusing to me, since it is not necessarily the host that it sets for all values except -1No, the accuracy of the beat change callback might not be enough. Use the onGridChange callback, this will get you a sample accurate position with a timestamp within the current buffer.
Oh of course how couldn't I see this!
Math.pow(idiot, greg)
... -
But this confirms how setHostBpm term is confusing to me, since it is not necessarily the host that it sets for all values except -1
Yeah, it was super convoluted and prone to weird edge cases, but I think I've boiled it down to a very simple logic:
if(linkBpmToSyncMode) // this is the new function TH.setLinkBpmToSyncMode() { if(syncMode == Internal || syncMode == PreferInternal) return internalBPM; else return hostBpm; } else { if(internalBpm != -1) return internalBpm; else return hostBpm; }
-
@Christoph-Hart Hmmm... It seems the endOfTrack is still not taken into account for some reasons
The NumBars meta should be 1.0 in the above 4/4 sequence example, but is 0.79270833333 in reality, which again seems to correspond to the last noteOff
This is the midi file in question:
Rock Groove 01A Bsc Qtrs cl hats.mid.zipCould the endOfTrack be at the same timestamp as the last noteOff?
-
@ustk yes. I noticed that when you export a clip from ableton it will also set the end of track to the last note off.
-
@Christoph-Hart hmm that's annoying... Someone will not be dancing when learning this
-
But I downloaded a random MIDI pack (took me a few minutes to find something that didn‘t want my email address in exchange) and with those it worked so the end of track is definitely detected now).
-
@Christoph-Hart Well apparently it's the same thing from Pro Tools... I have to try another DAW...
-
@Christoph-Hart Well that's a bit too weird... I tried exporting from Ableton, Cubase, Pro Tools and Reaper, same thing... Knowing that I selected "Export Locator Range" in Cubase and "Time Selection Only" in Reaper
Same issue from 4 major DAWs isn't a coincidence... I wonder which DAW has been used for the library you downloaded so I could test it... Or perhaps there's a ghost note that has the noteOff right at the end of the bar? This is the only trick that I found to make it work...
The MIDI Viewer still considers the last noteOff...
Could you check the last noteOff timestamp in your MIDI files to be sure it is BEFORE the end of the bar? This would be the only indicator that tells if it's the endOfTrack that is then read, or a ghost note...
Or the endOfTrack timestamp in this file -> Cubase 4-4 1bar noGhostNote.midi.zipWhen I re-import back into a DAW, I obtain the full bar length, meaning the endOfTrack is where it should be I think.
So I think Hise still doesn't seem to read it... Or is there another indicator for the bar length?(before you ask, yes I updated Hise because I can see the new
setLinkBpmToSyncMode
method :) ) -
@ustk I just checked the file and it has an end of track marker, however the event has a timestamp of zero (so it can‘t deduce where the actual event is).
-
@Christoph-Hart Interesting... And what about the one from the library you downloaded yourself? It would be weird that all files exported from 4 different DAWs have the same issue.
Could you please send to me the one you used? I'm lost with all these weirdnesses... -
@Christoph-Hart Is this normal that I have to set the
tempoFactor
ofsetEnableGrid
to 0.5 in order to get the gridChange to be in sync?
setting to 1.0 doesn't simply double the speed but make it to trigger at a weird tempo... -
@ustk the tempofactor is the enum from 1-18 (check the values by setting a slider mode to tempo and then read out the integers). 1 is probably 1/1D or something which some people without a feeling for polyrhythms might call „weird“ :)
-
@Christoph-Hart Oh that makes sense in this case!
some people without a feeling for polyrhythms might call „weird“ :)
Then I don't !
-
@Christoph-Hart After testing this in all ways I could imagine, this endOfTrack issue still doesn't make sense to me.
Effectively the EOT timestamp is wrong in the library I am using.
But this library is playing nicely in other players, meaning they are not taking the EOT into account (or they fall to another calculation method when the EOT is wrong)Even if somehow we fix the EOT timestamps of the library, since the exports from major DAWs also have this issue, what will happen when users make their own midi files exports from any DAW? They won't play in our player despite they will work in other players...
All of this tells me that it is Hise that should take care of the sequence length, isn't it?
Another consequence is that the MidiView or rectangle list also reflects this wrong sequence length
-
@ustk I've just pushed a commit that will round up the value if it can't be detected properly (which I'm guessing is everybody else doing since there is no other way to retrieve that information).
-
@Christoph-Hart Great! I will test this asap!
I agree with the principle, and that's what I am doing in the midi browser to display the right sequence length.
I just couldn't do the player side of it, so thanks!