View Issue Details

IDProjectCategoryView StatusLast Update
0001017OpenMPT[All Projects] libopenmptpublic2018-08-18 12:49
ReporterSaga MusixAssigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
Product Version 
Target Versionlibopenmpt 0.5 (goals)Fixed in Version 
Summary0001017: Tick boundary rendering (was: Provide access to next play position)
Description

PoroCYon asked on IRC if it's possible to retrieve the next play position (row/pattern). We already have this information, but it is currently not exposed.

Additional Information

https://forum.openmpt.org/index.php?topic=5935

TagsNo tags attached.
Has the bug occurred in previous versions?
Tested code revision (in case you know it)

Activities

manx

manx

2017-08-27 06:38

administrator   ~0003194

Uhm, what would be the use case here?

I'd rather see this aspect to be factored into the already planned tick-boundary accurate playback.

Saga Musix

Saga Musix

2017-08-27 14:34

administrator   ~0003195

I can see use cases like OpenMPT's smooth pattern scrolling - depending on the next play position, you may have to scroll either up or down.

Saga Musix

Saga Musix

2017-08-27 18:07

administrator   ~0003196

Another use case is any general monitoring of pattern transitions. Let's say you want to do a transition to a different pattern once the current pattern has finished playing. Since the pattern may end on any row due to pattern break commands, it may not be known what is going to be the last row of the current pattern. If you want to solve this using tick-boundary rendering, you will have to throw away rendered audio for at least one tick, which I think would generally make control flow more complicated (and of course increase the required processing time).

manx

manx

2017-08-27 18:27

administrator   ~0003197

Another use case is any general monitoring of pattern transitions. Let's say you want to do a transition to a different pattern once the current pattern has finished playing. Since the pattern may end on any row due to pattern break commands, it may not be known what is going to be the last row of the current pattern.

In that case, the required API would be more narrow than what is required to solve this issue. It would only be necessary to query the next play position after a tick has been rendered completely. And I would be very much OK with an API only implementing exactly that (once we have tick-boundary rendering).

I am very hesitant to add an API like the one described in this issue as it (on the API level) requires predicting the future. After all, semantically, the next play position does not actually need to be known until after the current tick has been rendered completely. It may be possible to implement that unambiguously for the currently known and supported formats, but if some other format or tracker quirk shows up that makes the next play position depending on anything mixer-related (sample loops or whatever), this API would not be supportable without adding another buffering or prediction layer inside libopenmpt.

I do not think it makes much sense to try to handle any of the use cases described here while not thinking about tick-boundary rendering at the same time.

Saga Musix

Saga Musix

2018-02-14 19:48

administrator   ~0003421

Related: It might make sense to provide two more functions,

  • get_current_tick(): Returns the currently processed tick on the current row.
  • get_ticks_on_current_row(): Some pattern commands can extend the duration of a row and are not considered by get_current_speed(). This function would return the true number of ticks on the current row.
manx

manx

2018-02-14 20:04

administrator   ~0003422

To summarize the additional design suggestions so far:

  • set_tick_auto_advance(bool): Set tick-auto-advance mode, true meaning the default and old behaviour, false requiring manual tock advancing
  • get_tick_auto_advance(): Getter for the above setting
  • get_current_tick_frames(): Returns the number of sample frames in the current tick
  • get_current_tick_remaining_frames(): Returns the number of sample frames until the current tick is done (this maps 1:1 to the internal m_PlayState.m_nBufferCount value)
  • advance_tick(): Advances the internal play state by one tick. This would only be valid when get_current_tick_remaining_frames() == 0.
    This is by no means meant to be the final API design, but merely a suggestion for further discussion.
    How to handle read() in tick-boundary mode still has to be designed.
    Also, most of the API goes somewhat haywire when considering changing sample rates (which probably were not that good of a design decision in the first place). We might just deprecate changing sample rates and require explicit sample rate setting when desiring a change. However, the even more concerning (future) feature in this area is internal mixer oversampling and the inherent delay it would cause in the output path.
manx

manx

2018-02-14 20:08

administrator   ~0003423

We also should investigate whether splitting advance_tick() into finish_tick() and start_tick() (or similar) could turn out to be useful for certain use cases.

Saga Musix

Saga Musix

2018-02-14 20:13

administrator   ~0003424

One challenge here is going to be that, from what I understand, information like get_current_tick_frames() needs to be available before the actual read() call, but currently this information is updated during the read() call (i.e. at the beginning of a tick). Internally, we might have to split up the calls to CSoundFile::ReadNote() and the rest of CSoundFile::Read(). Further complications arise from interactive functions that e.g. set the current play position or tempo. The semantics of doing such things before calling advance_tick() and after calling it need to be considered.

manx

manx

2018-02-14 20:23

administrator   ~0003425

One challenge here is going to be that, from what I understand, information like get_current_tick_frames() needs to be available before the actual read() call, but currently this information is updated during the read() call

This is precisely the reason why I think we need the explicit advance_tick() call or something similar. Unless advance_tick() got called, the information would apply to the previous, just finished, tick (what happens on seek and song start needs to be considered here). And yes, that obviously requires splitting CSoundFile::Read() into multiple functions. However, I do not think that can be avoided anyway, regardless of what the API looks like. It currently does too many things at once, which makes designing an API on top of the current implementation close to infeasible, or at the very least inflexible and limited in what use cases it could solve. Preferably, the CSoundFile::Read() split would both, closely match the exported libopenmpt API, as well as suite the internal needs of the OpenMPT playback engine.

Issue History

Date Modified Username Field Change
2017-08-26 21:27 Saga Musix New Issue
2017-08-27 06:38 manx Note Added: 0003194
2017-08-27 09:27 manx Target Version => libopenmpt 0.5 (goals)
2017-08-27 14:34 Saga Musix Note Added: 0003195
2017-08-27 18:07 Saga Musix Note Added: 0003196
2017-08-27 18:27 manx Note Added: 0003197
2018-02-13 15:39 manx Additional Information Updated View Revisions
2018-02-14 19:48 Saga Musix Note Added: 0003421
2018-02-14 20:04 manx Note Added: 0003422
2018-02-14 20:08 manx Note Added: 0003423
2018-02-14 20:08 manx Target Version libopenmpt 0.5 (goals) => libopenmpt 0.4 (goals)
2018-02-14 20:13 Saga Musix Note Added: 0003424
2018-02-14 20:23 manx Note Added: 0003425
2018-02-14 20:25 manx Summary libopenmpt: Provide access to next play position => Tick boundary rendering (was: Provide access to next play position)
2018-08-18 12:49 Saga Musix Target Version libopenmpt 0.4 (goals) => libopenmpt 0.5 (goals)