hydrogen-music / hydrogen

The advanced drum machine for Linux, macOS, and Windows
http://www.hydrogen-music.org
GNU General Public License v2.0
1.03k stars 172 forks source link

jack transport playhead relocations with pipewire-jack #2033

Open devloop0123 opened 3 days ago

devloop0123 commented 3 days ago

Hydrogen version * :1.3.0-alpha-702beb51e, compiled fom git Operating system + version : Linux Mint 22 Audio driver + version : pipewire with pipewire-jack, version1.0.5


The issue does not occur on my Linux Mint 21.3 Jack system, so I already reported this issue to Pipewire. But in case it may be a H2 issue (too), here's what happens.

Using MusE sequencer as transport master, Hydrogen as slave, I get the following misbehaviour on playhead relocations (but only if "jack timebase master support" is enabled in H2's preferences):

The playhead in the slave (Hydrogen) will be moved to the location from where the playhead moved in the master (MusE). So if initially, with playback stopped, the playheads align at bar 1, and I move the playhead in MusE to bar 8, then the playhead in H2 does not move. If I then move the playhead in MusE to bar 2, the playhead in H2 moves to bar 8, etcetera. With playback, if they initially align, and I set a loop in MusE from bar 5 to 8, the first return to bar 5 is ignored in H2 which will just play on from bar 9, but the second time MusE returns from the end of bar 8 to bar 5, H2 will move from the end of bar 12 to bar 9.

Suggested steps to reproduce:

1 Start MusE, enable "Jack Transport" and "Timebase Master" in its GUI.

2 Start Hydrogen, enable song mode, go to Preferences, tab Audio System, and enable Jack timebase master support there, click "apply and restart output", "ok".

3 Enable "Jack Transport" via H2's GUI button, and ensure "J. master" is off. Click it for good measure until you've seen the message "Jack timebase mode = listener" beside it.

4 Draw a good few blocks to increase the song length. By default, the Hydrogen block size coincides with MusE's bar size in measure 4/4.

5 Arrange the MusE and Hydrogen windows so you see them simultaneously.

6 Both playheads should be located at position 1 (first bar/block). Now click at position 8 in MusE's location strip. Its playhead will move there. But Hydrogen's playhead will remain at position 1.

7 Now click at position 4 in MusE's location strip. MusE's playhead will jump there, and now you'll see Hydrogen's playhead move to location 8, the position just vacated by MusE's playhead. And so forth and so on...

There is a workaround: do not enable Jack timebase master support in Hydrogen. But then you'll have to manually copy all tempo settings and changes from the Master's timeline to Hydrogen's timeline.

theGreatWhiteShark commented 3 days ago

Hey @devloop0123 ,

Thanks for reporting! Which MusE version/commit you are on? I'll try to reproduce the behavior in a couple of days

devloop0123 commented 3 days ago

Hi, my MusE version is MusE 4.2.1, (master | 4.2.1-24-g6356b206 | 2024-08-30 17:09:38 -0400)

devloop0123 commented 3 days ago

Some extra clues maybe:

On my Jack system, where MusE + Hydrogen work fine with time-based transport enabled, I found that Qtractor + Hydrogen exhibits the same misbehaviour as do MusE + Hydrogen on my pipewire system.

Is the issue maybe related to jack-transport itself, and pipewire-jack faithfully emulates this issue? That would imply that MusE + Hydrogen gets around this issue on a Jack system in a way that does not work anymore with pipewire-jack....

theGreatWhiteShark commented 2 days ago

Hmmm... it is starting to point in my direction. Classical JACK + Hydrogen + MusE is the exact setup I used during development.

I'll check out the pipewire-jack stuff first.

Qtractor

Which version?

devloop0123 commented 2 days ago

Hmmm... it is starting to point in my direction. Classical JACK + Hydrogen + MusE is the exact setup I used during development.

I'll check out the pipewire-jack stuff first.

Qtractor

Which version?

qtractor-1.2.0-4.1.x86_64.appimage I found that, with Qtractor+H2, the misbehaviour only occurs after having pressed play/stop once, both with Jack and Pipewire-jack....

devloop0123 commented 2 days ago

By the way, pipewire got a commit for improving transport, based on my issue report there: https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/ed0556e34c8869da991af7efaa42162ec2e7a062

So it may have been fixed there already. But I can't test that : I wouldn't know how to succesfully replace my distro version with the gitlab one.

theGreatWhiteShark commented 1 day ago

I was able to reproduce your pipewire-jack issue. Nice catch by the way.

By the way, pipewire got a commit for improving transport, based on my issue report there: https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/ed0556e34c8869da991af7efaa42162ec2e7a062

Wow. Nice! So, maybe there is still hope for JACK Timebase after all. Devs at the original JACK project did not seem to be that interested in this protocol (which some big conceptions flaws, way too little documentation, no reference implementation or test suite. Quite a pain to properly support it).

I'll do some debugging and back up your issue on pipewire with commands sent and received via JACK API.

But I can't test that : I wouldn't know how to succesfully replace my distro version with the gitlab one.

I did when setting up my laptop anew. I wouldn't recommend to do this as I need to restart the service quite often. (But this could very well be my fault since I did not had time to properly introduce myself into the internals of pipewire).

Their recommended way to test and manually upgrade pipewire is actually not to install it system-wide but to compile it, stop the system's instance and start the compiled one from the build folder https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/INSTALL.md?ref_type=heads#running

3 Enable "Jack Transport" via H2's GUI button, and ensure "J. master" is off. Click it for good measure until you've seen the message "Jack timebase mode = listener" beside it.

About that one: Hydrogen is only picking up Timebase information in case playback is rolling. Otherwise, it just ignores this information. I implemented it this way since a couple of applications use the default JACK API for relocation (which stops transport for an instance) and not its dedicated Timebase counterpart. As a result JACK would indicate on each relocation that Timebase master is gone and Hydrogen would pick up its original tempo (and maybe recalculated samples using Rubberband) only to switch back to Timebase mode during the next processing cycle of JACK.

We are still a long way from proper JACK Timebase support. Even in Linux audio. Not sure whether we will get there.

But that's why it is so important that users like you bring those deficiencies to attention!

I found that, with Qtractor+H2, the misbehaviour only occurs after having pressed play/stop once, both with Jack and Pipewire-jack....

Is the misbehaviour the same as the one you described in your step by step guide?

theGreatWhiteShark commented 1 day ago

qtractor-1.2.0-4.1.x86_64.appimage I found that, with Qtractor+H2, the misbehaviour only occurs after having pressed play/stop once, both with Jack and Pipewire-jack....

Okay. There are a couple of things off in here. But this seems to be on QTractor's side, not JACK or PipeWire.

First of all QTractor does not use the Timebase part of the JACK API for relocation. Means it just sends the frame position like with Timebase support being turned off.

I also got it to inappropriately fill the position the current bar is starting at in ticks. But as Hydrogen is yet not expecting to find position fields provided by JACK filled with nan, its audio engine somewhat chokes on it when hitting play and the application is no longer responsive. I have add more sanity checks.