liquidsoap icon indicating copy to clipboard operation
liquidsoap copied to clipboard

Crossfade operator messes up source.elapsed(s) and source.duration(s)

Open gAlleb opened this issue 1 year ago • 6 comments

Describe the bug

If you have sources before crossfade operator and want to use source after applying crossfade operator as a source of time data then time data of tracks will be inaccurate — in an increasing pattern: source.elapsed(s) and source.duration(s) will always increase source.remaining(s) will not be affected

To Reproduce

radio = switch([({ 7h-22h }, dayshift), ({ 22h-7h }, nightshift)])
radio = crossfade(smart = false, fade_out=3.00, fade_in=0.00, duration=3.00)
def print_source_info(s)
    elapsed = format_time(source.elapsed(s))
    remaining = format_time(source.remaining(s))
    duration = format_time(source.duration(s))
    id = source.id(s)
    print("id=#{id} elapsed=#{elapsed} remaining=#{remaining} duration=#{duration}")
end
thread.run({print_source_info(radio)}, every=5.)
id=switch.23 elapsed=01m:29s remaining=00m:26s duration=01m:56s
id=switch.23 elapsed=01m:31s remaining=00m:24s duration=01m:56s
id=switch.23 elapsed=01m:33s remaining=00m:22s duration=01m:56s
id=switch.23 elapsed=01m:35s remaining=00m:20s duration=01m:56s
id=switch.23 elapsed=01m:37s remaining=00m:18s duration=01m:56s
id=switch.23 elapsed=01m:39s remaining=00m:16s duration=01m:56s
id=switch.23 elapsed=01m:41s remaining=00m:14s duration=01m:56s
id=switch.23 elapsed=01m:43s remaining=00m:12s duration=01m:56s
id=switch.23 elapsed=01m:45s remaining=00m:10s duration=01m:56s
id=switch.23 elapsed=01m:47s remaining=00m:08s duration=01m:56s
id=switch.23 elapsed=01m:49s remaining=00m:06s duration=01m:56s
id=switch.23 elapsed=01m:51s remaining=00m:04s duration=01m:56s
id=switch.23 elapsed=01m:53s remaining=00m:02s duration=01m:56s
id=switch.23 elapsed=01m:55s remaining=00m:00s duration=01m:56s
Track changed
id=switch.23 elapsed=01m:57s remaining=00m:01s duration=01m:59s
id=switch.23 elapsed=01m:59s remaining=04m:19s duration=06m:18s
id=switch.23 elapsed=02m:01s remaining=04m:17s duration=06m:18s
id=switch.23 elapsed=02m:03s remaining=04m:15s duration=06m:18s
id=switch.23 elapsed=02m:05s remaining=04m:13s duration=06m:18s
id=switch.23 elapsed=02m:07s remaining=04m:11s duration=06m:18s

or

radio1 = switch([({ 7h-22h }, dayshift), ({ 22h-7h }, nightshift)], id="switch_radio1")
radio2 = crossfade(smart = false, fade_out=3.00, fade_in=0.00, duration=3.00, radio1, id="crossfade_radio2")
thread.run({print_source_info(radio1)}, every=5.)
thread.run({print_source_info(radio2)}, every=5.)

id=switch_radio1 elapsed=02m:49s remaining=00m:24s duration=03m:14s
id=switch_radio1 elapsed=02m:54s remaining=00m:19s duration=03m:14s
id=switch.23 elapsed=02m:51s remaining=00m:19s duration=03m:11s
id=switch_radio1 elapsed=02m:59s remaining=00m:14s duration=03m:14s
id=switch.23 elapsed=02m:56s remaining=00m:14s duration=03m:11s
id=switch_radio1 elapsed=03m:04s remaining=00m:09s duration=03m:14s
id=switch.23 elapsed=03m:01s remaining=00m:09s duration=03m:11s
id=switch_radio1 elapsed=03m:09s remaining=00m:04s duration=03m:14s
id=switch.23 elapsed=03m:06s remaining=00m:04s duration=03m:11s
id=switch.23 elapsed=03m:11s remaining=00m:00s duration=03m:11s
id=switch_radio1 elapsed=03m:14s remaining=00m:00s duration=03m:14s

ta-dam

id=switch.23 elapsed=03m:16s remaining=02m:50s duration=06m:06s
id=switch_radio1 elapsed=00m:08s remaining=02m:50s duration=02m:58s
id=switch.23 elapsed=03m:21s remaining=02m:45s duration=06m:06s
id=switch_radio1 elapsed=00m:13s remaining=02m:45s duration=02m:58s
id=switch_radio1 elapsed=00m:18s remaining=02m:40s duration=02m:58s
id=switch.23 elapsed=03m:26s remaining=02m:40s duration=06m:06s
id=switch_radio1 elapsed=00m:23s remaining=02m:35s duration=02m:58s
id=switch.23 elapsed=03m:31s remaining=02m:35s duration=06m:06s
id=switch_radio1 elapsed=00m:28s remaining=02m:30s duration=02m:58s
id=switch.23 elapsed=03m:36s remaining=02m:30s duration=06m:06s
id=switch_radio1 elapsed=00m:33s remaining=02m:25s duration=02m:58s
id=switch.23 elapsed=03m:41s remaining=02m:25s duration=06m:06s
id=switch_radio1 elapsed=00m:38s remaining=02m:20s duration=02m:58s
id=switch.23 elapsed=03m:46s remaining=02m:20s duration=06m:06s
id=switch_radio1 elapsed=00m:43s remaining=02m:15s duration=02m:58s

Expected behavior Crossfade operator should not affect source.elapsed(s) and source.duration(s) time data

As for now to fetch correct time data one must use source before applying crossfade operator

Version details

  • OS: Ubuntu 20.04
  • Liquidsoap 2.2.1

Install method opam

Thanks to @vitoyucepi for pointing it out!

gAlleb avatar Sep 13 '23 14:09 gAlleb

We’ve been having that for some time (and been trying to find ways for progress indicators, hee hee). One could argue that the new source after crossfading/mixing is essentially one new, long track. Apparently this is what LS does, so the previous single track info gets lost.

Moonbase59 avatar Sep 14 '23 21:09 Moonbase59

Yes I can concur. How would y'all think we should mark a single track change in the presence of a crossfade? What would be the most expected behavior?

For reference:

Drawing

toots avatar Sep 18 '23 10:09 toots

@toots I might insist that this is a somewhat incorrect example. An example of a professional crossfade is as follows: image

pozhiloy-enotik avatar Sep 20 '23 21:09 pozhiloy-enotik

@pozhiloy-enotik I can see that. I think that the problem is that we also rely on events triggered by track start as well as track end and, as of now, we only have one type of even, track_mark so, the above, if we were to mark the end of track there, we would also implicitly say that the new track starts there are well, which would mess up events related to the new track's start.

I'll see if we could do better.

toots avatar Sep 25 '23 09:09 toots

Actually, to give another example: what would you return for source.elapsed during this part of your timeline:

269422931-b6ff8224-b4db-48a4-8580-a8a42028f37e

toots avatar Sep 25 '23 09:09 toots

This is actually complicated, since we don’t really have track-based counts.

Personally, I’d probably count out "source.elapsed" until "End of track" above, but introduce a "help counter" that starts with track "blue" starting. After track "red" is finished, I’d update "source.elapsed" to the value of the "help counter" and count on, so as to show the real playtime of track "blue" again.

This is of course only a workaround, but might mirror "reality" a bit more closely.

Thinking that you already might have "start track" and "end track" events, and possibly a hi-res internal timebase, or frame counts, this might actually be doable.

Moonbase59 avatar Feb 06 '24 14:02 Moonbase59