rncbc / qtractor

Qtractor - An Audio/MIDI multi-track sequencer
https://qtractor.org
GNU General Public License v2.0
509 stars 88 forks source link

Latency compensation current status #258

Open lpgasparotto opened 4 years ago

lpgasparotto commented 4 years ago

Hi, I'm using Qtractor 0.9.10 (OS is Fedora 31 KDE) and I'm having issues when recording new audio tracks over previously recorded tracks. Qtractor compensates latency partially even after adding the values suggested by jack_iodelay to QJackCTL configuration. It seems like Qtractor ignores those values and only seems to compensates considering the frame/period/Freq values. The question is. Was this solved in the GIT version? This is not listed as "Fixed" in more recent releases. I've attached a few screenshots for a better understanding of this. Thank you very much in advance QJackCTL-Config1 QJackCTL-Config2 QJackCTL-Graph Qtractor-tracks Qtractor-version

rncbc commented 4 years ago

you're recording on a in insane frames/period setting (buffer-size); in your case, JACK will surely report an input latency of at least 2048 + 447frames/period which I think is insane and not quite what you possibly ever desire; Qtractor compensates to the value that JACK reports, no more no less.

you shall get better results if you record on buffer-sizes (frames/period) that are lesser than the jack_iodelay figure (447frames in your case) which stands for round-trip external I/O latency alone.

so I would suggest for you to try with at least on 256frames/period and even reduce that as much as you don't get a xrun storm; 128fpp is a good overall compromise as all modern systems should (must) cope with that.

cheers

lpgasparotto commented 4 years ago

Hi Rui, Thank you very, very much for your reply and a very big thank you for making QTractor for free. I tried with lower buffer setting (256 Frames) and despite the delay is less noticeable it still happens. I've attached a couple of screenshots QJackCTL-Config1b Qtractor-tracksb Ardour has no problems with latency compensation even with large buffer configurations. But Qtractor and Muse, which is supposed to do latency compensation, don't fully compensate latency. I also tested with Rosegarden and had no luck but I'm not sure it does latency compensation.

That's strange, why Ardour can do latency compensation while QTractor and Muse can't do it? It could be related to my system configuration? Maybe a permissions issue? Is there some way I could get more information for finding the cause of the problem?

Thank you very much again and best regards!

Luis Pablo Gasparotto

lpgasparotto commented 4 years ago

After some experimentation I realized that QTractor only consider the values on -I and -O parameters because changing those values it was able to compensate latency nicely. I needed to add a pair of values which are slightly bigger than the half of the total roundtrip latency reported by jack_iodelay and that explains why latency compensation works better with lower buffers, because the buffer is not considered for doing latency compensation. I guess this qualifies as a bug. QJackCTL-Config1c Qtractor-tracksc Thank you very much again, Luis Pablo Gasparotto

rncbc commented 4 years ago

as said, qtractor reads reported latency from JACK and just sets the new recorded clip offset, as for recording latency compensation;

usually, when recording from a physical capture ports, this value is the sum of the one buffer-size (-p, frames/period) plus the input latency you set on JACK advanced settings (-I).

if you're not happy with the reported value, you can always adjust the clip offset value, manually afterwards (Clip > Edit..)

both muse and qtractor are using the same JACK API to dumbly read input latency and compensate by just offsetting the recorded audio clip in the timeline; on the other hand, ardour is probably a lot more sophisticated in that area and most certainly does its own magic calculations for sure :)

byee

lpgasparotto commented 4 years ago

Thank you very much for your reply Rui! It makes sense, I did a new test with the following values: 2048 Frames, 2 periods and -I 3000 And the latency compensation was around the same as 2048 Frames, 3 periods and -I 5000 Which makes me confirm what you said, QTractor only consider 1 period for latency and ignores the -O value So, the value of -I should be (total periods - 1) Frames per period + I value recommended by jack_iodelay 2 Am I right? If this is the case and total periods information and the -O setting are available to QTractor it would be great to use that information in the same way Ardour and Reaper (Linux version) do it: frames to compensate = Frames per period * total periods + I value + O value Is that possible? What do you think about it? I guess to standardize this would make easier to switch between DAWs without changing the Jack configuration every time you need to change from one to another. Best regards, Luis Pablo

lpgasparotto commented 4 years ago

Hi, This is an update to my previous post. I was working on a project which required to record over previously recorded tracks and I used this formula for the value of -I parameter: (total periods - 1) Frames per period + I value recommended by jack_iodelay 2 2 2048 + 438 2 = 4972 Considering QTractor would add 1 period * the amount of frames per period which should be 7020 frames but QTractor considered 2 periods + I value and clip offset was 9068 frames. So, I realized I should use -I 2924 for QTractor and -I 438 -O 438 for Ardour, MuSE (3.1, previous versions didn't compensate latency) and Reaper. That's a weird thing.

rncbc commented 4 years ago

you don't have to have different JACK latency settings for qtractor ...

please test with qtractor > 0.9.16git. https://github.com/rncbc/qtractor/commit/e419f0, whether you need for that special make up. much appreciated cheers

lpgasparotto commented 4 years ago

Hi Rui, Thank you very much for your reply. I compiled and tested the new version (with the fixed qtractorAudioEngine.cpp file). I used the same Jack configuration I use with Ardour and Muse: 3 Periods 2048 Frames per period 438 / 438 I/O Latency The expected offset was 3 * 2048 + 438 + 438 = 7020 Frames The added offset was 2481 Frames which is even more weird. QJackCTL-Config1d QJackCTL-Config2d Qtractor-ClipOffset Best regards

rncbc commented 4 years ago

the expected offset should be the one reported by JACK API for the input port for which the audio clip was recorded from, that is: 2048 + 438 = 2486!

as a sidenote: the number of periods (3 in your example) is irrelevant for input latency estimation--it is only meaningful for output latency, and JACK knows that for sure!

however, this clip offset value is quantized to current MIDI PPQN (aka. ticks-per-beat or -quarter-note) so it's also slightly adjusted depending on the local clip start position and tempo (BPM); so the clip offset number of frames should be more or less that mark (2481 is just 5 frames below exact 2486, so I don't consider that weird at all :)).

ps. check qtractor >= 0.9.13.17git. https://github.com/rncbc/qtractor/commit/c14661 where that weirdness has been ruled out--however take note that's highly experimental for the time being, as some hardcore users might not be so pleased with this move :)

lpgasparotto commented 4 years ago

Hi Rui, Thank you very, very much for taking care about my comments. I cloned and compiled the last version and I'm still no lucky. I agree with you about "-I 438 -O 438" it's the same as using "-I 876 -O 0" in my case. I did a test comparing the way Ardour, QTractor, MusE and Rosegarden compensate latency when recording over previously recorded tracks. In all programs I imported a click exported from Hydrogen as WAV and recorded 2 tracks using this I/O latency configurations: Track 2: -I 438 -O 438 Track 3: -I 4972 -O 0 I found Rosegarden didn't compensate latency no matter the values I used for Latency I/O configuration. Then Ardour and MusE did it fine in track 2 but overcompensated on track 3. QTractor did it fine in track 2 but didn't compensate enough in track 2. This confirms QTractor needs a different value for latency compensation. I attached screenshots as a reference: Ardour-Latency MusE-Latency QTractor-Latency Rosegarden-Latency Thank you very much again and best regards,

lpgasparotto commented 4 years ago

I want to add that Reaper behaves in the same way as Ardour and MusE: Reaper-Latency

rncbc commented 4 years ago

I agree with you about "-I 438 -O 438" it's the same as using "-I 876 -O 0" in my case.

no, it is not, and I 'm sure I have not said such a thing either.

I imported a click exported from Hydrogen as WAV and recorded 2 tracks using this I/O latency configurations: Track 2: -I 438 -O 438 Track 3: -I 4972 -O 0 ... QTractor did it fine in track 2 but didn't compensate enough in track 2. This confirms QTractor needs a different value for latency compensation. I attached screenshots as a reference: QTractor-Latency

can you please tell what are the recorded clip offsets in track 2 and track 3 ? and how are you conduction your recordings? I suppose you're relying on JACK-transport to trigger the playback: that being the case do you start playback on hydrogen or is it on qtractor ?

lpgasparotto commented 4 years ago

I agree with you about "-I 438 -O 438" it's the same as using "-I 876 -O 0" in my case.

no, it is not, and I 'm sure I have not said such a thing either.

You didn't say that, I assumed that's the idea behind using only -I parameter and dismissing -O parameter, I know it's not the same, I was talking exclusively about the use of these values for calculating the clip offset. AFAIK, the -O parameter is for the latency between the moment on which the computer plays a sound and the moment the sound is played by the audio card/interface, on the other hand the -I parameter is for the latency between the moment the sound goes into the audio card/interface and the moment on which that sound is recorded in the computer disk. For example, if my audio interface takes 438 frames to play a sound since the computer plays it, it means I will hear that sound 438 frames later and then my audio interface takes 438 frames to make the recorded audio to the computer hard disk, it means the audio will be recorded 438 frames after I heard it. Conclusion: the audio interface added a total delay of 876 frames between the existent tracks and the new recording.

I imported a click exported from Hydrogen as WAV and recorded 2 tracks using this I/O latency configurations: Track 2: -I 438 -O 438 Track 3: -I 4972 -O 0 ... QTractor did it fine in track 2 but didn't compensate enough in track 2. This confirms QTractor needs a different value for latency compensation. I attached screenshots as a reference: QTractor-Latency

can you please tell what are the recorded clip offsets in track 2 and track 3 ? and how are you conduction your recordings? I suppose you're relying on JACK-transport to trigger the playback: that being the case do you start playback on hydrogen or is it on qtractor ?

Track 2 offset is 2486 Track 3 offset is 7020 I'm not using Hydrogen for the reference track, I just exported that track as a WAV file from Hydrogen and then imported that WAV file on QTractor, that clip offset is zero. I used a loop back cable between OUT 1 and IN 1 of my Mackie Onyx Blackjack audio interface.

Best regards, Luis Pablo

rncbc commented 4 years ago

ok. may you redo all your tests with qtractor >= 0.9.13.20git.https://github.com/rncbc/qtractor/commit/3b02b9 ?

let me tell you that all your kind efforts on this topic are very much appreciated many thanks again

lpgasparotto commented 4 years ago

Thank you very much for considering my comments. I'll download the new version and I tell you how it works. Best regards, Luis Pablo

lpgasparotto commented 4 years ago

Hi Rui, I downloaded that version and compiled it. The clip offset is still 2486 for -I 438 -O 438 QTractor-Latency2 QTractor-Latency2b Best regards, Luis Pablo

rncbc commented 4 years ago

getting somewhere... please retry with qtractor >= 0.9.13.21git. https://github.com/rncbc/qtractor/commit/4f0a6d thanks

lpgasparotto commented 4 years ago

Thank you very much! I'll do it and I'll tell you how it works.

lpgasparotto commented 4 years ago

I tested it, clip offset was 4534 for -I 438 -O 438 Best regards

lpgasparotto commented 4 years ago

It seems 2048 frames (1 period) + 438 frames were not considered in the formula

lpgasparotto commented 4 years ago

I changed the configuration and reduced the number of periods from 3 to 2 and the clip offset was again 4534 which seems to be 2048 2 + 438 Then I reduced frames per period from 2048 to 1024 and offset was 2486 which seems to be 1024 2 + 438 Then I increased the number of periods from 2 to 4 and offset was 2486 again which makes me think the number of periods is considered a constant with value = 2

rncbc commented 4 years ago

for recording, the number of periods is irrelevant for input latency compensation; the number of periods is only meaningful for output latency calculations, being this exactly one shown on the qjackctl setup/settings dialog.

anyway, having a recorded audio clip-offset = 4534 frames is exactly the kind of compensation you should expect when running JACK on frames/period (-p) = 2048 and additional input latency (-I) = 486 frames.

lpgasparotto commented 4 years ago

Hi Rui, I guess the output latency should be also considered. The clips need to be moved 7020 frames to be compensated. In the usual workflow, the user will record a new clip while hearing other audio tracks which were previously recorded or imported, these previous tracks will be reproduced a number of frames later than their position in the QTractor timeline (I suppose you're refer to this delay as "output latency") and then the user will play an instrument or sing a song this audio information will be digitalized by the audio interface and then the digital information will be capturated by QTractor (I suppose we refer as "input latency" to the amount of frames between the audio signal gets into the audio interface and the moment on which the digital audio is placed in the timeline). Let me give you an example and please dismiss the number of frames because they are just for reference, I need to record my saxophone over existent tracks (drums, bass, piano and guitar, all of them starting at 10000 frames position in the QTractor timeline) so I create a new audio track and press the track's "R" button and the general recording button and then the Play button, QTractor begins to reproduce existent tracks and to record my saxophone but...

rncbc commented 4 years ago

i understand all that, but to keep the whole story short I'd say it again:

when recording and/or overdubbing, make sure to keep the frames/period setting (buffer-size) to an absolute minimum as possible, as short as your running system and/or hardware permits: meaning a JACK frames/period (-p) or buffer-size well under the jack_iodelay readings--assuming you are measuring it with a real physical out->in external loop (which you said you are).

please, leave the 2048 frames/periods setting for when you're only listening for playback :)

hth. cheers

lpgasparotto commented 4 years ago

Hi Rui, Thank you very much again for your time. I guess the best way to be able to use the same JACK setting with QTractor and the rest of the DAWs I could use is to set 2 periods instead 3 and to set the entire latency reported by jack_iodelay (876 frames in my case) to -I instead setting the half to -I an the other half to -O. I think it's better to reduce periods to 2 instead keeping 3 periods and reducing the frames per period since offset would be in a less amount but still wrong. Let's do another example, with these configurations

7u83 commented 1 year ago

Clip offset calculation is done wrong. There is only input latency considered. https://github.com/rncbc/qtractor/blob/master/src/qtractorSession.cpp#L1754 But you have to take account of both - output and input latency. Changing to something like "pAudioClip->setClipOffset(pAudioBus->latency_in() + pAudioBus->latency_out());" leads to the same behavior as known from other DAWs like Ardour.

rncbc commented 1 year ago

please provide a PR with your findings, assuming you have some empirical evidence ;)

cheers

7u83 commented 1 year ago

Sure, I have empirical evidence. I can create perfect recordings with insane settings like this: image I have sent you a PR. This should do perfect latency compensation in many cases. But Qtractor lacks latency compensation in other places. As far as my experience goes, it does not compensate latency between output busses with different latency. For example: There is an audio output bus with output latency of 1700 ms. And a MIDI output bus to an external synth with almost zero latency. When playing back a WAV and a MIDI track, the external synth will be 1700 ms ahead. To do latency compensation here, the start of MIDI track has to be delayed by 1700 ms. The code in my PR works fine, when all output busses have the same latency. That's definitely a big step forward, because it satisfies many users who only work with WAV and softsynths.