MuseScore icon indicating copy to clipboard operation
MuseScore copied to clipboard

jack-midi support

Open lyrra opened this issue 1 year ago • 205 comments

  • [x] I signed the CLA

Purpose

For linux users, the ability to at runtime switch between alsa and jack audio+midi driver.

Changes

  • Make both jack and alsa(linuxdriver) more similar to osx-driver
  • Make jack and alsa drivers "subdrivers" of linuxdriver (AudioDriverState).

class design changes

Before:

AudioModule
│
├── LinuxAudioDriver
│   │
│   Alsa
│   └──> device: "default"
│
├── OSXAudioDriver
│   ...
│
└── WasapiAudioDriver
    ...

MidiModule
│
├── LinuxAudioDriver
│   │
│   ├────> AlsaMidiOutPort
│   └────> AlsaMidiInPort
│   
:

After:


AudioModule
│
|         MidiModule
│             |
├── AudioMidiManager (was LinuxAudioDriver)
│        |      │
│        |      ├─── JackDriverState
│        |      │    │
│        |      │    (jack-code)
│        |      │    └──> jack client open
│        |      └──> AlsaDriverState
│        |                      │
│        |              (alsa-code)
│        |                      └──> device: "default"
│        │
│        + LinuxMidiOutPort
│        │
│        ├────> JackMidiOutPort
│        ├────> AlsaMidiOutPort
│        + LinuxMidiInPort
|          :
│
├── OSXAudioDriver
│   ...
│
└── WasapiAudioDriver
    ...

MidiModule
│
├── AudioMidiManager (was LinuxAudioDriver)
│   │
│   + LinuxMidiOutPort
│   │
│   ├────> JackMidiOutPort
│   ├────> AlsaMidiOutPort
│   + LinuxMidiInPort
:

Audio Tests

  • start with jack, play and hear audio OK
  • start with alsa, play and hear audio OK
  • start with jack, switch to alsa, then play OK
  • start with alsa, switch to jack, then play OK
  • switch from jack to alsa during play OK
  • switch from alsa to jack during play OK

Midi tests

  • start fluidsynth in verbose mode, musescore and qjackctl (to midi-connect them), verify midi-events are logged by fluidsynth.

Optional cleanups / redesign

Remove LinuxAudioDriver and keep only AlsaAudioDriver and JackAudioDriver as two independent implementations. To switch between them, you need to add another class, something like IAudioDriverProvider. This is what you need to add to IoC (and remove the drivers from IoC). Access the driver through this class, like:

class IAudioDriverProvider ...
{
...

        std::shared_ptr<IAudioDriver> driver() const;
  
        void swithDriver(const std::string& name); 
        async::Chanel<std::string /*name*/> dirverChanged() const;
}


class SomeClass
    Inject<IAudioDriverProvider > audioDriverProvider;


...

     audioDriverProvider()->driver();

This greatly simplifies everything, each class becomes simple and does one thing. Moreover, such a system is easily scalable; we can easily add other drivers, cross-platform or platform-specific.

Not in scope for this PR

  • MIDI-channel-per-instrument

Known cleanups & fixes before merge

  • [x] send foreign commits upstream: https://github.com/musescore/MuseScore/pull/22373
  • [x] cleanup: avoid global in app
  • [x] ~If possible do mutual dependency Injection between module Audio and Midi.~ Testing confirmed, can't inject modules. Injection is used, but not at modul level.
  • [x] de-pollute any interfaces that got sprinkled with data members
  • [x] ensure no public data members begins with m_ (those should be private)
  • [x] remove sample-rate dropdown OR make it work, No 'requires restart' added
  • [x] ~automatic connection to audio ports upon start~ Not in scope, brings in too much arbitrary heuristics code from Mu3.
  • [ ] Possible to switch between jack/alsa driver (currently it crashes)
  • [ ] Possible to switch bufferSize in jack without crash (possible in alsa)
  • [x] Possible to disable jack-transport via configuration checkbox

lyrra avatar Sep 01 '23 08:09 lyrra

@Jojo-Schmitz builds on mingw

Also, manually edit src/app/CMakeLists.txt for install to work:

@@ -332,10 +337,6 @@ if (OS_IS_WIN)
     install(FILES
             ${PROJECT_SOURCE_DIR}/build/qt.conf
             ${QtInstallLibraries}
-            ${QT_INSTALL_BINS}/libEGL.dll
-            ${QT_INSTALL_BINS}/libGLESv2.dll
-            ${QT_INSTALL_BINS}/opengl32sw.dll
-            ${QT_INSTALL_BINS}/d3dcompiler_47.dll
             ${QT_INSTALL_BINS}/Qt5QmlModels.dll
             ${QT_INSTALL_BINS}/Qt5QmlWorkerScript.dll
             DESTINATION bin)
@@ -374,12 +375,6 @@ if (OS_IS_WIN)
         install(FILES ${SNDFILE_DLL} DESTINATION bin)
     endif()
 
-    # Install ssl
-    install(FILES
-            ${DEPENDENCIES_DIR}/libcrypto-1_1-x64.dll
-            ${DEPENDENCIES_DIR}/libssl-1_1-x64.dll
-            DESTINATION bin)
-
     if (WIN_PORTABLE)
         # deploy the files and directory structure needed for the PortableApps.com format
         install(DIRECTORY ${PROJECT_SOURCE_DIR}/build/PortableApps/App DESTINATION ${CMAKE_INSTALL_PREFIX}/../..)

Though it wont run:

~/ms/ms4$ ./builds/Win-Qtmsys64-mingw64-Make-Debug/install/bin/MuseScore4.exe
bash: ./builds/Win-Qtmsys64-mingw64-Make-Debug/install/bin/MuseScore4.exe: cannot execute binary file: Exec format error

EDIT: the reason it wont run for me was that it was compiled with unrecognized debug info, I'll probably need to upgrade my msys2 installation. To overcome this, use the "strip" tool from cygwin: strip builds/Win-Qtmsys64-mingw64-Make-Debug/src/app/MuseScore4.exe (yes, use that binary, not the one in install/bin, since that wont start (gets RC 127)).

lyrra avatar Sep 15 '23 18:09 lyrra

Let's introduce the concept of an API(aka driver) within this PR. Since jack and alsa are an API, not devices as you did in LinuxAudioDriver::availableOutputDevices. These APIs can provide a list of available devices. I also see a problem in this PR: we use linuxaudiodriver in Windows.

I suggest adding a register IApiRegister - a register of various APIs for platforms. There should be something like this api->regApi(os, IAudioDriver)

We can get a list of APIs for os from this register and show it to the user in the preferences.

Eism avatar Sep 20 '23 11:09 Eism

I also see a problem in this PR: we use linuxaudiodriver in Windows.

This is perfectly fine under mingw, becase we are pretenting to be a native linux app that is to be compiled under windows, which is the sole purpose of mingw (yes, that makes no sense because MuseScore is aware of windows, but we are supporting mingw purely for open-source reasons, and better interoperability with GCC & free OS's).

Let's introduce the concept of an API(aka driver) within this PR. Since jack and alsa are an API, not devices as you did in LinuxAudioDriver::availableOutputDevices. These APIs can provide a list of available devices. I suggest adding a register IApiRegister - a register of various APIs for platforms. There should be something like this api->regApi(os, IAudioDriver)

We can get a list of APIs for os from this register and show it to the user in the preferences.

That is out of scope for this PR. This PR is only to enable runtime support for jack, using the MuseScore API. Since the current MuseScore API isn't designed for multi-devices, this PR might introduce stuff that needs later refactorization.

Another problem of extending this PR as suggested is that it won't take into account jack-midi. This PR is a prerequisite for starting to work with jack-midi support (because in jack, audio and midi are linked into the same process-loop, unlike alsa).

lyrra avatar Sep 20 '23 13:09 lyrra

That is out of scope for this PR. This PR is only to enable runtime support for jack, using the MuseScore API.

I liked the previous solution - for each platform there is a driver implementation that is supported by this platform. Now we are adding one more driver. We just need to add an implementation of this driver and include this driver in cmake for the platform that supports it. If this driver is used for different platforms, then we need to move this driver from the platform folder to a higher level.

And that's what you did. (The only point is that I don’t understand why you removed alsa from the linux folder. It is only available on Linux)

You changed the LinuxAudioDriver class, which now returns alsa and jack in the list of available devices, but this is incorrect. alsa and jack are drivers, not devices

If you want to test the jack driver and you do not want to create a driver switch class, then you can solve this using flags. By default, everything will remain the same after merging your PR and you can add a class that will provide a list of available drivers in the next PR and the user will be able to switch from the UI.

Eism avatar Sep 25 '23 12:09 Eism

And that's what you did. (The only point is that I don’t understand why you removed alsa from the linux folder. It is only available on Linux)

Alsa isn't linux-only (BSD's).

You changed the LinuxAudioDriver class, which now returns alsa and jack in the list of available devices, but this is incorrect. alsa and jack are drivers, not devices

It is a list of audio-api's that is sent to the gui-option where you select between which API, alsa or jack to use (the next gui step, if feasible, could be to select the underlying audio-device). So calling it driver or devices seems like an musescore-internal code-style issue, there is no drivers or devices, just API's like you said earlier.

Do you mean it should be presented in the gui-options differently?

If you want to test the jack driver and you do not want to create a driver switch class, then you can solve this using flags. By default, everything will remain the same after merging your PR and you can add a class that will provide a list of available drivers in the next PR and the user will be able to switch from the UI.

But this is what the PR does now, it uses compile-time flags to include jack (and at runtime you can select between alsa or jack). Not sure why it needs to be postponed to next PR.

Do you have concrete change suggestions to this PR? Else, if it is more abstract design changes, it is better to change this PR back to draft-PR.

lyrra avatar Sep 28 '23 15:09 lyrra

I really hop this PR will be merged. It's totally incredible that the jack support has been removed from 4.1 ...

ycollet avatar Oct 02 '23 16:10 ycollet

Added jack-midi, which builds upon jack-audio.

lyrra avatar Oct 09 '23 06:10 lyrra

It is a list of audio-api's that is sent to the gui-option where you select between which API, alsa or jack to use (the next gui step, if feasible, could be to select the underlying audio-device). So calling it driver or devices seems like an musescore-internal code-style issue, there is no drivers or devices, just API's like you said earlier.

Do you mean it should be presented in the gui-options differently?

We can select ALSA as a driver and select the device to output audio to? For example, if there are several sound cards, or for example if we have bluetooth headphones connected. i.e. it looks like we need to improve UI so that there is both a choice of audio API and a choice of device. However, for some APIs, device selection is not available (jack)

igorkorsukov avatar Oct 09 '23 07:10 igorkorsukov

Dear all, I am willing to help testing (especially Jack MIDI Input) under Ubuntu22. Can I already get a test version from here?

loeten avatar Nov 15 '23 07:11 loeten

Dear all, I am willing to help testing (especially Jack MIDI Input) under Ubuntu22. Can I already get a test version from here?

Thanks! I've just rebased, artifacts appimage for linux at https://github.com/musescore/MuseScore/suites/18227907955/artifacts/1052918005

lyrra avatar Nov 15 '23 22:11 lyrra

Seems not yet so successful foe me, started like you see here:

https://pastebin.com/mvs4bjGj

I can choose only ALSA on top, no matter if qjackctl is running, and I can't choose my keyboard as MIdiI Input, but funny enough as Midi output.

Hope it helps!

Am 15. November 2023 23:25:26 MEZ schrieb Larry @.***>:

Dear all, I am willing to help testing (especially Jack MIDI Input) under Ubuntu22. Can I already get a test version from here?

Thanks! I've just rebased, artifacts appimage for linux at https://github.com/musescore/MuseScore/suites/18227907955/artifacts/1052918005

-- Reply to this email directly or view it on GitHub: https://github.com/musescore/MuseScore/pull/19246#issuecomment-1813358962 You are receiving this because you commented.

Message ID: @.***>

loeten avatar Nov 16 '23 20:11 loeten

and I can't choose my keyboard as MIdiI Input

Thanks for reporting! In qJackctl graph there should be an midi-input slot for musescore, but it is missing. See the attached picture. I'll try to figure out why it isn't registered with jackd.

mu4-jack-midi

lyrra avatar Nov 17 '23 17:11 lyrra

@loeten new artifacts at https://github.com/musescore/MuseScore/suites/18311400721/artifacts/1059272015 Musescore will register a midi-input port to jack-daemon. It will not autoconnect, so you need to create the connection in qjackctl-graph. For some reason, midi-input will not be received until you press a note in the score. jack-midi2

lyrra avatar Nov 18 '23 23:11 lyrra

Hi Larry,

 

sorry for the delay, my laptop crashed (not because of your software :-) ) and I needed some time to reinstall and get back data.

 

This means also clean fresh ubuntu22. I did not yet install jack (will do so and report), but tested your version already with just plugging in the keyboard. it is visible under /dev/midi1.

 

When opening your version and trying to set it up, I can't set it as input unsing ALSA, but - funny enough - as output (ALSA, yet w/o jack) - see screenshots attached.

 

Loeten

   

Gesendet: Sonntag, 19. November 2023 um 00:16 Uhr Von: "Larry" @.> An: "musescore/MuseScore" @.> Cc: "loeten" @.>, "Mention" @.> Betreff: Re: [musescore/MuseScore] jack-midi support (PR #19246)

  Message ID: @.***>

 

 

loeten avatar Nov 21 '23 19:11 loeten

Hello again,

 

because I had to finish a sheet, I installed also the official Musescore 4.1 AppImage from the Musescore website. This looks different - without having set anything it shows right from the start per default my Midi keyboard as input (Systemvoreinstellung means system default). See attached.

 

Will report back when I had used Jack - will take some days yet unfortunately.

 

greetings from Berlin

   

Gesendet: Sonntag, 19. November 2023 um 00:16 Uhr Von: "Larry" @.> An: "musescore/MuseScore" @.> Cc: "loeten" @.>, "Mention" @.> Betreff: Re: [musescore/MuseScore] jack-midi support (PR #19246)

 

loeten avatar Nov 21 '23 19:11 loeten

Hey, I can't seem to get this running with Pipewire. The Jack option doesn't even appear here. Is there anything I can do to help you debug it?

LucasGGamerM avatar Nov 21 '23 23:11 LucasGGamerM

Hey, I can't seem to get this running with Pipewire. The Jack option doesn't even appear here. Is there anything I can do to help you debug it?

The jack-audio option wasn't appearing, it was purely a cosmetic bug, now fixed.

lyrra avatar Dec 08 '23 18:12 lyrra

I just built this branch to try it out on my system (using Pipewire and running with pw-jack) and have a similar issue as @LucasGGamerM where I do not have any Jack option and in qjackctl it only shows the ALSA output from MuseScore. Is this supposed to be working in it's current state? Any way I can help troubleshooting?

pkupper avatar Mar 04 '24 16:03 pkupper

I just built this branch to try it out on my system (using Pipewire and running with pw-jack) and have a similar issue as @LucasGGamerM where I do not have any Jack option and in qjackctl it only shows the ALSA output from MuseScore. Is this supposed to be working in it's current state? Any way I can help troubleshooting?

  1. jack-audio should work without this PR (this PR tries to bring in jack-midi too).
  2. using jackd (not pipewire) with this PR, should work, I can see the devices and playback: bild

lyrra avatar Mar 04 '24 21:03 lyrra

I've also periodically tried running the artifacts & building this branch (on Arch, with and without Pipewire) and had the same issue as the others. Has anyone else been able to successfully test this?

rovantiq avatar Mar 04 '24 21:03 rovantiq

I just built this branch to try it out on my system (using Pipewire and running with pw-jack) and have a similar issue as @LucasGGamerM where I do not have any Jack option and in qjackctl it only shows the ALSA output from MuseScore. Is this supposed to be working in it's current state? Any way I can help troubleshooting?

  1. jack-audio should work without this PR (this PR tries to bring in jack-midi too).
  2. using jackd (not pipewire) with this PR, should work, I can see the devices and playback: bild

Is there an appimage build of this? I would love to test it, but don't have the immediate means to attempt building it. As a user (rather than developer) I get more errors than I frankly have time to trace down. But as a prolific user, I could really test drive this thing.

cfirwin3 avatar Mar 05 '24 14:03 cfirwin3

Just to clarify, using this PR to get audio with jack/pipewire isn't needed, because jack support should be working with official build. Please report audio issues here instead: https://github.com/musescore/MuseScore/issues/11220

Of course, regression problems like if you can't get jack/pipewire to work with this PR but it works with an official build, would be useful to know about.

Likewise any midi issues with jack/pipewire, please report any findings here.

lyrra avatar Mar 05 '24 19:03 lyrra

Just to clarify, using this PR to get audio with jack/pipewire isn't needed, because jack support should be working with official build. Please report audio issues here instead: #11220

Of course, regression problems like if you can't get jack/pipewire to work with this PR but it works with an official build, would be useful to know about.

Likewise any midi issues with jack/pipewire, please report any findings here.

I don't think the official build supports Jack, but rather it can be routed to Jack via Pipewire from the default (and only) option which is Alsa (though not labeled as such in the GUI). Regardless, I'm only interested in the midi timecode sync issue for film score. But I simply can't get a good build of this thing right now. So until there is a package to install or AppImage to run... I can't really run it through it's paces re: midi timecode sync. Has there been any indication that this will be merged to the master soon?

cfirwin3 avatar Mar 05 '24 20:03 cfirwin3

Just to clarify, using this PR to get audio with jack/pipewire isn't needed, because jack support should be working with official build. Please report audio issues here instead: #11220

Of course, regression problems like if you can't get jack/pipewire to work with this PR but it works with an official build, would be useful to know about.

Likewise any midi issues with jack/pipewire, please report any findings here.

@lyrra Right, I'm able to get audio out with the official build as well as this one (via routed ALSA-plugin). Interested in testing this to run MIDI out to a DAW, but when trying to test this PR so far I've been unable to get the MIDI ports or JACK option as shown in your screenshot. Sounds like other testers are having the same issue. Possibly pipewire is complicating things, but I first tried testing a while back before switching over and had the same troubles.

So until there is a package to install or AppImage to run...

@cfirwin3 AppImage artifacts are under the "Checks" tab -> CI_Linux

rovantiq avatar Mar 05 '24 20:03 rovantiq

@cfirwin3 AppImage artifacts are under the "Checks" tab -> CI_Linux

Can confirm that the current lyrra:Jack branch AppImage does not recognize "Jack" under Pipewire (which will need to be addressed as Pipewire is becoming the standard emulation of Jack).

May try to revert a system to Pulseaudio/Jack and try it without emulation when I get the chance.

EDIT:

Can also confirm that Jack does not show under a classic pulseaudio/jack configuration. The dropdown only shows 'Alsa". Midi sockets are not viewable for Musescore from QJackCtl patchbay, Carla or Qtractor's patchbay. This is with all Pipewire modules and components removed and Pulseaudio / Jackd running.

cfirwin3 avatar Mar 05 '24 21:03 cfirwin3

I was able to try this again on a different system that is completely free of Pipewire. This is on a vanilla install of UbuntuStudio 22.04 with Jack and Pulseaudio running: M4NoJack I started Jack via QJackCtl first. I also opened Carla Patchbay for an extra view. I initialized AppImage build: MU4_240591834_Lin_19246_jack-midi support. There is no dropdown option for Jack in the playback settings. It only shows 'ALSA'. No sockets are viewable from either QJackCtl or Carla patchbays.

Hopefully that helps.

cfirwin3 avatar Mar 06 '24 13:03 cfirwin3

I've added some error checks and more debug logging. Here's what I get on terminal output when starting (filtering out only audio/midi logging):

logs
cd builds/Linux-*Make-Debug/install; ./bin/mscore | grep -i -e jack -e alsa -e LinuxAudioDriver -e LinuxMidiOutPort

07:33:31.852 | ERROR | main_thread     | LinuxAudioDriver::outputDevice | device is not opened, deviceId: 
07:33:31.852 | WARN  | main_thread     | LinuxAudioDriver::selectOutputDevice | no previously opened device
07:33:31.852 | INFO  | main_thread     | LinuxAudioDriver::makeDevice |  -- driver: 558bccbb2650
07:33:31.852 | INFO  | main_thread     | LinuxAudioDriver::init |  -- init, this: 558bcc8e9c00
07:33:31.875 | WARN  | main_thread     | JackDriverState::open | Musescores samplerate: 44100, is NOT the same as jack's: 48000
07:33:31.892 | INFO  | main_thread     | AlsaMidiOutPort::init | ---- linux ALSA init ----
07:33:31.892 | INFO  | 139992349267648 | LinuxMidiOutPort::availableDevices | polling for availableDevices
07:33:31.892 | INFO  | 139992349267648 | JackMidiOutPort::availableDevices | found output device
07:33:31.892 | INFO  | 139992349267648 | LinuxMidiOutPort::availableDevices | found 1 jack midi-output devices
07:33:31.893 | INFO  | 139992349267648 | AlsaMidiOutPort::availableDevices | found output device ALSA/Midi Through
07:33:31.893 | INFO  | 139992349267648 | LinuxMidiOutPort::availableDevices | found 1 alsa midi-output devices
07:33:32.342 | WARN  | main_thread     | MidiInputOutputController::checkConnection | failed connect to device, deviceID: -1, err: not found device, id: -1
07:33:32.342 | INFO  | main_thread     | LinuxMidiOutPort::availableDevices | polling for availableDevices
07:33:32.342 | INFO  | main_thread     | JackMidiOutPort::availableDevices | found output device
07:33:32.342 | INFO  | main_thread     | LinuxMidiOutPort::availableDevices | found 1 jack midi-output devices
07:33:32.342 | INFO  | main_thread     | AlsaMidiOutPort::availableDevices | found output device ALSA/Midi Through
07:33:32.342 | INFO  | main_thread     | LinuxMidiOutPort::availableDevices | found 1 alsa midi-output devices

lyrra avatar Mar 07 '24 07:03 lyrra

@cfirwin3 @rovantiq @pkupper My bad! Jack isn't enabled by default. That means that the official builds nor artifacts of this PR will have neither jack-audio nor jack-midi. Essentially, if you build the official (or master branch), do this patch to enable jack:

CMakeLists.txt:
-option(MUE_ENABLE_AUDIO_JACK "Jack audio support" OFF)
+option(MUE_ENABLE_AUDIO_JACK "Jack audio support" ON)

I've changed the PR so it is enabled by default. Which means the artifacts should have jack audio/midi enabled.

Thanks for kicking around and testing this PR!

lyrra avatar Mar 07 '24 09:03 lyrra

My bad! Jack isn't enabled by default. That means that the official builds nor artifacts of this PR will have neither jack-audio nor jack-midi.

Thank you! I can confirm both jack-audio and jack-midi are working for me now.

pkupper avatar Mar 07 '24 10:03 pkupper

My bad! Jack isn't enabled by default. That means that the official builds nor artifacts of this PR will have neither jack-audio nor jack-midi.

Thank you! I can confirm both jack-audio and jack-midi are working for me now.

I can also confirm that the basic structure is now working with Pipewire. I need to dig deeper to see if midi timecode transport is part of the output socket stream (it appears not, at first glance). The Jack midi timecode output socket would be necessary for transport sync in DAW or for video player/editor sync (Xjadeo or Blender) in film scoring.

cfirwin3 avatar Mar 07 '24 11:03 cfirwin3