Skip to content

Commit

Permalink
fix #285307: JACK Audio on Musescore 3.x not working +collect_artifacts
Browse files Browse the repository at this point in the history
syncing our jackweakapi.cpp with https://github.com/jackaudio/jack2's
JackWeakAPI.c (commenting out new(?) APIs we most probably don't use
anyhow)
This minimizes the diffs between those 2 files and should bring
MuseScore 3 64bit back to play along with Jack.
  • Loading branch information
Jojo-Schmitz committed Oct 31, 2019
1 parent 0fbc29c commit 1ebceea
Showing 1 changed file with 44 additions and 15 deletions.
59 changes: 44 additions & 15 deletions mscore/jackweakapi.cpp
Expand Up @@ -5,7 +5,7 @@
// jackWeakAPI based on code from Stéphane Letz (Grame)
// partly based on Julien Pommier (PianoTeq : http://www.pianoteq.com/) code.
//
// Copyright (C) 2002-2007 Werner Schweer and others
// Copyright (C) 2002-2019 Werner Schweer and others
// Copyright (C) 2009 Grame

// This program is free software; you can redistribute it and/or modify
Expand All @@ -22,14 +22,14 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


#if (defined (_MSCVER) || defined (_MSC_VER))
// Include stdint.h and #define _STDINT_H to prevent <systemdeps.h> from redefining types
// #undef UNICODE to force LoadLibrary to use the char-based implementation instead of the wchar_t one.
#include <stdint.h>
#define _STDINT_H 1
#endif
#include <jack/jack.h>
#include <jack/session.h>
#include <jack/thread.h>
#include <jack/midiport.h>
#include <math.h>
Expand All @@ -41,29 +41,28 @@ typedef pthread_t jack_native_thread_t;
#include <stdlib.h>
#include <iostream>

using std::cerr;

/* dynamically load libjack and forward all registered calls to libjack
(similar to what relaytool is trying to do, but more portably..)
*/

typedef void (*print_function)(const char *);
typedef void *(*thread_routine)(void*);

using std::cerr;

int libjack_is_present = 0; // public symbol, similar to what relaytool does.
static int libjack_is_present = 0; // public symbol, similar to what relaytool does.

#ifdef WIN32
HMODULE libjack_handle = 0;
static HMODULE libjack_handle = 0;
#else
static void *libjack_handle = 0;
#endif


#ifndef WIN32
// Since MSVC does not support the __attribute(constructor)__ extension, an alternative through
// static object construction is implemented.
// See https://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc for a similar
// approach.
#if (!defined (_MSCVER) && !defined (_MSC_VER))
//#if (!defined (_MSCVER) && !defined (_MSC_VER))
static void __attribute__((constructor)) tryload_libjack()
#else
static int tryload_libjack();
Expand All @@ -74,16 +73,27 @@ static int tryload_libjack()
if (getenv("SKIP_LIBJACK") == 0) { // just in case libjack is causing troubles..
#ifdef __APPLE__
libjack_handle = dlopen("libjack.0.dylib", RTLD_LAZY);
if (!libjack_handle) {
qDebug("dlopen error : %s ", dlerror());
}
libjack_handle = dlopen("/usr/local/lib/libjack.0.dylib", RTLD_LAZY);
if (!libjack_handle) {
qDebug("dlopen error : %s ", dlerror());
}
#elif defined(WIN32)
// Force char implementation of library instead of possibly wchar_t implementation to be called.
libjack_handle = LoadLibraryA("libjack.dll");
#ifdef _WIN64
libjack_handle = LoadLibraryA("libjack64.dll");

This comment has been minimized.

Copy link
@Spire42

Spire42 Feb 13, 2020

Contributor

These calls should be:

libjack_handle = LoadLibraryW(L"libjack64.dll");

and:

libjack_handle = LoadLibraryW(L"libjack.dll");

The preceding comment (“Force char implementation of library”) is incorrect; that's not what LoadLibraryA() does. There's no reason to call LoadLibraryA() instead of LoadLibraryW() on any version of Windows from Windows 2000 onwards.

Although it's ultimately harmless to call LoadLibraryA() instead of LoadLibraryW(), it's a tiny bit less efficient and also pointless. If we're adding new code here we might as well call the right version of the function.

This comment has been minimized.

Copy link
@Jojo-Schmitz

Jojo-Schmitz Feb 13, 2020

Author Contributor

Ooops, too late now... And also not in sync with upstream, maybe it should get fixed there first?

Hmm, actually it is not in sync, they use:

#elif defined(WIN32)
    #ifdef _WIN64
        libjack_handle = LoadLibrary("libjack64.dll");
    #else
        libjack_handle = LoadLibrary("libjack.dll");
    #endif
#else
    libjack_handle = dlopen("libjack.so.0", RTLD_LAZY);
#endif

See https://github.com/jackaudio/jack2/blob/develop/common/JackWeakAPI.c

This comment has been minimized.

Copy link
@Spire42

Spire42 Feb 13, 2020

Contributor

Unfortunately, the upstream version of the code is also incorrect, as it will fail to compile if Unicode is enabled.

Some background info:

LoadLibrary() is a macro that expands to LoadLibraryW() if Unicode is enabled and LoadLibraryA() otherwise.

LoadLibraryW() takes a wchar_t* argument, which is why the L literal string prefix is required.

LoadLibraryA() takes a char* argument, which is why the L literal string prefix must not be present.

There is a corresponding helper macro, _T(), that adds the L prefix to its argument if Unicode is enabled and adds nothing otherwise.

Therefore if you want to use the LoadLibrary() macro instead of calling one of the two functions directly, the right way to do so is:

libjack_handle = LoadLibrary(_T("libjack64.dll"));

However, this is completely unnecessary unless you want to support ancient non-Unicode systems such as Windows 98. Nowadays, it's best to call LoadLibraryW() directly as I originally suggested.

This comment has been minimized.

Copy link
@Jojo-Schmitz

Jojo-Schmitz Feb 13, 2020

Author Contributor

OK, thanks for the explanation, but I guess this needs to get reported and fixed upstream.
We may fix our's independantly though, if it is truely broken, which as far as I understand it is not?

We're not supporting anything below Windows 7 anymore, although XP and Vista might still works, if WebEngine gets disabled (the -w commandline option)

This comment has been minimized.

Copy link
@Spire42

Spire42 Feb 13, 2020

Contributor

The way we're doing it right now is weird and a bit suboptimal but completely harmless.

This comment has been minimized.

Copy link
@npetrangelo

npetrangelo Oct 3, 2020

I just installed MuseScore 3.5 on my MacBook Pro running High Sierra and I keep getting these errors:

dlopen error : dlopen(libjack.0.dylib, 1): image not found 
dlopen error : dlopen(/usr/local/lib/libjack.0.dylib, 1): image not found

and it looks like this is the code that prints those errors. Do you know what could be causing it? I previously had MuseScore 2 and that worked fine, but now that too produces those same errors after installing 3.5.

It also prints these messages after that:

No device selected.  PortAudio detected 0 devices.  Will use the default device (index -1).
init PortAudio failed
Portaudio close stream failed: Invalid stream pointer
no audio driver found
ZoomBox::setLogicalZoom(): Formatting logical zoom level as 100% (rounded from 1.000000)
qrc:/qml/TelemetryPermissionDialog.qml:37: ReferenceError: globalStyle is not defined
qrc:/qml/DialogButton.qml:74: ReferenceError: globalStyle is not defined
qrc:/qml/DialogButton.qml:74: ReferenceError: globalStyle is not defined

This comment has been minimized.

Copy link
@Jojo-Schmitz

Jojo-Schmitz Oct 3, 2020

Author Contributor

Do you have JACK installed? If not, this isn't really an error, not of MuseScore at least, but if it is installed, please report this in the issue tracker on musescore.org.
Not sure about the PortAudio stuff, whether on macOS this is used at all.
The ZoomBox message seems a left debuggung artifact and shouzld be harmless
The qrc/qml messages might be worth a report in the issue tracker (on musescore.com)

#else
libjack_handle = LoadLibraryA("libjack.dll");
#endif
#else
libjack_handle = dlopen("libjack.so.0", RTLD_LAZY);
#endif

}
libjack_is_present = (libjack_handle != 0);
#if (defined (_MSCVER) || defined (_MSC_VER))
#ifdef WIN32
//#if (defined (_MSCVER) || defined (_MSC_VER))
return 1;
#endif
}
Expand Down Expand Up @@ -197,6 +207,9 @@ DECL_FUNCTION(int, jack_set_graph_order_callback, (jack_client_t *client,
DECL_FUNCTION(int, jack_set_xrun_callback, (jack_client_t *client,
JackXRunCallback xrun_callback,
void *arg), (client, xrun_callback, arg));
//DECL_FUNCTION(int, jack_set_latency_callback, (jack_client_t *client,
// JackLatencyCallback latency_callback,
// void *arg), (client, latency_callback, arg));
DECL_FUNCTION(int, jack_activate, (jack_client_t *client), (client));
DECL_FUNCTION(int, jack_deactivate, (jack_client_t *client), (client));
DECL_FUNCTION_NULL(jack_port_t *, jack_port_register, (jack_client_t *client, const char *port_name, const char *port_type,
Expand All @@ -220,9 +233,12 @@ DECL_FUNCTION(jack_nframes_t, jack_port_get_latency, (jack_port_t *port), (port)
DECL_FUNCTION(jack_nframes_t, jack_port_get_total_latency ,(jack_client_t * client, jack_port_t *port), (client, port));
DECL_VOID_FUNCTION(jack_port_set_latency, (jack_port_t * port, jack_nframes_t frames), (port, frames));
DECL_FUNCTION(int, jack_recompute_total_latency, (jack_client_t* client, jack_port_t* port), (client, port));
//DECL_VOID_FUNCTION(jack_port_get_latency_range, (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range), (port, mode, range));
//DECL_VOID_FUNCTION(jack_port_set_latency_range, (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range), (port, mode, range));
DECL_FUNCTION(int, jack_recompute_total_latencies, (jack_client_t* client),(client));

DECL_FUNCTION(int, jack_port_set_name, (jack_port_t *port, const char *port_name), (port, port_name));
//DECL_FUNCTION(int, jack_port_rename, (jack_client_t *client, jack_port_t *port, const char *port_name), (client, port, port_name));
DECL_FUNCTION(int, jack_port_set_alias, (jack_port_t *port, const char *alias), (port, alias));
DECL_FUNCTION(int, jack_port_unset_alias, (jack_port_t *port, const char *alias), (port, alias));
DECL_FUNCTION(int, jack_port_get_aliases, (const jack_port_t *port, char* const aliases[2]), (port,aliases));
Expand All @@ -235,6 +251,7 @@ DECL_FUNCTION(int, jack_disconnect, (jack_client_t * client, const char *source_
DECL_FUNCTION(int, jack_port_disconnect, (jack_client_t * client, jack_port_t * port), (client, port));
DECL_FUNCTION(int, jack_port_name_size,(),());
DECL_FUNCTION(int, jack_port_type_size,(),());
//DECL_FUNCTION(size_t, jack_port_type_get_buffer_size, (jack_client_t *client, const char* port_type), (client, port_type));

DECL_FUNCTION(jack_nframes_t, jack_get_sample_rate, (jack_client_t *client), (client));
DECL_FUNCTION(jack_nframes_t, jack_get_buffer_size, (jack_client_t *client), (client));
Expand Down Expand Up @@ -272,16 +289,16 @@ DECL_FUNCTION(jack_nframes_t, jack_get_current_transport_frame, (const jack_clie
DECL_FUNCTION(int, jack_transport_reposition, (jack_client_t *client, const jack_position_t *pos), (client, pos));
DECL_VOID_FUNCTION(jack_transport_start, (jack_client_t *client), (client));
DECL_VOID_FUNCTION(jack_transport_stop, (jack_client_t *client), (client));
// DECL_VOID_FUNCTION(jack_get_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo));
// DECL_VOID_FUNCTION(jack_set_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo));
//DECL_VOID_FUNCTION(jack_get_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo));
//DECL_VOID_FUNCTION(jack_set_transport_info, (jack_client_t *client, jack_transport_info_t *tinfo), (client,tinfo));

DECL_FUNCTION(int, jack_client_real_time_priority, (jack_client_t* client), (client));
DECL_FUNCTION(int, jack_client_max_real_time_priority, (jack_client_t* client), (client));
DECL_FUNCTION(int, jack_acquire_real_time_scheduling, (jack_native_thread_t thread, int priority), (thread, priority));
DECL_FUNCTION(int, jack_client_create_thread, (jack_client_t* client,
jack_native_thread_t *thread,
int priority,
int realtime, // boolean
int realtime, // boolean
thread_routine routine,
void *arg), (client, thread, priority, realtime, routine, arg));
DECL_FUNCTION(int, jack_drop_real_time_scheduling, (jack_native_thread_t thread), (thread));
Expand All @@ -303,6 +320,18 @@ DECL_FUNCTION(jack_intclient_t, jack_internal_client_load, (jack_client_t *clien
DECL_FUNCTION(jack_status_t, jack_internal_client_unload, (jack_client_t *client, jack_intclient_t intclient), (client, intclient));
DECL_VOID_FUNCTION(jack_free, (void* ptr), (ptr));

// session
//DECL_FUNCTION(int, jack_set_session_callback, (jack_client_t* ext_client, JackSessionCallback session_callback, void* arg), (ext_client, session_callback, arg));
//DECL_FUNCTION(jack_session_command_t*, jack_session_notify, (jack_client_t* ext_client, const char* target, jack_session_event_type_t ev_type, const char* path), (ext_client, target, ev_type, path));
//DECL_FUNCTION(int, jack_session_reply, (jack_client_t* ext_client, jack_session_event_t *event), (ext_client, event));
//DECL_VOID_FUNCTION(jack_session_event_free, (jack_session_event_t* ev), (ev));
//DECL_FUNCTION(char*, jack_client_get_uuid, (jack_client_t* ext_client),(ext_client));
//DECL_FUNCTION(char*, jack_get_uuid_for_client_name, (jack_client_t* ext_client, const char* client_name),(ext_client, client_name));
//DECL_FUNCTION(char*, jack_get_client_name_by_uuid, (jack_client_t* ext_client, const char* client_uuid),(ext_client, client_uuid));
//DECL_FUNCTION(int, jack_reserve_client_name, (jack_client_t* ext_client, const char* name, const char* uuid),(ext_client, name, uuid));
//DECL_VOID_FUNCTION(jack_session_commands_free, (jack_session_command_t *cmds),(cmds));
//DECL_FUNCTION(int, jack_client_has_session_callback, (jack_client_t *client, const char* client_name),(client, client_name));

// MIDI

DECL_FUNCTION(jack_nframes_t, jack_midi_get_event_count, (void* port_buffer), (port_buffer));
Expand Down

0 comments on commit 1ebceea

Please sign in to comment.