MuseScore/mscore/jackaudio.cpp

988 lines
36 KiB
C++
Raw Normal View History

2012-05-26 14:49:10 +02:00
//=============================================================================
// MusE Score
// Linux Music Score Editor
// $Id: jackaudio.cpp 5660 2012-05-22 14:17:39Z wschweer $
//
// Copyright (C) 2002-2010 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
Solved all compilation errors on MSVC This commit contains changes required for MuseScore to compile under MSVC with no errors. There are several general categories of problems that resulted in errors with the compilation. Main issues: - Variable Length Arrays (VLA). This is a non-standard extension to C++, supported by clang toolchains, but not by MSVC. The initial workaround is to use std::vector<> instead of VLAs, eventually (if needed) with the original variable pointing to the beginning of the allocated array. More efficient alternatives are possible if profiling shows any code using VLAs to be timing-critical. - Floating-point constants not suffixed with "f" are doubles by default; in some instances, this leads to narrowing conversion errors (in other instances, just warnings). - MSVC does not support "or"/"and"/"not" in lieu of "||"/"&&"/"!". Changed unconditionally to use standard C++ symbols. - MSVC does not support the "__builtin_unreachable()" compiler hint. A similar, albeit not exactly equal, alternative is "__assume(0)", which is MSVC-specific. - MSVC does not support ranges in case statements. Replaced with list of cases instead of range (non-conditionally) Detailed changes, with per-file comments: - all.h: opt-in to deprecated features, include <io.h> and <process.h> instead of POSIX <unistd.h>, undefine "STRING_NONE" and "small", which Microsoft defines as macros, which result in compilation errors. - effects/compressor/zita.cpp: eliminated narrowing conversion error by appending "f" to float constants. - fluid/voice.cpp: appended "f" to float constants to eliminate narrowing conversion errors/warnings - libmscore/beam.cpp: conditionally replaced VLA - libmscore/edit.cpp: conditionally replaced VLA - libmscore/element.cpp: appended "f" to float constant - libmscore/fret.cpp: changed or -> || - libmscore/layout.cpp: conditionally replaced VLA - libmscore/mscore.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - libmscore/scorefile.coo: use correct char representation conversion for MSVC - libmscore/stringdata.cpp: conditionally replaced VLA - libmscore/system.cpp: conditionally replaced VLA - libmscroe/text.cpp: replaced range in case statement. - manual/genManual.cpp: use getopt() replacement. - midi/midifile.cpp: conditionally replaced VLA. This does not use the default replacement. - mscore/bb.cpp: replaced range in case statement. - mscore/capella.cpp: conditionally replaced VLA. Changed and -> && - mscore/driver:cpp: preclude errors due to macro redefinitions. - mscore/editstyle.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - mscore/importgtp-gp6.cpp: conditionally replaced VLA. - mscore/instrwidget.cpp: conditionally replaced VLA. - mscore/jackaudio.cpp: conditionally replaced VLA. Preclude errors due to macro redefinitions. - mscore/jackweakapi.cpp: Preclude errors due to macro redefinitions. Replacement for __atribute__((constructor)) through static object construction for MSVC. Force use of LoadLibraryA instead of LoadLibrary. - mscore/mididriver.h: Changed not -> ! - mscore/musescore.cpp: Changed not -> !. Conditionally replaced VLA. - mscore/resourceManager.cpp: conditionally replaced VLA. - mscore/timeline.cpp: conditionally replaced VLA. - omr/omrpage.cpp: conditionally replaced VLA. - synthesizer/msynthesizer.cpp: replaced UNIX sleep(1) method with MSVC Sleep(1000) (equivalent, but in ms instead of seconds) - synthesizer/msynthsizer.h: appended "f" to float constant - thirdparty/poppler/config.h: set defines for MSVC to preclude the use of inexistent libraries. - thirdparty/poppler/poppler/poppler-config.h: set defines for MSVC to preclude the use of inexistent libraries. Eliminated #defines for fmin and fmax which where causing problems. - thirdparty/poppler/poppler/PSOutputDev.cc: added #include <algorithm> for std::min() and std::max(). Note this is required per-C++ standard. - thirdparty/portmidi/pm_win/pmwinmm.c: undefined UNICODE to use char-based library functions. - thirdparty/qzip/qzip.cpp: changed or -> || - thirdparty/rtf2html/rtf_keyword.h: file format changed from Apple to UNIX, as MSVC does not supported the former. (NOT error related, just improvement on previous commit; manual/getopt/README.md: added link to source article)
2018-05-01 19:14:44 +02:00
#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
Solved all compilation errors on MSVC This commit contains changes required for MuseScore to compile under MSVC with no errors. There are several general categories of problems that resulted in errors with the compilation. Main issues: - Variable Length Arrays (VLA). This is a non-standard extension to C++, supported by clang toolchains, but not by MSVC. The initial workaround is to use std::vector<> instead of VLAs, eventually (if needed) with the original variable pointing to the beginning of the allocated array. More efficient alternatives are possible if profiling shows any code using VLAs to be timing-critical. - Floating-point constants not suffixed with "f" are doubles by default; in some instances, this leads to narrowing conversion errors (in other instances, just warnings). - MSVC does not support "or"/"and"/"not" in lieu of "||"/"&&"/"!". Changed unconditionally to use standard C++ symbols. - MSVC does not support the "__builtin_unreachable()" compiler hint. A similar, albeit not exactly equal, alternative is "__assume(0)", which is MSVC-specific. - MSVC does not support ranges in case statements. Replaced with list of cases instead of range (non-conditionally) Detailed changes, with per-file comments: - all.h: opt-in to deprecated features, include <io.h> and <process.h> instead of POSIX <unistd.h>, undefine "STRING_NONE" and "small", which Microsoft defines as macros, which result in compilation errors. - effects/compressor/zita.cpp: eliminated narrowing conversion error by appending "f" to float constants. - fluid/voice.cpp: appended "f" to float constants to eliminate narrowing conversion errors/warnings - libmscore/beam.cpp: conditionally replaced VLA - libmscore/edit.cpp: conditionally replaced VLA - libmscore/element.cpp: appended "f" to float constant - libmscore/fret.cpp: changed or -> || - libmscore/layout.cpp: conditionally replaced VLA - libmscore/mscore.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - libmscore/scorefile.coo: use correct char representation conversion for MSVC - libmscore/stringdata.cpp: conditionally replaced VLA - libmscore/system.cpp: conditionally replaced VLA - libmscroe/text.cpp: replaced range in case statement. - manual/genManual.cpp: use getopt() replacement. - midi/midifile.cpp: conditionally replaced VLA. This does not use the default replacement. - mscore/bb.cpp: replaced range in case statement. - mscore/capella.cpp: conditionally replaced VLA. Changed and -> && - mscore/driver:cpp: preclude errors due to macro redefinitions. - mscore/editstyle.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - mscore/importgtp-gp6.cpp: conditionally replaced VLA. - mscore/instrwidget.cpp: conditionally replaced VLA. - mscore/jackaudio.cpp: conditionally replaced VLA. Preclude errors due to macro redefinitions. - mscore/jackweakapi.cpp: Preclude errors due to macro redefinitions. Replacement for __atribute__((constructor)) through static object construction for MSVC. Force use of LoadLibraryA instead of LoadLibrary. - mscore/mididriver.h: Changed not -> ! - mscore/musescore.cpp: Changed not -> !. Conditionally replaced VLA. - mscore/resourceManager.cpp: conditionally replaced VLA. - mscore/timeline.cpp: conditionally replaced VLA. - omr/omrpage.cpp: conditionally replaced VLA. - synthesizer/msynthesizer.cpp: replaced UNIX sleep(1) method with MSVC Sleep(1000) (equivalent, but in ms instead of seconds) - synthesizer/msynthsizer.h: appended "f" to float constant - thirdparty/poppler/config.h: set defines for MSVC to preclude the use of inexistent libraries. - thirdparty/poppler/poppler/poppler-config.h: set defines for MSVC to preclude the use of inexistent libraries. Eliminated #defines for fmin and fmax which where causing problems. - thirdparty/poppler/poppler/PSOutputDev.cc: added #include <algorithm> for std::min() and std::max(). Note this is required per-C++ standard. - thirdparty/portmidi/pm_win/pmwinmm.c: undefined UNICODE to use char-based library functions. - thirdparty/qzip/qzip.cpp: changed or -> || - thirdparty/rtf2html/rtf_keyword.h: file format changed from Apple to UNIX, as MSVC does not supported the former. (NOT error related, just improvement on previous commit; manual/getopt/README.md: added link to source article)
2018-05-01 19:14:44 +02:00
#endif
2012-05-26 14:49:10 +02:00
#include "jackaudio.h"
#include "musescore.h"
2012-05-26 14:49:10 +02:00
#include "libmscore/mscore.h"
#include "preferences.h"
2013-03-26 19:59:51 +01:00
// #include "msynth/synti.h"
2012-05-26 14:49:10 +02:00
#include "seq.h"
#include "libmscore/score.h"
2014-06-18 21:36:53 +02:00
#include "libmscore/repeatlist.h"
#include "mscore/playpanel.h"
2012-05-26 14:49:10 +02:00
#include <jack/midiport.h>
// Prevent killing sequencer with wrong data
#define less128(__less) ((__less >=0 && __less <= 127) ? __less : 0)
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// JackAudio
//---------------------------------------------------------
JackAudio::JackAudio(Seq* s)
: Driver(s)
{
client = 0;
}
//---------------------------------------------------------
// ~JackAudio
//---------------------------------------------------------
JackAudio::~JackAudio()
{
if (client) {
2014-05-24 21:30:33 +02:00
stop();
2012-05-26 14:49:10 +02:00
if (jack_client_close(client)) {
qDebug("jack_client_close() failed: %s",
2012-05-26 14:49:10 +02:00
strerror(errno));
}
}
}
//---------------------------------------------------------
// updateOutPortCount
// Add/remove JACK MIDI Out ports
//---------------------------------------------------------
void JackAudio::updateOutPortCount(int maxport)
{
if (!preferences.getBool(PREF_IO_JACK_USEJACKMIDI) || maxport == midiOutputPorts.size())
return;
if (MScore::debugMode)
qDebug()<<"JACK number of ports:"<<midiOutputPorts.size()<<", change to:"<<maxport;
bool oldremember = preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS);
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, true);
if (maxport > midiOutputPorts.size()) {
for (int i = midiOutputPorts.size(); i < maxport; ++i)
registerPort(QString("mscore-midi-%1").arg(i+1), false, true);
restoreMidiConnections();
}
else if (maxport < midiOutputPorts.size()) {
rememberMidiConnections();
for(int i = midiOutputPorts.size() - 1; i >= maxport; --i) {
unregisterPort(midiOutputPorts[i]);
midiOutputPorts.removeAt(i);
}
}
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, oldremember);
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// registerPort
//---------------------------------------------------------
void JackAudio::registerPort(const QString& name, bool input, bool midi)
{
int portFlag = input ? JackPortIsInput : JackPortIsOutput;
const char* portType = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
jack_port_t* port = jack_port_register(client, qPrintable(name), portType, portFlag, 0);
if (port == 0) {
qDebug("JackAudio:registerPort(%s) failed", qPrintable(name));
2012-05-26 14:49:10 +02:00
return;
}
if (midi) {
if (input)
midiInputPorts.append(port);
else
midiOutputPorts.append(port);
}
else
ports.append(port);
}
//---------------------------------------------------------
// unregisterPort
//---------------------------------------------------------
void JackAudio::unregisterPort(jack_port_t* port)
2012-05-26 14:49:10 +02:00
{
2014-07-05 20:59:24 +02:00
if (jack_port_is_mine(client,port)) {
jack_port_unregister(client, port);
port = 0;
}
else
qDebug("Trying to unregister port that is not my!");
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// inputPorts
//---------------------------------------------------------
QList<QString> JackAudio::inputPorts()
{
2018-08-17 15:06:15 +02:00
const char** prts = jack_get_ports(client, 0, 0, 0);
2012-05-26 14:49:10 +02:00
QList<QString> clientList;
2018-08-17 15:06:15 +02:00
for (const char** p = prts; p && *p; ++p) {
2012-05-26 14:49:10 +02:00
jack_port_t* port = jack_port_by_name(client, *p);
int flags = jack_port_flags(port);
if (!(flags & JackPortIsInput))
continue;
char buffer[128];
strncpy(buffer, *p, 128);
if (strncmp(buffer, "Mscore", 6) == 0)
continue;
clientList.append(QString(buffer));
}
return clientList;
}
//---------------------------------------------------------
// connect
//---------------------------------------------------------
void JackAudio::connect(void* src, void* dst)
{
const char* sn = jack_port_name((jack_port_t*) src);
const char* dn = jack_port_name((jack_port_t*) dst);
if (sn == 0 || dn == 0) {
qDebug("JackAudio::connect: unknown jack ports");
2012-05-26 14:49:10 +02:00
return;
}
if (jack_connect(client, sn, dn)) {
qDebug("jack connect <%s>%p - <%s>%p failed",
2012-05-26 14:49:10 +02:00
sn, src, dn, dst);
}
}
//---------------------------------------------------------
2014-07-05 20:59:24 +02:00
// connect
//---------------------------------------------------------
void JackAudio::connect(const char* src, const char* dst)
{
if (src == 0 || dst == 0) {
qDebug("JackAudio::connect: unknown jack ports");
return;
}
qDebug("JackAudio::connect <%s> <%s>", src, dst);
2014-07-05 20:59:24 +02:00
int rv = jack_connect(client, src, dst);
if (rv)
qDebug("jack connect port <%s> - <%s> failed: %d", src, dst, rv);
}
2014-07-05 20:59:24 +02:00
//---------------------------------------------------------
2012-05-26 14:49:10 +02:00
// disconnect
//---------------------------------------------------------
void JackAudio::disconnect(void* src, void* dst)
{
const char* sn = jack_port_name((jack_port_t*) src);
const char* dn = jack_port_name((jack_port_t*) dst);
if (sn == 0 || dn == 0) {
qDebug("JackAudio::disconnect: unknown jack ports");
2012-05-26 14:49:10 +02:00
return;
}
if (jack_disconnect(client, sn, dn)) {
qDebug("jack disconnect <%s> - <%s> failed", sn, dn);
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// start
// return false on error
//---------------------------------------------------------
bool JackAudio::start(bool hotPlug)
2012-05-26 14:49:10 +02:00
{
bool oldremember = preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS);
if (hotPlug)
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, true);
2012-05-26 14:49:10 +02:00
if (jack_activate(client)) {
qDebug("JACK: cannot activate client");
2012-05-26 14:49:10 +02:00
return false;
}
2014-07-05 20:59:24 +02:00
/* connect the ports. Note: you can't do this before
the client is activated, because we can't allow
connections to be made to clients that aren't
running.
*/
if (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO))
restoreAudioConnections();
if (preferences.getBool(PREF_IO_JACK_USEJACKMIDI))
restoreMidiConnections();
if (hotPlug)
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, oldremember);
2012-05-26 14:49:10 +02:00
return true;
}
//---------------------------------------------------------
// stop
// return false on error
//---------------------------------------------------------
bool JackAudio::stop()
{
if (preferences.getBool(PREF_IO_JACK_USEJACKMIDI))
rememberMidiConnections();
if (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO))
2014-07-05 20:59:24 +02:00
rememberAudioConnections();
2012-05-26 14:49:10 +02:00
if (jack_deactivate(client)) {
qDebug("cannot deactivate client");
return false;
}
return true;
}
//---------------------------------------------------------
// framePos
//---------------------------------------------------------
int JackAudio::framePos() const
{
jack_nframes_t n = jack_frame_time(client);
return (int)n;
}
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
// freewheel_callback
//---------------------------------------------------------
2012-05-26 14:49:10 +02:00
2014-06-18 21:36:53 +02:00
static void freewheel_callback(int /*starting*/, void*)
2012-05-26 14:49:10 +02:00
{
}
//---------------------------------------------------------
2014-06-18 21:36:53 +02:00
// sampleRateCallback
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
2014-06-18 21:36:53 +02:00
int sampleRateCallback(jack_nframes_t sampleRate, void*)
2012-05-26 14:49:10 +02:00
{
2014-06-18 21:36:53 +02:00
qDebug("JACK: sample rate changed: %d", sampleRate);
MScore::sampleRate = sampleRate;
return 0;
2012-05-26 14:49:10 +02:00
}
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
// bufferSizeCallback called if JACK buffer changed
//---------------------------------------------------------
int bufferSizeCallback(jack_nframes_t nframes, void *arg)
2012-05-26 14:49:10 +02:00
{
2014-06-18 21:36:53 +02:00
JackAudio* audio = (JackAudio*)arg;
audio->setBufferSize(nframes);
2012-05-26 14:49:10 +02:00
return 0;
}
static void registration_callback(jack_port_id_t, int, void*)
{
// qDebug("JACK: registration changed");
2012-05-26 14:49:10 +02:00
}
static int graph_callback(void*)
{
// qDebug("JACK: graph changed");
2012-05-26 14:49:10 +02:00
return 0;
}
2015-06-13 17:57:57 +02:00
//---------------------------------------------------------
// timebase
//---------------------------------------------------------
2014-06-05 17:50:29 +02:00
void JackAudio::timebase(jack_transport_state_t state, jack_nframes_t /*nframes*/, jack_position_t *pos, int /*new_pos*/, void *arg)
{
JackAudio* audio = (JackAudio*)arg;
if (!audio->seq->score()) {
if (state==JackTransportLooping || state==JackTransportRolling)
audio->stopTransport();
}
else if (audio->seq->isRunning()) {
if (!audio->seq->score()->repeatList() || !audio->seq->score()->sigmap())
return;
pos->valid = JackPositionBBT;
int curTick = audio->seq->score()->repeatList()->utick2tick(audio->seq->getCurTick());
int bar,beat,tick;
audio->seq->score()->sigmap()->tickValues(curTick, &bar, &beat, &tick);
// Providing the final tempo
pos->beats_per_minute = 60 * audio->seq->curTempo() * audio->seq->score()->tempomap()->relTempo();
pos->ticks_per_beat = MScore::division;
pos->tick = tick;
pos->bar = bar+1;
pos->beat = beat+1;
if (audio->timeSigTempoChanged) {
Fraction timeSig = audio->seq->score()->sigmap()->timesig(curTick).nominal();
pos->beats_per_bar = timeSig.numerator();
pos->beat_type = timeSig.denominator();
audio->timeSigTempoChanged = false;
qDebug()<<"Time signature changed: "<< pos->beats_per_minute<<", bar: "<< pos->bar<<",beat: "<<pos->beat<<", tick:"<<pos->tick<<", time sig: "<<pos->beats_per_bar<<"/"<<pos->beat_type;
}
}
2014-06-18 21:36:53 +02:00
// TODO: Handle new_pos
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// processAudio
// JACK callback
//---------------------------------------------------------
int JackAudio::processAudio(jack_nframes_t frames, void* p)
{
JackAudio* audio = (JackAudio*)p;
// Prevent from crash if score not opened yet
if(!audio->seq->score())
return 0;
2012-05-26 14:49:10 +02:00
float* l;
float* r;
if (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO) && audio->ports.size() == 2) {
2012-05-26 14:49:10 +02:00
l = (float*)jack_port_get_buffer(audio->ports[0], frames);
r = (float*)jack_port_get_buffer(audio->ports[1], frames);
}
else {
l = 0;
r = 0;
}
if (preferences.getBool(PREF_IO_JACK_USEJACKMIDI)) {
2012-05-26 14:49:10 +02:00
foreach(jack_port_t* port, audio->midiOutputPorts) {
void* portBuffer = jack_port_get_buffer(port, frames);
jack_midi_clear_buffer(portBuffer);
}
foreach(jack_port_t* port, audio->midiInputPorts) {
void* portBuffer = jack_port_get_buffer(port, frames);
if (portBuffer) {
jack_nframes_t n = jack_midi_get_event_count(portBuffer);
for (jack_nframes_t i = 0; i < n; ++i) {
jack_midi_event_t event;
2018-08-17 15:06:15 +02:00
if (jack_midi_event_get(&event, portBuffer, i) != 0)
2012-05-26 14:49:10 +02:00
continue;
size_t nn = event.size;
2012-05-26 14:49:10 +02:00
int type = event.buffer[0];
if (nn && (type == ME_CLOCK || type == ME_SENSE))
continue;
Event e;
e.setChannel(type & 0xf);
type &= 0xf0;
e.setType(type);
2012-05-26 14:49:10 +02:00
if (type == ME_NOTEON || type == ME_NOTEOFF) {
e.setPitch(event.buffer[1]);
e.setVelo(event.buffer[2]);
audio->seq->eventToGui(e);
}
else if (type == ME_CONTROLLER) {
e.setController(event.buffer[1]);
e.setValue(event.buffer[2]);
audio->seq->eventToGui(e);
}
}
}
}
}
if (l && r) {
Solved all compilation errors on MSVC This commit contains changes required for MuseScore to compile under MSVC with no errors. There are several general categories of problems that resulted in errors with the compilation. Main issues: - Variable Length Arrays (VLA). This is a non-standard extension to C++, supported by clang toolchains, but not by MSVC. The initial workaround is to use std::vector<> instead of VLAs, eventually (if needed) with the original variable pointing to the beginning of the allocated array. More efficient alternatives are possible if profiling shows any code using VLAs to be timing-critical. - Floating-point constants not suffixed with "f" are doubles by default; in some instances, this leads to narrowing conversion errors (in other instances, just warnings). - MSVC does not support "or"/"and"/"not" in lieu of "||"/"&&"/"!". Changed unconditionally to use standard C++ symbols. - MSVC does not support the "__builtin_unreachable()" compiler hint. A similar, albeit not exactly equal, alternative is "__assume(0)", which is MSVC-specific. - MSVC does not support ranges in case statements. Replaced with list of cases instead of range (non-conditionally) Detailed changes, with per-file comments: - all.h: opt-in to deprecated features, include <io.h> and <process.h> instead of POSIX <unistd.h>, undefine "STRING_NONE" and "small", which Microsoft defines as macros, which result in compilation errors. - effects/compressor/zita.cpp: eliminated narrowing conversion error by appending "f" to float constants. - fluid/voice.cpp: appended "f" to float constants to eliminate narrowing conversion errors/warnings - libmscore/beam.cpp: conditionally replaced VLA - libmscore/edit.cpp: conditionally replaced VLA - libmscore/element.cpp: appended "f" to float constant - libmscore/fret.cpp: changed or -> || - libmscore/layout.cpp: conditionally replaced VLA - libmscore/mscore.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - libmscore/scorefile.coo: use correct char representation conversion for MSVC - libmscore/stringdata.cpp: conditionally replaced VLA - libmscore/system.cpp: conditionally replaced VLA - libmscroe/text.cpp: replaced range in case statement. - manual/genManual.cpp: use getopt() replacement. - midi/midifile.cpp: conditionally replaced VLA. This does not use the default replacement. - mscore/bb.cpp: replaced range in case statement. - mscore/capella.cpp: conditionally replaced VLA. Changed and -> && - mscore/driver:cpp: preclude errors due to macro redefinitions. - mscore/editstyle.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - mscore/importgtp-gp6.cpp: conditionally replaced VLA. - mscore/instrwidget.cpp: conditionally replaced VLA. - mscore/jackaudio.cpp: conditionally replaced VLA. Preclude errors due to macro redefinitions. - mscore/jackweakapi.cpp: Preclude errors due to macro redefinitions. Replacement for __atribute__((constructor)) through static object construction for MSVC. Force use of LoadLibraryA instead of LoadLibrary. - mscore/mididriver.h: Changed not -> ! - mscore/musescore.cpp: Changed not -> !. Conditionally replaced VLA. - mscore/resourceManager.cpp: conditionally replaced VLA. - mscore/timeline.cpp: conditionally replaced VLA. - omr/omrpage.cpp: conditionally replaced VLA. - synthesizer/msynthesizer.cpp: replaced UNIX sleep(1) method with MSVC Sleep(1000) (equivalent, but in ms instead of seconds) - synthesizer/msynthsizer.h: appended "f" to float constant - thirdparty/poppler/config.h: set defines for MSVC to preclude the use of inexistent libraries. - thirdparty/poppler/poppler/poppler-config.h: set defines for MSVC to preclude the use of inexistent libraries. Eliminated #defines for fmin and fmax which where causing problems. - thirdparty/poppler/poppler/PSOutputDev.cc: added #include <algorithm> for std::min() and std::max(). Note this is required per-C++ standard. - thirdparty/portmidi/pm_win/pmwinmm.c: undefined UNICODE to use char-based library functions. - thirdparty/qzip/qzip.cpp: changed or -> || - thirdparty/rtf2html/rtf_keyword.h: file format changed from Apple to UNIX, as MSVC does not supported the former. (NOT error related, just improvement on previous commit; manual/getopt/README.md: added link to source article)
2018-05-01 19:14:44 +02:00
#if (!defined (_MSCVER) && !defined (_MSC_VER))
float buffer[frames * 2];
#else
// MSVC does not support VLA. Replace with std::vector. If profiling determines that the
// heap allocation is slow, an optimization might be used.
std::vector<float> vBuffer(frames * 2);
float* buffer = vBuffer.data();
#endif
audio->seq->process((unsigned)frames, buffer);
float* sp = buffer;
for (unsigned i = 0; i < frames; ++i) {
*l++ = *sp++;
*r++ = *sp++;
}
2012-05-26 14:49:10 +02:00
}
2014-05-24 21:30:33 +02:00
else {
// JACK MIDI only
Solved all compilation errors on MSVC This commit contains changes required for MuseScore to compile under MSVC with no errors. There are several general categories of problems that resulted in errors with the compilation. Main issues: - Variable Length Arrays (VLA). This is a non-standard extension to C++, supported by clang toolchains, but not by MSVC. The initial workaround is to use std::vector<> instead of VLAs, eventually (if needed) with the original variable pointing to the beginning of the allocated array. More efficient alternatives are possible if profiling shows any code using VLAs to be timing-critical. - Floating-point constants not suffixed with "f" are doubles by default; in some instances, this leads to narrowing conversion errors (in other instances, just warnings). - MSVC does not support "or"/"and"/"not" in lieu of "||"/"&&"/"!". Changed unconditionally to use standard C++ symbols. - MSVC does not support the "__builtin_unreachable()" compiler hint. A similar, albeit not exactly equal, alternative is "__assume(0)", which is MSVC-specific. - MSVC does not support ranges in case statements. Replaced with list of cases instead of range (non-conditionally) Detailed changes, with per-file comments: - all.h: opt-in to deprecated features, include <io.h> and <process.h> instead of POSIX <unistd.h>, undefine "STRING_NONE" and "small", which Microsoft defines as macros, which result in compilation errors. - effects/compressor/zita.cpp: eliminated narrowing conversion error by appending "f" to float constants. - fluid/voice.cpp: appended "f" to float constants to eliminate narrowing conversion errors/warnings - libmscore/beam.cpp: conditionally replaced VLA - libmscore/edit.cpp: conditionally replaced VLA - libmscore/element.cpp: appended "f" to float constant - libmscore/fret.cpp: changed or -> || - libmscore/layout.cpp: conditionally replaced VLA - libmscore/mscore.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - libmscore/scorefile.coo: use correct char representation conversion for MSVC - libmscore/stringdata.cpp: conditionally replaced VLA - libmscore/system.cpp: conditionally replaced VLA - libmscroe/text.cpp: replaced range in case statement. - manual/genManual.cpp: use getopt() replacement. - midi/midifile.cpp: conditionally replaced VLA. This does not use the default replacement. - mscore/bb.cpp: replaced range in case statement. - mscore/capella.cpp: conditionally replaced VLA. Changed and -> && - mscore/driver:cpp: preclude errors due to macro redefinitions. - mscore/editstyle.cpp: conditionally replaced "__builtin_unreachable()" with "__assume(0)" for MSVC - mscore/importgtp-gp6.cpp: conditionally replaced VLA. - mscore/instrwidget.cpp: conditionally replaced VLA. - mscore/jackaudio.cpp: conditionally replaced VLA. Preclude errors due to macro redefinitions. - mscore/jackweakapi.cpp: Preclude errors due to macro redefinitions. Replacement for __atribute__((constructor)) through static object construction for MSVC. Force use of LoadLibraryA instead of LoadLibrary. - mscore/mididriver.h: Changed not -> ! - mscore/musescore.cpp: Changed not -> !. Conditionally replaced VLA. - mscore/resourceManager.cpp: conditionally replaced VLA. - mscore/timeline.cpp: conditionally replaced VLA. - omr/omrpage.cpp: conditionally replaced VLA. - synthesizer/msynthesizer.cpp: replaced UNIX sleep(1) method with MSVC Sleep(1000) (equivalent, but in ms instead of seconds) - synthesizer/msynthsizer.h: appended "f" to float constant - thirdparty/poppler/config.h: set defines for MSVC to preclude the use of inexistent libraries. - thirdparty/poppler/poppler/poppler-config.h: set defines for MSVC to preclude the use of inexistent libraries. Eliminated #defines for fmin and fmax which where causing problems. - thirdparty/poppler/poppler/PSOutputDev.cc: added #include <algorithm> for std::min() and std::max(). Note this is required per-C++ standard. - thirdparty/portmidi/pm_win/pmwinmm.c: undefined UNICODE to use char-based library functions. - thirdparty/qzip/qzip.cpp: changed or -> || - thirdparty/rtf2html/rtf_keyword.h: file format changed from Apple to UNIX, as MSVC does not supported the former. (NOT error related, just improvement on previous commit; manual/getopt/README.md: added link to source article)
2018-05-01 19:14:44 +02:00
#if (!defined (_MSCVER) && !defined (_MSC_VER))
float buffer[frames * 2];
#else
// MSVC does not support VLA. Replace with std::vector. If profiling determines that the
// heap allocation is slow, an optimization might be used.
std::vector<float> vBuffer(frames * 2);
float* buffer = vBuffer.data();
#endif
2014-05-24 21:30:33 +02:00
audio->seq->process((unsigned)frames, buffer);
}
2012-05-26 14:49:10 +02:00
return 0;
}
//---------------------------------------------------------
// jackError
//---------------------------------------------------------
static void jackError(const char *s)
{
qDebug("JACK ERROR: %s", s);
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// noJackError
//---------------------------------------------------------
2014-05-24 21:30:33 +02:00
static void noJackError(const char* s )
2012-05-26 14:49:10 +02:00
{
2014-05-24 21:30:33 +02:00
qDebug("noJACK ERROR: %s", s);
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// init
// return false on error
//---------------------------------------------------------
bool JackAudio::init(bool hot)
2012-05-26 14:49:10 +02:00
{
if (hot) {
hotPlug();
return true;
}
2012-05-26 14:49:10 +02:00
jack_set_error_function(noJackError);
client = 0;
timeSigTempoChanged = false;
fakeState = Transport::STOP;
2012-05-26 14:49:10 +02:00
strcpy(_jackName, "mscore");
jack_options_t options = (jack_options_t)0;
jack_status_t status;
client = jack_client_open(_jackName, options, &status);
2014-07-07 17:31:41 +02:00
2012-05-26 14:49:10 +02:00
if (client == 0) {
qDebug("JackAudio()::init(): failed, status 0x%0x", status);
2012-05-26 14:49:10 +02:00
return false;
}
jack_set_error_function(jackError);
jack_set_process_callback(client, processAudio, this);
//jack_on_shutdown(client, processShutdown, this);
2014-06-18 21:36:53 +02:00
jack_set_sample_rate_callback(client, sampleRateCallback, this);
2012-05-26 14:49:10 +02:00
jack_set_port_registration_callback(client, registration_callback, this);
jack_set_graph_order_callback(client, graph_callback, this);
jack_set_freewheel_callback (client, freewheel_callback, this);
if (preferences.getBool(PREF_IO_JACK_TIMEBASEMASTER))
setTimebaseCallback();
if (jack_set_buffer_size_callback (client, bufferSizeCallback, this) != 0)
qDebug("Can not set bufferSizeCallback");
2012-05-26 14:49:10 +02:00
_segmentSize = jack_get_buffer_size(client);
MScore::sampleRate = sampleRate();
// register mscore left/right output ports
if (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO)) {
2012-05-26 14:49:10 +02:00
registerPort("left", false, false);
registerPort("right", false, false);
}
if (preferences.getBool(PREF_IO_JACK_USEJACKMIDI)) {
registerPort(QString("mscore-midi-1"), false, true);
2012-05-26 14:49:10 +02:00
registerPort(QString("mscore-midiin-1"), true, true);
}
return true;
}
//---------------------------------------------------------
// startTransport
//---------------------------------------------------------
void JackAudio::startTransport()
{
if (preferences.getBool(PREF_IO_JACK_USEJACKTRANSPORT))
jack_transport_start(client);
else
fakeState = Transport::PLAY;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// stopTrasnport
//---------------------------------------------------------
void JackAudio::stopTransport()
{
if (preferences.getBool(PREF_IO_JACK_USEJACKTRANSPORT))
jack_transport_stop(client);
else
fakeState = Transport::STOP;
2012-05-26 14:49:10 +02:00
}
//---------------------------------------------------------
// getState
//---------------------------------------------------------
Transport JackAudio::getState()
2012-05-26 14:49:10 +02:00
{
if (!preferences.getBool(PREF_IO_JACK_USEJACKTRANSPORT))
return fakeState;
2014-06-18 21:36:53 +02:00
int transportState = jack_transport_query(client, NULL);
2012-05-26 14:49:10 +02:00
switch (transportState) {
case JackTransportStopped: return Transport::STOP;
2012-05-26 14:49:10 +02:00
case JackTransportLooping:
case JackTransportRolling: return Transport::PLAY;
2014-06-18 21:36:53 +02:00
case JackTransportStarting: return seq->isPlaying()?Transport::PLAY:Transport::STOP;// Keep current state
2012-05-26 14:49:10 +02:00
default:
return Transport::STOP;
2012-05-26 14:49:10 +02:00
}
}
//---------------------------------------------------------
// putEvent
//---------------------------------------------------------
2014-05-24 21:30:33 +02:00
void JackAudio::putEvent(const NPlayEvent& e, unsigned framePos)
2012-05-26 14:49:10 +02:00
{
if (!preferences.getBool(PREF_IO_JACK_USEJACKMIDI))
2012-05-26 14:49:10 +02:00
return;
int portIdx = seq->score()->midiPort(e.channel());
int chan = seq->score()->midiChannel(e.channel());
2012-05-26 14:49:10 +02:00
// qDebug("JackAudio::putEvent %d:%d pos %d(%d)", portIdx, chan, framePos, _segmentSize);
2012-05-26 14:49:10 +02:00
if (portIdx < 0 || portIdx >= midiOutputPorts.size()) {
qDebug("JackAudio::putEvent: invalid port %d", portIdx);
2012-05-26 14:49:10 +02:00
return;
}
jack_port_t* port = midiOutputPorts[portIdx];
if (midiOutputTrace) {
const char* portName = jack_port_name(port);
2014-07-05 20:59:24 +02:00
int a = e.dataA();
int b = e.dataB();
qDebug("MidiOut<%s>: jackMidi: %02x %02x %02x, chan: %i", portName, e.type(), a, b, chan);
2012-05-26 14:49:10 +02:00
// e.dump();
}
void* pb = jack_port_get_buffer(port, _segmentSize);
if (pb == NULL) {
qDebug()<<"jack_port_get_buffer failed, cannot send anything";
}
2012-05-26 14:49:10 +02:00
if (framePos >= _segmentSize) {
qDebug("JackAudio::putEvent: time out of range %d(seg=%d)", framePos, _segmentSize);
2012-05-26 14:49:10 +02:00
if (framePos > _segmentSize)
framePos = _segmentSize - 1;
}
switch(e.type()) {
case ME_NOTEON:
case ME_NOTEOFF:
case ME_POLYAFTER:
case ME_CONTROLLER:
// Catch CTRL_PROGRAM and let other ME_CONTROLLER events to go
if (e.dataA() == CTRL_PROGRAM) {
// Convert CTRL_PROGRAM event to ME_PROGRAM
unsigned char* p = jack_midi_event_reserve(pb, framePos, 2);
if (p == 0) {
qDebug("JackMidi: buffer overflow, event lost");
return;
}
p[0] = ME_PROGRAM | chan;
p[1] = less128(e.dataB());
break;
}
//fall through
2012-05-26 14:49:10 +02:00
case ME_PITCHBEND:
{
unsigned char* p = jack_midi_event_reserve(pb, framePos, 3);
if (p == 0) {
qDebug("JackMidi: buffer overflow, event lost");
2012-05-26 14:49:10 +02:00
return;
}
p[0] = e.type() | chan;
p[1] = less128(e.dataA());
p[2] = less128(e.dataB());
2012-05-26 14:49:10 +02:00
}
break;
case ME_PROGRAM:
case ME_AFTERTOUCH:
{
unsigned char* p = jack_midi_event_reserve(pb, framePos, 2);
if (p == 0) {
qDebug("JackMidi: buffer overflow, event lost");
2012-05-26 14:49:10 +02:00
return;
}
p[0] = e.type() | chan;
p[1] = less128(e.dataA());
2012-05-26 14:49:10 +02:00
}
break;
2014-05-24 21:30:33 +02:00
// Do we really need to handle ME_SYSEX?
/* case ME_SYSEX:
2012-05-26 14:49:10 +02:00
{
2013-04-08 10:31:17 +02:00
const unsigned char* data = e.edata();
2012-05-26 14:49:10 +02:00
int len = e.len();
unsigned char* p = jack_midi_event_reserve(pb, framePos, len+2);
if (p == 0) {
qDebug("JackMidi: buffer overflow, event lost");
2012-05-26 14:49:10 +02:00
return;
}
p[0] = 0xf0;
p[len+1] = 0xf7;
memcpy(p+1, data, len);
}
2014-05-24 21:30:33 +02:00
break;*/
2012-05-26 14:49:10 +02:00
case ME_SONGPOS:
case ME_CLOCK:
case ME_START:
case ME_CONTINUE:
case ME_STOP:
qDebug("JackMidi: event type %x not supported", e.type());
2012-05-26 14:49:10 +02:00
break;
}
}
//---------------------------------------------------------
// midiRead
//---------------------------------------------------------
void JackAudio::midiRead()
{
// midiDriver->read();
}
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
2015-06-13 17:57:57 +02:00
// handleTimeSigTempoChanged
2014-06-18 21:36:53 +02:00
// Called after tempo or time signature
// changed while playback
//---------------------------------------------------------
void JackAudio::handleTimeSigTempoChanged()
{
2014-06-18 21:36:53 +02:00
timeSigTempoChanged = true;
}
2012-05-26 14:49:10 +02:00
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
// checkTransportSeek
// The opposite of Timebase master:
// check JACK Transport for a new position or tempo.
2014-06-18 21:36:53 +02:00
//---------------------------------------------------------
2014-07-07 17:31:41 +02:00
void JackAudio::checkTransportSeek(int cur_frame, int nframes, bool inCountIn)
2014-06-18 21:36:53 +02:00
{
2014-10-01 20:17:30 +02:00
if (!seq || !seq->score() || inCountIn)
return;
2014-06-18 21:36:53 +02:00
// Obtaining the current JACK Transport position
jack_position_t pos;
jack_transport_query(client, &pos);
if (preferences.getBool(PREF_IO_JACK_USEJACKTRANSPORT)) {
2014-07-07 17:31:41 +02:00
if (mscore->getPlayPanel() && mscore->getPlayPanel()->isTempoSliderPressed())
return;
int cur_utick = seq->score()->utime2utick((qreal)cur_frame / MScore::sampleRate);
int utick = seq->score()->utime2utick((qreal)pos.frame / MScore::sampleRate);
// Conversion is not precise, should check frames and uticks
if (labs((long int)cur_frame - (long int)pos.frame)>nframes + 1 && abs(utick - cur_utick)> seq->score()->utime2utick((qreal)nframes / MScore::sampleRate) + 1) {
if (MScore::debugMode)
qDebug()<<"JACK Transport position changed, cur_frame: "<<cur_frame<<",pos.frame: "<<pos.frame<<", frame diff: "<<labs((long int)cur_frame - (long int)pos.frame)<<"cur utick:"<<cur_utick<<",seek to utick: "<<utick<<", tick diff: "<<abs(utick - cur_utick);
seq->seekRT(utick);
}
2014-06-18 21:36:53 +02:00
}
// Tempo
if (!preferences.getBool(PREF_IO_JACK_TIMEBASEMASTER) && (pos.valid & JackPositionBBT)) {
2014-07-07 17:31:41 +02:00
if (!seq->score()->tempomap())
return;
2014-07-07 17:31:41 +02:00
if (int(pos.beats_per_minute) != int(60 * seq->curTempo() * seq->score()->tempomap()->relTempo())) {
2014-07-07 17:31:41 +02:00
if (MScore::debugMode)
qDebug()<<"JACK Transport tempo changed! JACK bpm: "<<(int)pos.beats_per_minute<<", current bpm: "<<int(60 * seq->curTempo() * seq->score()->tempomap()->relTempo());
if (60 * seq->curTempo() == 0.0)
return;
qreal newRelTempo = pos.beats_per_minute / (60* seq->curTempo());
2014-07-07 17:31:41 +02:00
seq->setRelTempo(newRelTempo);
// Update UI
if (mscore->getPlayPanel()) {
mscore->getPlayPanel()->setRelTempo(newRelTempo);
mscore->getPlayPanel()->setTempo(seq->curTempo() * newRelTempo);
}
}
}
2014-06-18 21:36:53 +02:00
}
//---------------------------------------------------------
// seekTransport
//---------------------------------------------------------
void JackAudio::seekTransport(int utick)
{
2014-07-07 17:31:41 +02:00
if (MScore::debugMode)
qDebug()<<"jack locate to utick: "<<utick<<", frame: "<<int(seq->score()->utick2utime(utick) * MScore::sampleRate);
2014-06-18 21:36:53 +02:00
jack_transport_locate(client, seq->score()->utick2utime(utick) * MScore::sampleRate);
}
//---------------------------------------------------------
// setTimebaseCallback
//---------------------------------------------------------
void JackAudio::setTimebaseCallback()
{
int errCode = jack_set_timebase_callback(client, 0, timebase, this); // 0: force set timebase
if (errCode == 0) {
2014-07-05 20:59:24 +02:00
if (MScore::debugMode)
qDebug("Registered as JACK Timebase Master.");
}
else {
preferences.setPreference(PREF_IO_JACK_TIMEBASEMASTER, false);
qDebug("Unable to take over JACK Timebase, error code: %i",errCode);
}
}
//---------------------------------------------------------
// releaseTimebaseCallback
//---------------------------------------------------------
void JackAudio::releaseTimebaseCallback()
{
int errCode = jack_release_timebase(client);
if (errCode == 0)
qDebug("Unregistered as JACK Timebase Master");
else
qDebug("Unable to unregister as JACK Timebase Master (not a Timebase Master?), error code: %i", errCode);
}
2014-07-05 20:59:24 +02:00
//---------------------------------------------------------
// rememberAudioConnections
//---------------------------------------------------------
void JackAudio::rememberAudioConnections()
{
if (!preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS))
2014-07-05 20:59:24 +02:00
return;
if (MScore::debugMode)
qDebug("Saving audio connections...");
QSettings settings;
settings.setValue(QString("audio-0-connections"), 0);
settings.setValue(QString("audio-1-connections"), 0);
2014-07-05 20:59:24 +02:00
int port = 0;
foreach(jack_port_t* mp, ports) {
const char** cc = jack_port_get_connections(mp);
const char** c = cc;
int idx = 0;
while (c) {
const char* p = *c++;
if (p == 0)
break;
settings.setValue(QString("audio-%1-%2").arg(port).arg(idx), p);
++idx;
}
settings.setValue(QString("audio-%1-connections").arg(port), idx);
free((void*)cc);
++port;
}
}
//---------------------------------------------------------
// restoreAudioConnections
// Connect to the ports in Preferences->I/O
//---------------------------------------------------------
void JackAudio::restoreAudioConnections()
{
for (auto p : ports)
jack_port_disconnect(client, p);
2014-07-05 20:59:24 +02:00
QList<QString> portList = inputPorts();
QList<QString>::iterator pi = portList.begin();
2014-07-05 20:59:24 +02:00
QSettings settings;
// Number of saved ports
int n = settings.value(QString("audio-0-connections"), 0).toInt() + settings.value(QString("audio-1-connections"), 0).toInt();
// Connecting to system ports
if (!preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS) || n == 0) {
2014-07-05 20:59:24 +02:00
if (MScore::debugMode)
qDebug("Connecting to system ports...");
for (auto p : ports) {
const char* src = jack_port_name(p);
2014-07-05 20:59:24 +02:00
if (pi != portList.end()) {
connect(src, qPrintable(*pi));
++pi;
}
}
return;
}
if (MScore::debugMode)
qDebug("Restoring audio connections...");
// Connecting to saved ports
int nPorts = ports.size();
for (int i = 0; i < nPorts; ++i) {
2018-08-17 15:06:15 +02:00
int j = settings.value(QString("audio-%1-connections").arg(i), 0).toInt();
2014-07-05 20:59:24 +02:00
const char* src = jack_port_name(ports[i]);
2018-08-17 15:06:15 +02:00
for (int k = 0; k < j; ++k) {
2014-07-05 20:59:24 +02:00
QString dst = settings.value(QString("audio-%1-%2").arg(i).arg(k), "").toString();
if (!dst.isEmpty()) {
if (jack_port_connected_to(ports[i], qPrintable(dst)))
qDebug()<<"Audio port "<<src<<" ("<<i<<") already connected to "<<qPrintable(dst);
else
connect(src, qPrintable(dst));
}
}
}
}
//---------------------------------------------------------
// rememberMidiConnections
//---------------------------------------------------------
void JackAudio::rememberMidiConnections()
{
if (!preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS))
2014-07-05 20:59:24 +02:00
return;
if (MScore::debugMode)
qDebug("Saving midi connections...");
QSettings settings;
int port = 0;
foreach(jack_port_t* mp, midiOutputPorts) {
const char** cc = jack_port_get_connections(mp);
const char** c = cc;
int idx = 0;
while (c) {
const char* p = *c++;
if (p == 0)
break;
settings.setValue(QString("midi-%1-%2").arg(port).arg(idx), p);
++idx;
}
settings.setValue(QString("midi-%1-connections").arg(port), idx);
free((void*)cc);
++port;
}
2014-07-05 20:59:24 +02:00
port = 0;
foreach(jack_port_t* mp, midiInputPorts) {
const char** cc = jack_port_get_connections(mp);
const char** c = cc;
int idx = 0;
while (c) {
const char* p = *c++;
if (p == 0)
break;
settings.setValue(QString("midiin-%1-%2").arg(idx).arg(port), p);
++idx;
}
settings.setValue(QString("midiin-%1-connections").arg(port), idx);
free((void*)cc);
++port;
}
}
//---------------------------------------------------------
// restoreMidiConnections
// Connects to the ports from previous connection
//---------------------------------------------------------
void JackAudio::restoreMidiConnections()
{
if (!preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS))
2014-07-05 20:59:24 +02:00
return;
if (MScore::debugMode)
qDebug("Restoring midi connections...");
QSettings settings;
int nPorts = midiOutputPorts.size();
for (int i = 0; i < nPorts; ++i) {
int n = settings.value(QString("midi-%1-connections").arg(i), 0).toInt();
const char* src = jack_port_name(midiOutputPorts[i]);
for (int k = 0; k < n; ++k) {
QString dst = settings.value(QString("midi-%1-%2").arg(i).arg(k), "").toString();
if (!dst.isEmpty()) {
if (jack_port_connected_to(midiOutputPorts[i], qPrintable(dst)))
continue;
2014-07-05 20:59:24 +02:00
connect(src, qPrintable(dst));
}
}
}
nPorts = midiInputPorts.size();
for (int i = 0; i < nPorts; ++i) {
int n = settings.value(QString("midiin-%1-connections").arg(i), 0).toInt();
const char* dst = jack_port_name(midiInputPorts[i]);
for (int k = 0; k < n; ++k) {
QString src = settings.value(QString("midiin-%1-%2").arg(k).arg(i), "").toString();
if (!src.isEmpty()) {
if (jack_port_connected_to(midiInputPorts[i], qPrintable(src)))
continue;
2014-07-05 20:59:24 +02:00
connect(qPrintable(src), dst);
}
}
}
}
//---------------------------------------------------------
// hotPlug
// Change driver settings without unload
//---------------------------------------------------------
void JackAudio::hotPlug()
{
bool oldremember = preferences.getBool(PREF_IO_JACK_REMEMBERLASTCONNECTIONS);
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, true);
// Remember connections before calling jack_deactivate() - it disconnects all ports
rememberMidiConnections();
if (ports.size() != 0)
2014-07-05 20:59:24 +02:00
rememberAudioConnections();
// We must set callbacks only on inactive client
if (jack_deactivate(client))
qDebug("cannot deactivate client");
// Audio connections
if (preferences.getBool(PREF_IO_JACK_USEJACKAUDIO)) {
if (ports.size() == 0) {
registerPort("left", false, false);
registerPort("right", false, false);
}
}
else if (!preferences.getBool(PREF_IO_JACK_USEJACKAUDIO)) {
foreach(jack_port_t* p, ports) {
unregisterPort(p);
ports.removeOne(p);
}
}
// Midi connections
if (preferences.getBool(PREF_IO_JACK_USEJACKMIDI)) {
if (midiInputPorts.size() == 0)
registerPort(QString("mscore-midiin-1"), true, true);
}
else { // No midi
updateOutPortCount(0);
if (midiInputPorts.size() != 0) {
unregisterPort(midiInputPorts[0]);
midiInputPorts.removeOne(midiInputPorts[0]);
}
}
2014-07-05 20:59:24 +02:00
// Timebase Master callback
if (preferences.getBool(PREF_IO_JACK_TIMEBASEMASTER))
2014-07-05 20:59:24 +02:00
setTimebaseCallback();
else
releaseTimebaseCallback();
preferences.setPreference(PREF_IO_JACK_REMEMBERLASTCONNECTIONS, oldremember);
}
2014-06-18 21:36:53 +02:00
}