From cac893c369379fb5957b0e89a4fe12f8adae6f8b Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 21 Apr 2024 18:18:42 +0200 Subject: [PATCH 01/60] cleanup namespace playbackcontroller --- src/playback/internal/playbackcontroller.cpp | 52 ++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 1eb8a8932c6c7..caf4629500781 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -139,6 +139,34 @@ void PlaybackController::init() }); m_measureInputLag = configuration()->shouldMeasureInputLag(); + + m_playbackPositionChanged.onNotify(this, [this]() { + updateCurrentTempo(); + + msecs_t endMsecs = playbackEndMsecs(); + const LoopBoundaries& loop = notationPlayback()->loopBoundaries(); + if (m_currentPlaybackTimeMsecs == endMsecs && m_currentPlaybackTimeMsecs != loop.loopOutTick) { + stop(); + } + }); + + m_remoteSeek.onReceive(this, [this](const msecs_t msecs) { + seek(msecs); + }); + + m_remotePlayOrStop.onReceive(this, [this](const bool playOrStop) { + if (playOrStop) { + if (isPlaying()) { + resume(); + } else { + play(); + } + } else { + if (isPlaying()) { + pause(); + } + } + }); } void PlaybackController::updateCurrentTempo() @@ -234,6 +262,22 @@ void PlaybackController::seek(const audio::secs_t secs) currentPlayer()->seek(secs); } +void PlaybackController::remoteSeek(const msecs_t msecs) +{ + IF_ASSERT_FAILED(playback()) { + return; + } + m_remoteSeek.send(msecs); +} + +void PlaybackController::remotePlayOrStop(const bool playOrStop) +{ + if (!isPlayAllowed()) { + return; + } + m_remotePlayOrStop.send(playOrStop); +} + muse::async::Channel PlaybackController::currentPlaybackPositionChanged() const { return m_currentPlaybackPositionChanged; @@ -1102,7 +1146,7 @@ void PlaybackController::setTrackActivity(const engraving::InstrumentTrackId& in outParams.muted = !isActive; - audio::TrackId trackId = m_instrumentTrackIdMap[instrumentTrackId]; + TrackId trackId = m_instrumentTrackIdMap[instrumentTrackId]; playback()->audioOutput()->setOutputParams(m_currentSequenceId, trackId, std::move(outParams)); } @@ -1205,7 +1249,7 @@ void PlaybackController::setupNewCurrentSequence(const TrackSequenceId sequenceI return; } - const audio::AudioOutputParams& masterOutputParams = audioSettings()->masterAudioOutputParams(); + const AudioOutputParams& masterOutputParams = audioSettings()->masterAudioOutputParams(); playback()->audioOutput()->setMasterOutputParams(masterOutputParams); subscribeOnAudioParamsChanges(); @@ -1217,7 +1261,7 @@ void PlaybackController::setupNewCurrentSequence(const TrackSequenceId sequenceI void PlaybackController::subscribeOnAudioParamsChanges() { - playback()->audioOutput()->masterOutputParamsChanged().onReceive(this, [this](const audio::AudioOutputParams& params) { + playback()->audioOutput()->masterOutputParamsChanged().onReceive(this, [this](const AudioOutputParams& params) { audioSettings()->setMasterAudioOutputParams(params); }); @@ -1445,7 +1489,7 @@ void PlaybackController::updateSoloMuteStates() params.muted = soloMuteState.mute || shouldForceMute; params.forceMute = shouldForceMute; - audio::TrackId trackId = m_instrumentTrackIdMap.at(instrumentTrackId); + TrackId trackId = m_instrumentTrackIdMap.at(instrumentTrackId); playback()->audioOutput()->setOutputParams(m_currentSequenceId, trackId, std::move(params)); } From 6db155c667611f5c041f5c5e16f1077f93fc7223 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 29 Mar 2024 07:27:00 +0100 Subject: [PATCH 02/60] fix hardcoded samplerate --- src/framework/audio/internal/audioconfiguration.cpp | 4 ++-- src/framework/audio/internal/fx/reverb/reverbprocessor.cpp | 6 +++--- src/framework/audio/internal/fx/reverb/reverbprocessor.h | 3 +++ .../audioexport/internal/audioexportconfiguration.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/framework/audio/internal/audioconfiguration.cpp b/src/framework/audio/internal/audioconfiguration.cpp index 6cf4681f6019d..9fe6516c56384 100644 --- a/src/framework/audio/internal/audioconfiguration.cpp +++ b/src/framework/audio/internal/audioconfiguration.cpp @@ -75,8 +75,8 @@ void AudioConfiguration::init() m_audioOutputDeviceIdChanged.notify(); }); - settings()->setDefaultValue(AUDIO_SAMPLE_RATE_KEY, Val(44100)); - settings()->setCanBeManuallyEdited(AUDIO_SAMPLE_RATE_KEY, false, Val(44100), Val(192000)); + settings()->setDefaultValue(AUDIO_SAMPLE_RATE_KEY, Val(48000)); + settings()->setCanBeManuallyEdited(AUDIO_SAMPLE_RATE_KEY, false, Val(48000), Val(192000)); settings()->valueChanged(AUDIO_SAMPLE_RATE_KEY).onReceive(nullptr, [this](const Val&) { m_driverSampleRateChanged.notify(); }); diff --git a/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp b/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp index 5e42df6c95177..a8974d81c1fc1 100644 --- a/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp +++ b/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp @@ -287,7 +287,7 @@ ReverbProcessor::ReverbProcessor(const AudioFxParams& params, audioch_t audioCha setParameter(Params::PreDelayMs, getParameter(Params::PreDelayMs)); setParameter(Params::FeedbackTop, getParameter(Params::FeedbackTop)); - setFormat(audioChannelsCount, 44100.0 /*sampleRate*/, 512 /*maximumBlockSize*/); + setFormat(audioChannelsCount, audioConfiguration()->sampleRate(), 512 /*maximumBlockSize*/); } ReverbProcessor::~ReverbProcessor() @@ -380,7 +380,7 @@ float ReverbProcessor::getParameter(int32_t index) void ReverbProcessor::calculateTailParams() { const int* delayTimes = _delayTimesForN(m_delays); - float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / 44100.); + float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / static_cast(audioConfiguration()->sampleRate())); const float log_db60 = std::log(fromDecibel(-60.f)); @@ -438,7 +438,7 @@ void ReverbProcessor::calculateModParams() float modDepthSmp = float(depthMs * 0.001f * m_processor._sampleRate); d->sinLfo.setup(m_delays, freqHz * d->modStep, modDepthSmp, m_processor._sampleRate); - float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / 44100.); + float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / static_cast(audioConfiguration()->sampleRate())); for (int i = 0; i < m_delays; ++i) { d->modDelay[i].setBaseDelay(delayTimes[i] * scale, modDepthSmp * 2.f); } diff --git a/src/framework/audio/internal/fx/reverb/reverbprocessor.h b/src/framework/audio/internal/fx/reverb/reverbprocessor.h index b84f9bfced4f5..2c7deca03cb7d 100644 --- a/src/framework/audio/internal/fx/reverb/reverbprocessor.h +++ b/src/framework/audio/internal/fx/reverb/reverbprocessor.h @@ -28,11 +28,14 @@ #include #include +#include "modularity/ioc.h" +#include "iaudioconfiguration.h" #include "ifxprocessor.h" namespace muse::audio::fx { class ReverbProcessor : public IFxProcessor { + Inject audioConfiguration; public: ReverbProcessor(const audio::AudioFxParams& params, audioch_t audioChannelsCount = 2); ~ReverbProcessor() override; diff --git a/src/importexport/audioexport/internal/audioexportconfiguration.cpp b/src/importexport/audioexport/internal/audioexportconfiguration.cpp index 0dd8d1502f590..79a467fc432be 100644 --- a/src/importexport/audioexport/internal/audioexportconfiguration.cpp +++ b/src/importexport/audioexport/internal/audioexportconfiguration.cpp @@ -34,7 +34,7 @@ static const Settings::Key EXPORT_MP3_BITRATE("iex_audioexport", "export/audio/m void AudioExportConfiguration::init() { - settings()->setDefaultValue(EXPORT_SAMPLE_RATE_KEY, Val(44100)); + settings()->setDefaultValue(EXPORT_SAMPLE_RATE_KEY, Val(48000)); settings()->setDefaultValue(EXPORT_MP3_BITRATE, Val(128)); } From f24348f48725e31592719ac568ffa77c172d0bfe Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 29 Mar 2024 07:49:03 +0100 Subject: [PATCH 03/60] cosmetic variable rename to avoid 'bufferSize' --- src/engraving/dom/note.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engraving/dom/note.cpp b/src/engraving/dom/note.cpp index dbe4b4cfe793c..736c836a62f22 100644 --- a/src/engraving/dom/note.cpp +++ b/src/engraving/dom/note.cpp @@ -876,9 +876,9 @@ String Note::tpcUserName(const bool explicitAccidental, bool full) const String pitchOffset; if (tuning() != 0) { - static constexpr size_t bufferSize = 50; - char buffer[bufferSize]; - snprintf(buffer, bufferSize, "%+.3f", tuning()); + static constexpr size_t maxLen = 50; + char buffer[maxLen]; + snprintf(buffer, maxLen, "%+.3f", tuning()); pitchOffset = String::fromAscii(buffer); } From 6f0b59e35cfa1b378d07daa83f4fe77849417d7b Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 5 Apr 2024 14:26:39 +0200 Subject: [PATCH 04/60] macos cleanup --- src/framework/audio/internal/platform/osx/osxaudiodriver.h | 2 +- src/framework/audio/internal/platform/osx/osxaudiodriver.mm | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 11298dfd25652..8a1c50155f7cc 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -86,7 +86,7 @@ class OSXAudioDriver : public IAudioDriver struct Data; - std::shared_ptr m_data = nullptr; + std::shared_ptr m_data; std::map m_outputDevices = {}, m_inputDevices = {}; mutable std::mutex m_devicesMutex; async::Notification m_outputDeviceChanged; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index 25ebc51bb75ce..5e775c0a7ba3d 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -42,7 +42,6 @@ }; OSXAudioDriver::OSXAudioDriver() - : m_data(nullptr) { m_data = std::make_shared(); m_data->audioQueue = nullptr; From 6d6b861f8a3ed617e2ba7dc18fbe1a8ed406b089 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 31 Mar 2024 09:39:11 +0200 Subject: [PATCH 05/60] playbackcontroller remoteSeek/remotePlayOrStop --- src/playback/internal/playbackcontroller.cpp | 2 +- src/playback/internal/playbackcontroller.h | 4 ++++ src/playback/iplaybackcontroller.h | 2 ++ src/playback/tests/mocks/playbackcontrollermock.h | 2 ++ src/stubs/playback/playbackcontrollerstub.cpp | 8 ++++++++ src/stubs/playback/playbackcontrollerstub.h | 2 ++ 6 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index caf4629500781..5ef29c1e97ed7 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -150,7 +150,7 @@ void PlaybackController::init() } }); - m_remoteSeek.onReceive(this, [this](const msecs_t msecs) { + m_remoteSeek.onReceive(this, [this](const muse::audio::msecs_t msecs) { seek(msecs); }); diff --git a/src/playback/internal/playbackcontroller.h b/src/playback/internal/playbackcontroller.h index be1a42229a920..bd842f28fa90d 100644 --- a/src/playback/internal/playbackcontroller.h +++ b/src/playback/internal/playbackcontroller.h @@ -64,6 +64,8 @@ class PlaybackController : public IPlaybackController, public muse::actions::Act void reset() override; muse::async::Channel currentPlaybackPositionChanged() const override; + void remoteSeek(const muse::audio::msecs_t msecs) override; + void remotePlayOrStop(const bool playOrStop) override; muse::audio::TrackSequenceId currentTrackSequenceId() const override; muse::async::Notification currentTrackSequenceIdChanged() const override; @@ -224,6 +226,8 @@ class PlaybackController : public IPlaybackController, public muse::actions::Act muse::async::Notification m_currentTempoChanged; muse::async::Channel m_currentPlaybackPositionChanged; muse::async::Channel m_actionCheckedChanged; + muse::async::Channel m_remoteSeek; + muse::async::Channel m_remotePlayOrStop; muse::audio::TrackSequenceId m_currentSequenceId = -1; diff --git a/src/playback/iplaybackcontroller.h b/src/playback/iplaybackcontroller.h index 0248e56851637..ff72318b685a4 100644 --- a/src/playback/iplaybackcontroller.h +++ b/src/playback/iplaybackcontroller.h @@ -48,6 +48,8 @@ class IPlaybackController : MODULE_EXPORT_INTERFACE virtual bool isPlaying() const = 0; virtual muse::async::Notification isPlayingChanged() const = 0; + virtual void remoteSeek(const muse::audio::msecs_t msecs) = 0; + virtual void remotePlayOrStop(const bool playOrStop) = 0; virtual void reset() = 0; virtual muse::async::Channel currentPlaybackPositionChanged() const = 0; diff --git a/src/playback/tests/mocks/playbackcontrollermock.h b/src/playback/tests/mocks/playbackcontrollermock.h index 317da3bc41388..2e43fccbbb899 100644 --- a/src/playback/tests/mocks/playbackcontrollermock.h +++ b/src/playback/tests/mocks/playbackcontrollermock.h @@ -36,6 +36,8 @@ class PlaybackControllerMock : public IPlaybackController MOCK_METHOD(bool, isPlaying, (), (const, override)); MOCK_METHOD(muse::async::Notification, isPlayingChanged, (), (const, override)); + MOCK_METHOD(void, remoteSeek, (const muse::audio::msecs_t), (override)); + MOCK_METHOD(void, remotePlayOrStop, (const bool), (override)); MOCK_METHOD(void, reset, (), (override)); MOCK_METHOD((muse::async::Channel), currentPlaybackPositionChanged, (), (const, override)); diff --git a/src/stubs/playback/playbackcontrollerstub.cpp b/src/stubs/playback/playbackcontrollerstub.cpp index fa2ad74f3aacd..7acb28c489c4d 100644 --- a/src/stubs/playback/playbackcontrollerstub.cpp +++ b/src/stubs/playback/playbackcontrollerstub.cpp @@ -44,6 +44,14 @@ muse::async::Notification PlaybackControllerStub::isPlayingChanged() const return muse::async::Notification(); } +void PlaybackControllerStub::remoteSeek(const muse::audio::msecs_t msecs) +{ +} + +void PlaybackControllerStub::remotePlayOrStop(const bool playOrStop) +{ +} + void PlaybackControllerStub::reset() { } diff --git a/src/stubs/playback/playbackcontrollerstub.h b/src/stubs/playback/playbackcontrollerstub.h index 9ab3f484559fe..41e1c72d08d69 100644 --- a/src/stubs/playback/playbackcontrollerstub.h +++ b/src/stubs/playback/playbackcontrollerstub.h @@ -34,6 +34,8 @@ class PlaybackControllerStub : public IPlaybackController bool isPlaying() const override; muse::async::Notification isPlayingChanged() const override; + void remoteSeek(const muse::audio::msecs_t msecs) override; + void remotePlayOrStop(const bool playOrStop) override; void reset() override; muse::async::Channel currentPlaybackPositionChanged() const override; From 4824f6282470acf01d33767af82a9bc1201f1c4d Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 3 Apr 2024 10:47:20 +0200 Subject: [PATCH 06/60] mingw dynamic-library --- src/app/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 9824cb9fd06e9..97690674c5298 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -239,6 +239,12 @@ if (CC_IS_EMSCRIPTEN) list(APPEND MSCORE_APPEND_SRC $) endif() +# if any above modules are using dynamic-library loading (musesampler) +# then if mingw, use dl-lib which emulates unix-dl +if (MINGW) + list(APPEND LINK_LIB "-ldl -fstack-protector") +endif (MINGW) + ########################################### # Resources ########################################### From 50ca69054c8e4b4558560fd3fd8f95a14bf3e720 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 7 Mar 2024 09:52:26 +0100 Subject: [PATCH 07/60] jack: enable jack (not mingw) --- SetupConfigure.cmake | 6 +- src/framework/audio/CMakeLists.txt | 72 +++++++++++--------- src/framework/cmake/MuseDeclareOptions.cmake | 2 +- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/SetupConfigure.cmake b/SetupConfigure.cmake index e70c7f504734f..be5efe9add946 100644 --- a/SetupConfigure.cmake +++ b/SetupConfigure.cmake @@ -195,10 +195,10 @@ endif() set(QT_SUPPORT ON) if (MUSE_MODULE_AUDIO_JACK) - if (OS_IS_LIN OR MINGW) - add_compile_definitions(JACK_AUDIO) - else() + if (OS_IS_WIN AND (NOT MINGW)) set(MUSE_MODULE_AUDIO_JACK OFF) + else() + add_compile_definitions(JACK_AUDIO) endif() endif() diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index 3efcbeb488376..41102e834c9f1 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -23,7 +23,7 @@ set(MODULE_ALIAS muse::audio) include(GetPlatformInfo) -if (OS_IS_WIN) +if (OS_IS_WIN AND (NOT MINGW)) set(DRIVER_SRC #${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.cpp #${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.h @@ -37,24 +37,23 @@ if (OS_IS_WIN) ${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/audiodeviceslistener.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/audiodeviceslistener.h ) -elseif(OS_IS_LIN OR OS_IS_FBSD) +elseif(OS_IS_LIN OR OS_IS_FBSD OR MINGW) + set(JACK_SRC "") if (MUSE_MODULE_AUDIO_JACK) - set(DRIVER_SRC + set(JACK_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/audiodeviceslistener.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/audiodeviceslistener.h - ) - else() - set(DRIVER_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.h - ) - endif() + ) + endif(MUSE_MODULE_AUDIO_JACK) + set(DRIVER_SRC + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsaaudiodriver.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsaaudiodriver.h + ${JACK_SRC} + ) elseif(OS_IS_MAC) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.mm @@ -275,24 +274,31 @@ else () ) endif() -if (MUSE_MODULE_AUDIO_JACK) - find_package(Jack REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS} ) - set(MODULE_LINK ${MODULE_LINK} ${JACK_LIBRARIES} pthread ) - find_package(ALSA REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS} ) - set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread ) -else () - if (OS_IS_MAC) - find_library(AudioToolbox NAMES AudioToolbox) - find_library(CoreAudio NAMES CoreAudio) - set(MODULE_LINK ${MODULE_LINK} ${AudioToolbox} ${CoreAudio}) - elseif (OS_IS_WIN) - set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) - elseif (OS_IS_LIN) +if (OS_IS_MAC) + find_library(AudioToolbox NAMES AudioToolbox) + find_library(CoreAudio NAMES CoreAudio) + set(MODULE_LINK ${MODULE_LINK} ${AudioToolbox} ${CoreAudio}) +elseif (OS_IS_WIN AND (NOT (MINGW))) + set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) +elseif (OS_IS_LIN) + if (MUSE_MODULE_AUDIO_JACK) + find_package(ALSA REQUIRED) + find_package(Jack REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} ${ALSA_LIBRARIES} pthread) + else() find_package(ALSA REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS} ) - set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread ) + set(MODULE_INCLUDE ${MODULE_INCLUDE} ${ALSA_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread) + endif() +elseif (MINGW) + if (MUSE_MODULE_AUDIO_JACK) + find_package(Jack REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) + else() + set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) endif() endif() diff --git a/src/framework/cmake/MuseDeclareOptions.cmake b/src/framework/cmake/MuseDeclareOptions.cmake index 5c3b4a2221822..296132d9a50ce 100644 --- a/src/framework/cmake/MuseDeclareOptions.cmake +++ b/src/framework/cmake/MuseDeclareOptions.cmake @@ -11,7 +11,7 @@ option(MUSE_MODULE_ACCESSIBILITY_TRACE "Enable accessibility logging" OFF) declare_muse_module_opt(ACTIONS ON) declare_muse_module_opt(AUDIO ON) -option(MUSE_MODULE_AUDIO_JACK "Enable jack support" OFF) +option(MUSE_MODULE_AUDIO_JACK "Enable jack support" ON) option(MUSE_MODULE_AUDIO_EXPORT "Enable audio export" ON) declare_muse_module_opt(AUDIOPLUGINS ON) From 936a6a0aad2c747d7775c3b2a6e1fd237c2bf138 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 30 Mar 2024 21:25:02 +0100 Subject: [PATCH 08/60] audiodrivers cleanup, prepare for jack/alsa * misc cleanups * remove same static variables used for jack and alsa * remove unneeded files --- .../platform/jack/audiodeviceslistener.cpp | 86 ------------- .../platform/jack/audiodeviceslistener.h | 62 ---------- .../platform/jack/jackaudiodriver.cpp | 105 +++++++--------- .../internal/platform/jack/jackaudiodriver.h | 20 +++- .../platform/lin/linuxaudiodriver.cpp | 113 +++++------------- .../internal/platform/lin/linuxaudiodriver.h | 16 +++ 6 files changed, 104 insertions(+), 298 deletions(-) delete mode 100644 src/framework/audio/internal/platform/jack/audiodeviceslistener.cpp delete mode 100644 src/framework/audio/internal/platform/jack/audiodeviceslistener.h diff --git a/src/framework/audio/internal/platform/jack/audiodeviceslistener.cpp b/src/framework/audio/internal/platform/jack/audiodeviceslistener.cpp deleted file mode 100644 index ba08eceeff3b2..0000000000000 --- a/src/framework/audio/internal/platform/jack/audiodeviceslistener.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) 2021 MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -#include "audiodeviceslistener.h" - -#include - -#include "log.h" - -using namespace muse::audio; - -AudioDevicesListener::~AudioDevicesListener() -{ - stop(); -} - -void AudioDevicesListener::startWithCallback(const ActualDevicesCallback& callback) -{ - IF_ASSERT_FAILED(!m_isRunning) { - LOGE() << "Cannot set callback while already running."; - return; - } - - m_actualDevicesCallback = callback; - m_isRunning = true; - m_devicesUpdateThread = std::make_shared(&AudioDevicesListener::th_updateDevices, this); -} - -void AudioDevicesListener::stop() -{ - if (!m_devicesUpdateThread) { - return; - } - - m_isRunning = false; - m_runningCv.notify_all(); - - m_devicesUpdateThread->join(); - m_devicesUpdateThread = nullptr; -} - -async::Notification AudioDevicesListener::devicesChanged() const -{ - return m_devicesChanged; -} - -void AudioDevicesListener::th_updateDevices() -{ - std::unique_lock lock(m_mutex); - - while (m_isRunning) { - AudioDeviceList devices = m_actualDevicesCallback(); - - th_setDevices(devices); - - m_runningCv.wait_for(lock, std::chrono::milliseconds(5000)); - } -} - -void AudioDevicesListener::th_setDevices(const AudioDeviceList& devices) -{ - if (devices == m_devices) { - return; - } - - m_devices = devices; - m_devicesChanged.notify(); -} diff --git a/src/framework/audio/internal/platform/jack/audiodeviceslistener.h b/src/framework/audio/internal/platform/jack/audiodeviceslistener.h deleted file mode 100644 index 29095ceaa8a60..0000000000000 --- a/src/framework/audio/internal/platform/jack/audiodeviceslistener.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) 2021 MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -#ifndef MUSE_AUDIO_AUDIODEVICESLISTENER_H -#define MUSE_AUDIO_AUDIODEVICESLISTENER_H - -#include -#include -#include - -#include "async/notification.h" -#include "audiotypes.h" - -namespace muse::audio { -class AudioDevicesListener -{ -public: - ~AudioDevicesListener(); - - using ActualDevicesCallback = std::function; - - void startWithCallback(const ActualDevicesCallback& callback); - - async::Notification devicesChanged() const; - -private: - void th_updateDevices(); - void th_setDevices(const AudioDeviceList& devices); - void stop(); - - std::shared_ptr m_devicesUpdateThread; - std::atomic m_isRunning = false; - - mutable std::mutex m_mutex; - std::condition_variable m_runningCv; - - AudioDeviceList m_devices; - async::Notification m_devicesChanged; - - ActualDevicesCallback m_actualDevicesCallback; -}; -} - -#endif // MUSE_AUDIO_AUDIODEVICESLISTENER_H diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 3245ec240d300..4a94a9855e14d 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -5,7 +5,7 @@ * MuseScore * Music Composition & Notation * - * Copyright (C) 2021 MuseScore BVBA and others + * Copyright (C) MuseScore BVBA 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 3 as @@ -33,32 +33,22 @@ #include "log.h" #include "runtime.h" +#define DEFAULT_DEVICE_ID "jack" +#define DEFAULT_IDENTIFY_AS "MuseScore" + using namespace muse::audio; -struct JackData -{ - float* buffer = nullptr; - jack_client_t* jackDeviceHandle = nullptr; - unsigned long samples = 0; - int channels = 0; - std::vector outputPorts; - IAudioDriver::Callback callback; - void* userdata = nullptr; -}; - -static JackData* s_jackData{ nullptr }; -static muse::audio::IAudioDriver::Spec s_format2; - -int muse::audio::jack_process_callback(jack_nframes_t nframes, void*) +namespace muse::audio { +static int jack_process_callback(jack_nframes_t nframes, void* args) { - JackData* data = s_jackData; + JackDriverState* state = static_cast(args); - jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(data->outputPorts[0], nframes); - jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(data->outputPorts[1], nframes); + jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(state->outputPorts[0], nframes); + jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(state->outputPorts[1], nframes); - uint8_t* stream = (uint8_t*)data->buffer; - data->callback(data->userdata, stream, nframes * data->channels * sizeof(float)); - float* sp = data->buffer; + uint8_t* stream = (uint8_t*)state->buffer; + state->callback(state->userdata, stream, nframes * state->channels * sizeof(float)); + float* sp = state->buffer; for (size_t i = 0; i < nframes; i++) { *l++ = *sp++; *r++ = *sp++; @@ -66,32 +56,24 @@ int muse::audio::jack_process_callback(jack_nframes_t nframes, void*) return 0; } -void muse::audio::jack_cleanup_callback(void*) +static void jack_cleanup_callback(void*) { } - -void jackCleanup() -{ - if (!s_jackData) { - return; - } - - if (nullptr != s_jackData->buffer) { - delete[] s_jackData->buffer; - } - - delete s_jackData; - s_jackData = nullptr; } JackAudioDriver::JackAudioDriver() { m_deviceId = DEFAULT_DEVICE_ID; + m_deviceName = DEFAULT_IDENTIFY_AS; + m_jackDriverState = std::make_unique(); } JackAudioDriver::~JackAudioDriver() { - jackCleanup(); + if (m_jackDriverState->jackDeviceHandle != nullptr) { + jack_client_close(static_cast(m_jackDriverState->jackDeviceHandle)); + } + delete[] m_jackDriverState->buffer; } void JackAudioDriver::init() @@ -107,7 +89,7 @@ void JackAudioDriver::init() std::string JackAudioDriver::name() const { - return "MUAUDIO(JACK)"; + return "MUAUDIO(JACK)"; // why not return m_deviceName, ie what we identify ourself as towards jack? } int jack_srate_callback(jack_nframes_t nframes, void* args) @@ -120,11 +102,14 @@ int jack_srate_callback(jack_nframes_t nframes, void* args) bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) { - s_jackData = new JackData(); - // s_jackData->samples = spec.samples; // client doesn't set sample-rate - s_jackData->channels = spec.channels; - s_jackData->callback = spec.callback; - s_jackData->userdata = spec.userdata; + if (isOpened()) { + LOGW() << "Jack is already opened"; + return false; + } + // m_jackDriverState->samples = spec.samples; // client doesn't set sample-rate + m_jackDriverState->channels = spec.channels; + m_jackDriverState->callback = spec.callback; + m_jackDriverState->userdata = spec.userdata; // FIX: "default" is not a good name for jack-clients // const char *clientName = // outputDevice().c_str() == "default" ? "MuseScore" : @@ -141,15 +126,15 @@ bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&spec); - s_jackData->jackDeviceHandle = handle; + m_jackDriverState->jackDeviceHandle = handle; jack_port_t* output_port_left = jack_port_register(handle, "audio_out_left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - s_jackData->outputPorts.push_back(output_port_left); + m_jackDriverState->outputPorts.push_back(output_port_left); jack_port_t* output_port_right = jack_port_register(handle, "audio_out_right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - s_jackData->outputPorts.push_back(output_port_right); + m_jackDriverState->outputPorts.push_back(output_port_right); - s_jackData->samples = jack_get_buffer_size(handle); - LOGI() << "buffer size (in samples): " << s_jackData->samples; + m_jackDriverState->samples = jack_get_buffer_size(handle); + LOGI() << "buffer size (in samples): " << m_jackDriverState->samples; unsigned int jackSamplerate = jack_get_sample_rate(handle); LOGI() << "sampleRate used by jack: " << jackSamplerate; @@ -160,17 +145,17 @@ bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) //return false; } - s_jackData->buffer = new float[s_jackData->samples * s_jackData->channels]; + m_jackDriverState->buffer = new float[m_jackDriverState->samples * m_jackDriverState->channels]; if (activeSpec) { *activeSpec = spec; activeSpec->format = Format::AudioF32; activeSpec->sampleRate = jackSamplerate; - s_format2 = *activeSpec; + m_jackDriverState->format = *activeSpec; } - jack_on_shutdown(handle, jack_cleanup_callback, 0); - jack_set_process_callback(handle, jack_process_callback, (void*)&s_jackData); + jack_on_shutdown(handle, jack_cleanup_callback, (void*)m_jackDriverState.get()); + jack_set_process_callback(handle, jack_process_callback, (void*)m_jackDriverState.get()); if (jack_activate(handle)) { LOGE() << "cannot activate client"; @@ -182,12 +167,14 @@ bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) void JackAudioDriver::close() { - jackCleanup(); + jack_client_close(static_cast(m_jackDriverState->jackDeviceHandle)); + m_jackDriverState->jackDeviceHandle = nullptr; + delete[] m_jackDriverState->buffer; } bool JackAudioDriver::isOpened() const { - return s_jackData != nullptr; + return m_jackDriverState->jackDeviceHandle != nullptr; } const JackAudioDriver::Spec& JackAudioDriver::activeSpec() const @@ -212,7 +199,7 @@ bool JackAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) bool ok = true; if (reopen) { - ok = open(s_format2, &s_format2); + ok = open(m_jackDriverState->format, &m_jackDriverState->format); } if (ok) { @@ -247,22 +234,22 @@ async::Notification JackAudioDriver::availableOutputDevicesChanged() const unsigned int JackAudioDriver::outputDeviceBufferSize() const { - return s_format2.samples; + return m_jackDriverState->format.samples; } bool JackAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) { - if (s_format2.samples == bufferSize) { + if (m_jackDriverState->format.samples == bufferSize) { return true; } bool reopen = isOpened(); close(); - s_format2.samples = bufferSize; + m_jackDriverState->format.samples = bufferSize; bool ok = true; if (reopen) { - ok = open(s_format2, &s_format2); + ok = open(m_jackDriverState->format, &m_jackDriverState->format); } if (ok) { diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 0d488693a9a10..15f68e7d92e54 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -5,7 +5,7 @@ * MuseScore * Music Composition & Notation * - * Copyright (C) 2021 MuseScore BVBA and others + * Copyright (C) MuseScore BVBA 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 3 as @@ -27,11 +27,19 @@ #include "async/asyncable.h" #include "iaudiodriver.h" -#include "audiodeviceslistener.h" +#include "../lin/audiodeviceslistener.h" namespace muse::audio { -int jack_process_callback(jack_nframes_t nframes, void* jackParam); -void jack_cleanup_callback(void* args); +struct JackDriverState { + float* buffer = nullptr; + void* jackDeviceHandle = nullptr; + unsigned long samples = 0; + int channels = 0; + std::vector outputPorts; + IAudioDriver::Callback callback; + void* userdata = nullptr; + IAudioDriver::Spec format; +}; class JackAudioDriver : public IAudioDriver, public async::Asyncable { @@ -78,10 +86,12 @@ class JackAudioDriver : public IAudioDriver, public async::Asyncable AudioDevicesListener m_devicesListener; async::Notification m_availableOutputDevicesChanged; - std::string m_deviceId; + std::string m_deviceName; async::Notification m_bufferSizeChanged; async::Notification m_sampleRateChanged; + + std::unique_ptr m_jackDriverState; }; } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 7c73c5975f694..ea93db451d926 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -37,76 +37,25 @@ using namespace muse; using namespace muse::audio; -namespace { -struct ALSAData +void LinuxAudioDriver::alsaCleanup() { - float* buffer = nullptr; - snd_pcm_t* alsaDeviceHandle = nullptr; - unsigned long samples = 0; - int channels = 0; - bool audioProcessingDone = false; - pthread_t threadHandle = 0; - IAudioDriver::Callback callback; - void* userdata = nullptr; -}; - -static ALSAData* s_alsaData{ nullptr }; -static muse::audio::IAudioDriver::Spec s_format; - -static void* alsaThread(void* aParam) -{ - muse::runtime::setThreadName("audio_driver"); - ALSAData* data = static_cast(aParam); - - int ret = snd_pcm_wait(data->alsaDeviceHandle, 1000); - IF_ASSERT_FAILED(ret > 0) { - return nullptr; + m_alsaDriverState->audioProcessingDone = true; + if (m_alsaDriverState->threadHandle) { + pthread_join(m_alsaDriverState->threadHandle, nullptr); } - - while (!data->audioProcessingDone) - { - uint8_t* stream = (uint8_t*)data->buffer; - int len = data->samples * data->channels * sizeof(float); - - data->callback(data->userdata, stream, len); - - snd_pcm_sframes_t pcm = snd_pcm_writei(data->alsaDeviceHandle, data->buffer, data->samples); - if (pcm != -EPIPE) { - } else { - snd_pcm_prepare(data->alsaDeviceHandle); - } + if (m_alsaDriverState->alsaDeviceHandle != nullptr) { + snd_pcm_t* alsaDeviceHandle = static_cast(m_alsaDriverState->alsaDeviceHandle); + snd_pcm_drain(alsaDeviceHandle); + snd_pcm_close(alsaDeviceHandle); } - LOGI() << "exit"; - return nullptr; -} - -static void alsaCleanup() -{ - if (!s_alsaData) { - return; - } - - s_alsaData->audioProcessingDone = true; - if (s_alsaData->threadHandle) { - pthread_join(s_alsaData->threadHandle, nullptr); - } - if (nullptr != s_alsaData->alsaDeviceHandle) { - snd_pcm_drain(s_alsaData->alsaDeviceHandle); - snd_pcm_close(s_alsaData->alsaDeviceHandle); - } - - if (nullptr != s_alsaData->buffer) { - delete[] s_alsaData->buffer; - } - - delete s_alsaData; - s_alsaData = nullptr; -} + m_alsaDriverState->alsaDeviceHandle = nullptr; + delete[] m_alsaDriverState->buffer; } LinuxAudioDriver::LinuxAudioDriver() { + m_alsaDriverState = std::make_unique(); m_deviceId = DEFAULT_DEVICE_ID; } @@ -133,11 +82,10 @@ std::string LinuxAudioDriver::name() const bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) { - s_alsaData = new ALSAData(); - s_alsaData->samples = spec.samples; - s_alsaData->channels = spec.channels; - s_alsaData->callback = spec.callback; - s_alsaData->userdata = spec.userdata; + m_alsaDriverState->samples = spec.samples; + m_alsaDriverState->channels = spec.channels; + m_alsaDriverState->callback = spec.callback; + m_alsaDriverState->userdata = spec.userdata; snd_pcm_t* handle; int rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); @@ -146,7 +94,7 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) return false; } - s_alsaData->alsaDeviceHandle = handle; + m_alsaDriverState->alsaDeviceHandle = handle; snd_pcm_hw_params_t* params; snd_pcm_hw_params_alloca(¶ms); @@ -165,9 +113,9 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) return false; } - rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &s_alsaData->samples); + rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_alsaDriverState->samples); if (rc < 0) { - LOGE() << "Unable to set buffer size: " << s_alsaData->samples << ", err code: " << rc; + LOGE() << "Unable to set buffer size: " << m_alsaDriverState->samples << ", err code: " << rc; } rc = snd_pcm_hw_params(handle, params); @@ -179,23 +127,16 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) snd_pcm_hw_params_get_rate(params, &val, &dir); aSamplerate = val; - s_alsaData->buffer = new float[s_alsaData->samples * s_alsaData->channels]; - //_alsaData->sampleBuffer = new short[_alsaData->samples * _alsaData->channels]; + m_alsaDriverState->buffer = new float[m_alsaDriverState->samples * m_alsaDriverState->channels]; if (activeSpec) { *activeSpec = spec; activeSpec->format = Format::AudioF32; activeSpec->sampleRate = aSamplerate; - s_format = *activeSpec; + m_alsaDriverState->format = *activeSpec; } - s_alsaData->threadHandle = 0; - int ret = pthread_create(&s_alsaData->threadHandle, NULL, alsaThread, (void*)s_alsaData); - - if (0 != ret) { - LOGE() << "Unable to create audio thread, err code: " << ret; - return false; - } + m_alsaDriverState->threadHandle = 0; LOGI() << "Connected to " << outputDevice() << " with bufferSize " << s_format.samples @@ -212,7 +153,7 @@ void LinuxAudioDriver::close() bool LinuxAudioDriver::isOpened() const { - return s_alsaData != nullptr; + return m_alsaDriverState->alsaDeviceHandle != nullptr; } const LinuxAudioDriver::Spec& LinuxAudioDriver::activeSpec() const @@ -237,7 +178,7 @@ bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) bool ok = true; if (reopen) { - ok = open(s_format, &s_format); + ok = open(m_alsaDriverState->format, &m_alsaDriverState->format); } if (ok) { @@ -272,22 +213,22 @@ async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const unsigned int LinuxAudioDriver::outputDeviceBufferSize() const { - return s_format.samples; + return m_alsaDriverState->format.samples; } bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) { - if (s_format.samples == bufferSize) { + if (m_alsaDriverState->format.samples == bufferSize) { return true; } bool reopen = isOpened(); close(); - s_format.samples = bufferSize; + m_alsaDriverState->format.samples = bufferSize; bool ok = true; if (reopen) { - ok = open(s_format, &s_format); + ok = open(m_alsaDriverState->format, &m_alsaDriverState->format); } if (ok) { diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index f827178bb0824..ef1c6e7ac3f03 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -30,6 +30,19 @@ #include "audiodeviceslistener.h" namespace muse::audio { +struct ALSADriverState +{ + float* buffer = nullptr; + void* alsaDeviceHandle = nullptr; + unsigned long samples = 0; + int channels = 0; + bool audioProcessingDone = false; + pthread_t threadHandle = 0; + IAudioDriver::Callback callback; + void* userdata = nullptr; + IAudioDriver::Spec format; +}; + class LinuxAudioDriver : public IAudioDriver, public async::Asyncable { public: @@ -69,6 +82,7 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable void suspend() override; private: + void alsaCleanup(); async::Notification m_outputDeviceChanged; mutable std::mutex m_devicesMutex; @@ -79,6 +93,8 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable async::Notification m_bufferSizeChanged; async::Notification m_sampleRateChanged; + + std::unique_ptr m_alsaDriverState; }; } From b4ba1c4250159249ecca7b6bb99c4d7f13cc78f0 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 30 Mar 2024 21:17:06 +0100 Subject: [PATCH 09/60] separate alsa-driver "lift out" the alsa-driver from linuxaudiodriver --- .../platform/alsa/alsaaudiodriver.cpp | 179 ++++++++++++++++++ .../internal/platform/alsa/alsaaudiodriver.h | 59 ++++++ 2 files changed, 238 insertions(+) create mode 100644 src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp create mode 100644 src/framework/audio/internal/platform/alsa/alsaaudiodriver.h diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp new file mode 100644 index 0000000000000..d7883a4005d01 --- /dev/null +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -0,0 +1,179 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2023 MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#include "alsaaudiodriver.h" + +#define ALSA_PCM_NEW_HW_PARAMS_API +#include + +#include +#include +#include +#include +#include + +#include "translation.h" +#include "log.h" +#include "runtime.h" + +static constexpr char DEFAULT_DEVICE_ID[] = "alsa"; + +using namespace muse::audio; + +namespace { +static void* alsaThread(void* aParam) +{ + muse::runtime::setThreadName("audio_driver"); + ALSADriverState* data = static_cast(aParam); + + int ret = snd_pcm_wait(static_cast(data->alsaDeviceHandle), 1000); + IF_ASSERT_FAILED(ret > 0) { + return nullptr; + } + + while (!data->audioProcessingDone) + { + uint8_t* stream = (uint8_t*)data->buffer; + int len = data->samples * data->channels * sizeof(float); + + data->callback(data->userdata, stream, len); + + snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(data->alsaDeviceHandle), data->buffer, data->samples); + if (pcm != -EPIPE) { + } else { + snd_pcm_prepare(static_cast(data->alsaDeviceHandle)); + } + } + + LOGI() << "exit"; + return nullptr; +} +} + +void AlsaAudioDriver::alsaCleanup() +{ + m_alsaDriverState->audioProcessingDone = true; + if (m_alsaDriverState->threadHandle) { + pthread_join(m_alsaDriverState->threadHandle, nullptr); + } + if (m_alsaDriverState->alsaDeviceHandle != nullptr) { + snd_pcm_t* alsaDeviceHandle = static_cast(m_alsaDriverState->alsaDeviceHandle); + snd_pcm_drain(alsaDeviceHandle); + snd_pcm_close(alsaDeviceHandle); + m_alsaDriverState->alsaDeviceHandle = nullptr; + } + + delete[] m_alsaDriverState->buffer; +} + +AlsaAudioDriver::AlsaAudioDriver() +{ + m_alsaDriverState = std::make_shared(); + m_deviceId = DEFAULT_DEVICE_ID; +} + +AlsaAudioDriver::~AlsaAudioDriver() +{ + alsaCleanup(); +} + +std::string AlsaAudioDriver::name() const +{ + return "MUAUDIO(ALSA)"; +} + +bool AlsaAudioDriver::open(const Spec& spec, Spec* activeSpec) +{ + m_alsaDriverState->samples = spec.samples; + m_alsaDriverState->channels = spec.channels; + m_alsaDriverState->callback = spec.callback; + m_alsaDriverState->userdata = spec.userdata; + + int rc; + snd_pcm_t* handle; + rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); + if (rc < 0) { + return false; + } + + m_alsaDriverState->alsaDeviceHandle = handle; + + snd_pcm_hw_params_t* params; + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_hw_params_any(handle, params); + + snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT_LE); + snd_pcm_hw_params_set_channels(handle, params, spec.channels); + + unsigned int aSamplerate = spec.sampleRate; + unsigned int val = aSamplerate; + int dir = 0; + rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); + if (rc < 0) { + return false; + } + + snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_alsaDriverState->samples); + + rc = snd_pcm_hw_params(handle, params); + if (rc < 0) { + return false; + } + + snd_pcm_hw_params_get_rate(params, &val, &dir); + aSamplerate = val; + + if (m_alsaDriverState->buffer != nullptr) { + LOGW() << "open before close"; + delete[] m_alsaDriverState->buffer; + } + + m_alsaDriverState->buffer = new float[m_alsaDriverState->samples * m_alsaDriverState->channels]; + //m_alsaDriverState->sampleBuffer = new short[m_alsaDriverState->samples * m_alsaDriverState->channels]; + + if (activeSpec) { + *activeSpec = spec; + activeSpec->format = Format::AudioF32; + activeSpec->sampleRate = aSamplerate; + m_alsaDriverState->format = *activeSpec; + } + + m_alsaDriverState->threadHandle = 0; + int ret = pthread_create(&m_alsaDriverState->threadHandle, NULL, alsaThread, (void*)m_alsaDriverState.get()); + + if (0 != ret) { + return false; + } + + LOGD() << "Connected to " << outputDevice(); + return true; +} + +void AlsaAudioDriver::close() +{ + alsaCleanup(); +} + +bool AlsaAudioDriver::isOpened() const +{ + return m_alsaDriverState->alsaDeviceHandle != nullptr; +} diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h new file mode 100644 index 0000000000000..318e3e235b21d --- /dev/null +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2023 MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ + +#ifndef MU_AUDIO_ALSAAUDIODRIVER_H +#define MU_AUDIO_ALSAAUDIODRIVER_H + +#include "async/asyncable.h" + +#include "iaudiodriver.h" + +#include "audiodeviceslistener.h" + +namespace muse::audio { + +class AlsaDriverState +{ +public: + AlsaDriverState(); + ~AlsaDriverState(); + + std::string name() const; + bool open(const Spec& spec, Spec* activeSpec); + void close(); + bool isOpened() const; + +private: + float* buffer = nullptr; + void* alsaDeviceHandle = nullptr; + unsigned long samples = 0; + int channels = 0; + bool audioProcessingDone = false; + pthread_t threadHandle = 0; + IAudioDriver::Callback callback; + void* userdata = nullptr; + IAudioDriver::Spec format; + void alsaCleanup(); +}; +} + +#endif // MU_AUDIO_ALSAAUDIODRIVER_H From 5e5ad733b2af29a70f539a192e8ef4754433ec2c Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 1 Sep 2023 14:53:01 +0200 Subject: [PATCH 10/60] alsadriver: rename to AlsaDriverState --- .../platform/alsa/alsaaudiodriver.cpp | 88 +++++++++---------- .../internal/platform/alsa/alsaaudiodriver.h | 26 +++--- 2 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index d7883a4005d01..a668f0e723674 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -34,87 +34,82 @@ #include "log.h" #include "runtime.h" -static constexpr char DEFAULT_DEVICE_ID[] = "alsa"; - using namespace muse::audio; -namespace { static void* alsaThread(void* aParam) { muse::runtime::setThreadName("audio_driver"); - ALSADriverState* data = static_cast(aParam); + AlsaDriverState* data = static_cast(aParam); - int ret = snd_pcm_wait(static_cast(data->alsaDeviceHandle), 1000); + int ret = snd_pcm_wait(static_cast(data->m_alsaDeviceHandle), 1000); IF_ASSERT_FAILED(ret > 0) { return nullptr; } - while (!data->audioProcessingDone) + while (!data->m_audioProcessingDone) { - uint8_t* stream = (uint8_t*)data->buffer; - int len = data->samples * data->channels * sizeof(float); + uint8_t* stream = (uint8_t*)data->m_buffer; + int len = data->m_samples * data->m_channels * sizeof(float); - data->callback(data->userdata, stream, len); + data->m_callback(data->m_userdata, stream, len); - snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(data->alsaDeviceHandle), data->buffer, data->samples); + snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(data->m_alsaDeviceHandle), data->m_buffer, data->m_samples); if (pcm != -EPIPE) { } else { - snd_pcm_prepare(static_cast(data->alsaDeviceHandle)); + snd_pcm_prepare(static_cast(data->m_alsaDeviceHandle)); } } LOGI() << "exit"; return nullptr; } -} -void AlsaAudioDriver::alsaCleanup() +void AlsaDriverState::alsaCleanup() { - m_alsaDriverState->audioProcessingDone = true; - if (m_alsaDriverState->threadHandle) { - pthread_join(m_alsaDriverState->threadHandle, nullptr); + m_audioProcessingDone = true; + if (m_threadHandle) { + pthread_join(m_threadHandle, nullptr); } - if (m_alsaDriverState->alsaDeviceHandle != nullptr) { - snd_pcm_t* alsaDeviceHandle = static_cast(m_alsaDriverState->alsaDeviceHandle); - snd_pcm_drain(alsaDeviceHandle); - snd_pcm_close(alsaDeviceHandle); - m_alsaDriverState->alsaDeviceHandle = nullptr; + if (m_alsaDeviceHandle != nullptr) { + snd_pcm_t* aDevice = static_cast(m_alsaDeviceHandle); + snd_pcm_drain(aDevice); + snd_pcm_close(aDevice); + m_alsaDeviceHandle = nullptr; } - delete[] m_alsaDriverState->buffer; + delete[] m_buffer; } -AlsaAudioDriver::AlsaAudioDriver() +AlsaDriverState::AlsaDriverState() { - m_alsaDriverState = std::make_shared(); - m_deviceId = DEFAULT_DEVICE_ID; + m_deviceId = "alsa"; } -AlsaAudioDriver::~AlsaAudioDriver() +AlsaDriverState::~AlsaDriverState() { alsaCleanup(); } -std::string AlsaAudioDriver::name() const +std::string AlsaDriverState::name() const { return "MUAUDIO(ALSA)"; } -bool AlsaAudioDriver::open(const Spec& spec, Spec* activeSpec) +bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { - m_alsaDriverState->samples = spec.samples; - m_alsaDriverState->channels = spec.channels; - m_alsaDriverState->callback = spec.callback; - m_alsaDriverState->userdata = spec.userdata; + m_samples = spec.samples; + m_channels = spec.channels; + m_callback = spec.callback; + m_userdata = spec.userdata; int rc; snd_pcm_t* handle; - rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); + rc = snd_pcm_open(&handle, name().c_str(), SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { return false; } - m_alsaDriverState->alsaDeviceHandle = handle; + m_alsaDeviceHandle = handle; snd_pcm_hw_params_t* params; snd_pcm_hw_params_alloca(¶ms); @@ -132,7 +127,7 @@ bool AlsaAudioDriver::open(const Spec& spec, Spec* activeSpec) return false; } - snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_alsaDriverState->samples); + snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_samples); rc = snd_pcm_hw_params(handle, params); if (rc < 0) { @@ -142,38 +137,37 @@ bool AlsaAudioDriver::open(const Spec& spec, Spec* activeSpec) snd_pcm_hw_params_get_rate(params, &val, &dir); aSamplerate = val; - if (m_alsaDriverState->buffer != nullptr) { + if (m_buffer != nullptr) { LOGW() << "open before close"; - delete[] m_alsaDriverState->buffer; + delete[] m_buffer; } - m_alsaDriverState->buffer = new float[m_alsaDriverState->samples * m_alsaDriverState->channels]; - //m_alsaDriverState->sampleBuffer = new short[m_alsaDriverState->samples * m_alsaDriverState->channels]; + m_buffer = new float[m_samples * m_channels]; if (activeSpec) { *activeSpec = spec; - activeSpec->format = Format::AudioF32; + activeSpec->format = IAudioDriver::Format::AudioF32; activeSpec->sampleRate = aSamplerate; - m_alsaDriverState->format = *activeSpec; + m_format = *activeSpec; } - m_alsaDriverState->threadHandle = 0; - int ret = pthread_create(&m_alsaDriverState->threadHandle, NULL, alsaThread, (void*)m_alsaDriverState.get()); + m_threadHandle = 0; + int ret = pthread_create(&m_threadHandle, NULL, alsaThread, (void*)this); if (0 != ret) { return false; } - LOGD() << "Connected to " << outputDevice(); + LOGD() << "Connected to " << name(); return true; } -void AlsaAudioDriver::close() +void AlsaDriverState::close() { alsaCleanup(); } -bool AlsaAudioDriver::isOpened() const +bool AlsaDriverState::isOpened() const { - return m_alsaDriverState->alsaDeviceHandle != nullptr; + return m_alsaDeviceHandle != nullptr; } diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 318e3e235b21d..fb519d8215d4f 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -23,12 +23,8 @@ #ifndef MU_AUDIO_ALSAAUDIODRIVER_H #define MU_AUDIO_ALSAAUDIODRIVER_H -#include "async/asyncable.h" - #include "iaudiodriver.h" -#include "audiodeviceslistener.h" - namespace muse::audio { class AlsaDriverState @@ -38,20 +34,22 @@ class AlsaDriverState ~AlsaDriverState(); std::string name() const; - bool open(const Spec& spec, Spec* activeSpec); + bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec); void close(); bool isOpened() const; + void* m_alsaDeviceHandle = nullptr; + + float* m_buffer = nullptr; + unsigned long m_samples = 0; + int m_channels = 0; + bool m_audioProcessingDone = false; + pthread_t m_threadHandle = 0; + IAudioDriver::Callback m_callback; + void* m_userdata = nullptr; + IAudioDriver::Spec m_format; + std::string m_deviceId; private: - float* buffer = nullptr; - void* alsaDeviceHandle = nullptr; - unsigned long samples = 0; - int channels = 0; - bool audioProcessingDone = false; - pthread_t threadHandle = 0; - IAudioDriver::Callback callback; - void* userdata = nullptr; - IAudioDriver::Spec format; void alsaCleanup(); }; } From 43eb0ac7fd6f5178c1b2baaae101de6d1ae8b858 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 1 Sep 2023 19:17:10 +0200 Subject: [PATCH 11/60] rearrange linuxaudiodriver with alsa/jack - move out alsaaudiodriver things into alsaaudiodriver - linuxaudiodriver is the driver hander, that musescore talks to, and is responsible for running jack or alsa --- src/framework/audio/iaudiodriver.h | 12 ++ .../platform/alsa/alsaaudiodriver.cpp | 41 +++--- .../internal/platform/alsa/alsaaudiodriver.h | 17 +-- .../platform/lin/linuxaudiodriver.cpp | 128 ++++-------------- .../internal/platform/lin/linuxaudiodriver.h | 16 +-- 5 files changed, 65 insertions(+), 149 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 4a6a80520becd..936b780627f51 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -91,6 +91,18 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual void suspend() = 0; }; using IAudioDriverPtr = std::shared_ptr; + +class AudioDriverState +{ +public: + virtual std::string name() const = 0; + virtual bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) = 0; + virtual void close() = 0; + virtual bool isOpened() const = 0; + + IAudioDriver::Spec m_spec; // current running spec + std::string m_deviceId; +}; } #endif // MUSE_AUDIO_IAUDIODRIVER_H diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index a668f0e723674..004a4fd6d7e11 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -39,24 +39,24 @@ using namespace muse::audio; static void* alsaThread(void* aParam) { muse::runtime::setThreadName("audio_driver"); - AlsaDriverState* data = static_cast(aParam); + AlsaDriverState* state = static_cast(aParam); - int ret = snd_pcm_wait(static_cast(data->m_alsaDeviceHandle), 1000); + int ret = snd_pcm_wait(static_cast(state->m_alsaDeviceHandle), 1000); IF_ASSERT_FAILED(ret > 0) { return nullptr; } - while (!data->m_audioProcessingDone) + while (!state->m_audioProcessingDone) { - uint8_t* stream = (uint8_t*)data->m_buffer; - int len = data->m_samples * data->m_channels * sizeof(float); + uint8_t* stream = (uint8_t*)state->m_buffer; + int len = state->m_spec.samples * state->m_spec.channels * sizeof(float); - data->m_callback(data->m_userdata, stream, len); + state->m_spec.callback(state->m_spec.userdata, stream, len); - snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(data->m_alsaDeviceHandle), data->m_buffer, data->m_samples); + snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(state->m_alsaDeviceHandle), state->m_buffer, state->m_spec.samples); if (pcm != -EPIPE) { } else { - snd_pcm_prepare(static_cast(data->m_alsaDeviceHandle)); + snd_pcm_prepare(static_cast(state->m_alsaDeviceHandle)); } } @@ -97,15 +97,15 @@ std::string AlsaDriverState::name() const bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { - m_samples = spec.samples; - m_channels = spec.channels; - m_callback = spec.callback; - m_userdata = spec.userdata; + m_spec.samples = spec.samples; + m_spec.channels = spec.channels; + m_spec.callback = spec.callback; + m_spec.userdata = spec.userdata; - int rc; snd_pcm_t* handle; - rc = snd_pcm_open(&handle, name().c_str(), SND_PCM_STREAM_PLAYBACK, 0); + int rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { + LOGE() << "Unable to open device: " << outputDevice() << ", err code: " << rc; return false; } @@ -124,10 +124,16 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a int dir = 0; rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); if (rc < 0) { + LOGE() << "Unable to set sample rate: " << val << ", err code: " << rc; return false; } - snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_samples); + long unsigned int samples = m_spec.samples; + rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &samples); + if (rc < 0) { + LOGE() << "Unable to set buffer size: " << samples << ", err code: " << rc; + } + m_spec.samples = (int)samples; rc = snd_pcm_hw_params(handle, params); if (rc < 0) { @@ -142,18 +148,17 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a delete[] m_buffer; } - m_buffer = new float[m_samples * m_channels]; + m_buffer = new float[m_spec.samples * m_spec.channels]; if (activeSpec) { *activeSpec = spec; activeSpec->format = IAudioDriver::Format::AudioF32; activeSpec->sampleRate = aSamplerate; - m_format = *activeSpec; + m_spec = *activeSpec; } m_threadHandle = 0; int ret = pthread_create(&m_threadHandle, NULL, alsaThread, (void*)this); - if (0 != ret) { return false; } diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index fb519d8215d4f..0d475cbac7c17 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -26,29 +26,22 @@ #include "iaudiodriver.h" namespace muse::audio { - -class AlsaDriverState +class AlsaDriverState : public AudioDriverState { public: AlsaDriverState(); ~AlsaDriverState(); - std::string name() const; - bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec); - void close(); - bool isOpened() const; + std::string name() const override; + bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; + void close() override; + bool isOpened() const override; void* m_alsaDeviceHandle = nullptr; float* m_buffer = nullptr; - unsigned long m_samples = 0; - int m_channels = 0; bool m_audioProcessingDone = false; pthread_t m_threadHandle = 0; - IAudioDriver::Callback m_callback; - void* m_userdata = nullptr; - IAudioDriver::Spec m_format; - std::string m_deviceId; private: void alsaCleanup(); }; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index ea93db451d926..1df9260c240b2 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -20,15 +20,7 @@ * along with this program. If not, see . */ #include "linuxaudiodriver.h" - -#define ALSA_PCM_NEW_HW_PARAMS_API -#include - -#include -#include -#include -#include -#include +#include "../alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists #include "translation.h" #include "log.h" @@ -37,31 +29,13 @@ using namespace muse; using namespace muse::audio; -void LinuxAudioDriver::alsaCleanup() -{ - m_alsaDriverState->audioProcessingDone = true; - if (m_alsaDriverState->threadHandle) { - pthread_join(m_alsaDriverState->threadHandle, nullptr); - } - if (m_alsaDriverState->alsaDeviceHandle != nullptr) { - snd_pcm_t* alsaDeviceHandle = static_cast(m_alsaDriverState->alsaDeviceHandle); - snd_pcm_drain(alsaDeviceHandle); - snd_pcm_close(alsaDeviceHandle); - } - - m_alsaDriverState->alsaDeviceHandle = nullptr; - delete[] m_alsaDriverState->buffer; -} - LinuxAudioDriver::LinuxAudioDriver() { - m_alsaDriverState = std::make_unique(); - m_deviceId = DEFAULT_DEVICE_ID; + m_current_audioDriverState = std::make_unique(); } LinuxAudioDriver::~LinuxAudioDriver() { - alsaCleanup(); } void LinuxAudioDriver::init() @@ -77,83 +51,22 @@ void LinuxAudioDriver::init() std::string LinuxAudioDriver::name() const { - return "MUAUDIO(ALSA)"; + return m_current_audioDriverState->name(); } bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) { - m_alsaDriverState->samples = spec.samples; - m_alsaDriverState->channels = spec.channels; - m_alsaDriverState->callback = spec.callback; - m_alsaDriverState->userdata = spec.userdata; - - snd_pcm_t* handle; - int rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); - if (rc < 0) { - LOGE() << "Unable to open device: " << outputDevice() << ", err code: " << rc; - return false; - } - - m_alsaDriverState->alsaDeviceHandle = handle; - - snd_pcm_hw_params_t* params; - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_hw_params_any(handle, params); - - snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT_LE); - snd_pcm_hw_params_set_channels(handle, params, spec.channels); - - unsigned int aSamplerate = spec.sampleRate; - unsigned int val = aSamplerate; - int dir = 0; - rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); - if (rc < 0) { - LOGE() << "Unable to set sample rate: " << val << ", err code: " << rc; - return false; - } - - rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_alsaDriverState->samples); - if (rc < 0) { - LOGE() << "Unable to set buffer size: " << m_alsaDriverState->samples << ", err code: " << rc; - } - - rc = snd_pcm_hw_params(handle, params); - if (rc < 0) { - LOGE() << "Unable to set params, err code: " << rc; - return false; - } - - snd_pcm_hw_params_get_rate(params, &val, &dir); - aSamplerate = val; - - m_alsaDriverState->buffer = new float[m_alsaDriverState->samples * m_alsaDriverState->channels]; - - if (activeSpec) { - *activeSpec = spec; - activeSpec->format = Format::AudioF32; - activeSpec->sampleRate = aSamplerate; - m_alsaDriverState->format = *activeSpec; - } - - m_alsaDriverState->threadHandle = 0; - - LOGI() << "Connected to " << outputDevice() - << " with bufferSize " << s_format.samples - << ", sampleRate " << s_format.sampleRate - << ", channels: " << s_format.channels; - - return true; + return m_current_audioDriverState->open(spec, activeSpec); } void LinuxAudioDriver::close() { - alsaCleanup(); + return m_current_audioDriverState->close(); } bool LinuxAudioDriver::isOpened() const { - return m_alsaDriverState->alsaDeviceHandle != nullptr; + return m_current_audioDriverState->isOpened(); } const LinuxAudioDriver::Spec& LinuxAudioDriver::activeSpec() const @@ -163,23 +76,25 @@ const LinuxAudioDriver::Spec& LinuxAudioDriver::activeSpec() const AudioDeviceID LinuxAudioDriver::outputDevice() const { - return m_deviceId; + return m_current_audioDriverState->name(); // m_deviceId; } bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) { - if (m_deviceId == deviceId) { + if (m_current_audioDriverState->name() == deviceId) { return true; } - bool reopen = isOpened(); - close(); - m_deviceId = deviceId; + //FIX: no, we need to create the new device conditioned on the deviceId + bool reopen = m_current_audioDriverState->isOpened(); + IAudioDriver::Spec spec(m_current_audioDriverState->m_spec); + m_current_audioDriverState->close(); bool ok = true; if (reopen) { - ok = open(m_alsaDriverState->format, &m_alsaDriverState->format); + ok = m_current_audioDriverState->open(spec, &spec); } + m_current_audioDriverState->m_spec = spec; if (ok) { m_outputDeviceChanged.notify(); @@ -190,7 +105,7 @@ bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) bool LinuxAudioDriver::resetToDefaultOutputDevice() { - return selectOutputDevice(DEFAULT_DEVICE_ID); + return selectOutputDevice("alsa"); // FIX: } async::Notification LinuxAudioDriver::outputDeviceChanged() const @@ -201,7 +116,8 @@ async::Notification LinuxAudioDriver::outputDeviceChanged() const AudioDeviceList LinuxAudioDriver::availableOutputDevices() const { AudioDeviceList devices; - devices.push_back({ DEFAULT_DEVICE_ID, muse::trc("audio", "System default") }); + devices.push_back({ "alsa", muse::trc("audio", "ALSA") }); + devices.push_back({ "jack", muse::trc("audio", "JACK") }); return devices; } @@ -213,22 +129,24 @@ async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const unsigned int LinuxAudioDriver::outputDeviceBufferSize() const { - return m_alsaDriverState->format.samples; + return m_current_audioDriverState->m_spec.samples; } bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) { - if (m_alsaDriverState->format.samples == bufferSize) { + if (m_current_audioDriverState->m_spec.samples == (int)bufferSize) { return true; } bool reopen = isOpened(); close(); - m_alsaDriverState->format.samples = bufferSize; + m_current_audioDriverState->m_spec.samples = bufferSize; bool ok = true; if (reopen) { - ok = open(m_alsaDriverState->format, &m_alsaDriverState->format); + // FIX: + // FIX: + //ok = open(m_current_audioDriverState->m_spec, &m_current_audioDriverState->m_spec); } if (ok) { diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index ef1c6e7ac3f03..b615ff25bdd55 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -30,19 +30,6 @@ #include "audiodeviceslistener.h" namespace muse::audio { -struct ALSADriverState -{ - float* buffer = nullptr; - void* alsaDeviceHandle = nullptr; - unsigned long samples = 0; - int channels = 0; - bool audioProcessingDone = false; - pthread_t threadHandle = 0; - IAudioDriver::Callback callback; - void* userdata = nullptr; - IAudioDriver::Spec format; -}; - class LinuxAudioDriver : public IAudioDriver, public async::Asyncable { public: @@ -94,7 +81,8 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable async::Notification m_bufferSizeChanged; async::Notification m_sampleRateChanged; - std::unique_ptr m_alsaDriverState; + struct IAudioDriver::Spec m_spec; + std::unique_ptr m_current_audioDriverState; }; } From f634d9d3a6fed082da86ba8c25506d001b7b83c3 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 30 Mar 2024 21:07:46 +0100 Subject: [PATCH 12/60] enable linuxaudiodriver runs jack+alsa --- src/framework/audio/audiomodule.cpp | 10 - .../platform/alsa/alsaaudiodriver.cpp | 35 ++- .../internal/platform/alsa/alsaaudiodriver.h | 3 + .../platform/jack/jackaudiodriver.cpp | 272 ++++-------------- .../internal/platform/jack/jackaudiodriver.h | 61 +--- .../platform/lin/linuxaudiodriver.cpp | 100 ++++--- .../internal/platform/lin/linuxaudiodriver.h | 3 +- 7 files changed, 160 insertions(+), 324 deletions(-) diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index 68217272404c4..9b4d3393c16df 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -54,10 +54,6 @@ using namespace muse::audio; using namespace muse::audio::synth; using namespace muse::audio::fx; -#ifdef MUSE_MODULE_AUDIO_JACK -#include "internal/platform/jack/jackaudiodriver.h" -#endif - #ifdef Q_OS_LINUX #include "internal/platform/lin/linuxaudiodriver.h" #endif @@ -118,10 +114,6 @@ void AudioModule::registerExports() m_playbackFacade = std::make_shared(iocContext()); m_soundFontRepository = std::make_shared(iocContext()); -#if defined(MUSE_MODULE_AUDIO_JACK) - m_audioDriver = std::shared_ptr(new JackAudioDriver()); -#else - #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) m_audioDriver = std::shared_ptr(new LinuxAudioDriver()); #endif @@ -140,8 +132,6 @@ void AudioModule::registerExports() m_audioDriver = std::shared_ptr(new WebAudioDriver()); #endif -#endif // MUSE_MODULE_AUDIO_JACK - ioc()->registerExport(moduleName(), m_configuration); ioc()->registerExport(moduleName(), m_audioEngine); ioc()->registerExport(moduleName(), std::make_shared()); diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 004a4fd6d7e11..2dde13ccfda23 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -34,6 +34,8 @@ #include "log.h" #include "runtime.h" +#define ALSA_DEFAULT_DEVICE_ID "default" + using namespace muse::audio; static void* alsaThread(void* aParam) @@ -64,6 +66,17 @@ static void* alsaThread(void* aParam) return nullptr; } +AlsaDriverState::AlsaDriverState() +{ + m_deviceId = "alsa"; + m_deviceName = ALSA_DEFAULT_DEVICE_ID; +} + +AlsaDriverState::~AlsaDriverState() +{ + alsaCleanup(); +} + void AlsaDriverState::alsaCleanup() { m_audioProcessingDone = true; @@ -76,23 +89,25 @@ void AlsaDriverState::alsaCleanup() snd_pcm_close(aDevice); m_alsaDeviceHandle = nullptr; } - - delete[] m_buffer; + if (m_buffer) { + delete[] m_buffer; + } + m_buffer = nullptr; } -AlsaDriverState::AlsaDriverState() +std::string AlsaDriverState::name() const { - m_deviceId = "alsa"; + return "alsa"; } -AlsaDriverState::~AlsaDriverState() +std::string AlsaDriverState::deviceName() const { - alsaCleanup(); + return m_deviceName; } -std::string AlsaDriverState::name() const +void AlsaDriverState::deviceName(const std::string newDeviceName) { - return "MUAUDIO(ALSA)"; + m_deviceName = newDeviceName; } bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) @@ -103,7 +118,7 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a m_spec.userdata = spec.userdata; snd_pcm_t* handle; - int rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0); + int rc = snd_pcm_open(&handle, m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { LOGE() << "Unable to open device: " << outputDevice() << ", err code: " << rc; return false; @@ -142,10 +157,12 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a snd_pcm_hw_params_get_rate(params, &val, &dir); aSamplerate = val; + m_spec.sampleRate = aSamplerate; if (m_buffer != nullptr) { LOGW() << "open before close"; delete[] m_buffer; + m_buffer = nullptr; } m_buffer = new float[m_spec.samples * m_spec.channels]; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 0d475cbac7c17..0ca59d4b95052 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -36,6 +36,8 @@ class AlsaDriverState : public AudioDriverState bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; + std::string deviceName() const; + void deviceName(const std::string newDeviceName); void* m_alsaDeviceHandle = nullptr; @@ -43,6 +45,7 @@ class AlsaDriverState : public AudioDriverState bool m_audioProcessingDone = false; pthread_t m_threadHandle = 0; private: + std::string m_deviceName = "default"; void alsaCleanup(); }; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 4a94a9855e14d..04993e57c1045 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -33,8 +33,8 @@ #include "log.h" #include "runtime.h" -#define DEFAULT_DEVICE_ID "jack" -#define DEFAULT_IDENTIFY_AS "MuseScore" +#define JACK_DEFAULT_DEVICE_ID "jack" +#define JACK_DEFAULT_IDENTIFY_AS "MuseScore" using namespace muse::audio; @@ -43,12 +43,12 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) { JackDriverState* state = static_cast(args); - jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(state->outputPorts[0], nframes); - jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(state->outputPorts[1], nframes); + jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(state->m_outputPorts[0], nframes); + jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(state->m_outputPorts[1], nframes); - uint8_t* stream = (uint8_t*)state->buffer; - state->callback(state->userdata, stream, nframes * state->channels * sizeof(float)); - float* sp = state->buffer; + uint8_t* stream = (uint8_t*)state->m_buffer; + state->m_spec.callback(state->m_spec.userdata, stream, nframes * state->m_spec.channels * sizeof(float)); + float* sp = state->m_buffer; for (size_t i = 0; i < nframes; i++) { *l++ = *sp++; *r++ = *sp++; @@ -61,83 +61,67 @@ static void jack_cleanup_callback(void*) } } -JackAudioDriver::JackAudioDriver() +JackDriverState::JackDriverState() { - m_deviceId = DEFAULT_DEVICE_ID; - m_deviceName = DEFAULT_IDENTIFY_AS; - m_jackDriverState = std::make_unique(); + m_deviceId = JACK_DEFAULT_DEVICE_ID; + m_deviceName = JACK_DEFAULT_IDENTIFY_AS; } -JackAudioDriver::~JackAudioDriver() +JackDriverState::~JackDriverState() { - if (m_jackDriverState->jackDeviceHandle != nullptr) { - jack_client_close(static_cast(m_jackDriverState->jackDeviceHandle)); + if (m_jackDeviceHandle != nullptr) { + jack_client_close(static_cast(m_jackDeviceHandle)); } - delete[] m_jackDriverState->buffer; + delete[] m_buffer; } -void JackAudioDriver::init() +std::string JackDriverState::name() const { - m_devicesListener.startWithCallback([this]() { - return availableOutputDevices(); - }); + return m_deviceId; +} - m_devicesListener.devicesChanged().onNotify(this, [this]() { - m_availableOutputDevicesChanged.notify(); - }); +std::string JackDriverState::deviceName() const +{ + return m_deviceName; } -std::string JackAudioDriver::name() const +void JackDriverState::deviceName(const std::string newDeviceName) { - return "MUAUDIO(JACK)"; // why not return m_deviceName, ie what we identify ourself as towards jack? + m_deviceName = newDeviceName; } -int jack_srate_callback(jack_nframes_t nframes, void* args) +int jack_srate_callback(jack_nframes_t newSampleRate, void* args) { IAudioDriver::Spec* spec = (IAudioDriver::Spec*)args; - LOGI() << "Jack reported sampleRate change. Pray to god, musescores samplerate: " << spec->sampleRate << ", is the same as jacks: " << - nframes; + if (newSampleRate != spec->sampleRate) { + LOGW() << "Jack reported system sampleRate change. new samplerate: " << newSampleRate << ", MuseScore: " << spec->sampleRate; + // FIX: notify Musescore audio-layer to adjust musescores samplerate + } + spec->sampleRate = newSampleRate; return 0; } -bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) +bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { if (isOpened()) { LOGW() << "Jack is already opened"; - return false; + return true; } - // m_jackDriverState->samples = spec.samples; // client doesn't set sample-rate - m_jackDriverState->channels = spec.channels; - m_jackDriverState->callback = spec.callback; - m_jackDriverState->userdata = spec.userdata; - // FIX: "default" is not a good name for jack-clients - // const char *clientName = - // outputDevice().c_str() == "default" ? "MuseScore" : - // outputDevice().c_str(); - const char* clientName = "MuseScore"; - LOGI() << "clientName: " << clientName; - + // m_spec.samples = spec.samples; // client doesn't set sample-rate + m_spec.channels = spec.channels; + m_spec.callback = spec.callback; + m_spec.userdata = spec.userdata; + const char* clientName = m_deviceName.c_str(); jack_status_t status; jack_client_t* handle; if (!(handle = jack_client_open(clientName, JackNullOption, &status))) { LOGE() << "jack_client_open() failed: " << status; return false; } - - jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&spec); - - m_jackDriverState->jackDeviceHandle = handle; - - jack_port_t* output_port_left = jack_port_register(handle, "audio_out_left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - m_jackDriverState->outputPorts.push_back(output_port_left); - jack_port_t* output_port_right = jack_port_register(handle, "audio_out_right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - m_jackDriverState->outputPorts.push_back(output_port_right); - - m_jackDriverState->samples = jack_get_buffer_size(handle); - LOGI() << "buffer size (in samples): " << m_jackDriverState->samples; + m_jackDeviceHandle = handle; unsigned int jackSamplerate = jack_get_sample_rate(handle); - LOGI() << "sampleRate used by jack: " << jackSamplerate; + m_spec.sampleRate = jackSamplerate; if (spec.sampleRate != jackSamplerate) { LOGW() << "Musescores samplerate: " << spec.sampleRate << ", is NOT the same as jack's: " << jackSamplerate; // FIX: enable this if it is possible for user to adjust samplerate (AUDIO_SAMPLE_RATE_KEY) @@ -145,17 +129,24 @@ bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) //return false; } - m_jackDriverState->buffer = new float[m_jackDriverState->samples * m_jackDriverState->channels]; + jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&m_spec); + + jack_port_t* output_port_left = jack_port_register(handle, "audio_out_left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + m_outputPorts.push_back(output_port_left); + jack_port_t* output_port_right = jack_port_register(handle, "audio_out_right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + m_outputPorts.push_back(output_port_right); + m_spec.samples = jack_get_buffer_size(handle); + m_buffer = new float[m_spec.samples * m_spec.channels]; if (activeSpec) { *activeSpec = spec; - activeSpec->format = Format::AudioF32; + activeSpec->format = IAudioDriver::Format::AudioF32; activeSpec->sampleRate = jackSamplerate; - m_jackDriverState->format = *activeSpec; + m_spec = *activeSpec; } - jack_on_shutdown(handle, jack_cleanup_callback, (void*)m_jackDriverState.get()); - jack_set_process_callback(handle, jack_process_callback, (void*)m_jackDriverState.get()); + jack_on_shutdown(handle, jack_cleanup_callback, (void*)this); + jack_set_process_callback(handle, jack_process_callback, (void*)this); if (jack_activate(handle)) { LOGE() << "cannot activate client"; @@ -165,166 +156,15 @@ bool JackAudioDriver::open(const Spec& spec, Spec* activeSpec) return true; } -void JackAudioDriver::close() -{ - jack_client_close(static_cast(m_jackDriverState->jackDeviceHandle)); - m_jackDriverState->jackDeviceHandle = nullptr; - delete[] m_jackDriverState->buffer; -} - -bool JackAudioDriver::isOpened() const -{ - return m_jackDriverState->jackDeviceHandle != nullptr; -} - -const JackAudioDriver::Spec& JackAudioDriver::activeSpec() const -{ - return s_format2; -} - -AudioDeviceID JackAudioDriver::outputDevice() const -{ - return m_deviceId; -} - -bool JackAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) -{ - if (m_deviceId == deviceId) { - return true; - } - - bool reopen = isOpened(); - close(); - m_deviceId = deviceId; - - bool ok = true; - if (reopen) { - ok = open(m_jackDriverState->format, &m_jackDriverState->format); - } - - if (ok) { - m_outputDeviceChanged.notify(); - } - - return ok; -} - -bool JackAudioDriver::resetToDefaultOutputDevice() -{ - return selectOutputDevice(DEFAULT_DEVICE_ID); -} - -async::Notification JackAudioDriver::outputDeviceChanged() const -{ - return m_outputDeviceChanged; -} - -AudioDeviceList JackAudioDriver::availableOutputDevices() const -{ - AudioDeviceList devices; - devices.push_back({ DEFAULT_DEVICE_ID, muse::trc("audio", "System default") }); - - return devices; -} - -async::Notification JackAudioDriver::availableOutputDevicesChanged() const -{ - return m_availableOutputDevicesChanged; -} - -unsigned int JackAudioDriver::outputDeviceBufferSize() const -{ - return m_jackDriverState->format.samples; -} - -bool JackAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) -{ - if (m_jackDriverState->format.samples == bufferSize) { - return true; - } - - bool reopen = isOpened(); - close(); - m_jackDriverState->format.samples = bufferSize; - - bool ok = true; - if (reopen) { - ok = open(m_jackDriverState->format, &m_jackDriverState->format); - } - - if (ok) { - m_bufferSizeChanged.notify(); - } - - return ok; -} - -async::Notification JackAudioDriver::outputDeviceBufferSizeChanged() const -{ - return m_bufferSizeChanged; -} - -std::vector JackAudioDriver::availableOutputDeviceBufferSizes() const -{ - std::vector result; - - unsigned int n = MAXIMUM_BUFFER_SIZE; - while (n >= MINIMUM_BUFFER_SIZE) { - result.push_back(n); - n /= 2; - } - - std::sort(result.begin(), result.end()); - - return result; -} - -unsigned int JackAudioDriver::outputDeviceSampleRate() const -{ - return s_format2.sampleRate; -} - -bool JackAudioDriver::setOutputDeviceSampleRate(unsigned int sampleRate) -{ - if (s_format2.sampleRate == sampleRate) { - return true; - } - - bool reopen = isOpened(); - close(); - s_format2.sampleRate = sampleRate; - - bool ok = true; - if (reopen) { - ok = open(s_format2, &s_format2); - } - - if (ok) { - m_sampleRateChanged.notify(); - } - - return ok; -} - -async::Notification JackAudioDriver::outputDeviceSampleRateChanged() const -{ - return m_sampleRateChanged; -} - -std::vector JackAudioDriver::availableOutputDeviceSampleRates() const -{ - return { - 44100, - 48000, - 88200, - 96000, - }; -} - -void JackAudioDriver::resume() +void JackDriverState::close() { + jack_client_close(static_cast(m_jackDeviceHandle)); + m_jackDeviceHandle = nullptr; + delete[] m_buffer; + m_buffer = nullptr; } -void JackAudioDriver::suspend() +bool JackDriverState::isOpened() const { + return m_jackDeviceHandle != nullptr; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 15f68e7d92e54..beb47e484ce83 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -25,73 +25,30 @@ #include -#include "async/asyncable.h" #include "iaudiodriver.h" -#include "../lin/audiodeviceslistener.h" namespace muse::audio { -struct JackDriverState { - float* buffer = nullptr; - void* jackDeviceHandle = nullptr; - unsigned long samples = 0; - int channels = 0; - std::vector outputPorts; - IAudioDriver::Callback callback; - void* userdata = nullptr; - IAudioDriver::Spec format; -}; - -class JackAudioDriver : public IAudioDriver, public async::Asyncable +class JackDriverState : public AudioDriverState { public: - JackAudioDriver(); - ~JackAudioDriver(); - - void init() override; + JackDriverState(); + ~JackDriverState(); std::string name() const override; - bool open(const Spec& spec, Spec* activeSpec) override; + bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; + std::string deviceName() const; + void deviceName(const std::string newDeviceName); - const Spec& activeSpec() const override; - - AudioDeviceID outputDevice() const override; - bool selectOutputDevice(const AudioDeviceID& deviceId) override; - bool resetToDefaultOutputDevice() override; - async::Notification outputDeviceChanged() const override; - - AudioDeviceList availableOutputDevices() const override; - async::Notification availableOutputDevicesChanged() const override; - - unsigned int outputDeviceBufferSize() const override; - bool setOutputDeviceBufferSize(unsigned int bufferSize) override; - async::Notification outputDeviceBufferSizeChanged() const override; + void* m_jackDeviceHandle = nullptr; - std::vector availableOutputDeviceBufferSizes() const override; + float* m_buffer = nullptr; - unsigned int outputDeviceSampleRate() const override; - bool setOutputDeviceSampleRate(unsigned int bufferSize) override; - async::Notification outputDeviceSampleRateChanged() const override; - - std::vector availableOutputDeviceSampleRates() const override; - - void resume() override; - void suspend() override; + std::vector m_outputPorts; private: - async::Notification m_outputDeviceChanged; - - mutable std::mutex m_devicesMutex; - AudioDevicesListener m_devicesListener; - async::Notification m_availableOutputDevicesChanged; - std::string m_deviceName; - - async::Notification m_bufferSizeChanged; - async::Notification m_sampleRateChanged; - - std::unique_ptr m_jackDriverState; }; } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 1df9260c240b2..46e3d370df5a1 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -21,6 +21,9 @@ */ #include "linuxaudiodriver.h" #include "../alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists +#if JACK_AUDIO +#include "../jack/jackaudiodriver.h" //FIX: relative path, set path in CMakeLists +#endif #include "translation.h" #include "log.h" @@ -31,7 +34,6 @@ using namespace muse::audio; LinuxAudioDriver::LinuxAudioDriver() { - m_current_audioDriverState = std::make_unique(); } LinuxAudioDriver::~LinuxAudioDriver() @@ -56,7 +58,11 @@ std::string LinuxAudioDriver::name() const bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) { - return m_current_audioDriverState->open(spec, activeSpec); + if (!m_current_audioDriverState->open(spec, activeSpec)) { + return false; + } + m_spec = *activeSpec; + return true; } void LinuxAudioDriver::close() @@ -76,31 +82,64 @@ const LinuxAudioDriver::Spec& LinuxAudioDriver::activeSpec() const AudioDeviceID LinuxAudioDriver::outputDevice() const { - return m_current_audioDriverState->name(); // m_deviceId; + if (m_current_audioDriverState != nullptr) { + return m_current_audioDriverState->m_deviceId; + } else { + LOGE("device is not opened"); + return m_deviceId; // FIX: should return optional type + } } -bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) +bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) { - if (m_current_audioDriverState->name() == deviceId) { - return true; + if (deviceId == "alsa") { + m_current_audioDriverState = std::make_unique(); +#if JACK_AUDIO + } else if (deviceId == "jack") { + m_current_audioDriverState = std::make_unique(); +#endif + } else { + LOGE() << "Unknown device name: " << deviceId; + return false; } + return true; +} - //FIX: no, we need to create the new device conditioned on the deviceId - bool reopen = m_current_audioDriverState->isOpened(); - IAudioDriver::Spec spec(m_current_audioDriverState->m_spec); - m_current_audioDriverState->close(); - - bool ok = true; - if (reopen) { - ok = m_current_audioDriverState->open(spec, &spec); +// reopens the same device (if m_spec has changed) +bool LinuxAudioDriver::reopen(const AudioDeviceID& deviceId, Spec newSpec) +{ + // close current device if opened + if (m_current_audioDriverState->isOpened()) { + m_current_audioDriverState->close(); } - m_current_audioDriverState->m_spec = spec; - - if (ok) { - m_outputDeviceChanged.notify(); + // maybe change device, if needed + if (m_current_audioDriverState->name() != deviceId) { + // select the new device driver + if (!makeDevice(deviceId)) { + return false; + } } + // open the device driver + if (!m_current_audioDriverState->open(newSpec, &newSpec)) { + return false; + } + return true; +} - return ok; +bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) +{ + // When starting, no previously device has been selected + if (m_current_audioDriverState == nullptr) { + LOGW() << "no previously opened device"; + return makeDevice(deviceId); + } + // If for some reason we select the same device, do nothing + if (m_current_audioDriverState->name() == deviceId) { + return true; + } + reopen(deviceId, m_spec); + m_outputDeviceChanged.notify(); + return true; } bool LinuxAudioDriver::resetToDefaultOutputDevice() @@ -134,26 +173,15 @@ unsigned int LinuxAudioDriver::outputDeviceBufferSize() const bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) { - if (m_current_audioDriverState->m_spec.samples == (int)bufferSize) { + if (m_spec.samples == (int)bufferSize) { return true; } - - bool reopen = isOpened(); - close(); - m_current_audioDriverState->m_spec.samples = bufferSize; - - bool ok = true; - if (reopen) { - // FIX: - // FIX: - //ok = open(m_current_audioDriverState->m_spec, &m_current_audioDriverState->m_spec); - } - - if (ok) { - m_bufferSizeChanged.notify(); + m_spec.samples = (int)bufferSize; + if (!reopen(m_current_audioDriverState->name(), m_spec)) { + return false; } - - return ok; + m_bufferSizeChanged.notify(); + return true; } async::Notification LinuxAudioDriver::outputDeviceBufferSizeChanged() const diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index b615ff25bdd55..beec3f757b6d3 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -69,7 +69,8 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable void suspend() override; private: - void alsaCleanup(); + bool makeDevice(const AudioDeviceID& deviceId); + bool reopen(const AudioDeviceID& deviceId, Spec newSpec); async::Notification m_outputDeviceChanged; mutable std::mutex m_devicesMutex; From 835156b5bd1c757c6dc4cce86ff3de6c751f0597 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 30 Mar 2024 21:14:13 +0100 Subject: [PATCH 13/60] enable jack-audio for win too --- src/framework/audio/audiomodule.cpp | 11 ++++----- .../platform/lin/linuxaudiodriver.cpp | 24 +++++++++++++++---- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index 9b4d3393c16df..00ae7d37a013b 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -54,14 +54,11 @@ using namespace muse::audio; using namespace muse::audio::synth; using namespace muse::audio::fx; -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) #include "internal/platform/lin/linuxaudiodriver.h" #endif -#ifdef Q_OS_FREEBSD -#include "internal/platform/lin/linuxaudiodriver.h" -#endif -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(MINGW) //#include "internal/platform/win/winmmdriver.h" //#include "internal/platform/win/wincoreaudiodriver.h" #include "internal/platform/win/wasapiaudiodriver.h" @@ -114,11 +111,11 @@ void AudioModule::registerExports() m_playbackFacade = std::make_shared(iocContext()); m_soundFontRepository = std::make_shared(iocContext()); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) m_audioDriver = std::shared_ptr(new LinuxAudioDriver()); #endif -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) && !defined(MINGW) //m_audioDriver = std::shared_ptr(new WinmmDriver()); //m_audioDriver = std::shared_ptr(new CoreAudioDriver()); m_audioDriver = std::shared_ptr(new WasapiAudioDriver()); diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 46e3d370df5a1..33dc47c6c82bb 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -92,11 +92,18 @@ AudioDeviceID LinuxAudioDriver::outputDevice() const bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) { +#if defined(JACK_AUDIO) + if (deviceId == "jack") { + m_current_audioDriverState = std::make_unique(); +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) + } else if (deviceId == "alsa") { + m_current_audioDriverState = std::make_unique(); +#endif +#else +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); -#if JACK_AUDIO - } else if (deviceId == "jack") { - m_current_audioDriverState = std::make_unique(); +#endif #endif } else { LOGE() << "Unknown device name: " << deviceId; @@ -144,7 +151,11 @@ bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) bool LinuxAudioDriver::resetToDefaultOutputDevice() { +#if defined(JACK_AUDIO) + return selectOutputDevice("jack"); // FIX: +#else return selectOutputDevice("alsa"); // FIX: +#endif } async::Notification LinuxAudioDriver::outputDeviceChanged() const @@ -155,9 +166,12 @@ async::Notification LinuxAudioDriver::outputDeviceChanged() const AudioDeviceList LinuxAudioDriver::availableOutputDevices() const { AudioDeviceList devices; - devices.push_back({ "alsa", muse::trc("audio", "ALSA") }); +#if defined(JACK_AUDIO) devices.push_back({ "jack", muse::trc("audio", "JACK") }); - +#endif +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) + devices.push_back({ "alsa", muse::trc("audio", "ALSA") }); +#endif return devices; } From 2d63588cef2132efd3c5d08daac85a62a9508ef8 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 10 Sep 2023 20:09:50 +0200 Subject: [PATCH 14/60] jack midi for linux * separate linux-midi from linux-alsa * move alsa to own directory * midimodule separate linux/alsa --- src/framework/midi/CMakeLists.txt | 37 +++- .../platform/{lin => alsa}/alsamidiinport.cpp | 0 .../platform/{lin => alsa}/alsamidiinport.h | 0 .../{lin => alsa}/alsamidioutport.cpp | 0 .../platform/{lin => alsa}/alsamidioutport.h | 0 .../internal/platform/jack/jackmidiinport.cpp | 104 +++++++++ .../internal/platform/jack/jackmidiinport.h | 52 +++++ .../platform/jack/jackmidioutport.cpp | 128 +++++++++++ .../internal/platform/jack/jackmidioutport.h | 54 +++++ .../internal/platform/lin/linuxmidiinport.cpp | 201 +++++++++++++++++ .../internal/platform/lin/linuxmidiinport.h | 92 ++++++++ .../platform/lin/linuxmidioutport.cpp | 204 ++++++++++++++++++ .../internal/platform/lin/linuxmidioutport.h | 83 +++++++ src/framework/midi/midimodule.cpp | 18 +- src/framework/midi/midimodule.h | 8 +- 15 files changed, 960 insertions(+), 21 deletions(-) rename src/framework/midi/internal/platform/{lin => alsa}/alsamidiinport.cpp (100%) rename src/framework/midi/internal/platform/{lin => alsa}/alsamidiinport.h (100%) rename src/framework/midi/internal/platform/{lin => alsa}/alsamidioutport.cpp (100%) rename src/framework/midi/internal/platform/{lin => alsa}/alsamidioutport.h (100%) create mode 100644 src/framework/midi/internal/platform/jack/jackmidiinport.cpp create mode 100644 src/framework/midi/internal/platform/jack/jackmidiinport.h create mode 100644 src/framework/midi/internal/platform/jack/jackmidioutport.cpp create mode 100644 src/framework/midi/internal/platform/jack/jackmidioutport.h create mode 100644 src/framework/midi/internal/platform/lin/linuxmidiinport.cpp create mode 100644 src/framework/midi/internal/platform/lin/linuxmidiinport.h create mode 100644 src/framework/midi/internal/platform/lin/linuxmidioutport.cpp create mode 100644 src/framework/midi/internal/platform/lin/linuxmidioutport.h diff --git a/src/framework/midi/CMakeLists.txt b/src/framework/midi/CMakeLists.txt index af737341c397d..0336818e98246 100644 --- a/src/framework/midi/CMakeLists.txt +++ b/src/framework/midi/CMakeLists.txt @@ -22,6 +22,17 @@ declare_module(muse_midi) set(MODULE_ALIAS muse::midi) include(GetPlatformInfo) + +set(JACK_SRC "") +if (MUSE_MODULE_AUDIO_JACK) + set(JACK_SRC + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidioutport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidioutport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidiinport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidiinport.h + ) +endif() + if (OS_IS_WIN) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmidioutport.cpp @@ -31,17 +42,27 @@ if (OS_IS_WIN) ) elseif(OS_IS_LIN) set(DRIVER_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidioutport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidioutport.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidiinport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidiinport.h + ${JACK_SRC} + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidioutport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidioutport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidiinport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidiinport.h ) elseif(OS_IS_FBSD) set(DRIVER_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidioutport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidioutport.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidiinport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/alsamidiinport.h + ${JACK_SRC} + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidioutport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidioutport.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidiinport.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxmidiinport.h ) elseif(OS_IS_MAC) set(DRIVER_SRC diff --git a/src/framework/midi/internal/platform/lin/alsamidiinport.cpp b/src/framework/midi/internal/platform/alsa/alsamidiinport.cpp similarity index 100% rename from src/framework/midi/internal/platform/lin/alsamidiinport.cpp rename to src/framework/midi/internal/platform/alsa/alsamidiinport.cpp diff --git a/src/framework/midi/internal/platform/lin/alsamidiinport.h b/src/framework/midi/internal/platform/alsa/alsamidiinport.h similarity index 100% rename from src/framework/midi/internal/platform/lin/alsamidiinport.h rename to src/framework/midi/internal/platform/alsa/alsamidiinport.h diff --git a/src/framework/midi/internal/platform/lin/alsamidioutport.cpp b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp similarity index 100% rename from src/framework/midi/internal/platform/lin/alsamidioutport.cpp rename to src/framework/midi/internal/platform/alsa/alsamidioutport.cpp diff --git a/src/framework/midi/internal/platform/lin/alsamidioutport.h b/src/framework/midi/internal/platform/alsa/alsamidioutport.h similarity index 100% rename from src/framework/midi/internal/platform/lin/alsamidioutport.h rename to src/framework/midi/internal/platform/alsa/alsamidioutport.h diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp new file mode 100644 index 0000000000000..95ec560dd4e61 --- /dev/null +++ b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp @@ -0,0 +1,104 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#include "jackmidiinport.h" + +#include +#include + +#include "midierrors.h" +#include "stringutils.h" +#include "translation.h" +#include "defer.h" +#include "log.h" + +using namespace muse::midi; + +void JackMidiInPort::init() +{ + LOGI("---- linux JACK-midi input init ----"); + m_jack = std::make_unique(); +} + +void JackMidiInPort::deinit() +{ + if (isConnected()) { + disconnect(); + } +} + +std::vector JackMidiInPort::availableDevices() const +{ + std::vector ports; + + std::vector ret; + + const char** prts = jack_get_ports(m_jack->client, 0, 0, 0); + int devIndex = 0; + for (const char** p = prts; p && *p; ++p) { + jack_port_t* port = jack_port_by_name(m_jack->client, *p); + int flags = jack_port_flags(port); + if (!(flags & JackPortIsInput)) + continue; + char buffer[128]; + strncpy(buffer, *p, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = 0; + if (strncmp(buffer, "MuseScore", 9) == 0) + continue; + MidiDevice dev; + dev.name = buffer; + dev.id = makeUniqueDeviceId(devIndex++,0,0); + ports.push_back(std::move(dev)); + } + return ports; +} + +muse::Ret JackMidiInPort::connect(const MidiDeviceID& deviceID) +{ + return muse::Ret(true); +} + +void JackMidiInPort::disconnect() +{ +} + +bool JackMidiInPort::isConnected() const +{ + LOGI("---- JACK input isConnect ----"); + return m_jack && m_jack->midiIn && !m_deviceID.empty(); +} + +MidiDeviceID JackMidiInPort::deviceID() const +{ + return m_deviceID; +} + +bool JackMidiInPort::deviceExists(const MidiDeviceID& deviceId) const +{ + LOGI("---- JACK-midi input deviceExists ----"); + for (const MidiDevice& device : availableDevices()) { + if (device.id == deviceId) { + return true; + } + } + + return false; +} diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.h b/src/framework/midi/internal/platform/jack/jackmidiinport.h new file mode 100644 index 0000000000000..2a4605bf6932e --- /dev/null +++ b/src/framework/midi/internal/platform/jack/jackmidiinport.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#ifndef MU_MIDI_JACKMIDIINPORT_H +#define MU_MIDI_JACKMIDIINPORT_H + +#include +#include "midi/midiportstate.h" + +namespace muse::midi { +class JackMidiInPort : public MidiPortState +{ +public: + JackMidiInPort() = default; + ~JackMidiInPort() = default; + void init(); + void deinit(); + + std::vector availableDevices() const override; + Ret connect(const MidiDeviceID& deviceID) override; + void disconnect() override; + bool isConnected() const override; + MidiDeviceID deviceID() const override; + +private: + bool deviceExists(const MidiDeviceID& deviceId) const; + + struct Jack; + std::unique_ptr m_jack; + MidiDeviceID m_deviceID; +}; +} + +#endif // MU_MIDI_JACKMIDIINPORT_H diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp new file mode 100644 index 0000000000000..d698f78ca0709 --- /dev/null +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp @@ -0,0 +1,128 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#include "jackmidioutport.h" + +#include +#include + +#include "midierrors.h" +#include "translation.h" +#include "log.h" + +struct muse::midi::JackMidiOutPort::Jack { + jack_port_t* midiOut = nullptr; + jack_client_t* client = nullptr; + int port = -1; + int segmentSize; +}; + +using namespace muse::midi; + +void JackMidiOutPort::init() +{ + LOGI("---- linux JACK-midi output init ----"); + m_jack = std::make_unique(); +} + +void JackMidiOutPort::deinit() +{ + if (isConnected()) { + disconnect(); + } +} + +std::vector JackMidiOutPort::availableDevices() const +{ + //LOGI("---- linux JACK availableDevices ----"); + std::vector ret; + MidiDevice dev; + dev.name = "JACK"; + dev.id = makeUniqueDeviceId(0,9999,0); + ret.push_back(std::move(dev)); + return ret; +} + +muse::Ret JackMidiOutPort::connect(const MidiDeviceID& deviceID) +{ + LOGI("---- JACK output connect ----"); + //----> common with jackaudio <---- + jack_client_t* client; + jack_options_t options = (jack_options_t)0; + jack_status_t status; + client = jack_client_open("MuseScore", options, &status); + if (!client) { + return make_ret(Err::MidiInvalidDeviceID, "jack-open fail, device: " + deviceID); + } + m_jack->client = client; + return muse::Ret(true); +} + +void JackMidiOutPort::disconnect() +{ + LOGI("---- linux JACK disconnect ----"); + if (!isConnected()) { + return; + } + + //FIX: + //const char* sn = jack_port_name((jack_port_t*) src); + //const char* dn = jack_port_name((jack_port_t*) dst); + //jackdisconnect(m_jack->midiOut, 0, m_jack->client, m_jack->port); + if (jack_deactivate(m_jack->client)) { + LOGE() << "failed to deactive jack"; + } + + m_jack->client = nullptr; + m_jack->port = -1; + m_jack->midiOut = nullptr; + m_deviceID.clear(); +} + +bool JackMidiOutPort::isConnected() const +{ + LOGI("---- JACK output isConnect ----"); + return m_jack && m_jack->midiOut && !m_deviceID.empty(); +} + +MidiDeviceID JackMidiOutPort::deviceID() const +{ + LOGI("---- JACK output deviceID ----"); + return m_deviceID; +} + +bool JackMidiOutPort::supportsMIDI20Output() const +{ + LOGI("---- JACK output supportsMIDI20Output ----"); + return false; +} + +bool JackMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const +{ + LOGI("---- JACK-midi output deviceExists ----"); + for (const MidiDevice& device : availableDevices()) { + if (device.id == deviceId) { + return true; + } + } + + return false; +} diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.h b/src/framework/midi/internal/platform/jack/jackmidioutport.h new file mode 100644 index 0000000000000..00325182bc2f5 --- /dev/null +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.h @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#ifndef MU_MIDI_JACKMIDIOUTPORT_H +#define MU_MIDI_JACKMIDIOUTPORT_H + +#include +#include "midi/midiportstate.h" + +namespace muse::midi { +class JackMidiOutPort : public MidiPortState +{ +public: + JackMidiOutPort() = default; + ~JackMidiOutPort() = default; + void init(); + void deinit(); + + std::vector availableDevices() const override; + Ret connect(const MidiDeviceID& deviceID) override; + void disconnect() override; + bool isConnected() const override; + MidiDeviceID deviceID() const override; + bool supportsMIDI20Output() const override; + Ret sendEvent(const Event& e) override; + +private: + bool deviceExists(const MidiDeviceID& deviceId) const; + + struct Jack; + std::unique_ptr m_jack; + MidiDeviceID m_deviceID; +}; +} + +#endif // MU_MIDI_JACKMIDIOUTPORT_H diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp new file mode 100644 index 0000000000000..cab8f0faa0f6c --- /dev/null +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -0,0 +1,201 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#include "linuxmidiinport.h" + +#include "midierrors.h" +#include "stringutils.h" +#include "translation.h" +#include "defer.h" +#include "log.h" + +using namespace muse::midi; + +void LinuxMidiInPort::init() +{ + //m_alsa = std::make_shared(); + + m_devicesListener.startWithCallback([this]() { + return availableDevices(); + }); + + m_devicesListener.devicesChanged().onNotify(this, [this]() { + bool connectedDeviceRemoved = true; + for (const MidiDevice& device: availableDevices()) { + if (m_deviceID == device.id) { + connectedDeviceRemoved = false; + } + } + + if (connectedDeviceRemoved) { + disconnect(); + } + + m_availableDevicesChanged.notify(); + }); +} + +void LinuxMidiInPort::deinit() +{ + if (isConnected()) { + disconnect(); + } +} + +std::vector LinuxMidiInPort::availableDevices() const +{ + std::lock_guard lock(m_devicesMutex); + + std::vector ret; + + ret.push_back({ NONE_DEVICE_ID, muse::trc("midi", "No device") }); + + // return concatenation of alsa + jack devices + + return ret; +} + +muse::async::Notification LinuxMidiInPort::availableDevicesChanged() const +{ + return m_availableDevicesChanged; +} + +muse::Ret LinuxMidiInPort::connect(const MidiDeviceID& deviceID) +{ + if (!deviceExists(deviceID)) { + return make_ret(Err::MidiFailedConnect, "not found device, id: " + deviceID); + } + + if (isConnected()) { + disconnect(); + } + + DEFER { + m_deviceChanged.notify(); + }; + + muse::Ret ret = muse::make_ok(); + + if (!deviceID.empty() && deviceID != NONE_DEVICE_ID) { + std::vector deviceParams = splitDeviceId(deviceID); + IF_ASSERT_FAILED(deviceParams.size() == 3) { + return make_ret(Err::MidiInvalidDeviceID, "invalid device id: " + deviceID); + } + + //m_alsa->client = deviceParams.at(1); + //m_alsa->port = deviceParams.at(2); + + m_deviceID = deviceID; + ret = run(); + } else { + m_deviceID = deviceID; + } + + if (ret) { + LOGD() << "Connected to " << m_deviceID; + } + + return ret; +} + +void LinuxMidiInPort::disconnect() +{ + if (!isConnected()) { + return; + } + + stop(); + + LOGD() << "Disconnected from " << m_deviceID; + + //m_alsa->client = -1; + //m_alsa->port = -1; + //m_alsa->midiIn = nullptr; + m_deviceID.clear(); +} + +bool LinuxMidiInPort::isConnected() const +{ + return /* m_alsa && m_alsa->midiIn && */ !m_deviceID.empty(); +} + +MidiDeviceID LinuxMidiInPort::deviceID() const +{ + return m_deviceID; +} + +muse::async::Notification LinuxMidiInPort::deviceChanged() const +{ + return m_deviceChanged; +} + +muse::async::Channel LinuxMidiInPort::eventReceived() const +{ + return m_eventReceived; +} + +muse::Ret LinuxMidiInPort::run() +{ + if (!isConnected()) { + return make_ret(Err::MidiNotConnected); + } + + if (m_thread) { + LOGW() << "already started"; + return muse::Ret(true); + } + + m_running.store(true); + m_thread = std::make_shared(process, this); + return muse::Ret(true); +} + +void LinuxMidiInPort::stop() +{ + if (!m_thread) { + LOGW() << "already stopped"; + return; + } + + m_running.store(false); + m_thread->join(); + m_thread = nullptr; +} + +void LinuxMidiInPort::process(LinuxMidiInPort* self) +{ + self->doProcess(); +} + +void LinuxMidiInPort::doProcess() +{ +} + +bool LinuxMidiInPort::deviceExists(const MidiDeviceID& deviceId) const +{ + for (const MidiDevice& device : availableDevices()) { + if (device.id == deviceId) { + return true; + } + } + + return false; +} diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.h b/src/framework/midi/internal/platform/lin/linuxmidiinport.h new file mode 100644 index 0000000000000..1f9c0f1fa9b5a --- /dev/null +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.h @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#ifndef MU_MIDI_LINUXMIDIINPORT_H +#define MU_MIDI_LINUXMIDIINPORT_H + +#include +#include + +#include "async/asyncable.h" + +#include "imidiinport.h" +#include "internal/midideviceslistener.h" + +#if defined(JACK_AUDIO) +#include "internal/platform/jack/jackmidiinport.h" +#endif + +#include "internal/platform/alsa/alsamidiinport.h" + +namespace muse::midi { +class LinuxMidiInPort : public IMidiInPort, public async::Asyncable +{ +public: + LinuxMidiInPort() = default; + ~LinuxMidiInPort() = default; + + void init(); + void deinit(); + + std::vector availableDevices() const override; + async::Notification availableDevicesChanged() const override; + + Ret connect(const MidiDeviceID& deviceID) override; + void disconnect() override; + bool isConnected() const override; + MidiDeviceID deviceID() const override; + async::Notification deviceChanged() const override; + + async::Channel eventReceived() const override; + +private: + Ret run(); + void stop(); + + static void process(LinuxMidiInPort* self); + void doProcess(); + + bool deviceExists(const MidiDeviceID& deviceId) const; + + //std::shared_ptr m_alsa; + MidiDeviceID m_deviceID; + std::shared_ptr m_thread; + std::atomic m_running{ false }; + async::Notification m_deviceChanged; + + async::Notification m_availableDevicesChanged; + MidiDevicesListener m_devicesListener; + + mutable std::mutex m_devicesMutex; + + async::Channel m_eventReceived; + + // + +#if defined(JACK_AUDIO) + std::shared_ptr m_midiInPortJack; +#endif + std::shared_ptr m_midiInPortAlsa; + +}; +} + +#endif // MU_MIDI_ALSAMIDIINPORT_H diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp new file mode 100644 index 0000000000000..1c9b334215fdd --- /dev/null +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp @@ -0,0 +1,204 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#include "linuxmidioutport.h" + +#include "midierrors.h" +#include "translation.h" +#include "defer.h" +#include "log.h" + +using namespace muse::midi; + +void LinuxMidiOutPort::init() +{ + LOGI("---- linux init ----"); + //m_alsa = std::make_shared(); + +#if JACK_AUDIO + m_midiOutPortJack = std::make_unique(); + m_midiOutPortJack->init(); +#endif + m_midiOutPortAlsa = std::make_unique(); + m_midiOutPortAlsa->init(); + + m_devicesListener.startWithCallback([this]() { + return availableDevices(); + }); + + m_devicesListener.devicesChanged().onNotify(this, [this]() { + bool connectedDeviceRemoved = true; + for (const MidiDevice& device: availableDevices()) { + if (m_deviceID == device.id) { + connectedDeviceRemoved = false; + } + } + + if (connectedDeviceRemoved) { + disconnect(); + } + + m_availableDevicesChanged.notify(); + }); +} + +void LinuxMidiOutPort::deinit() +{ + LOGI("---- linux deinit ----"); + if (isConnected()) { + disconnect(); + } +} + +std::vector LinuxMidiOutPort::availableDevices() const +{ + std::lock_guard lock(m_devicesMutex); + + std::vector ret; +#if JACK_AUDIO + auto vj = m_midiOutPortJack->availableDevices(); + ret.insert(ret.end(), vj.begin(), vj.end()); +#endif + auto va = m_midiOutPortAlsa->availableDevices(); + ret.insert(ret.end(), va.begin(), va.end()); + + // FIX: this should be done by gui/caller + ret.push_back({ NONE_DEVICE_ID, muse::trc("midi", "No device") }); + return ret; +} + +muse::async::Notification LinuxMidiOutPort::availableDevicesChanged() const +{ + LOGI("---- linux availableDevicesChanged ----"); + return m_availableDevicesChanged; +} + +muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) +{ + LOGI("---- linux connect to %s ----", deviceID.c_str()); + if (!deviceExists(deviceID)) { + return make_ret(Err::MidiFailedConnect, "not found device, id: " + deviceID); + } + + DEFER { + m_deviceChanged.notify(); + }; + + if (!deviceID.empty() && deviceID != NONE_DEVICE_ID) { + std::vector deviceParams = splitDeviceId(deviceID); + IF_ASSERT_FAILED(deviceParams.size() == 3) { + return make_ret(Err::MidiInvalidDeviceID, "invalid device id: " + deviceID); + } + + if (deviceParams.at(1) == 9999) { // This is an jack device + LOGI("---- linux connect to jack ----"); + m_midiOutPortCurrent = /* JackMidiOutPort */ m_midiOutPortJack.get(); + } else { + LOGI("---- linux connect to alsa ----"); + m_midiOutPortCurrent = /* AlsaMidiOutPort */ m_midiOutPortAlsa.get(); + } + + if (m_midiOutPortCurrent->isConnected()) { + m_midiOutPortCurrent->disconnect(); + } + LOGD() << "Connected to " << deviceID; // FIX: let caller log instead (has return state of connect) + m_deviceID = deviceID; + // continue the connect in the driver + return m_midiOutPortCurrent ->connect(deviceID); + } + + return Ret(true); +} + +void LinuxMidiOutPort::disconnect() +{ + LOGI("---- linux disconnect ----"); + if (!isConnected()) { + return; + } + + LOGD() << "Disconnected from " << m_deviceID; + + //m_alsa->client = -1; + //m_alsa->port = -1; + //m_alsa->midiOut = nullptr; + m_deviceID.clear(); +} + +bool LinuxMidiOutPort::isConnected() const +{ + LOGI("---- linux isConnect ----"); + return m_midiOutPortCurrent && !m_deviceID.empty(); +} + +MidiDeviceID LinuxMidiOutPort::deviceID() const +{ + LOGI("---- linux deviceID ----"); + return m_deviceID; +} + +muse::async::Notification LinuxMidiOutPort::deviceChanged() const +{ + LOGI("---- linux deviceChanged ----"); + return m_deviceChanged; +} + +bool LinuxMidiOutPort::supportsMIDI20Output() const +{ + LOGI("---- linux supportsMIDI20Output ----"); + return false; +} + +muse::Ret LinuxMidiOutPort::sendEvent(const Event& e) +{ + // LOGI() << e.to_string(); + LOGI() << "---- linux sendEvent ----" << e.to_string(); + + if (!isConnected()) { + LOGI() << "---- linux sendEvent NOT CONNECTED"; + return make_ret(Err::MidiNotConnected); + } + + if (e.isChannelVoice20()) { + auto events = e.toMIDI10(); + for (auto& event : events) { + muse::Ret ret = sendEvent(event); + if (!ret) { + return ret; + } + } + return muse::Ret(true); + } + + return m_midiOutPortCurrent->sendEvent(e); +} + +bool LinuxMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const +{ + LOGI("---- linux deviceExists ----"); + for (const MidiDevice& device : availableDevices()) { + LOGI("---- linux deviceExists dev equal? %s <=> %s", deviceId.c_str(), device.id.c_str()); + if (device.id == deviceId) { + return true; + } + } + return false; +} diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.h b/src/framework/midi/internal/platform/lin/linuxmidioutport.h new file mode 100644 index 0000000000000..3ca0fb3886d73 --- /dev/null +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.h @@ -0,0 +1,83 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#ifndef MU_MIDI_LINUXMIDIOUTPORT_H +#define MU_MIDI_LINUXMIDIOUTPORT_H + +#include + +#include "async/asyncable.h" +#include "midi/imidioutport.h" +#include "internal/midideviceslistener.h" + +#if defined(JACK_AUDIO) +#include "internal/platform/jack/jackmidioutport.h" +#endif + +#include "internal/platform/alsa/alsamidioutport.h" + +namespace muse::midi { +class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable +{ +public: + LinuxMidiOutPort() = default; + ~LinuxMidiOutPort() = default; + + void init(); + void deinit(); + + std::vector availableDevices() const override; + async::Notification availableDevicesChanged() const override; + + Ret connect(const MidiDeviceID& deviceID) override; + void disconnect() override; + bool isConnected() const override; + MidiDeviceID deviceID() const override; + async::Notification deviceChanged() const override; + + bool supportsMIDI20Output() const override; + + Ret sendEvent(const Event& e) override; + +private: + bool deviceExists(const MidiDeviceID& deviceId) const; + + //std::shared_ptr m_alsa; + MidiDeviceID m_deviceID; + async::Notification m_deviceChanged; + + async::Notification m_availableDevicesChanged; + MidiDevicesListener m_devicesListener; + + mutable std::mutex m_devicesMutex; + + // + MidiPortState* m_midiOutPortCurrent; + +#if defined(JACK_AUDIO) + std::unique_ptr m_midiOutPortJack; +#endif + std::unique_ptr m_midiOutPortAlsa; + +}; +} + +#endif // MU_MIDI_ALSAMIDIOUTPORT_H diff --git a/src/framework/midi/midimodule.cpp b/src/framework/midi/midimodule.cpp index 9bbd1bc698024..9777e493907be 100644 --- a/src/framework/midi/midimodule.cpp +++ b/src/framework/midi/midimodule.cpp @@ -35,8 +35,8 @@ using namespace muse::midi; #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) -#include "internal/platform/lin/alsamidioutport.h" -#include "internal/platform/lin/alsamidiinport.h" +#include "internal/platform/lin/linuxmidioutport.h" +#include "internal/platform/lin/linuxmidiinport.h" #elif defined(Q_OS_WIN) #include "internal/platform/win/winmidioutport.h" #include "internal/platform/win/winmidiinport.h" @@ -57,19 +57,19 @@ void MidiModule::registerExports() { m_configuration = std::make_shared(); - #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - m_midiOutPort = std::make_shared(); - m_midiInPort = std::make_shared(); - #elif defined(Q_OS_WIN) +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) + m_midiOutPort = std::make_shared(); + m_midiInPort = std::make_shared(); +#elif defined(Q_OS_WIN) m_midiOutPort = std::make_shared(); m_midiInPort = std::make_shared(); - #elif defined(Q_OS_MACOS) +#elif defined(Q_OS_MACOS) m_midiOutPort = std::make_shared(); m_midiInPort = std::make_shared(); - #else +#else m_midiOutPort = std::make_shared(); m_midiInPort = std::make_shared(); - #endif +#endif ioc()->registerExport(moduleName(), m_configuration); ioc()->registerExport(moduleName(), m_midiOutPort); diff --git a/src/framework/midi/midimodule.h b/src/framework/midi/midimodule.h index c2d7dfafb6d08..b0121d3fad896 100644 --- a/src/framework/midi/midimodule.h +++ b/src/framework/midi/midimodule.h @@ -29,8 +29,8 @@ namespace muse::midi { class MidiConfiguration; #if defined(Q_OS_LINUX) -class AlsaMidiOutPort; -class AlsaMidiInPort; +class LinuxMidiOutPort; +class LinuxMidiInPort; #elif defined(Q_OS_FREEBSD) class AlsaMidiOutPort; class AlsaMidiInPort; @@ -58,8 +58,8 @@ class MidiModule : public modularity::IModuleSetup std::shared_ptr m_configuration; #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - std::shared_ptr m_midiOutPort; - std::shared_ptr m_midiInPort; + std::shared_ptr m_midiOutPort; + std::shared_ptr m_midiInPort; #elif defined(Q_OS_WIN) std::shared_ptr m_midiOutPort; From b8a52ee9d3dd109c74d08953f5bee2581a7f1281 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 7 Apr 2024 20:54:47 +0200 Subject: [PATCH 15/60] jack-midi: jack/alsa subdrivers --- .../internal/platform/alsa/alsamidiinport.cpp | 4 +- .../internal/platform/alsa/alsamidiinport.h | 2 +- .../platform/alsa/alsamidioutport.cpp | 80 ++++++------------- .../internal/platform/alsa/alsamidioutport.h | 19 +---- 4 files changed, 32 insertions(+), 73 deletions(-) diff --git a/src/framework/midi/internal/platform/alsa/alsamidiinport.cpp b/src/framework/midi/internal/platform/alsa/alsamidiinport.cpp index 1e9fcc72a7a1b..cda5737c6bcdc 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidiinport.cpp +++ b/src/framework/midi/internal/platform/alsa/alsamidiinport.cpp @@ -71,7 +71,7 @@ void AlsaMidiInPort::deinit() } } -MidiDeviceList AlsaMidiInPort::availableDevices() const +std::vector AlsaMidiInPort::availableDevices() const { std::lock_guard lock(m_devicesMutex); @@ -80,7 +80,7 @@ MidiDeviceList AlsaMidiInPort::availableDevices() const const unsigned int type_hw = SND_SEQ_PORT_TYPE_PORT | SND_SEQ_PORT_TYPE_HARDWARE; const unsigned int type_sw = SND_SEQ_PORT_TYPE_PORT | SND_SEQ_PORT_TYPE_SOFTWARE; - MidiDeviceList ret; + std::vector ret; ret.push_back({ NONE_DEVICE_ID, muse::trc("midi", "No device") }); diff --git a/src/framework/midi/internal/platform/alsa/alsamidiinport.h b/src/framework/midi/internal/platform/alsa/alsamidiinport.h index bea92176ef0bc..e83a4b1f77e77 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidiinport.h +++ b/src/framework/midi/internal/platform/alsa/alsamidiinport.h @@ -40,7 +40,7 @@ class AlsaMidiInPort : public IMidiInPort, public async::Asyncable void init(); void deinit(); - MidiDeviceList availableDevices() const override; + std::vector availableDevices() const override; async::Notification availableDevicesChanged() const override; Ret connect(const MidiDeviceID& deviceID) override; diff --git a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp index 90e2496a719bb..0c1f9238c7f46 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp +++ b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp @@ -5,7 +5,7 @@ * MuseScore * Music Composition & Notation * - * Copyright (C) 2021 MuseScore BVBA and others + * Copyright (C) 2023 MuseScore BVBA 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 3 as @@ -41,8 +41,10 @@ using namespace muse::midi; void AlsaMidiOutPort::init() { + LOGI("---- linux ALSA init ----"); m_alsa = std::make_shared(); + /* m_devicesListener.startWithCallback([this]() { return availableDevices(); }); @@ -61,10 +63,12 @@ void AlsaMidiOutPort::init() m_availableDevicesChanged.notify(); }); + */ } void AlsaMidiOutPort::deinit() { + LOGI("---- linux ALSA deinit ----"); if (isConnected()) { disconnect(); } @@ -72,8 +76,6 @@ void AlsaMidiOutPort::deinit() std::vector AlsaMidiOutPort::availableDevices() const { - std::lock_guard lock(m_devicesMutex); - int streams = SND_SEQ_OPEN_OUTPUT; const unsigned int cap = SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE; const unsigned int type_hw = SND_SEQ_PORT_TYPE_PORT | SND_SEQ_PORT_TYPE_HARDWARE; @@ -81,8 +83,6 @@ std::vector AlsaMidiOutPort::availableDevices() const std::vector ret; - ret.push_back({ NONE_DEVICE_ID, muse::trc("midi", "No device") }); - snd_seq_client_info_t* cinfo; snd_seq_port_info_t* pinfo; int client; @@ -118,7 +118,6 @@ std::vector AlsaMidiOutPort::availableDevices() const if (canConnect) { MidiDevice dev; dev.name = snd_seq_client_info_get_name(cinfo); - int client = snd_seq_port_info_get_client(pinfo); int port = snd_seq_port_info_get_port(pinfo); dev.id = makeUniqueDeviceId(index++, client, port); @@ -133,58 +132,36 @@ std::vector AlsaMidiOutPort::availableDevices() const return ret; } -async::Notification AlsaMidiOutPort::availableDevicesChanged() const +muse::Ret AlsaMidiOutPort::connect(const MidiDeviceID& deviceID) { - return m_availableDevicesChanged; -} - -Ret AlsaMidiOutPort::connect(const MidiDeviceID& deviceID) -{ - if (!deviceExists(deviceID)) { - return make_ret(Err::MidiFailedConnect, "not found device, id: " + deviceID); - } - - DEFER { - m_deviceChanged.notify(); - }; - Ret ret = muse::make_ok(); - if (!deviceID.empty() && deviceID != NONE_DEVICE_ID) { - std::vector deviceParams = splitDeviceId(deviceID); - IF_ASSERT_FAILED(deviceParams.size() == 3) { - return make_ret(Err::MidiInvalidDeviceID, "invalid device id: " + deviceID); - } - - if (isConnected()) { - disconnect(); - } - - int err = snd_seq_open(&m_alsa->midiOut, "default", SND_SEQ_OPEN_OUTPUT, 0); - if (err < 0) { - return make_ret(Err::MidiFailedConnect, "failed open seq, err: " + std::string(snd_strerror(err))); - } - snd_seq_set_client_name(m_alsa->midiOut, "MuseScore"); - - int port = snd_seq_create_simple_port(m_alsa->midiOut, "MuseScore Port-0", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); - if (port < 0) { - return make_ret(Err::MidiFailedConnect, "failed create port"); - } + std::vector deviceParams = splitDeviceId(deviceID); + IF_ASSERT_FAILED(deviceParams.size() == 3) { + return make_ret(Err::MidiInvalidDeviceID, "invalid device id: " + deviceID); + } - m_alsa->client = deviceParams.at(1); - m_alsa->port = deviceParams.at(2); - err = snd_seq_connect_to(m_alsa->midiOut, port, m_alsa->client, m_alsa->port); - if (err < 0) { - return make_ret(Err::MidiFailedConnect, "failed connect, err: " + std::string(snd_strerror(err))); - } + if (isConnected()) { + disconnect(); } - m_deviceID = deviceID; + int err = snd_seq_open(&m_alsa->midiOut, "default", SND_SEQ_OPEN_OUTPUT, 0); + if (err < 0) { + return make_ret(Err::MidiFailedConnect, "failed open seq, err: " + std::string(snd_strerror(err))); + } + snd_seq_set_client_name(m_alsa->midiOut, "MuseScore"); - if (ret) { - LOGD() << "Connected to " << m_deviceID; + int port = snd_seq_create_simple_port(m_alsa->midiOut, "MuseScore Port-0", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + if (port < 0) { + return make_ret(Err::MidiFailedConnect, "failed create port"); } + m_alsa->client = deviceParams.at(1); + m_alsa->port = deviceParams.at(2); + err = snd_seq_connect_to(m_alsa->midiOut, port, m_alsa->client, m_alsa->port); + if (err < 0) { + return make_ret(Err::MidiFailedConnect, "failed connect, err: " + std::string(snd_strerror(err))); + } return Ret(true); } @@ -215,11 +192,6 @@ MidiDeviceID AlsaMidiOutPort::deviceID() const return m_deviceID; } -async::Notification AlsaMidiOutPort::deviceChanged() const -{ - return m_deviceChanged; -} - bool AlsaMidiOutPort::supportsMIDI20Output() const { return false; diff --git a/src/framework/midi/internal/platform/alsa/alsamidioutport.h b/src/framework/midi/internal/platform/alsa/alsamidioutport.h index 0396b405abb7f..e5dfda43978b5 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidioutport.h +++ b/src/framework/midi/internal/platform/alsa/alsamidioutport.h @@ -24,31 +24,24 @@ #include -#include "async/asyncable.h" -#include "midi/imidioutport.h" -#include "internal/midideviceslistener.h" +#include "midi/midiportstate.h" namespace muse::midi { -class AlsaMidiOutPort : public IMidiOutPort, public async::Asyncable +class AlsaMidiOutPort : public MidiPortState { public: AlsaMidiOutPort() = default; ~AlsaMidiOutPort() = default; - void init(); void deinit(); - MidiDeviceList availableDevices() const override; - async::Notification availableDevicesChanged() const override; + std::vector availableDevices() const override; Ret connect(const MidiDeviceID& deviceID) override; void disconnect() override; bool isConnected() const override; MidiDeviceID deviceID() const override; - async::Notification deviceChanged() const override; - bool supportsMIDI20Output() const override; - Ret sendEvent(const Event& e) override; private: @@ -57,12 +50,6 @@ class AlsaMidiOutPort : public IMidiOutPort, public async::Asyncable struct Alsa; std::shared_ptr m_alsa; MidiDeviceID m_deviceID; - async::Notification m_deviceChanged; - - async::Notification m_availableDevicesChanged; - MidiDevicesListener m_devicesListener; - - mutable std::mutex m_devicesMutex; }; } From 86fae41bd00ecb841d44ec399bfc4942008bccbb Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 30 Sep 2023 17:20:59 +0200 Subject: [PATCH 16/60] jack-midi: midiportstate (separate subdrivers) --- src/framework/midi/midiportstate.h | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/framework/midi/midiportstate.h diff --git a/src/framework/midi/midiportstate.h b/src/framework/midi/midiportstate.h new file mode 100644 index 0000000000000..d33d0dedc9ed5 --- /dev/null +++ b/src/framework/midi/midiportstate.h @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) MuseScore BVBA 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 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +#ifndef MU_MIDI_MIDIPORTSTATE_H +#define MU_MIDI_MIDIPORTSTATE_H + +#include "types/ret.h" +#include "miditypes.h" + +namespace muse::midi { +class MidiPortState +{ + +public: + virtual ~MidiPortState() = default; + + virtual void init() = 0; + virtual void deinit() = 0; + + virtual std::vector availableDevices() const = 0; + + virtual Ret connect(const MidiDeviceID& deviceID) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + virtual MidiDeviceID deviceID() const = 0; + + // + // Whether the output port supports it, rather than whether the receiver supports it + // (If the receiver does not support MIDI 2.0, then it's the output port's resposibility to convert to MIDI 1.0) + virtual bool supportsMIDI20Output() const = 0; + + virtual Ret sendEvent(const Event& e) = 0; +}; +} + + +#endif // MU_MIDI_MIDIPORTSTATE_H From b519785df9ad746a7ceb8c8a01ddd49af0cfbb6a Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 8 Oct 2023 21:36:21 +0200 Subject: [PATCH 17/60] WIP: queue midi events towards jackaudiodriver --- src/framework/audio/iaudiodriver.h | 7 +- .../platform/alsa/alsaaudiodriver.cpp | 5 + .../internal/platform/alsa/alsaaudiodriver.h | 1 + .../platform/jack/jackaudiodriver.cpp | 127 +++++++++++++++++- .../internal/platform/jack/jackaudiodriver.h | 5 + .../platform/lin/linuxaudiodriver.cpp | 10 ++ .../internal/platform/lin/linuxaudiodriver.h | 1 + .../internal/platform/osx/osxaudiodriver.h | 1 + .../internal/platform/osx/osxaudiodriver.mm | 5 + .../platform/win/wasapiaudiodriver.cpp | 4 + .../internal/platform/win/wasapiaudiodriver.h | 1 + src/framework/audio/midiqueue.h | 45 +++++++ .../platform/alsa/alsamidioutport.cpp | 2 - .../internal/platform/jack/jackmidiinport.cpp | 12 +- .../platform/jack/jackmidioutport.cpp | 43 +++--- .../internal/platform/jack/jackmidioutport.h | 12 +- .../internal/platform/lin/linuxmidiinport.cpp | 37 ++--- .../internal/platform/lin/linuxmidiinport.h | 10 +- .../platform/lin/linuxmidioutport.cpp | 39 ++---- .../internal/platform/lin/linuxmidioutport.h | 7 +- src/framework/midi/midimodule.cpp | 2 +- src/framework/midi/midiportstate.h | 2 - src/framework/stubs/audio/audiodriverstub.cpp | 5 + src/framework/stubs/audio/audiodriverstub.h | 1 + 24 files changed, 284 insertions(+), 100 deletions(-) create mode 100644 src/framework/audio/midiqueue.h diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 936b780627f51..9d0470dca5265 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -32,8 +32,12 @@ #include "modularity/imoduleinterface.h" #include "audiotypes.h" +#include "framework/midi/miditypes.h" +#include "framework/audio/midiqueue.h" namespace muse::audio { +class AudioDriverState; + class IAudioDriver : MODULE_EXPORT_INTERFACE { INTERFACE_ID(IAudioDriver) @@ -86,11 +90,11 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual async::Notification outputDeviceSampleRateChanged() const = 0; virtual std::vector availableOutputDeviceSampleRates() const = 0; + virtual bool pushMidiEvent(muse::midi::Event&) = 0; virtual void resume() = 0; virtual void suspend() = 0; }; -using IAudioDriverPtr = std::shared_ptr; class AudioDriverState { @@ -99,6 +103,7 @@ class AudioDriverState virtual bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) = 0; virtual void close() = 0; virtual bool isOpened() const = 0; + virtual bool pushMidiEvent(muse::midi::Event&) = 0; IAudioDriver::Spec m_spec; // current running spec std::string m_deviceId; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 2dde13ccfda23..d97f251233bc1 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -193,3 +193,8 @@ bool AlsaDriverState::isOpened() const { return m_alsaDeviceHandle != nullptr; } + +bool AlsaDriverState::pushMidiEvent(muse::midi::Event& e) +{ + return true; // dummy +} diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 0ca59d4b95052..d7c0235db088d 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -36,6 +36,7 @@ class AlsaDriverState : public AudioDriverState bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; + bool pushMidiEvent(muse::midi::Event& e) override; std::string deviceName() const; void deviceName(const std::string newDeviceName); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 04993e57c1045..9e9ebf96cd1fc 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -20,6 +20,8 @@ * along with this program. If not, see . */ #include "jackaudiodriver.h" +#include +#include "framework/midi/midierrors.h" #include #include @@ -37,8 +39,87 @@ #define JACK_DEFAULT_IDENTIFY_AS "MuseScore" using namespace muse::audio; - +using namespace muse::midi; namespace muse::audio { +muse::Ret sendEvent_noteonoff(void* pb, int framePos, const muse::midi::Event& e) +{ + unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); + if (p == 0) { + LOGE("JackMidi: buffer overflow, event lost"); + return muse::Ret(false); + } + // FIX: is opcode an compatible MIDI enumeration? + if (e.opcode() == muse::midi::Event::Opcode::NoteOn) { + p[0] = /* e.opcode() */ 0x90 | e.channel(); + } else { + p[0] = /* e.opcode() */ 0x80 | e.channel(); + } + p[1] = e.note(); + p[2] = e.velocity(); + return muse::Ret(true); +} + +muse::Ret sendEvent_control(void* pb, int framePos, const Event& e) +{ + unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); + if (p == 0) { + LOGE("JackMidi: buffer overflow, event lost"); + return muse::Ret(false); + } + p[0] = /* e.opcode() */ 0xb0 | e.channel(); + p[1] = e.index(); + p[2] = e.data(); + return muse::Ret(true); +} + +muse::Ret sendEvent_program(void* pb, int framePos, const Event& e) +{ + unsigned char* p = jack_midi_event_reserve(pb, framePos, 2); + if (p == 0) { + LOGE("JackMidiOutput: buffer overflow, event lost"); + return muse::Ret(false); + } + p[0] = /* e.opcode() */ 0xc0 | e.channel(); + p[1] = e.program(); + return muse::Ret(true); +} + +muse::Ret sendEvent_pitchbend(void* pb, int framePos, const Event& e) +{ + unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); + if (p == 0) { + LOGE("JackMidiOutput: buffer overflow, event lost"); + return muse::Ret(false); + } + p[0] = /* e.opcode() */ 0xe0 | e.channel(); + p[1] = e.data(); // dataA + p[2] = e.velocity(); // dataB + return muse::Ret(true); +} + +muse::Ret sendEvent(const Event& e, void* pb) +{ + int framePos = 0; + switch (e.opcode()) { + // FIX: Event::Opcode::POLYAFTER ? + case Event::Opcode::NoteOn: + return sendEvent_noteonoff(pb, framePos, e); + case Event::Opcode::NoteOff: + return sendEvent_noteonoff(pb, framePos, e); + case Event::Opcode::ControlChange: + return sendEvent_control(pb, framePos, e); + case Event::Opcode::ProgramChange: + return sendEvent_control(pb, framePos, e); + case Event::Opcode::PitchBend: + return sendEvent_pitchbend(pb, framePos, e); + default: + NOT_SUPPORTED << "event: " << e.to_string(); + return make_ret(muse::midi::Err::MidiNotSupported); + } + + return Ret(true); +} + static int jack_process_callback(jack_nframes_t nframes, void* args) { JackDriverState* state = static_cast(args); @@ -53,6 +134,37 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) *l++ = *sp++; *r++ = *sp++; } + + // if (!isConnected()) { + // LOGI() << "---- JACK-midi output sendEvent SORRY, not connected"; + // return make_ret(Err::MidiNotConnected); + // } + if (!state->m_midiOutputPorts.empty()) { + jack_port_t* port = state->m_midiOutputPorts.front(); + if (port) { + int segmentSize = jack_get_buffer_size(static_cast(state->m_jackDeviceHandle)); + void* pb = jack_port_get_buffer(port, segmentSize); + // handle midi + muse::midi::Event e; + while (1) { + if (state->m_midiQueue.pop(e)) { + sendEvent(e, pb); + } else { + break; + } + } + } + } else { + muse::midi::Event e; + while (1) { + if (state->m_midiQueue.pop(e)) { + LOGW() << "no jack-midi-outport, consumed unused Event: " << e.to_string(); + } else { + break; + } + } + } + return 0; } @@ -153,6 +265,13 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } + // midi + jack_options_t options = (jack_options_t)0; + int portFlag = JackPortIsOutput; + const char* portType = JACK_DEFAULT_MIDI_TYPE; + jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); + m_midiOutputPorts.push_back(port); + return true; } @@ -168,3 +287,9 @@ bool JackDriverState::isOpened() const { return m_jackDeviceHandle != nullptr; } + +bool JackDriverState::pushMidiEvent(muse::midi::Event& e) +{ + m_midiQueue.push(e); + return true; +} diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index beb47e484ce83..1b51956845630 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -38,6 +38,9 @@ class JackDriverState : public AudioDriverState bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; + //std::shared_ptr&> getAudioDriverQueue() const override; + bool pushMidiEvent(muse::midi::Event& e) override; + std::string deviceName() const; void deviceName(const std::string newDeviceName); @@ -46,6 +49,8 @@ class JackDriverState : public AudioDriverState float* m_buffer = nullptr; std::vector m_outputPorts; + std::vector m_midiOutputPorts; + ThreadSafeQueue m_midiQueue; private: std::string m_deviceName; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 33dc47c6c82bb..4297277f22512 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "framework/audio/midiqueue.h" #include "linuxaudiodriver.h" #include "../alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists #if JACK_AUDIO @@ -109,6 +110,7 @@ bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) LOGE() << "Unknown device name: " << deviceId; return false; } + LOGI(" -- driver: %lx", m_current_audioDriverState.get()); return true; } @@ -261,6 +263,14 @@ std::vector LinuxAudioDriver::availableOutputDeviceSampleRates() c 88200, 96000, }; + +bool LinuxAudioDriver::pushMidiEvent(muse::midi::Event& e) +{ + if (m_current_audioDriverState) { + m_current_audioDriverState->pushMidiEvent(e); + return true; + } + return false; } void LinuxAudioDriver::resume() diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index beec3f757b6d3..4fc9806360635 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -58,6 +58,7 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable async::Notification outputDeviceBufferSizeChanged() const override; std::vector availableOutputDeviceBufferSizes() const override; + bool pushMidiEvent(muse::midi::Event& e) override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 8a1c50155f7cc..7c0cacc1c78bf 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -67,6 +67,7 @@ class OSXAudioDriver : public IAudioDriver async::Notification outputDeviceBufferSizeChanged() const override; std::vector availableOutputDeviceBufferSizes() const override; + bool pushMidiEvent(muse::midi::Event& e) override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index 5e775c0a7ba3d..ce359732b9bea 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -575,3 +575,8 @@ static OSStatus onDeviceListChanged(AudioObjectID inObjectID, UInt32 inNumberAdd pData->callback(pData->mUserData, (uint8_t*)buffer->mAudioData, buffer->mAudioDataByteSize); AudioQueueEnqueueBuffer(pData->audioQueue, buffer, 0, NULL); } + +bool OSXAudioDriver::pushMidiEvent(muse::midi::Event&) +{ + return true; // dummy +} diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index c5b8f5f5da9ac..7da9eb4a75af5 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -367,4 +367,8 @@ unsigned int WasapiAudioDriver::minSupportedBufferSize() const } return closestBufferSize; + +bool WasapiAudioDriver::pushMidiEvent(muse::midi::Event&) +{ + return true; } diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 8388d734edc12..5bf180770422f 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -64,6 +64,7 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable async::Notification outputDeviceSampleRateChanged() const override; std::vector availableOutputDeviceSampleRates() const override; + bool pushMidiEvent(muse::midi::Event& e) override; void resume() override; void suspend() override; diff --git a/src/framework/audio/midiqueue.h b/src/framework/audio/midiqueue.h new file mode 100644 index 0000000000000..6d890e3dbfa81 --- /dev/null +++ b/src/framework/audio/midiqueue.h @@ -0,0 +1,45 @@ +#ifndef MUSE_MIDI_MIDIQUEUE_H +#define MUSE_MIDI_MIDIQUEUE_H + +#include +#include +#include + +template +class ThreadSafeQueue +{ +private: + std::queue queue_; + mutable std::mutex mtx_; + +public: + void push(const T& item) + { + std::lock_guard lock(mtx_); + queue_.push(item); + } + + bool pop(T& item) + { + std::lock_guard lock(mtx_); + if (queue_.empty()) { + return false; + } + //T* ptr = queue_.front(); + //item = *ptr; + //delete ptr; + //queue_.pop(); + //return true; + item = queue_.front(); + queue_.pop(); + return true; + } + + bool empty() const + { + std::lock_guard lock(mtx_); + return queue_.empty(); + } +}; + +#endif // MUSE_MIDI_MIDIQUEUE_H diff --git a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp index 0c1f9238c7f46..1b2ab9afc930c 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp +++ b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp @@ -199,8 +199,6 @@ bool AlsaMidiOutPort::supportsMIDI20Output() const Ret AlsaMidiOutPort::sendEvent(const Event& e) { - // LOGI() << e.to_string(); - if (!isConnected()) { return make_ret(Err::MidiNotConnected); } diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp index 95ec560dd4e61..e129adbde7e76 100644 --- a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp +++ b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp @@ -56,16 +56,18 @@ std::vector JackMidiInPort::availableDevices() const for (const char** p = prts; p && *p; ++p) { jack_port_t* port = jack_port_by_name(m_jack->client, *p); int flags = jack_port_flags(port); - if (!(flags & JackPortIsInput)) - continue; + if (!(flags & JackPortIsInput)) { + continue; + } char buffer[128]; strncpy(buffer, *p, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = 0; - if (strncmp(buffer, "MuseScore", 9) == 0) - continue; + if (strncmp(buffer, "MuseScore", 9) == 0) { + continue; + } MidiDevice dev; dev.name = buffer; - dev.id = makeUniqueDeviceId(devIndex++,0,0); + dev.id = makeUniqueDeviceId(devIndex++, 0, 0); ports.push_back(std::move(dev)); } return ports; diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp index d698f78ca0709..cf5318d501e8c 100644 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "framework/audio/audiomodule.h" #include "jackmidioutport.h" #include @@ -28,19 +29,10 @@ #include "translation.h" #include "log.h" -struct muse::midi::JackMidiOutPort::Jack { - jack_port_t* midiOut = nullptr; - jack_client_t* client = nullptr; - int port = -1; - int segmentSize; -}; - using namespace muse::midi; void JackMidiOutPort::init() { - LOGI("---- linux JACK-midi output init ----"); - m_jack = std::make_unique(); } void JackMidiOutPort::deinit() @@ -52,46 +44,39 @@ void JackMidiOutPort::deinit() std::vector JackMidiOutPort::availableDevices() const { - //LOGI("---- linux JACK availableDevices ----"); std::vector ret; MidiDevice dev; dev.name = "JACK"; - dev.id = makeUniqueDeviceId(0,9999,0); + dev.id = makeUniqueDeviceId(0, 9999, 0); ret.push_back(std::move(dev)); return ret; } muse::Ret JackMidiOutPort::connect(const MidiDeviceID& deviceID) { - LOGI("---- JACK output connect ----"); - //----> common with jackaudio <---- - jack_client_t* client; - jack_options_t options = (jack_options_t)0; - jack_status_t status; - client = jack_client_open("MuseScore", options, &status); - if (!client) { + if (!m_jack->client) { return make_ret(Err::MidiInvalidDeviceID, "jack-open fail, device: " + deviceID); } - m_jack->client = client; return muse::Ret(true); } void JackMidiOutPort::disconnect() { - LOGI("---- linux JACK disconnect ----"); if (!isConnected()) { return; } + if (!m_jack->client) { + return; + } + jack_client_t* client = static_cast(m_jack->client); //FIX: //const char* sn = jack_port_name((jack_port_t*) src); //const char* dn = jack_port_name((jack_port_t*) dst); //jackdisconnect(m_jack->midiOut, 0, m_jack->client, m_jack->port); - if (jack_deactivate(m_jack->client)) { + if (jack_deactivate(client)) { LOGE() << "failed to deactive jack"; } - - m_jack->client = nullptr; m_jack->port = -1; m_jack->midiOut = nullptr; m_deviceID.clear(); @@ -99,25 +84,21 @@ void JackMidiOutPort::disconnect() bool JackMidiOutPort::isConnected() const { - LOGI("---- JACK output isConnect ----"); - return m_jack && m_jack->midiOut && !m_deviceID.empty(); + return !(m_jack.get() && m_jack->midiOut && !m_deviceID.empty()); } MidiDeviceID JackMidiOutPort::deviceID() const { - LOGI("---- JACK output deviceID ----"); return m_deviceID; } bool JackMidiOutPort::supportsMIDI20Output() const { - LOGI("---- JACK output supportsMIDI20Output ----"); return false; } bool JackMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const { - LOGI("---- JACK-midi output deviceExists ----"); for (const MidiDevice& device : availableDevices()) { if (device.id == deviceId) { return true; @@ -126,3 +107,9 @@ bool JackMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const return false; } + +// Not used +muse::Ret JackMidiOutPort::sendEvent(const Event&) +{ + return muse::Ret(true); +} diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.h b/src/framework/midi/internal/platform/jack/jackmidioutport.h index 00325182bc2f5..80aa2fdd7417f 100644 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.h +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.h @@ -23,6 +23,8 @@ #define MU_MIDI_JACKMIDIOUTPORT_H #include +#include "framework/audio/midiqueue.h" +#include "framework/audio/audiomodule.h" #include "midi/midiportstate.h" namespace muse::midi { @@ -44,8 +46,14 @@ class JackMidiOutPort : public MidiPortState private: bool deviceExists(const MidiDeviceID& deviceId) const; - - struct Jack; + std::shared_ptr m_audioDriver; + std::shared_ptr > m_midiQueue; + struct Jack { + void* midiOut = nullptr; + void* client = nullptr; + int port = -1; + int segmentSize; + }; std::unique_ptr m_jack; MidiDeviceID m_deviceID; }; diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp index cab8f0faa0f6c..a6eeaac7ef8dd 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -20,6 +20,7 @@ * along with this program. If not, see . */ #include "linuxmidiinport.h" +#include "framework/audio/audiomodule.h" #include "midierrors.h" #include "stringutils.h" @@ -29,28 +30,16 @@ using namespace muse::midi; -void LinuxMidiInPort::init() +void LinuxMidiInPort::init(std::shared_ptr am) { //m_alsa = std::make_shared(); +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) + LOGI("-- init using audiomodule: %lx", am); - m_devicesListener.startWithCallback([this]() { - return availableDevices(); - }); - - m_devicesListener.devicesChanged().onNotify(this, [this]() { - bool connectedDeviceRemoved = true; - for (const MidiDevice& device: availableDevices()) { - if (m_deviceID == device.id) { - connectedDeviceRemoved = false; - } - } - - if (connectedDeviceRemoved) { - disconnect(); - } - - m_availableDevicesChanged.notify(); - }); + //std::shared_ptr ad = am->getDriver(); + //LOGI("-- init got audiodriver: %lx", ad); + //LOGI("-- audiohandle: %lx", ad->getAudioDriverHandle()); +#endif } void LinuxMidiInPort::deinit() @@ -62,15 +51,17 @@ void LinuxMidiInPort::deinit() std::vector LinuxMidiInPort::availableDevices() const { +// FIX: this is compile-time, change so that we call availableMidiDevices if jack is selected +#if defined(JACK_AUDIO) + return audioDriver()->availableMidiDevices(); +#else std::lock_guard lock(m_devicesMutex); - std::vector ret; - ret.push_back({ NONE_DEVICE_ID, muse::trc("midi", "No device") }); - // return concatenation of alsa + jack devices - + std::shared_ptr m_midiInPortJack; return ret; +#endif } muse::async::Notification LinuxMidiInPort::availableDevicesChanged() const diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.h b/src/framework/midi/internal/platform/lin/linuxmidiinport.h index 1f9c0f1fa9b5a..20f2b67bed75d 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.h @@ -27,6 +27,7 @@ #include "async/asyncable.h" +#include "framework/audio/audiomodule.h" #include "imidiinport.h" #include "internal/midideviceslistener.h" @@ -39,11 +40,12 @@ namespace muse::midi { class LinuxMidiInPort : public IMidiInPort, public async::Asyncable { + Inject audioDriver; public: LinuxMidiInPort() = default; ~LinuxMidiInPort() = default; - void init(); + void init(std::shared_ptr am); void deinit(); std::vector availableDevices() const override; @@ -66,7 +68,6 @@ class LinuxMidiInPort : public IMidiInPort, public async::Asyncable bool deviceExists(const MidiDeviceID& deviceId) const; - //std::shared_ptr m_alsa; MidiDeviceID m_deviceID; std::shared_ptr m_thread; std::atomic m_running{ false }; @@ -79,14 +80,11 @@ class LinuxMidiInPort : public IMidiInPort, public async::Asyncable async::Channel m_eventReceived; - // - #if defined(JACK_AUDIO) std::shared_ptr m_midiInPortJack; #endif std::shared_ptr m_midiInPortAlsa; - }; } -#endif // MU_MIDI_ALSAMIDIINPORT_H +#endif // MU_MIDI_LINUXMIDIINPORT_H diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp index 1c9b334215fdd..3e4b9dfc8739a 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp @@ -19,7 +19,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +//#include +//#include +//#include #include "linuxmidioutport.h" +#include "framework/audio/audiomodule.h" #include "midierrors.h" #include "translation.h" @@ -30,9 +34,6 @@ using namespace muse::midi; void LinuxMidiOutPort::init() { - LOGI("---- linux init ----"); - //m_alsa = std::make_shared(); - #if JACK_AUDIO m_midiOutPortJack = std::make_unique(); m_midiOutPortJack->init(); @@ -62,7 +63,6 @@ void LinuxMidiOutPort::init() void LinuxMidiOutPort::deinit() { - LOGI("---- linux deinit ----"); if (isConnected()) { disconnect(); } @@ -87,17 +87,15 @@ std::vector LinuxMidiOutPort::availableDevices() const muse::async::Notification LinuxMidiOutPort::availableDevicesChanged() const { - LOGI("---- linux availableDevicesChanged ----"); return m_availableDevicesChanged; } muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) { - LOGI("---- linux connect to %s ----", deviceID.c_str()); if (!deviceExists(deviceID)) { return make_ret(Err::MidiFailedConnect, "not found device, id: " + deviceID); } - + DEFER { m_deviceChanged.notify(); }; @@ -107,12 +105,12 @@ muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) IF_ASSERT_FAILED(deviceParams.size() == 3) { return make_ret(Err::MidiInvalidDeviceID, "invalid device id: " + deviceID); } - + if (deviceParams.at(1) == 9999) { // This is an jack device - LOGI("---- linux connect to jack ----"); +#if JACK_AUDIO m_midiOutPortCurrent = /* JackMidiOutPort */ m_midiOutPortJack.get(); +#endif } else { - LOGI("---- linux connect to alsa ----"); m_midiOutPortCurrent = /* AlsaMidiOutPort */ m_midiOutPortAlsa.get(); } @@ -122,7 +120,7 @@ muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) LOGD() << "Connected to " << deviceID; // FIX: let caller log instead (has return state of connect) m_deviceID = deviceID; // continue the connect in the driver - return m_midiOutPortCurrent ->connect(deviceID); + return m_midiOutPortCurrent->connect(deviceID); } return Ret(true); @@ -130,50 +128,38 @@ muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) void LinuxMidiOutPort::disconnect() { - LOGI("---- linux disconnect ----"); if (!isConnected()) { return; } LOGD() << "Disconnected from " << m_deviceID; - //m_alsa->client = -1; - //m_alsa->port = -1; - //m_alsa->midiOut = nullptr; m_deviceID.clear(); } bool LinuxMidiOutPort::isConnected() const { - LOGI("---- linux isConnect ----"); return m_midiOutPortCurrent && !m_deviceID.empty(); } MidiDeviceID LinuxMidiOutPort::deviceID() const { - LOGI("---- linux deviceID ----"); return m_deviceID; } muse::async::Notification LinuxMidiOutPort::deviceChanged() const { - LOGI("---- linux deviceChanged ----"); return m_deviceChanged; } bool LinuxMidiOutPort::supportsMIDI20Output() const { - LOGI("---- linux supportsMIDI20Output ----"); return false; } muse::Ret LinuxMidiOutPort::sendEvent(const Event& e) { - // LOGI() << e.to_string(); - LOGI() << "---- linux sendEvent ----" << e.to_string(); - if (!isConnected()) { - LOGI() << "---- linux sendEvent NOT CONNECTED"; return make_ret(Err::MidiNotConnected); } @@ -188,14 +174,17 @@ muse::Ret LinuxMidiOutPort::sendEvent(const Event& e) return muse::Ret(true); } +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) + Event e2(e); + return muse::Ret(audioDriver()->pushMidiEvent(e2)); +#else // alsa return m_midiOutPortCurrent->sendEvent(e); +#endif } bool LinuxMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const { - LOGI("---- linux deviceExists ----"); for (const MidiDevice& device : availableDevices()) { - LOGI("---- linux deviceExists dev equal? %s <=> %s", deviceId.c_str(), device.id.c_str()); if (device.id == deviceId) { return true; } diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.h b/src/framework/midi/internal/platform/lin/linuxmidioutport.h index 3ca0fb3886d73..278e11604e1b7 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidioutport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.h @@ -25,6 +25,7 @@ #include #include "async/asyncable.h" +#include "framework/audio/audiomodule.h" #include "midi/imidioutport.h" #include "internal/midideviceslistener.h" @@ -60,7 +61,6 @@ class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable private: bool deviceExists(const MidiDeviceID& deviceId) const; - //std::shared_ptr m_alsa; MidiDeviceID m_deviceID; async::Notification m_deviceChanged; @@ -69,14 +69,13 @@ class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable mutable std::mutex m_devicesMutex; - // - MidiPortState* m_midiOutPortCurrent; + std::shared_ptr m_audioModule; + MidiPortState* m_midiOutPortCurrent; #if defined(JACK_AUDIO) std::unique_ptr m_midiOutPortJack; #endif std::unique_ptr m_midiOutPortAlsa; - }; } diff --git a/src/framework/midi/midimodule.cpp b/src/framework/midi/midimodule.cpp index 9777e493907be..41119b67c6dd5 100644 --- a/src/framework/midi/midimodule.cpp +++ b/src/framework/midi/midimodule.cpp @@ -86,8 +86,8 @@ void MidiModule::onInit(const IApplication::RunMode& mode) m_configuration->init(); if (mode == IApplication::RunMode::GuiApp) { - m_midiOutPort->init(); m_midiInPort->init(); + m_midiOutPort->init(); } } diff --git a/src/framework/midi/midiportstate.h b/src/framework/midi/midiportstate.h index d33d0dedc9ed5..95df6579cb1e0 100644 --- a/src/framework/midi/midiportstate.h +++ b/src/framework/midi/midiportstate.h @@ -28,7 +28,6 @@ namespace muse::midi { class MidiPortState { - public: virtual ~MidiPortState() = default; @@ -51,5 +50,4 @@ class MidiPortState }; } - #endif // MU_MIDI_MIDIPORTSTATE_H diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index 4dd4e97c5e3de..e175526789b0b 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -130,3 +130,8 @@ void AudioDriverStub::resume() void AudioDriverStub::suspend() { } + +bool AudioDriverStub::pushMidiEvent(muse::midi::Event&) +{ + return true; +} diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index bfba3859020bd..bfbeba498bbcb 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -44,6 +44,7 @@ class AudioDriverStub : public IAudioDriver AudioDeviceList availableOutputDevices() const override; async::Notification availableOutputDevicesChanged() const override; + bool pushMidiEvent(muse::midi::Event& e) override; unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; From 3a39d62828bfb9d25acfeebe0194888a290cb259 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Tue, 24 Oct 2023 22:03:02 +0200 Subject: [PATCH 18/60] route midi-in-devices from midi-inport to jack-audio --- src/framework/audio/iaudiodriver.h | 2 + .../platform/alsa/alsaaudiodriver.cpp | 10 +++- .../internal/platform/alsa/alsaaudiodriver.h | 1 + .../platform/jack/jackaudiodriver.cpp | 47 ++++++++++++++++- .../internal/platform/jack/jackaudiodriver.h | 5 +- .../platform/lin/linuxaudiodriver.cpp | 11 +++- .../internal/platform/lin/linuxaudiodriver.h | 1 + .../internal/platform/osx/osxaudiodriver.h | 1 + .../internal/platform/osx/osxaudiodriver.mm | 6 +++ .../platform/win/wasapiaudiodriver.cpp | 6 +++ .../internal/platform/win/wasapiaudiodriver.h | 2 + .../internal/platform/jack/jackmidiinport.cpp | 51 +++++++------------ .../internal/platform/jack/jackmidiinport.h | 10 +++- .../internal/platform/lin/linuxmidiinport.cpp | 11 ++-- .../internal/platform/lin/linuxmidiinport.h | 4 +- src/framework/stubs/audio/audiodriverstub.cpp | 6 +++ src/framework/stubs/audio/audiodriverstub.h | 1 + 17 files changed, 127 insertions(+), 48 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 9d0470dca5265..7fe9dde95bf92 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -91,6 +91,7 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual std::vector availableOutputDeviceSampleRates() const = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; + virtual std::vector availableMidiDevices() const = 0; virtual void resume() = 0; virtual void suspend() = 0; @@ -104,6 +105,7 @@ class AudioDriverState virtual void close() = 0; virtual bool isOpened() const = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; + virtual std::vector availableMidiDevices() const = 0; IAudioDriver::Spec m_spec; // current running spec std::string m_deviceId; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index d97f251233bc1..546533d734b13 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -97,7 +97,7 @@ void AlsaDriverState::alsaCleanup() std::string AlsaDriverState::name() const { - return "alsa"; + return m_deviceId; } std::string AlsaDriverState::deviceName() const @@ -194,7 +194,13 @@ bool AlsaDriverState::isOpened() const return m_alsaDeviceHandle != nullptr; } -bool AlsaDriverState::pushMidiEvent(muse::midi::Event& e) +bool AlsaDriverState::pushMidiEvent(muse::midi::Event&) { return true; // dummy } + +std::vector AlsaDriverState::availableMidiDevices() const +{ + std::vector x; + return x; // dummy +} diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index d7c0235db088d..63fce3ff261d2 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -37,6 +37,7 @@ class AlsaDriverState : public AudioDriverState void close() override; bool isOpened() const override; bool pushMidiEvent(muse::midi::Event& e) override; + std::vector availableMidiDevices() const override; std::string deviceName() const; void deviceName(const std::string newDeviceName); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 9e9ebf96cd1fc..d261a97860630 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -21,6 +21,7 @@ */ #include "jackaudiodriver.h" #include +#include "framework/midi/miditypes.h" #include "framework/midi/midierrors.h" #include @@ -41,6 +42,10 @@ using namespace muse::audio; using namespace muse::midi; namespace muse::audio { +/* + * MIDI + */ + muse::Ret sendEvent_noteonoff(void* pb, int framePos, const muse::midi::Event& e) { unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); @@ -120,6 +125,10 @@ muse::Ret sendEvent(const Event& e, void* pb) return Ret(true); } +/* + * AUDIO + */ + static int jack_process_callback(jack_nframes_t nframes, void* args) { JackDriverState* state = static_cast(args); @@ -266,7 +275,6 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a } // midi - jack_options_t options = (jack_options_t)0; int portFlag = JackPortIsOutput; const char* portType = JACK_DEFAULT_MIDI_TYPE; jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); @@ -288,8 +296,45 @@ bool JackDriverState::isOpened() const return m_jackDeviceHandle != nullptr; } +/* + * MIDI + */ + bool JackDriverState::pushMidiEvent(muse::midi::Event& e) { m_midiQueue.push(e); return true; } + +std::vector JackDriverState::availableMidiDevices() const +{ + std::vector ports; + std::vector ret; + jack_client_t* client = static_cast(m_jackDeviceHandle); + const char** prts = jack_get_ports(client, 0, 0, 0); + if (!prts) { + return ports; + } + int devIndex = 0; + for (const char** p = prts; p && *p; ++p) { + 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, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = 0; + if (strncmp(buffer, "MuseScore", 9) == 0) { + continue; + } + muse::midi::MidiDevice dev; + dev.name = buffer; + dev.id = makeUniqueDeviceId(devIndex++, 0, 0); + ports.push_back(std::move(dev)); + } + + free(prts); + + return ports; +} diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 1b51956845630..79eae99850b30 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -25,6 +25,7 @@ #include +#include "framework/midi/miditypes.h" #include "iaudiodriver.h" namespace muse::audio { @@ -38,16 +39,14 @@ class JackDriverState : public AudioDriverState bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; - //std::shared_ptr&> getAudioDriverQueue() const override; bool pushMidiEvent(muse::midi::Event& e) override; std::string deviceName() const; void deviceName(const std::string newDeviceName); + std::vector availableMidiDevices() const; void* m_jackDeviceHandle = nullptr; - float* m_buffer = nullptr; - std::vector m_outputPorts; std::vector m_midiOutputPorts; ThreadSafeQueue m_midiQueue; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 4297277f22512..8807aaddb0576 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -86,7 +86,7 @@ AudioDeviceID LinuxAudioDriver::outputDevice() const if (m_current_audioDriverState != nullptr) { return m_current_audioDriverState->m_deviceId; } else { - LOGE("device is not opened"); + LOGE() << "device is not opened, deviceId: " << m_deviceId; return m_deviceId; // FIX: should return optional type } } @@ -273,6 +273,15 @@ bool LinuxAudioDriver::pushMidiEvent(muse::midi::Event& e) return false; } +std::vector LinuxAudioDriver::availableMidiDevices() const +{ + if (m_current_audioDriverState) { + return m_current_audioDriverState->availableMidiDevices(); + } + std::vector x; + return x; +} + void LinuxAudioDriver::resume() { } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index 4fc9806360635..f26869314d434 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -59,6 +59,7 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; + std::vector availableMidiDevices() const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 7c0cacc1c78bf..d8ac5e78a6e63 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -68,6 +68,7 @@ class OSXAudioDriver : public IAudioDriver std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; + std::vector availableMidiDevices() const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index ce359732b9bea..a5b08bcb027f5 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -580,3 +580,9 @@ static OSStatus onDeviceListChanged(AudioObjectID inObjectID, UInt32 inNumberAdd { return true; // dummy } + +std::vector OSXAudioDriver::availableMidiDevices() const +{ + std::vector x; + return x; // dummy +} diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index 7da9eb4a75af5..933c141410bb4 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -372,3 +372,9 @@ bool WasapiAudioDriver::pushMidiEvent(muse::midi::Event&) { return true; } + +std::vector WasapiAudioDriver::availableMidiDevices() const +{ + std::vector x; + return x; // dummy +} diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 5bf180770422f..16d80a9ca08c5 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -65,6 +65,8 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceSampleRates() const override; bool pushMidiEvent(muse::midi::Event& e) override; + std::vector availableMidiDevices() const override; + void resume() override; void suspend() override; diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp index e129adbde7e76..21541ded15eea 100644 --- a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp +++ b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp @@ -19,6 +19,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +//#include "linuxmidiinport.h" #include "jackmidiinport.h" #include @@ -34,7 +35,6 @@ using namespace muse::midi; void JackMidiInPort::init() { - LOGI("---- linux JACK-midi input init ----"); m_jack = std::make_unique(); } @@ -45,35 +45,7 @@ void JackMidiInPort::deinit() } } -std::vector JackMidiInPort::availableDevices() const -{ - std::vector ports; - - std::vector ret; - - const char** prts = jack_get_ports(m_jack->client, 0, 0, 0); - int devIndex = 0; - for (const char** p = prts; p && *p; ++p) { - jack_port_t* port = jack_port_by_name(m_jack->client, *p); - int flags = jack_port_flags(port); - if (!(flags & JackPortIsInput)) { - continue; - } - char buffer[128]; - strncpy(buffer, *p, sizeof(buffer) - 1); - buffer[sizeof(buffer) - 1] = 0; - if (strncmp(buffer, "MuseScore", 9) == 0) { - continue; - } - MidiDevice dev; - dev.name = buffer; - dev.id = makeUniqueDeviceId(devIndex++, 0, 0); - ports.push_back(std::move(dev)); - } - return ports; -} - -muse::Ret JackMidiInPort::connect(const MidiDeviceID& deviceID) +muse::Ret JackMidiInPort::connect(const MidiDeviceID&) { return muse::Ret(true); } @@ -84,7 +56,6 @@ void JackMidiInPort::disconnect() bool JackMidiInPort::isConnected() const { - LOGI("---- JACK input isConnect ----"); return m_jack && m_jack->midiIn && !m_deviceID.empty(); } @@ -95,7 +66,6 @@ MidiDeviceID JackMidiInPort::deviceID() const bool JackMidiInPort::deviceExists(const MidiDeviceID& deviceId) const { - LOGI("---- JACK-midi input deviceExists ----"); for (const MidiDevice& device : availableDevices()) { if (device.id == deviceId) { return true; @@ -104,3 +74,20 @@ bool JackMidiInPort::deviceExists(const MidiDeviceID& deviceId) const return false; } + +bool JackMidiInPort::supportsMIDI20Output() const +{ + return false; +} + +// dummy +muse::Ret JackMidiInPort::sendEvent(const Event&) +{ + return muse::make_ok(); +} + +std::vector JackMidiInPort::availableDevices() const +{ + std::vector x; + return x; // dummy +} diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.h b/src/framework/midi/internal/platform/jack/jackmidiinport.h index 2a4605bf6932e..cdb00af0717c2 100644 --- a/src/framework/midi/internal/platform/jack/jackmidiinport.h +++ b/src/framework/midi/internal/platform/jack/jackmidiinport.h @@ -39,11 +39,17 @@ class JackMidiInPort : public MidiPortState void disconnect() override; bool isConnected() const override; MidiDeviceID deviceID() const override; + bool supportsMIDI20Output() const override; + Ret sendEvent(const Event& e) override; private: bool deviceExists(const MidiDeviceID& deviceId) const; - - struct Jack; + struct Jack { + void* midiIn = nullptr; + void* client = nullptr; + int port = -1; + int segmentSize; + }; std::unique_ptr m_jack; MidiDeviceID m_deviceID; }; diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp index a6eeaac7ef8dd..f9f36bf7877eb 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -32,13 +32,14 @@ using namespace muse::midi; void LinuxMidiInPort::init(std::shared_ptr am) { - //m_alsa = std::make_shared(); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - LOGI("-- init using audiomodule: %lx", am); + m_audioModule = am; +#endif - //std::shared_ptr ad = am->getDriver(); - //LOGI("-- init got audiodriver: %lx", ad); - //LOGI("-- audiohandle: %lx", ad->getAudioDriverHandle()); +#if defined(JACK_AUDIO) + m_midiInPortJack = std::make_unique(); +#else + m_midiInPortAlsa = std::make_unique(); #endif } diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.h b/src/framework/midi/internal/platform/lin/linuxmidiinport.h index 20f2b67bed75d..7c57ebd9b3eb4 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.h @@ -81,9 +81,9 @@ class LinuxMidiInPort : public IMidiInPort, public async::Asyncable async::Channel m_eventReceived; #if defined(JACK_AUDIO) - std::shared_ptr m_midiInPortJack; + std::unique_ptr m_midiInPortJack; #endif - std::shared_ptr m_midiInPortAlsa; + std::unique_ptr m_midiInPortAlsa; }; } diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index e175526789b0b..aeaddee59586a 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -135,3 +135,9 @@ bool AudioDriverStub::pushMidiEvent(muse::midi::Event&) { return true; } + +std::vector AudioDriverStub::availableMidiDevices() const +{ + std::vector x; + return x; // dummy +} diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index bfbeba498bbcb..c71e4988ff94d 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -45,6 +45,7 @@ class AudioDriverStub : public IAudioDriver AudioDeviceList availableOutputDevices() const override; async::Notification availableOutputDevicesChanged() const override; bool pushMidiEvent(muse::midi::Event& e) override; + std::vector availableMidiDevices() const override; unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; From ef16f14fbc2c2adca31548d66f864b8749ae413d Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 18 Nov 2023 19:39:49 +0100 Subject: [PATCH 19/60] register jack midi inport --- .../platform/jack/jackaudiodriver.cpp | 42 +++++++++++++++++-- .../internal/platform/jack/jackaudiodriver.h | 2 + 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index d261a97860630..c7c254cde2651 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -23,6 +23,7 @@ #include #include "framework/midi/miditypes.h" #include "framework/midi/midierrors.h" +#include "framework/midi/imidiinport.h" #include #include @@ -143,7 +144,7 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) *l++ = *sp++; *r++ = *sp++; } - + jack_client_t* client = static_cast(state->m_jackDeviceHandle); // if (!isConnected()) { // LOGI() << "---- JACK-midi output sendEvent SORRY, not connected"; // return make_ret(Err::MidiNotConnected); @@ -151,9 +152,10 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) if (!state->m_midiOutputPorts.empty()) { jack_port_t* port = state->m_midiOutputPorts.front(); if (port) { - int segmentSize = jack_get_buffer_size(static_cast(state->m_jackDeviceHandle)); + int segmentSize = jack_get_buffer_size(client); void* pb = jack_port_get_buffer(port, segmentSize); // handle midi + // FIX: can portBuffer be nullptr? muse::midi::Event e; while (1) { if (state->m_midiQueue.pop(e)) { @@ -174,6 +176,36 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) } } + if (!state->m_midiInputPorts.empty()) { + jack_port_t* port = state->m_midiInputPorts.front(); + if (port) { + int segmentSize = jack_get_buffer_size(client); + void* pb = jack_port_get_buffer(port, segmentSize); + if (pb) { + muse::midi::Event ev; + jack_nframes_t n = jack_midi_get_event_count(pb); + for (jack_nframes_t i = 0; i < n; ++i) { + jack_midi_event_t event; + if (jack_midi_event_get(&event, pb, i) != 0) continue; + int type = event.buffer[0]; + uint32_t data = 0; + if ((type & 0xf0) == 0x90 || + (type & 0xf0) == 0x90) { + data = 0x90 + | (type & 0x0f) + | ((event.buffer[1] & 0x7F) << 8) + | ((event.buffer[2] & 0x7F) << 16); + Event e = Event::fromMIDI10Package(data); + e = e.toMIDI20(); + if (e) { + state->m_eventReceived.send(static_cast(0), e); + } + } + } + } + } + } + return 0; } @@ -274,7 +306,11 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } - // midi + // midi input + jack_port_t* midi_input_port = jack_port_register (handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + m_midiInputPorts.push_back(midi_input_port); + + // midi output int portFlag = JackPortIsOutput; const char* portType = JACK_DEFAULT_MIDI_TYPE; jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 79eae99850b30..85baefc747d3d 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -48,8 +48,10 @@ class JackDriverState : public AudioDriverState void* m_jackDeviceHandle = nullptr; float* m_buffer = nullptr; std::vector m_outputPorts; + std::vector m_midiInputPorts; std::vector m_midiOutputPorts; ThreadSafeQueue m_midiQueue; + async::Channel m_eventReceived; private: std::string m_deviceName; From d123134a9caffeb1babac914100258c8261536e7 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 18 Nov 2023 20:13:40 +0100 Subject: [PATCH 20/60] let audiomodule know about midimodule --- src/framework/audio/audiomodule.cpp | 1 + src/framework/audio/iaudiodriver.h | 1 + .../platform/alsa/alsaaudiodriver.cpp | 5 +++++ .../internal/platform/alsa/alsaaudiodriver.h | 2 ++ .../platform/jack/jackaudiodriver.cpp | 19 +++++++++++++++---- .../internal/platform/jack/jackaudiodriver.h | 3 ++- .../platform/lin/linuxaudiodriver.cpp | 10 ++++++++++ .../internal/platform/lin/linuxaudiodriver.h | 3 +++ .../platform/jack/jackmidioutport.cpp | 1 + .../internal/platform/jack/jackmidioutport.h | 1 - .../internal/platform/lin/linuxmidiinport.cpp | 6 +----- .../internal/platform/lin/linuxmidiinport.h | 4 +++- .../internal/platform/lin/linuxmidioutport.h | 4 ++-- 13 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index 00ae7d37a013b..ee70f8173bb23 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -24,6 +24,7 @@ #include "ui/iuiengine.h" #include "global/modularity/ioc.h" +#include "framework/midi/midimodule.h" #include "internal/audioconfiguration.h" #include "internal/audiosanitizer.h" #include "internal/audiothread.h" diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 7fe9dde95bf92..36c10beae66c4 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -105,6 +105,7 @@ class AudioDriverState virtual void close() = 0; virtual bool isOpened() const = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; + virtual void registerMidiInputQueue(async::Channel) = 0; virtual std::vector availableMidiDevices() const = 0; IAudioDriver::Spec m_spec; // current running spec diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 546533d734b13..60fb874f2f89e 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -199,6 +199,11 @@ bool AlsaDriverState::pushMidiEvent(muse::midi::Event&) return true; // dummy } +void AlsaDriverState::registerMidiInputQueue(async::Channel midiInputQueue) +{ + m_eventReceived = midiInputQueue; +} + std::vector AlsaDriverState::availableMidiDevices() const { std::vector x; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 63fce3ff261d2..f41c355fcefd5 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -37,6 +37,7 @@ class AlsaDriverState : public AudioDriverState void close() override; bool isOpened() const override; bool pushMidiEvent(muse::midi::Event& e) override; + void registerMidiInputQueue(async::Channel) override; std::vector availableMidiDevices() const override; std::string deviceName() const; void deviceName(const std::string newDeviceName); @@ -47,6 +48,7 @@ class AlsaDriverState : public AudioDriverState bool m_audioProcessingDone = false; pthread_t m_threadHandle = 0; private: + async::Channel m_eventReceived; std::string m_deviceName = "default"; void alsaCleanup(); }; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index c7c254cde2651..8674a5726e42e 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -186,11 +186,13 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) jack_nframes_t n = jack_midi_get_event_count(pb); for (jack_nframes_t i = 0; i < n; ++i) { jack_midi_event_t event; - if (jack_midi_event_get(&event, pb, i) != 0) continue; + if (jack_midi_event_get(&event, pb, i) != 0) { + continue; + } int type = event.buffer[0]; uint32_t data = 0; - if ((type & 0xf0) == 0x90 || - (type & 0xf0) == 0x90) { + if ((type & 0xf0) == 0x90 + || (type & 0xf0) == 0x90) { data = 0x90 | (type & 0x0f) | ((event.buffer[1] & 0x7F) << 8) @@ -198,6 +200,10 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) Event e = Event::fromMIDI10Package(data); e = e.toMIDI20(); if (e) { + LOGI("-- jack midi-input-port send %i,%i,%i", + event.buffer[1], + event.buffer[2], + event.buffer[0]); state->m_eventReceived.send(static_cast(0), e); } } @@ -307,7 +313,7 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a } // midi input - jack_port_t* midi_input_port = jack_port_register (handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + jack_port_t* midi_input_port = jack_port_register(handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); m_midiInputPorts.push_back(midi_input_port); // midi output @@ -342,6 +348,11 @@ bool JackDriverState::pushMidiEvent(muse::midi::Event& e) return true; } +void JackDriverState::registerMidiInputQueue(async::Channel midiInputQueue) +{ + m_eventReceived = midiInputQueue; +} + std::vector JackDriverState::availableMidiDevices() const { std::vector ports; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 85baefc747d3d..7a33d86faa393 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -40,6 +40,7 @@ class JackDriverState : public AudioDriverState void close() override; bool isOpened() const override; bool pushMidiEvent(muse::midi::Event& e) override; + void registerMidiInputQueue(async::Channel) override; std::string deviceName() const; void deviceName(const std::string newDeviceName); @@ -51,7 +52,7 @@ class JackDriverState : public AudioDriverState std::vector m_midiInputPorts; std::vector m_midiOutputPorts; ThreadSafeQueue m_midiQueue; - async::Channel m_eventReceived; + async::Channel m_eventReceived; private: std::string m_deviceName; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 8807aaddb0576..72bbfb6863453 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -59,6 +59,16 @@ std::string LinuxAudioDriver::name() const bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) { + /**************************************************************************/ + // a bit lazy registering the midi-input-queue here, but midimodule isn't + // available at audiomodule init, because midimodule starts after audiomodule + // not sure we got the identity of eventQueue (ie, passed by reference) +#if defined(JACK_AUDIO) + muse::async::Channel queue = midiInPort()->eventReceived(); + m_current_audioDriverState->registerMidiInputQueue(queue); +#endif + /**************************************************************************/ + if (!m_current_audioDriverState->open(spec, activeSpec)) { return false; } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index f26869314d434..6fa010a871fa9 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -25,6 +25,8 @@ #include "async/asyncable.h" +#include "framework/midi/imidiinport.h" +#include "framework/midi/midimodule.h" #include "iaudiodriver.h" #include "audiodeviceslistener.h" @@ -32,6 +34,7 @@ namespace muse::audio { class LinuxAudioDriver : public IAudioDriver, public async::Asyncable { + Inject midiInPort; public: LinuxAudioDriver(); ~LinuxAudioDriver(); diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp index cf5318d501e8c..926ecccef8f67 100644 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp @@ -33,6 +33,7 @@ using namespace muse::midi; void JackMidiOutPort::init() { + m_jack = std::make_unique(); } void JackMidiOutPort::deinit() diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.h b/src/framework/midi/internal/platform/jack/jackmidioutport.h index 80aa2fdd7417f..70fc45aecc9bb 100644 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.h +++ b/src/framework/midi/internal/platform/jack/jackmidioutport.h @@ -46,7 +46,6 @@ class JackMidiOutPort : public MidiPortState private: bool deviceExists(const MidiDeviceID& deviceId) const; - std::shared_ptr m_audioDriver; std::shared_ptr > m_midiQueue; struct Jack { void* midiOut = nullptr; diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp index f9f36bf7877eb..8c0d668fab717 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -30,12 +30,8 @@ using namespace muse::midi; -void LinuxMidiInPort::init(std::shared_ptr am) +void LinuxMidiInPort::init() { -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - m_audioModule = am; -#endif - #if defined(JACK_AUDIO) m_midiInPortJack = std::make_unique(); #else diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.h b/src/framework/midi/internal/platform/lin/linuxmidiinport.h index 7c57ebd9b3eb4..878016bedd91f 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.h @@ -25,9 +25,11 @@ #include #include +#include "modularity/ioc.h" #include "async/asyncable.h" #include "framework/audio/audiomodule.h" +#include "framework/audio/iaudiodriver.h" #include "imidiinport.h" #include "internal/midideviceslistener.h" @@ -45,7 +47,7 @@ class LinuxMidiInPort : public IMidiInPort, public async::Asyncable LinuxMidiInPort() = default; ~LinuxMidiInPort() = default; - void init(std::shared_ptr am); + void init(); void deinit(); std::vector availableDevices() const override; diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.h b/src/framework/midi/internal/platform/lin/linuxmidioutport.h index 278e11604e1b7..dd7be182637a5 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidioutport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.h @@ -24,6 +24,7 @@ #include +#include "modularity/ioc.h" #include "async/asyncable.h" #include "framework/audio/audiomodule.h" #include "midi/imidioutport.h" @@ -38,6 +39,7 @@ namespace muse::midi { class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable { + Inject audioDriver; public: LinuxMidiOutPort() = default; ~LinuxMidiOutPort() = default; @@ -69,8 +71,6 @@ class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable mutable std::mutex m_devicesMutex; - std::shared_ptr m_audioModule; - MidiPortState* m_midiOutPortCurrent; #if defined(JACK_AUDIO) std::unique_ptr m_midiOutPortJack; From 3b1b4d49102d05b4c6510556138a73960cb5b234 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 9 Dec 2023 17:38:35 +0100 Subject: [PATCH 21/60] GUI filter musescore-ingress midiport --- src/framework/audio/iaudiodriver.h | 4 ++-- .../internal/platform/alsa/alsaaudiodriver.cpp | 2 +- .../audio/internal/platform/alsa/alsaaudiodriver.h | 2 +- .../internal/platform/jack/jackaudiodriver.cpp | 14 +++++++++++--- .../audio/internal/platform/jack/jackaudiodriver.h | 2 +- .../internal/platform/lin/linuxaudiodriver.cpp | 4 ++-- .../audio/internal/platform/lin/linuxaudiodriver.h | 2 +- .../audio/internal/platform/osx/osxaudiodriver.h | 2 +- .../audio/internal/platform/osx/osxaudiodriver.mm | 2 +- .../internal/platform/win/wasapiaudiodriver.cpp | 2 +- .../internal/platform/win/wasapiaudiodriver.h | 2 +- .../midi/internal/platform/lin/linuxmidiinport.cpp | 3 ++- src/framework/midi/miditypes.h | 9 +++++++++ src/framework/stubs/audio/audiodriverstub.cpp | 2 +- src/framework/stubs/audio/audiodriverstub.h | 2 +- 15 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 36c10beae66c4..bd24845ca68ee 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -91,7 +91,7 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual std::vector availableOutputDeviceSampleRates() const = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; - virtual std::vector availableMidiDevices() const = 0; + virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; virtual void resume() = 0; virtual void suspend() = 0; @@ -106,7 +106,7 @@ class AudioDriverState virtual bool isOpened() const = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; virtual void registerMidiInputQueue(async::Channel) = 0; - virtual std::vector availableMidiDevices() const = 0; + virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; IAudioDriver::Spec m_spec; // current running spec std::string m_deviceId; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 60fb874f2f89e..4e30a8fc2b2f3 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -204,7 +204,7 @@ void AlsaDriverState::registerMidiInputQueue(async::Channel AlsaDriverState::availableMidiDevices() const +std::vector AlsaDriverState::availableMidiDevices(muse::midi::MidiPortDirection direction) const { std::vector x; return x; // dummy diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index f41c355fcefd5..2d87e6b0e9622 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -38,7 +38,7 @@ class AlsaDriverState : public AudioDriverState bool isOpened() const override; bool pushMidiEvent(muse::midi::Event& e) override; void registerMidiInputQueue(async::Channel) override; - std::vector availableMidiDevices() const override; + std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; std::string deviceName() const; void deviceName(const std::string newDeviceName); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 8674a5726e42e..139d65c0c7271 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -353,12 +353,12 @@ void JackDriverState::registerMidiInputQueue(async::Channel JackDriverState::availableMidiDevices() const +std::vector JackDriverState::availableMidiDevices(muse::midi::MidiPortDirection direction) const { std::vector ports; std::vector ret; jack_client_t* client = static_cast(m_jackDeviceHandle); - const char** prts = jack_get_ports(client, 0, 0, 0); + const char** prts = jack_get_ports(client, 0, "midi", 0); if (!prts) { return ports; } @@ -366,12 +366,20 @@ std::vector JackDriverState::availableMidiDevices() cons for (const char** p = prts; p && *p; ++p) { jack_port_t* port = jack_port_by_name(client, *p); int flags = jack_port_flags(port); - if (!(flags & JackPortIsInput)) { + + if ((flags & JackPortIsInput) + && direction == muse::midi::MidiPortDirection::Output) { + continue; + } + if ((flags & JackPortIsOutput) + && direction == muse::midi::MidiPortDirection::Input) { continue; } + char buffer[128]; strncpy(buffer, *p, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = 0; + if (strncmp(buffer, "MuseScore", 9) == 0) { continue; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 7a33d86faa393..b919dbbe2eaf1 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -44,7 +44,7 @@ class JackDriverState : public AudioDriverState std::string deviceName() const; void deviceName(const std::string newDeviceName); - std::vector availableMidiDevices() const; + std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const; void* m_jackDeviceHandle = nullptr; float* m_buffer = nullptr; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 72bbfb6863453..0c7f3d02d39cb 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -283,10 +283,10 @@ bool LinuxAudioDriver::pushMidiEvent(muse::midi::Event& e) return false; } -std::vector LinuxAudioDriver::availableMidiDevices() const +std::vector LinuxAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection direction) const { if (m_current_audioDriverState) { - return m_current_audioDriverState->availableMidiDevices(); + return m_current_audioDriverState->availableMidiDevices(direction); } std::vector x; return x; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index 6fa010a871fa9..2074a599cc783 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -62,7 +62,7 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices() const override; + std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index d8ac5e78a6e63..e59049e88eda2 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -68,7 +68,7 @@ class OSXAudioDriver : public IAudioDriver std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices() const override; + std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index a5b08bcb027f5..22f32daacc449 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -581,7 +581,7 @@ static OSStatus onDeviceListChanged(AudioObjectID inObjectID, UInt32 inNumberAdd return true; // dummy } -std::vector OSXAudioDriver::availableMidiDevices() const +std::vector OSXAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection dir) const { std::vector x; return x; // dummy diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index 933c141410bb4..ca3384bad7240 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -373,7 +373,7 @@ bool WasapiAudioDriver::pushMidiEvent(muse::midi::Event&) return true; } -std::vector WasapiAudioDriver::availableMidiDevices() const +std::vector WasapiAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection dir) const { std::vector x; return x; // dummy diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 16d80a9ca08c5..f2b59acf803f4 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -65,7 +65,7 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceSampleRates() const override; bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices() const override; + std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; void resume() override; void suspend() override; diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp index 8c0d668fab717..5d03888dde83f 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -50,7 +50,8 @@ std::vector LinuxMidiInPort::availableDevices() const { // FIX: this is compile-time, change so that we call availableMidiDevices if jack is selected #if defined(JACK_AUDIO) - return audioDriver()->availableMidiDevices(); + // the external jack-midi-ports that are connecing to Musescore are of output type + return audioDriver()->availableMidiDevices(muse::midi::MidiPortDirection::Output); #else std::lock_guard lock(m_devicesMutex); std::vector ret; diff --git a/src/framework/midi/miditypes.h b/src/framework/midi/miditypes.h index 9bff74e0da844..58532d1b2f37c 100644 --- a/src/framework/midi/miditypes.h +++ b/src/framework/midi/miditypes.h @@ -47,6 +47,15 @@ static constexpr int EXPRESSION_CONTROLLER = 11; static constexpr int SUSTAIN_PEDAL_CONTROLLER = 64; static constexpr int SOSTENUTO_PEDAL_CONTROLLER = 66; +// input/output relative to context +// ie, a MusescoreIngress port would be an external jack-midi output port +enum class MidiPortDirection +{ + Any, + Input, + Output +}; + struct Program { Program(bank_t b = 0, program_t p = 0) : bank(b), program(p) {} diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index aeaddee59586a..3b95fceca4abc 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -136,7 +136,7 @@ bool AudioDriverStub::pushMidiEvent(muse::midi::Event&) return true; } -std::vector AudioDriverStub::availableMidiDevices() const +std::vector AudioDriverStub::availableMidiDevices(muse::midi::MidiPortDirection direction) const { std::vector x; return x; // dummy diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index c71e4988ff94d..9046c81524d5d 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -45,7 +45,7 @@ class AudioDriverStub : public IAudioDriver AudioDeviceList availableOutputDevices() const override; async::Notification availableOutputDevicesChanged() const override; bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices() const override; + std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; From 372a3574ae8cc2f64e31123b9f3ed52e3c2d9121 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 7 Mar 2024 07:20:37 +0100 Subject: [PATCH 22/60] alsa: report errors + better alsa names --- src/framework/midi/internal/platform/alsa/alsamidioutport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp index 1b2ab9afc930c..44fe54a6546eb 100644 --- a/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp +++ b/src/framework/midi/internal/platform/alsa/alsamidioutport.cpp @@ -91,7 +91,7 @@ std::vector AlsaMidiOutPort::availableDevices() const err = snd_seq_open(&handle, "hw", streams, 0); if (err < 0) { - /* Use snd_strerror(errno) to get the error here. */ + LOGE("snd_seq_open failed: err: %s", snd_strerror(err)); return ret; } @@ -117,7 +117,7 @@ std::vector AlsaMidiOutPort::availableDevices() const if (canConnect) { MidiDevice dev; - dev.name = snd_seq_client_info_get_name(cinfo); + dev.name = "ALSA/" + std::string(snd_seq_client_info_get_name(cinfo)); int client = snd_seq_port_info_get_client(pinfo); int port = snd_seq_port_info_get_port(pinfo); dev.id = makeUniqueDeviceId(index++, client, port); From 0a6d65a28740bbc5b5b453fb7dd3084aea110256 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 31 Mar 2024 09:39:11 +0200 Subject: [PATCH 23/60] jack: use playbackcontroller remoteSeek/remotePlayOrStop --- src/framework/audio/internal/platform/jack/jackaudiodriver.h | 4 +++- .../audio/internal/platform/lin/linuxaudiodriver.cpp | 2 +- src/framework/audio/internal/platform/lin/linuxaudiodriver.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index b919dbbe2eaf1..3c488908c55c1 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -27,12 +27,13 @@ #include "framework/midi/miditypes.h" #include "iaudiodriver.h" +#include "playback/iplaybackcontroller.h" namespace muse::audio { class JackDriverState : public AudioDriverState { public: - JackDriverState(); + JackDriverState(std::shared_ptr); ~JackDriverState(); std::string name() const override; @@ -53,6 +54,7 @@ class JackDriverState : public AudioDriverState std::vector m_midiOutputPorts; ThreadSafeQueue m_midiQueue; async::Channel m_eventReceived; + std::shared_ptr m_playbackController; private: std::string m_deviceName; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 0c7f3d02d39cb..38ebd17613beb 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -105,7 +105,7 @@ bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) { #if defined(JACK_AUDIO) if (deviceId == "jack") { - m_current_audioDriverState = std::make_unique(); + m_current_audioDriverState = std::make_unique(playbackController()); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) } else if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index 2074a599cc783..ede0b3def9f8c 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -30,10 +30,12 @@ #include "iaudiodriver.h" #include "audiodeviceslistener.h" +#include "playback/iplaybackcontroller.h" namespace muse::audio { class LinuxAudioDriver : public IAudioDriver, public async::Asyncable { + Inject playbackController; Inject midiInPort; public: LinuxAudioDriver(); From 4c5a5cdde0b6495e5c2709f73d8cb3b1a72de162 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 31 Mar 2024 09:36:40 +0200 Subject: [PATCH 24/60] cli audioDelayCompensate in frames A commandline-option to handle changes in the jack-transport delay caused by buffering. --- src/app/cmdoptions.h | 4 ++++ src/app/internal/commandlineparser.cpp | 6 ++++++ src/app/internal/consoleapp.cpp | 2 ++ src/app/internal/consoleapp.h | 2 ++ src/framework/audio/audiomodule.cpp | 2 +- src/framework/audio/iaudioconfiguration.h | 3 +++ src/framework/audio/iaudiodriver.h | 4 ++++ .../audio/internal/audioconfiguration.cpp | 10 ++++++++++ .../audio/internal/audioconfiguration.h | 4 ++++ .../internal/platform/alsa/alsaaudiodriver.cpp | 4 ++++ .../internal/platform/alsa/alsaaudiodriver.h | 1 + .../internal/platform/lin/linuxaudiodriver.cpp | 17 +++++++++++++++++ .../internal/platform/lin/linuxaudiodriver.h | 5 +++++ .../internal/platform/osx/osxaudiodriver.h | 3 +++ .../internal/platform/osx/osxaudiodriver.mm | 9 +++++++++ .../internal/platform/win/wasapiaudiodriver.cpp | 9 +++++++++ .../internal/platform/win/wasapiaudiodriver.h | 2 ++ .../stubs/audio/audioconfigurationstub.cpp | 9 +++++++++ .../stubs/audio/audioconfigurationstub.h | 3 +++ src/framework/stubs/audio/audiodriverstub.cpp | 9 +++++++++ src/framework/stubs/audio/audiodriverstub.h | 3 +++ 21 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/app/cmdoptions.h b/src/app/cmdoptions.h index 3e1e2be50109e..47bbfaa1bfbf9 100644 --- a/src/app/cmdoptions.h +++ b/src/app/cmdoptions.h @@ -63,6 +63,10 @@ struct CmdOptions { std::optional pngDpiResolution; } exportImage; + struct { + std::optional audioDelayCompensate; + } audio; + struct { std::optional mp3Bitrate; } exportAudio; diff --git a/src/app/internal/commandlineparser.cpp b/src/app/internal/commandlineparser.cpp index 9db35c83e2acc..ec41a11ea6198 100644 --- a/src/app/internal/commandlineparser.cpp +++ b/src/app/internal/commandlineparser.cpp @@ -163,6 +163,8 @@ void CommandLineParser::init() "Check an audio plugin for compatibility with the application and register it", "path")); m_parser.addOption(QCommandLineOption("register-failed-audio-plugin", "Register an incompatible audio plugin", "path")); + m_parser.addOption(QCommandLineOption("audioDelayCompensate", "Compensate for delay in frames caused by MuseScore buffering", "1024")); + // Internal m_parser.addOption(internalCommandLineOption("score-display-name-override", "Display name to be shown in splash screen for the score that is being opened", "name")); @@ -275,6 +277,10 @@ void CommandLineParser::parse(int argc, char** argv) m_options.audioPluginRegistration.failCode = !args1.empty() ? args1[0].toInt() : -1; } + if (m_parser.isSet("audioDelayCompensate")) { + m_options.audio.audioDelayCompensate = intValue("audioDelayCompensate"); + } + // Converter mode if (m_parser.isSet("r")) { std::optional val = floatValue("r"); diff --git a/src/app/internal/consoleapp.cpp b/src/app/internal/consoleapp.cpp index b6fbea94992e7..46e1edaf3f7b8 100644 --- a/src/app/internal/consoleapp.cpp +++ b/src/app/internal/consoleapp.cpp @@ -211,6 +211,8 @@ void ConsoleApp::applyCommandLineOptions(const CmdOptions& options, IApplication notationConfiguration()->setTemplateModeEnabled(options.notation.templateModeEnabled); notationConfiguration()->setTestModeEnabled(options.notation.testModeEnabled); + audioConfiguration()->setAudioDelayCompensate(options.audio.audioDelayCompensate.value_or(1024)); // FIX: equal to buffer-size + if (runMode == IApplication::RunMode::ConsoleApp) { project::MigrationOptions migration; migration.appVersion = mu::engraving::Constants::MSC_VERSION; diff --git a/src/app/internal/consoleapp.h b/src/app/internal/consoleapp.h index 024254b705e1c..d8d4614420911 100644 --- a/src/app/internal/consoleapp.h +++ b/src/app/internal/consoleapp.h @@ -38,6 +38,7 @@ #include "engraving/devtools/drawdata/idiagnosticdrawprovider.h" #include "autobot/iautobot.h" #include "audioplugins/iregisteraudiopluginsscenario.h" +#include "audio/iaudioconfiguration.h" #include "multiinstances/imultiinstancesprovider.h" #include "ui/iuiconfiguration.h" @@ -68,6 +69,7 @@ class ConsoleApp : public muse::BaseApplication, public std::enable_shared_from_ muse::Inject notationConfiguration; muse::Inject projectConfiguration; muse::Inject soundProfilesRepository; + muse::Inject audioConfiguration; muse::Inject imagesExportConfiguration; muse::Inject midiImportExportConfiguration; muse::Inject audioExportConfiguration; diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index ee70f8173bb23..1bcdd4810366c 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -259,7 +259,7 @@ void AudioModule::setupAudioDriver(const IApplication::RunMode& mode) if (mode == IApplication::RunMode::GuiApp) { m_audioDriver->init(); - + m_audioDriver->setAudioDelayCompensate(m_configuration->audioDelayCompensate()); IAudioDriver::Spec activeSpec; if (m_audioDriver->open(requiredSpec, &activeSpec)) { setupAudioWorker(activeSpec); diff --git a/src/framework/audio/iaudioconfiguration.h b/src/framework/audio/iaudioconfiguration.h index b210eb3628e59..27bab87a94d0f 100644 --- a/src/framework/audio/iaudioconfiguration.h +++ b/src/framework/audio/iaudioconfiguration.h @@ -63,6 +63,9 @@ class IAudioConfiguration : MODULE_EXPORT_INTERFACE virtual async::Notification sampleRateChanged() const = 0; virtual size_t desiredAudioThreadNumber() const = 0; + virtual int audioDelayCompensate() const = 0; + virtual void setAudioDelayCompensate(const int frames) = 0; + virtual size_t minTrackCountForMultithreading() const = 0; // synthesizers diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index bd24845ca68ee..e63c45b6a3c52 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -90,6 +90,9 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual async::Notification outputDeviceSampleRateChanged() const = 0; virtual std::vector availableOutputDeviceSampleRates() const = 0; + virtual int audioDelayCompensate() const = 0; + virtual void setAudioDelayCompensate(const int frames) = 0; + virtual bool pushMidiEvent(muse::midi::Event&) = 0; virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; @@ -104,6 +107,7 @@ class AudioDriverState virtual bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) = 0; virtual void close() = 0; virtual bool isOpened() const = 0; + virtual void setAudioDelayCompensate(const int frames) = 0; virtual bool pushMidiEvent(muse::midi::Event&) = 0; virtual void registerMidiInputQueue(async::Channel) = 0; virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; diff --git a/src/framework/audio/internal/audioconfiguration.cpp b/src/framework/audio/internal/audioconfiguration.cpp index 9fe6516c56384..0b5ac64631d14 100644 --- a/src/framework/audio/internal/audioconfiguration.cpp +++ b/src/framework/audio/internal/audioconfiguration.cpp @@ -206,6 +206,16 @@ size_t AudioConfiguration::desiredAudioThreadNumber() const return settings()->value(AUDIO_DESIRED_THREAD_NUMBER_KEY).toInt(); } +int AudioConfiguration::audioDelayCompensate() const +{ + return m_audioDelayCompensate; +} + +void AudioConfiguration::setAudioDelayCompensate(const int frames) +{ + m_audioDelayCompensate = frames; +} + size_t AudioConfiguration::minTrackCountForMultithreading() const { // Start mutlithreading-processing only when there are more or equal number of tracks diff --git a/src/framework/audio/internal/audioconfiguration.h b/src/framework/audio/internal/audioconfiguration.h index 453c68b2f8cc3..41aedfbc110e9 100644 --- a/src/framework/audio/internal/audioconfiguration.h +++ b/src/framework/audio/internal/audioconfiguration.h @@ -66,6 +66,9 @@ class AudioConfiguration : public IAudioConfiguration, public Injectable async::Notification sampleRateChanged() const override; size_t desiredAudioThreadNumber() const override; + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; + size_t minTrackCountForMultithreading() const override; // synthesizers @@ -80,6 +83,7 @@ class AudioConfiguration : public IAudioConfiguration, public Injectable private: void updateSamplesToPreallocate(); + int m_audioDelayCompensate = 0; async::Channel m_soundFontDirsChanged; async::Channel m_samplesToPreallocateChanged; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 4e30a8fc2b2f3..09450f8b76c4c 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -110,6 +110,10 @@ void AlsaDriverState::deviceName(const std::string newDeviceName) m_deviceName = newDeviceName; } +void AlsaDriverState::setAudioDelayCompensate([[maybe_unused]] const int frames) +{ +} + bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { m_spec.samples = spec.samples; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 2d87e6b0e9622..ee72de31bc8db 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -36,6 +36,7 @@ class AlsaDriverState : public AudioDriverState bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; + void setAudioDelayCompensate(const int frames) override; bool pushMidiEvent(muse::midi::Event& e) override; void registerMidiInputQueue(async::Channel) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 38ebd17613beb..8d10c2dd9bb73 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -69,6 +69,9 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) #endif /**************************************************************************/ + // re-initialize devide + m_current_audioDriverState->setAudioDelayCompensate(m_audioDelayCompensate); + if (!m_current_audioDriverState->open(spec, activeSpec)) { return false; } @@ -138,6 +141,10 @@ bool LinuxAudioDriver::reopen(const AudioDeviceID& deviceId, Spec newSpec) return false; } } + + // re-initialize devide + m_current_audioDriverState->setAudioDelayCompensate(m_audioDelayCompensate); + // open the device driver if (!m_current_audioDriverState->open(newSpec, &newSpec)) { return false; @@ -192,6 +199,16 @@ async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const return m_availableOutputDevicesChanged; } +int LinuxAudioDriver::audioDelayCompensate() const +{ + return m_audioDelayCompensate; +} + +void LinuxAudioDriver::setAudioDelayCompensate(const int frames) +{ + m_audioDelayCompensate = frames; +} + unsigned int LinuxAudioDriver::outputDeviceBufferSize() const { return m_current_audioDriverState->m_spec.samples; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index ede0b3def9f8c..1ed1dd43b961d 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -63,6 +63,10 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable async::Notification outputDeviceBufferSizeChanged() const override; std::vector availableOutputDeviceBufferSizes() const override; + + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; + bool pushMidiEvent(muse::midi::Event& e) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; @@ -88,6 +92,7 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable async::Notification m_bufferSizeChanged; async::Notification m_sampleRateChanged; + int m_audioDelayCompensate; struct IAudioDriver::Spec m_spec; std::unique_ptr m_current_audioDriverState; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index e59049e88eda2..eea21b8445f6d 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -66,6 +66,9 @@ class OSXAudioDriver : public IAudioDriver bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; + std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index 22f32daacc449..d8e7d2ad209d8 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -412,6 +412,15 @@ }; } +int OSXAudioDriver::audioDelayCompensate() const +{ + return 0; +} + +void OSXAudioDriver::setAudioDelayCompensate(const int frames) +{ +} + bool OSXAudioDriver::audioQueueSetDeviceName(const AudioDeviceID& deviceId) { if (deviceId.empty() || deviceId == DEFAULT_DEVICE_ID) { diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index ca3384bad7240..de5de356133f1 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -338,6 +338,15 @@ void WasapiAudioDriver::reopen() open(m_activeSpec, &m_activeSpec); } +int WasapiAudioDriver::audioDelayCompensate(void) const +{ + return 0; +} + +void WasapiAudioDriver::setAudioDelayCompensate(const int frames) +{ +} + AudioDeviceID WasapiAudioDriver::defaultDeviceId() const { using namespace winrt::Windows::Media::Devices; diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index f2b59acf803f4..780d58b931d2e 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -64,6 +64,8 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable async::Notification outputDeviceSampleRateChanged() const override; std::vector availableOutputDeviceSampleRates() const override; + int audioDelayCompensate(void) const override; + void setAudioDelayCompensate(const int frames) override; bool pushMidiEvent(muse::midi::Event& e) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; diff --git a/src/framework/stubs/audio/audioconfigurationstub.cpp b/src/framework/stubs/audio/audioconfigurationstub.cpp index 59480cbd0b5b0..2262c85e447db 100644 --- a/src/framework/stubs/audio/audioconfigurationstub.cpp +++ b/src/framework/stubs/audio/audioconfigurationstub.cpp @@ -52,6 +52,15 @@ async::Notification AudioConfigurationStub::audioOutputDeviceIdChanged() const return async::Notification(); } +int AudioConfigurationStub::audioDelayCompensate() const +{ + return 0; +} + +void AudioConfigurationStub::setAudioDelayCompensate(const int frames) +{ +} + audioch_t AudioConfigurationStub::audioChannelsCount() const { return 2; diff --git a/src/framework/stubs/audio/audioconfigurationstub.h b/src/framework/stubs/audio/audioconfigurationstub.h index 798778e6cfa5b..0246674fa5272 100644 --- a/src/framework/stubs/audio/audioconfigurationstub.h +++ b/src/framework/stubs/audio/audioconfigurationstub.h @@ -54,6 +54,9 @@ class AudioConfigurationStub : public IAudioConfiguration async::Notification sampleRateChanged() const override; size_t desiredAudioThreadNumber() const override; + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; + size_t minTrackCountForMultithreading() const override; // synthesizers diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index 3b95fceca4abc..0ac1499d1e3cb 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -83,6 +83,15 @@ async::Notification AudioDriverStub::availableOutputDevicesChanged() const return async::Notification(); } +int AudioDriverStub::audioDelayCompensate() const +{ + return 0; +} + +void AudioDriverStub::setAudioDelayCompensate(const int frames) +{ +} + unsigned int AudioDriverStub::outputDeviceBufferSize() const { return 0; diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index 9046c81524d5d..54c9d0852d8f9 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -47,6 +47,9 @@ class AudioDriverStub : public IAudioDriver bool pushMidiEvent(muse::midi::Event& e) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; + unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; From c27a329a669913c45695f7bd2d084c011cf5d655 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 31 Mar 2024 09:40:20 +0200 Subject: [PATCH 25/60] jack-transport: slow-sync client * seek possible if not playing * jack is soft-realtime, use separate musescore access thread * start/stop transport from musescore * take into account wall-clock elapse by non-realtime worker when calculating musescore seek position * allow for some time-imprecision in playbackPositionInSeconds * avoid playbackPositionInSeconds due to imprecision * playbackposition remote{seek|playOrStop} * adjustable delay by cli jackTransportDelay --- .../platform/alsa/alsaaudiodriver.cpp | 2 +- .../platform/jack/jackaudiodriver.cpp | 328 +++++++++++++++++- .../internal/platform/jack/jackaudiodriver.h | 10 +- .../platform/lin/linuxaudiodriver.cpp | 1 - 4 files changed, 331 insertions(+), 10 deletions(-) diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 09450f8b76c4c..1f97d09e648d7 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -208,7 +208,7 @@ void AlsaDriverState::registerMidiInputQueue(async::Channel AlsaDriverState::availableMidiDevices(muse::midi::MidiPortDirection direction) const +std::vector AlsaDriverState::availableMidiDevices([[maybe_unused]] muse::midi::MidiPortDirection direction) const { std::vector x; return x; // dummy diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 139d65c0c7271..21acf801f63e8 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -29,20 +29,171 @@ #include #include #include -#include -#include // Used by usleep -#include // Used by usleep +#include +#include #include "translation.h" #include "log.h" #include "runtime.h" +/* How many milliseconds to we allow musescore to be out-of-sync to jack + * before we tell musescore to adjust (seek) its position + */ +#define FRAMESLIMIT 500 + #define JACK_DEFAULT_DEVICE_ID "jack" #define JACK_DEFAULT_IDENTIFY_AS "MuseScore" +static int g_jackTransportDelay = 0; using namespace muse::audio; using namespace muse::midi; namespace muse::audio { +// variables to communicate between soft-realtime jack thread and musescore +static msecs_t mpos_frame; // musescore frame and state +static jack_nframes_t muse_frame; // musescore frame and state +static jack_transport_state_t muse_state; +static jack_nframes_t jack_frame; // jack frame and state +static jack_transport_state_t jack_state; +static int g_musescore_is_synced; // tells jack-transport if musescore is synced +static jack_nframes_t g_nframes; +unsigned int g_samplerate; +msecs_t g_frameslimit; +static jack_nframes_t muse_seek_requested; +static int muse_seek_countdown = 0; + +std::chrono::time_point musescore_act_time; +static bool musescore_act; +static msecs_t musescore_act_seek; +static bool running_musescore_state; +static mu::playback::IPlaybackController* s_playbackController; +static std::vector threads; + +void musescore_state_check_musescore() +{ + jack_nframes_t pos = mpos_frame; + if (pos > static_cast(g_jackTransportDelay)) { + pos -= g_jackTransportDelay; + } + muse_frame = pos; + + if (s_playbackController->isPlaying()) { + muse_state = JackTransportRolling; + } else { + muse_state = JackTransportStopped; + } +} + +void musescore_state_do_seek() +{ + auto now = std::chrono::steady_clock::now(); + auto diff = std::chrono::duration_cast(now - musescore_act_time); + auto ms = static_cast(diff.count()); + auto millis = static_cast((double)musescore_act_seek * 1000 / (double)g_samplerate); + millis = std::max(millis - ms, 0L); + LOGW("Jack mst: really do musescore-seek to %lu (%lims) (diff: %i) mf=%u/%li jf=%u lag: %lims", + musescore_act_seek, millis, muse_frame - jack_frame, muse_frame, mpos_frame, jack_frame, ms); + s_playbackController->remoteSeek(millis); + //mpos_frame = static_cast(millis * g_samplerate / 1000); +} + +/* + * state thread + */ +void musescore_state() +{ + LOGI("Jack: start musescore_state thread"); + int is_seeking = 0; + int cnt = 0; + while (running_musescore_state) { + musescore_state_check_musescore(); + cnt++; + if (cnt > 4) { + cnt = 0; + LOGI("state: mframe=%u/%li jframe=%u (framedrift: %i / %i) ms=%s js=%s", + muse_frame, mpos_frame, jack_frame, + muse_frame - jack_frame, + mpos_frame - jack_frame, + (muse_state == JackTransportStopped ? "stop" + : (muse_state == JackTransportStarting ? "start" + : (muse_state == JackTransportRolling ? "roll" : "other"))), + (jack_state == JackTransportStopped ? "stop" + : (jack_state == JackTransportStarting ? "start" + : (jack_state == JackTransportRolling ? "roll" : "other")))); + } + if (musescore_act) { + if (is_seeking) { + // already seeking + } else { + if (labs(muse_frame - jack_frame) > g_frameslimit + && muse_seek_countdown == 0) { // && (muse_frame - jack_frame) != 0) { + musescore_state_do_seek(); + is_seeking = 1; + } else { + LOGI("Jack mst: act avoid musescore-seek to %lu (jack: %u) ", musescore_act_seek, jack_frame); + musescore_act = false; + } + } + } + if (is_seeking) { + is_seeking++; + if (is_seeking > 10) { + is_seeking = 0; + musescore_act = false; + } + } + if (muse_seek_countdown) { + muse_seek_countdown--; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + LOGW("Jack: quiting musescore_state thread"); +} + +bool musescore_seek(unsigned int pos) +{ + if (musescore_act) { + return false; // already seeking + } else { + musescore_act_seek = pos; + musescore_act = true; + musescore_act_time = std::chrono::steady_clock::now(); // record clock that pos is valid for + } + return true; +} + +void JackDriverState::musescore_changed_play_state() +{ + jack_client_t* client = static_cast(m_jackDeviceHandle); + + if (s_playbackController->isPlaying()) { + jack_nframes_t frames = static_cast(m_playbackController->playbackPositionInSeconds() * g_samplerate); + LOGW("musescore tell transport to START at %u", frames); + jack_transport_locate(client, frames); + jack_transport_start(client); + } else { + LOGW("musescore tell transport to STOP"); + jack_transport_stop(client); + } +} + +void JackDriverState::musescore_changed_position_state() +{ + jack_client_t* client = static_cast(m_jackDeviceHandle); + jack_nframes_t frames = static_cast(m_playbackController->playbackPositionInSeconds() * g_samplerate); + + // worker thread is updating muse_frame (which runs every 100ms) + // thats why we can get out of sync with "ourself" + if (labs((long int)muse_frame - (long int)frames) > g_frameslimit) { + LOGW("musescore tell transport to LOCATE mf=%u, fr=%u diff: %i (lim: %i)", + muse_frame, frames, + muse_frame - frames, + g_frameslimit); + jack_transport_locate(client, frames); + muse_frame = mpos_frame = frames; + muse_seek_countdown = 10; // KLUDGE: avoid transport seeking musescore for some time + } +} + /* * MIDI */ @@ -126,6 +277,118 @@ muse::Ret sendEvent(const Event& e, void* pb) return Ret(true); } +// musescore has around 200ms inaccuracy in playbackPositionInSeconds +bool is_muse_jack_frame_sync(jack_nframes_t mf, jack_nframes_t jf) +{ + return labs((long int)jack_frame - (long int)muse_frame + g_jackTransportDelay) < g_frameslimit; +} + +bool is_muse_jack_state_sync(jack_transport_state_t ms, jack_transport_state_t js) +{ + if (muse_state == JackTransportRolling) { + return jack_state == JackTransportRolling + || jack_state == JackTransportStarting; + } else { + return jack_state == JackTransportStopped; + } +} + +void jack_muse_update_verify_sync(JackDriverState* state, jack_client_t* client) +{ + jack_position_t jpos; + jack_state = jack_transport_query(client, &jpos); + jack_frame = jpos.frame; + if (is_muse_jack_state_sync(muse_state, jack_state) + && is_muse_jack_frame_sync(muse_frame, jack_frame)) { + g_musescore_is_synced = 1; + } else { + g_musescore_is_synced = 0; + } +} + +static int framecnt = 0; + +void check_jack_midi_transport(JackDriverState* state, jack_nframes_t nframes) +{ + jack_client_t* client = static_cast(state->m_jackDeviceHandle); + + jack_muse_update_verify_sync(state, client); + + if (g_musescore_is_synced) { + return; + } + + framecnt++; + if (framecnt > 40) { + framecnt = 0; + LOGI("jack-transport: mframe=%u/%li jframe=%u d=%i ms=%s js=%s nf=%i d=%i\n", + muse_frame, mpos_frame, jack_frame, + muse_frame - jack_frame, + (muse_state == JackTransportStopped ? "stop" + : (muse_state == JackTransportStarting ? "start" + : (muse_state == JackTransportRolling ? "roll" : "other"))), + (jack_state == JackTransportStopped ? "stop" + : (jack_state == JackTransportStarting ? "start" + : (jack_state == JackTransportRolling ? "roll" : "other"))), + nframes, + g_jackTransportDelay); + } + + bool state_sync = false; + if (muse_state == JackTransportStopped + && (jack_state == JackTransportStarting || jack_state == JackTransportRolling)) { + state->m_playbackController->remotePlayOrStop(true); + muse_state = JackTransportRolling; + } else if (muse_state == JackTransportRolling + && jack_state == JackTransportStopped) { + state->m_playbackController->remotePlayOrStop(false); + muse_state = JackTransportStopped; + } else { + state_sync = true; + } + + if (!(is_muse_jack_frame_sync(muse_frame, jack_frame))) { + jack_nframes_t pos = jack_frame; + if (pos > static_cast(g_jackTransportDelay)) { + pos -= g_jackTransportDelay; + } else { + pos = 0; + } + muse_seek_requested = pos; + musescore_seek(pos); + } else { + g_musescore_is_synced = state_sync; // only sync if both state and position matches jack + LOGW("jack-transport: SYNCED!"); + } +} + +// because jack callbacks are soft-realtime we use no resources +static int handle_jack_sync(jack_transport_state_t ts, jack_position_t* pos, void* args) +{ + if (jack_frame != pos->frame + || jack_state != ts + || (!is_muse_jack_frame_sync(jack_frame, muse_frame)) + || (!is_muse_jack_state_sync(jack_state, muse_state)) + ) { + jack_frame = pos->frame; + jack_state = ts; + g_musescore_is_synced = 0; + } + /* + LOGW("jack-transport: SYNC ms=%s ts=%s m/j-frame: %lu/%lu sync? %s", + (muse_state == JackTransportStopped ? "stop" : + (muse_state == JackTransportStarting ? "start" : + (muse_state == JackTransportRolling ? "roll" : "other"))), + (ts == JackTransportStopped ? "stop" : + (ts == JackTransportStarting ? "start" : + (ts == JackTransportRolling ? "roll" : "other"))), + muse_frame, + jack_frame, + g_musescore_is_synced ? "---- YES ----" : " -- no --"); + */ + return g_musescore_is_synced; +} + /* * AUDIO */ @@ -149,6 +412,12 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) // LOGI() << "---- JACK-midi output sendEvent SORRY, not connected"; // return make_ret(Err::MidiNotConnected); // } + + if (muse_state == JackTransportRolling) { + mpos_frame += nframes; + } + check_jack_midi_transport(state, nframes); + if (!state->m_midiOutputPorts.empty()) { jack_port_t* port = state->m_midiOutputPorts.front(); if (port) { @@ -215,15 +484,24 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) return 0; } +static int handle_buffersize_change(jack_nframes_t nframes, void* arg) +{ + g_nframes = nframes; + return 0; // successfully reallocated buffer +} + static void jack_cleanup_callback(void*) { } } -JackDriverState::JackDriverState() +JackDriverState::JackDriverState(mu::playback::IPlaybackController* playbackController) { + m_playbackController = playbackController; m_deviceId = JACK_DEFAULT_DEVICE_ID; m_deviceName = JACK_DEFAULT_IDENTIFY_AS; + + s_playbackController = playbackController; } JackDriverState::~JackDriverState() @@ -260,12 +538,25 @@ int jack_srate_callback(jack_nframes_t newSampleRate, void* args) return 0; } +void JackDriverState::setAudioDelayCompensate(const int frames) +{ + g_jackTransportDelay = frames; +} + bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { + LOGI("using jackTransportDelay: %i", g_jackTransportDelay); if (isOpened()) { LOGW() << "Jack is already opened"; return true; } + // start musescore state thread + running_musescore_state = true; + std::thread thread_musescore_state(musescore_state); + std::vector threadv; + threadv.push_back(std::move(thread_musescore_state)); + threads = std::move(threadv); + // m_spec.samples = spec.samples; // client doesn't set sample-rate m_spec.channels = spec.channels; m_spec.callback = spec.callback; @@ -281,6 +572,9 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a unsigned int jackSamplerate = jack_get_sample_rate(handle); m_spec.sampleRate = jackSamplerate; + g_samplerate = jackSamplerate; + // FIX: at samplerate change, this need to be adjusted + g_frameslimit = static_cast((double)g_samplerate * (double)FRAMESLIMIT / 1000.0d); if (spec.sampleRate != jackSamplerate) { LOGW() << "Musescores samplerate: " << spec.sampleRate << ", is NOT the same as jack's: " << jackSamplerate; // FIX: enable this if it is possible for user to adjust samplerate (AUDIO_SAMPLE_RATE_KEY) @@ -306,12 +600,24 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a jack_on_shutdown(handle, jack_cleanup_callback, (void*)this); jack_set_process_callback(handle, jack_process_callback, (void*)this); - + jack_set_sync_callback(handle, handle_jack_sync, (void*)this); + jack_set_buffer_size_callback(handle, handle_buffersize_change, NULL); if (jack_activate(handle)) { LOGE() << "cannot activate client"; return false; } + // get notification when musescore changes play-position or play/pause + + s_playbackController->isPlayingChanged().onNotify(this, [this]() { + musescore_changed_play_state(); + }); + + // HELP: is playbackPositionChanged notified for incremental changes too? + s_playbackController->playbackPositionChanged().onNotify(this, [this]() { + musescore_changed_position_state(); + }); + // midi input jack_port_t* midi_input_port = jack_port_register(handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); m_midiInputPorts.push_back(midi_input_port); @@ -322,6 +628,18 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); m_midiOutputPorts.push_back(port); + muse_seek_requested = 0; + mpos_frame = muse_frame = static_cast(m_playbackController->playbackPositionInSeconds() * jackSamplerate); + if (muse_frame >= g_jackTransportDelay) { + muse_frame -= g_jackTransportDelay; + } + + if (m_playbackController->isPlaying()) { + muse_state = JackTransportRolling; + } else { + muse_state = JackTransportStopped; + } + return true; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 3c488908c55c1..d40bc9dc4e5a8 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -30,10 +30,10 @@ #include "playback/iplaybackcontroller.h" namespace muse::audio { -class JackDriverState : public AudioDriverState +class JackDriverState : public AudioDriverState, public async::Asyncable { public: - JackDriverState(std::shared_ptr); + JackDriverState(mu::playback::IPlaybackController*); ~JackDriverState(); std::string name() const override; @@ -42,6 +42,7 @@ class JackDriverState : public AudioDriverState bool isOpened() const override; bool pushMidiEvent(muse::midi::Event& e) override; void registerMidiInputQueue(async::Channel) override; + void setAudioDelayCompensate(const int frames) override; std::string deviceName() const; void deviceName(const std::string newDeviceName); @@ -54,10 +55,13 @@ class JackDriverState : public AudioDriverState std::vector m_midiOutputPorts; ThreadSafeQueue m_midiQueue; async::Channel m_eventReceived; - std::shared_ptr m_playbackController; + mu::playback::IPlaybackController* m_playbackController; private: std::string m_deviceName; + + void musescore_changed_play_state(); + void musescore_changed_position_state(); }; } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 8d10c2dd9bb73..7e87c0c21f4f9 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -123,7 +123,6 @@ bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) LOGE() << "Unknown device name: " << deviceId; return false; } - LOGI(" -- driver: %lx", m_current_audioDriverState.get()); return true; } From 98f2f46f7c070392f38ae36822de1cdfa02bcf63 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 29 Mar 2024 07:50:01 +0100 Subject: [PATCH 26/60] samplerate dropdown --- .../commonaudioapiconfigurationmodel.cpp | 21 +++++++++++++++++++ .../internal/audiooutputdevicecontroller.cpp | 10 +++++++++ .../platform/lin/linuxaudiodriver.cpp | 19 ++++++++++++++++- .../internal/platform/lin/linuxaudiodriver.h | 4 ++++ .../internal/platform/osx/osxaudiodriver.h | 4 ++++ .../internal/platform/osx/osxaudiodriver.mm | 15 +++++++++++++ .../platform/win/wasapiaudiodriver.cpp | 15 +++++++++++++ .../internal/platform/win/wasapiaudiodriver.h | 8 +++++++ src/framework/stubs/audio/audiodriverstub.cpp | 15 +++++++++++++ src/framework/stubs/audio/audiodriverstub.h | 4 ++++ 10 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp index f5b3b394c16b4..7821cb8ac6eaf 100644 --- a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp +++ b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp @@ -41,10 +41,15 @@ void CommonAudioApiConfigurationModel::load() }); audioDriver()->outputDeviceChanged().onNotify(this, [this]() { + LOGE("---- emit currentDeviceIdChanged ----"); emit currentDeviceIdChanged(); emit sampleRateChanged(); emit bufferSizeListChanged(); emit bufferSizeChanged(); + + audioDriver()->sampleRateChanged().onNotify(this, [this]() { + LOGE("---- emit sampleRateChanged ----"); + emit sampleRateChanged(); }); audioDriver()->outputDeviceSampleRateChanged().onNotify(this, [this]() { @@ -82,6 +87,22 @@ void CommonAudioApiConfigurationModel::deviceSelected(const QString& deviceId) audioConfiguration()->setAudioOutputDeviceId(deviceId.toStdString()); } +int CommonAudioApiConfigurationModel::sampleRate() const +{ + return audioDriver()->sampleRate(); +} + +QList CommonAudioApiConfigurationModel::sampleRateList() const +{ + return { 16000, 32000, 44100, 48000 }; +} + +void CommonAudioApiConfigurationModel::sampleRateSelected(const QString& sampleRateStr) +{ + LOGE("------- selected samplerate: %s ------", qPrintable(sampleRateStr)); + audioConfiguration()->setSampleRate(sampleRateStr.toInt()); // FIX: setDriverSampleRate ? +} + unsigned int CommonAudioApiConfigurationModel::bufferSize() const { return audioDriver()->outputDeviceBufferSize(); diff --git a/src/framework/audio/internal/audiooutputdevicecontroller.cpp b/src/framework/audio/internal/audiooutputdevicecontroller.cpp index fb1a572c41c5f..22ddeb35ce1e9 100644 --- a/src/framework/audio/internal/audiooutputdevicecontroller.cpp +++ b/src/framework/audio/internal/audiooutputdevicecontroller.cpp @@ -48,6 +48,16 @@ void AudioOutputDeviceController::init() } }); + configuration()->sampleRateChanged().onNotify(this, [this]() { + unsigned int sampleRate = configuration()->sampleRate(); + bool ok = audioDriver()->setSampleRate(sampleRate); + if (ok) { + async::Async::call(this, [sampleRate](){ + AudioEngine::instance()->setSampleRate(sampleRate); + }, AudioThread::ID); + } + }); + configuration()->driverBufferSizeChanged().onNotify(this, [this]() { unsigned int bufferSize = configuration()->driverBufferSize(); LOGI() << "Trying to change buffer size: " << bufferSize; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 7e87c0c21f4f9..f6d53a75d62e0 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -246,13 +246,29 @@ std::vector LinuxAudioDriver::availableOutputDeviceBufferSizes() c return result; } +// FIX-JACK-20240823: change api callers, WAS: +// unsigned int LinuxAudioDriver::sampleRate() const unsigned int LinuxAudioDriver::outputDeviceSampleRate() const { - return s_format.sampleRate; + return m_current_audioDriverState->m_spec.sampleRate; } +// FIX-JACK-20240823: merge this code bool LinuxAudioDriver::setOutputDeviceSampleRate(unsigned int sampleRate) { + LOGE("------ setSamplerate: %u", sampleRate); + if (m_spec.sampleRate == (int)sampleRate) { + LOGE("------ SAME setSamplerate, doing nothing ------"); + return true; + } + m_spec.sampleRate = (int)sampleRate; + LOGE("------ CHANGED setSamplerate, doing nothing ------"); + if (!reopen(m_current_audioDriverState->name(), m_spec)) { + return false; + } + m_sampleRateChanged.notify(); + return true; +#if 0 if (s_format.sampleRate == sampleRate) { return true; } @@ -271,6 +287,7 @@ bool LinuxAudioDriver::setOutputDeviceSampleRate(unsigned int sampleRate) } return ok; +#endif } async::Notification LinuxAudioDriver::outputDeviceSampleRateChanged() const diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index 1ed1dd43b961d..e47e00ef3e637 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -62,6 +62,10 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; + unsigned int sampleRate() const override; + bool setSampleRate(unsigned int sampleRate) override; + async::Notification sampleRateChanged() const override; + std::vector availableOutputDeviceBufferSizes() const override; int audioDelayCompensate() const override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index eea21b8445f6d..4c60d635a3e6d 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -66,6 +66,10 @@ class OSXAudioDriver : public IAudioDriver bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; + unsigned int sampleRate() const override; + bool setSampleRate(unsigned int sampleRate) override; + async::Notification sampleRateChanged() const override; + int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index d8e7d2ad209d8..0e3512691dee5 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -335,6 +335,21 @@ return m_bufferSizeChanged; } +unsigned int OSXAudioDriver::sampleRate() const +{ + return 0; +} + +bool OSXAudioDriver::setSampleRate(unsigned int sampleRate) +{ + return true; +} + +async::Notification OSXAudioDriver::sampleRateChanged() const +{ + return m_sampleRateChanged; +} + std::vector OSXAudioDriver::availableOutputDeviceBufferSizes() const { OSXAudioDeviceID osxDeviceId = this->osxDeviceId(); diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index de5de356133f1..b3396790091bb 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -242,6 +242,21 @@ async::Notification WasapiAudioDriver::availableOutputDevicesChanged() const return m_availableOutputDevicesChanged; } +unsigned int WasapiAudioDriver::sampleRate() const +{ + return 0; +} + +bool WasapiAudioDriver::setSampleRate(unsigned int sampleRate) +{ + return true; +} + +async::Notification WasapiAudioDriver::sampleRateChanged() const +{ + return m_sampleRateChanged; +} + unsigned int WasapiAudioDriver::outputDeviceBufferSize() const { return m_activeSpec.samples; diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 780d58b931d2e..4507aeabfdd6a 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -59,9 +59,16 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceBufferSizes() const override; + // ------------------------------------------------------------------- + // FIX-JACK: api-change, WAS: + // unsigned int sampleRate() const override; + // bool setSampleRate(unsigned int sampleRate) override; + // async::Notification sampleRateChanged() const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; async::Notification outputDeviceSampleRateChanged() const override; + // ------------------------------------------------------------------- + std::vector availableOutputDeviceSampleRates() const override; int audioDelayCompensate(void) const override; @@ -87,6 +94,7 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable std::unique_ptr m_devicesListener; async::Notification m_outputDeviceChanged; + async::Notification m_sampleRateChanged; async::Notification m_availableOutputDevicesChanged; async::Notification m_outputDeviceBufferSizeChanged; async::Notification m_outputDeviceSampleRateChanged; diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index 0ac1499d1e3cb..ede89f15d0cfc 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -92,6 +92,21 @@ void AudioDriverStub::setAudioDelayCompensate(const int frames) { } +unsigned int AudioDriverStub::sampleRate() const +{ + return 0; +} + +bool AudioDriverStub::setSampleRate(unsigned int sampleRate) +{ + return true; +} + +async::Notification AudioDriverStub::sampleRateChanged() const +{ + return async::Notification(); +} + unsigned int AudioDriverStub::outputDeviceBufferSize() const { return 0; diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index 54c9d0852d8f9..da182ea1cca86 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -50,6 +50,10 @@ class AudioDriverStub : public IAudioDriver int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; + unsigned int sampleRate() const override; + bool setSampleRate(unsigned int sampleRate) override; + async::Notification sampleRateChanged() const override; + unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; From 95504696d8761c0f3d34aeef2971daca5f5df27a Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 11 Apr 2024 15:14:55 +0200 Subject: [PATCH 27/60] jack: thread usage cleanup --- .../internal/platform/jack/jackaudiodriver.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 21acf801f63e8..de57926371598 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -66,7 +66,7 @@ static bool musescore_act; static msecs_t musescore_act_seek; static bool running_musescore_state; static mu::playback::IPlaybackController* s_playbackController; -static std::vector threads; +//static std::vector threads; void musescore_state_check_musescore() { @@ -550,17 +550,12 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a LOGW() << "Jack is already opened"; return true; } - // start musescore state thread - running_musescore_state = true; - std::thread thread_musescore_state(musescore_state); - std::vector threadv; - threadv.push_back(std::move(thread_musescore_state)); - threads = std::move(threadv); // m_spec.samples = spec.samples; // client doesn't set sample-rate m_spec.channels = spec.channels; m_spec.callback = spec.callback; m_spec.userdata = spec.userdata; + const char* clientName = m_deviceName.c_str(); jack_status_t status; jack_client_t* handle; @@ -582,6 +577,14 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a //return false; } + // start musescore state thread + running_musescore_state = true; + std::thread thread_musescore_state(musescore_state); + thread_musescore_state.detach(); + //std::vector threadv; + //threadv.push_back(std::move(thread_musescore_state)); + //threads = std::move(threadv); + jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&m_spec); jack_port_t* output_port_left = jack_port_register(handle, "audio_out_left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); From bc9d862fc25f71f3721741917b381f48039aa7a2 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 11 Apr 2024 18:46:12 +0200 Subject: [PATCH 28/60] (maybe-squash) bugfix linuxdriver open The callback member isn't really a specification, so we need to copy it around, because it is set above the linuxdriver class, and needed if we change driver --- src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index f6d53a75d62e0..3d203342b9f14 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -73,6 +73,8 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) m_current_audioDriverState->setAudioDelayCompensate(m_audioDelayCompensate); if (!m_current_audioDriverState->open(spec, activeSpec)) { + // FIX: need to carry around the spec because of callback + m_spec = spec; return false; } m_spec = *activeSpec; From f5a9b2b1b8f2c0a08ae1565bce0287e47df4fed0 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 11 Apr 2024 19:17:16 +0200 Subject: [PATCH 29/60] TEMP jack logging turnoff --- src/framework/audio/internal/platform/jack/jackaudiodriver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index de57926371598..072c4783bb11b 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -109,6 +109,7 @@ void musescore_state() cnt++; if (cnt > 4) { cnt = 0; + /* LOGI("state: mframe=%u/%li jframe=%u (framedrift: %i / %i) ms=%s js=%s", muse_frame, mpos_frame, jack_frame, muse_frame - jack_frame, @@ -119,6 +120,7 @@ void musescore_state() (jack_state == JackTransportStopped ? "stop" : (jack_state == JackTransportStarting ? "start" : (jack_state == JackTransportRolling ? "roll" : "other")))); + */ } if (musescore_act) { if (is_seeking) { From 668ac42b8f5726caed1dd7fff2c6ffb0a57c8598 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Tue, 16 Apr 2024 16:35:14 +0200 Subject: [PATCH 30/60] move complexity from jackdriver to audiomidimanage --- src/framework/audio/iaudiodriver.h | 8 +++ .../platform/alsa/alsaaudiodriver.cpp | 8 +++ .../internal/platform/alsa/alsaaudiodriver.h | 2 + .../platform/jack/jackaudiodriver.cpp | 62 +++++++++++-------- .../internal/platform/jack/jackaudiodriver.h | 14 +++-- .../platform/lin/linuxaudiodriver.cpp | 46 +++++++++++++- .../internal/platform/lin/linuxaudiodriver.h | 8 +++ .../internal/platform/osx/osxaudiodriver.h | 4 ++ .../internal/platform/osx/osxaudiodriver.mm | 18 ++++++ .../platform/win/wasapiaudiodriver.cpp | 18 ++++++ .../internal/platform/win/wasapiaudiodriver.h | 4 ++ src/framework/stubs/audio/audiodriverstub.cpp | 18 ++++++ src/framework/stubs/audio/audiodriverstub.h | 4 ++ 13 files changed, 182 insertions(+), 32 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index e63c45b6a3c52..1a1a86bc165ed 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -90,6 +90,11 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual async::Notification outputDeviceSampleRateChanged() const = 0; virtual std::vector availableOutputDeviceSampleRates() const = 0; + virtual bool isPlaying() const = 0; + virtual float playbackPositionInSeconds() const = 0; + virtual void remotePlayOrStop(bool) const = 0; + virtual void remoteSeek(msecs_t) const = 0; + virtual int audioDelayCompensate() const = 0; virtual void setAudioDelayCompensate(const int frames) = 0; @@ -112,6 +117,9 @@ class AudioDriverState virtual void registerMidiInputQueue(async::Channel) = 0; virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; + virtual void changedPlaying() const = 0; + virtual void changedPosition() const = 0; + IAudioDriver::Spec m_spec; // current running spec std::string m_deviceId; }; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 1f97d09e648d7..0ab04415c5167 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -198,6 +198,14 @@ bool AlsaDriverState::isOpened() const return m_alsaDeviceHandle != nullptr; } +void AlsaDriverState::changedPlaying() const +{ +} + +void AlsaDriverState::changedPosition() const +{ +} + bool AlsaDriverState::pushMidiEvent(muse::midi::Event&) { return true; // dummy diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index ee72de31bc8db..0f5a0e6968028 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -42,6 +42,8 @@ class AlsaDriverState : public AudioDriverState std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; std::string deviceName() const; void deviceName(const std::string newDeviceName); + void changedPlaying() const override; + void changedPosition() const override; void* m_alsaDeviceHandle = nullptr; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 072c4783bb11b..537522ef38900 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -65,8 +65,8 @@ std::chrono::time_point musescore_act_time; static bool musescore_act; static msecs_t musescore_act_seek; static bool running_musescore_state; -static mu::playback::IPlaybackController* s_playbackController; //static std::vector threads; +static JackDriverState* s_jackDriver; void musescore_state_check_musescore() { @@ -76,7 +76,7 @@ void musescore_state_check_musescore() } muse_frame = pos; - if (s_playbackController->isPlaying()) { + if (s_jackDriver->isPlaying()) { muse_state = JackTransportRolling; } else { muse_state = JackTransportStopped; @@ -92,7 +92,7 @@ void musescore_state_do_seek() millis = std::max(millis - ms, 0L); LOGW("Jack mst: really do musescore-seek to %lu (%lims) (diff: %i) mf=%u/%li jf=%u lag: %lims", musescore_act_seek, millis, muse_frame - jack_frame, muse_frame, mpos_frame, jack_frame, ms); - s_playbackController->remoteSeek(millis); + s_jackDriver->remoteSeek(millis); //mpos_frame = static_cast(millis * g_samplerate / 1000); } @@ -163,12 +163,12 @@ bool musescore_seek(unsigned int pos) return true; } -void JackDriverState::musescore_changed_play_state() +void JackDriverState::changedPlaying() const { jack_client_t* client = static_cast(m_jackDeviceHandle); - if (s_playbackController->isPlaying()) { - jack_nframes_t frames = static_cast(m_playbackController->playbackPositionInSeconds() * g_samplerate); + if (s_jackDriver->isPlaying()) { + jack_nframes_t frames = static_cast(s_jackDriver->playbackPositionInSeconds() * g_samplerate); LOGW("musescore tell transport to START at %u", frames); jack_transport_locate(client, frames); jack_transport_start(client); @@ -178,10 +178,10 @@ void JackDriverState::musescore_changed_play_state() } } -void JackDriverState::musescore_changed_position_state() +void JackDriverState::changedPosition() const { jack_client_t* client = static_cast(m_jackDeviceHandle); - jack_nframes_t frames = static_cast(m_playbackController->playbackPositionInSeconds() * g_samplerate); + jack_nframes_t frames = static_cast(s_jackDriver->playbackPositionInSeconds() * g_samplerate); // worker thread is updating muse_frame (which runs every 100ms) // thats why we can get out of sync with "ourself" @@ -339,11 +339,11 @@ void check_jack_midi_transport(JackDriverState* state, jack_nframes_t nframes) bool state_sync = false; if (muse_state == JackTransportStopped && (jack_state == JackTransportStarting || jack_state == JackTransportRolling)) { - state->m_playbackController->remotePlayOrStop(true); + state->remotePlayOrStop(true); muse_state = JackTransportRolling; } else if (muse_state == JackTransportRolling && jack_state == JackTransportStopped) { - state->m_playbackController->remotePlayOrStop(false); + state->remotePlayOrStop(false); muse_state = JackTransportStopped; } else { state_sync = true; @@ -497,13 +497,12 @@ static void jack_cleanup_callback(void*) } } -JackDriverState::JackDriverState(mu::playback::IPlaybackController* playbackController) +JackDriverState::JackDriverState(IAudioDriver* amm) { - m_playbackController = playbackController; + s_jackDriver = this; m_deviceId = JACK_DEFAULT_DEVICE_ID; m_deviceName = JACK_DEFAULT_IDENTIFY_AS; - - s_playbackController = playbackController; + m_audiomidiManager = amm; } JackDriverState::~JackDriverState() @@ -612,17 +611,6 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } - // get notification when musescore changes play-position or play/pause - - s_playbackController->isPlayingChanged().onNotify(this, [this]() { - musescore_changed_play_state(); - }); - - // HELP: is playbackPositionChanged notified for incremental changes too? - s_playbackController->playbackPositionChanged().onNotify(this, [this]() { - musescore_changed_position_state(); - }); - // midi input jack_port_t* midi_input_port = jack_port_register(handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); m_midiInputPorts.push_back(midi_input_port); @@ -634,12 +622,12 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a m_midiOutputPorts.push_back(port); muse_seek_requested = 0; - mpos_frame = muse_frame = static_cast(m_playbackController->playbackPositionInSeconds() * jackSamplerate); + mpos_frame = muse_frame = static_cast(s_jackDriver->playbackPositionInSeconds() * jackSamplerate); if (muse_frame >= g_jackTransportDelay) { muse_frame -= g_jackTransportDelay; } - if (m_playbackController->isPlaying()) { + if (s_jackDriver->isPlaying()) { muse_state = JackTransportRolling; } else { muse_state = JackTransportStopped; @@ -661,6 +649,26 @@ bool JackDriverState::isOpened() const return m_jackDeviceHandle != nullptr; } +bool JackDriverState::isPlaying() const +{ + return m_audiomidiManager->isPlaying(); +} + +float JackDriverState::playbackPositionInSeconds() const +{ + return m_audiomidiManager->playbackPositionInSeconds(); +} + +void JackDriverState::remotePlayOrStop(bool ps) const +{ + m_audiomidiManager->remotePlayOrStop(ps); +} + +void JackDriverState::remoteSeek(msecs_t millis) const +{ + m_audiomidiManager->remoteSeek(millis); +} + /* * MIDI */ diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index d40bc9dc4e5a8..e8e3ca2235094 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -33,7 +33,7 @@ namespace muse::audio { class JackDriverState : public AudioDriverState, public async::Asyncable { public: - JackDriverState(mu::playback::IPlaybackController*); + JackDriverState(IAudioDriver* amm); ~JackDriverState(); std::string name() const override; @@ -57,11 +57,17 @@ class JackDriverState : public AudioDriverState, public async::Asyncable async::Channel m_eventReceived; mu::playback::IPlaybackController* m_playbackController; + void changedPlaying() const override; + void changedPosition() const override; + + bool isPlaying() const; + float playbackPositionInSeconds() const; + void remotePlayOrStop(bool) const; + void remoteSeek(msecs_t) const; + private: + IAudioDriver* m_audiomidiManager; std::string m_deviceName; - - void musescore_changed_play_state(); - void musescore_changed_position_state(); }; } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp index 3d203342b9f14..c036fde602c1c 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp @@ -50,6 +50,16 @@ void LinuxAudioDriver::init() m_devicesListener.devicesChanged().onNotify(this, [this]() { m_availableOutputDevicesChanged.notify(); }); + + // notify driver if when musescore changes play-position or play/pause + playbackController()->isPlayingChanged().onNotify(this, [this]() { + isPlayingChanged(); + }); + + // HELP: is playbackPositionChanged notified for incremental changes too? + playbackController()->playbackPositionChanged().onNotify(this, [this]() { + positionChanged(); + }); } std::string LinuxAudioDriver::name() const @@ -110,7 +120,7 @@ bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) { #if defined(JACK_AUDIO) if (deviceId == "jack") { - m_current_audioDriverState = std::make_unique(playbackController()); + m_current_audioDriverState = std::make_unique(this); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) } else if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); @@ -200,6 +210,40 @@ async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const return m_availableOutputDevicesChanged; } +void LinuxAudioDriver::isPlayingChanged() +{ + if (m_current_audioDriverState) { + m_current_audioDriverState->changedPlaying(); + } +} + +void LinuxAudioDriver::positionChanged() +{ + if (m_current_audioDriverState) { + m_current_audioDriverState->changedPosition(); + } +} + +bool LinuxAudioDriver::isPlaying() const +{ + return playbackController()->isPlaying(); +} + +float LinuxAudioDriver::playbackPositionInSeconds() const +{ + return playbackController()->playbackPositionInSeconds(); +} + +void LinuxAudioDriver::remotePlayOrStop(bool ps) const +{ + playbackController()->remotePlayOrStop(ps); +} + +void LinuxAudioDriver::remoteSeek(msecs_t millis) const +{ + playbackController()->remoteSeek(millis); +} + int LinuxAudioDriver::audioDelayCompensate() const { return m_audioDelayCompensate; diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h index e47e00ef3e637..b90a98e39b889 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/platform/lin/linuxaudiodriver.h @@ -80,6 +80,14 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceSampleRates() const override; + void isPlayingChanged(); + void positionChanged(); + + bool isPlaying() const override; + float playbackPositionInSeconds() const override; + void remotePlayOrStop(bool) const override; + void remoteSeek(msecs_t) const override; + void resume() override; void suspend() override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 4c60d635a3e6d..5c5313a7f9a9b 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -72,6 +72,10 @@ class OSXAudioDriver : public IAudioDriver int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; + bool isPlaying() const override; + float playbackPositionInSeconds() const override; + void remotePlayOrStop(bool) const override; + void remoteSeek(msecs_t) const override; std::vector availableOutputDeviceBufferSizes() const override; bool pushMidiEvent(muse::midi::Event& e) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index 0e3512691dee5..b2e9883e44c2c 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -436,6 +436,24 @@ { } +bool OSXAudioDriver::isPlaying() const +{ + return false; +} + +float OSXAudioDriver::playbackPositionInSeconds() const +{ + return 0; +} + +void OSXAudioDriver::remotePlayOrStop([[maybe_unused]] bool ps) const +{ +} + +void OSXAudioDriver::remoteSeek([[maybe_unused]] msecs_t millis) const +{ +} + bool OSXAudioDriver::audioQueueSetDeviceName(const AudioDeviceID& deviceId) { if (deviceId.empty() || deviceId == DEFAULT_DEVICE_ID) { diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index b3396790091bb..fd57180661ce3 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -362,6 +362,24 @@ void WasapiAudioDriver::setAudioDelayCompensate(const int frames) { } +bool WasapiAudioDriver::isPlaying() const +{ + return false; +} + +float WasapiAudioDriver::playbackPositionInSeconds() const +{ + return 0; +} + +void WasapiAudioDriver::remotePlayOrStop(bool ps) const +{ +} + +void WasapiAudioDriver::remoteSeek(msecs_t millis) const +{ +} + AudioDeviceID WasapiAudioDriver::defaultDeviceId() const { using namespace winrt::Windows::Media::Devices; diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 4507aeabfdd6a..c753a7df7fbe1 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -73,6 +73,10 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable int audioDelayCompensate(void) const override; void setAudioDelayCompensate(const int frames) override; + bool isPlaying() const override; + float playbackPositionInSeconds() const override; + void remotePlayOrStop(bool) const override; + void remoteSeek(msecs_t) const override; bool pushMidiEvent(muse::midi::Event& e) override; std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index ede89f15d0cfc..7d88007be8424 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -92,6 +92,16 @@ void AudioDriverStub::setAudioDelayCompensate(const int frames) { } +bool AudioDriverStub::isPlaying() const +{ + return false; +} + +float AudioDriverStub::playbackPositionInSeconds() const +{ + return 0; +} + unsigned int AudioDriverStub::sampleRate() const { return 0; @@ -107,6 +117,14 @@ async::Notification AudioDriverStub::sampleRateChanged() const return async::Notification(); } +void AudioDriverStub::remotePlayOrStop([[maybe_unused]] bool ps) const +{ +} + +void AudioDriverStub::remoteSeek([[maybe_unused]] msecs_t millis) const +{ +} + unsigned int AudioDriverStub::outputDeviceBufferSize() const { return 0; diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index da182ea1cca86..09bf78e7e6d12 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -49,6 +49,10 @@ class AudioDriverStub : public IAudioDriver int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; + bool isPlaying() const override; + float playbackPositionInSeconds() const override; + void remotePlayOrStop(bool) const override; + void remoteSeek(msecs_t) const override; unsigned int sampleRate() const override; bool setSampleRate(unsigned int sampleRate) override; From e3436935ea57f8547924356763fc3a6f0d08edf7 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Tue, 2 Apr 2024 14:40:23 +0200 Subject: [PATCH 31/60] LinuxAudioDriver -> AudioMidiManager --- src/framework/audio/CMakeLists.txt | 4 +- src/framework/audio/audiomodule.cpp | 4 +- ...uxaudiodriver.cpp => audiomidimanager.cpp} | 78 +++++++++---------- .../linuxaudiodriver.h => audiomidimanager.h} | 8 +- 4 files changed, 47 insertions(+), 47 deletions(-) rename src/framework/audio/internal/{platform/lin/linuxaudiodriver.cpp => audiomidimanager.cpp} (78%) rename src/framework/audio/internal/{platform/lin/linuxaudiodriver.h => audiomidimanager.h} (95%) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index 41102e834c9f1..4e50a6bf105a9 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -46,8 +46,8 @@ elseif(OS_IS_LIN OR OS_IS_FBSD OR MINGW) ) endif(MUSE_MODULE_AUDIO_JACK) set(DRIVER_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/linuxaudiodriver.h + ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsaaudiodriver.cpp diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index 1bcdd4810366c..6214ec9c98936 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -56,7 +56,7 @@ using namespace muse::audio::synth; using namespace muse::audio::fx; #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) -#include "internal/platform/lin/linuxaudiodriver.h" +#include "internal/audiomidimanager.h" #endif #if defined(Q_OS_WIN) && !defined(MINGW) @@ -113,7 +113,7 @@ void AudioModule::registerExports() m_soundFontRepository = std::make_shared(iocContext()); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) - m_audioDriver = std::shared_ptr(new LinuxAudioDriver()); + m_audioDriver = std::shared_ptr(new AudioMidiManager()); #endif #if defined(Q_OS_WIN) && !defined(MINGW) diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp b/src/framework/audio/internal/audiomidimanager.cpp similarity index 78% rename from src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp rename to src/framework/audio/internal/audiomidimanager.cpp index c036fde602c1c..7af7c3fe0d993 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -20,10 +20,10 @@ * along with this program. If not, see . */ #include "framework/audio/midiqueue.h" -#include "linuxaudiodriver.h" -#include "../alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists +#include "audiomidimanager.h" +#include "platform/alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists #if JACK_AUDIO -#include "../jack/jackaudiodriver.h" //FIX: relative path, set path in CMakeLists +#include "platform/jack/jackaudiodriver.h" //FIX: relative path, set path in CMakeLists #endif #include "translation.h" @@ -33,15 +33,15 @@ using namespace muse; using namespace muse::audio; -LinuxAudioDriver::LinuxAudioDriver() +AudioMidiManager::AudioMidiManager() { } -LinuxAudioDriver::~LinuxAudioDriver() +AudioMidiManager::~AudioMidiManager() { } -void LinuxAudioDriver::init() +void AudioMidiManager::init() { m_devicesListener.startWithCallback([this]() { return availableOutputDevices(); @@ -62,12 +62,12 @@ void LinuxAudioDriver::init() }); } -std::string LinuxAudioDriver::name() const +std::string AudioMidiManager::name() const { return m_current_audioDriverState->name(); } -bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) +bool AudioMidiManager::open(const Spec& spec, Spec* activeSpec) { /**************************************************************************/ // a bit lazy registering the midi-input-queue here, but midimodule isn't @@ -91,22 +91,22 @@ bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec) return true; } -void LinuxAudioDriver::close() +void AudioMidiManager::close() { return m_current_audioDriverState->close(); } -bool LinuxAudioDriver::isOpened() const +bool AudioMidiManager::isOpened() const { return m_current_audioDriverState->isOpened(); } -const LinuxAudioDriver::Spec& LinuxAudioDriver::activeSpec() const +const AudioMidiManager::Spec& AudioMidiManager::activeSpec() const { return s_format; } -AudioDeviceID LinuxAudioDriver::outputDevice() const +AudioDeviceID AudioMidiManager::outputDevice() const { if (m_current_audioDriverState != nullptr) { return m_current_audioDriverState->m_deviceId; @@ -116,7 +116,7 @@ AudioDeviceID LinuxAudioDriver::outputDevice() const } } -bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) +bool AudioMidiManager::makeDevice(const AudioDeviceID& deviceId) { #if defined(JACK_AUDIO) if (deviceId == "jack") { @@ -139,7 +139,7 @@ bool LinuxAudioDriver::makeDevice(const AudioDeviceID& deviceId) } // reopens the same device (if m_spec has changed) -bool LinuxAudioDriver::reopen(const AudioDeviceID& deviceId, Spec newSpec) +bool AudioMidiManager::reopen(const AudioDeviceID& deviceId, Spec newSpec) { // close current device if opened if (m_current_audioDriverState->isOpened()) { @@ -163,7 +163,7 @@ bool LinuxAudioDriver::reopen(const AudioDeviceID& deviceId, Spec newSpec) return true; } -bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) +bool AudioMidiManager::selectOutputDevice(const AudioDeviceID& deviceId) { // When starting, no previously device has been selected if (m_current_audioDriverState == nullptr) { @@ -179,7 +179,7 @@ bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId) return true; } -bool LinuxAudioDriver::resetToDefaultOutputDevice() +bool AudioMidiManager::resetToDefaultOutputDevice() { #if defined(JACK_AUDIO) return selectOutputDevice("jack"); // FIX: @@ -188,12 +188,12 @@ bool LinuxAudioDriver::resetToDefaultOutputDevice() #endif } -async::Notification LinuxAudioDriver::outputDeviceChanged() const +async::Notification AudioMidiManager::outputDeviceChanged() const { return m_outputDeviceChanged; } -AudioDeviceList LinuxAudioDriver::availableOutputDevices() const +AudioDeviceList AudioMidiManager::availableOutputDevices() const { AudioDeviceList devices; #if defined(JACK_AUDIO) @@ -205,61 +205,61 @@ AudioDeviceList LinuxAudioDriver::availableOutputDevices() const return devices; } -async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const +async::Notification AudioMidiManager::availableOutputDevicesChanged() const { return m_availableOutputDevicesChanged; } -void LinuxAudioDriver::isPlayingChanged() +void AudioMidiManager::isPlayingChanged() { if (m_current_audioDriverState) { m_current_audioDriverState->changedPlaying(); } } -void LinuxAudioDriver::positionChanged() +void AudioMidiManager::positionChanged() { if (m_current_audioDriverState) { m_current_audioDriverState->changedPosition(); } } -bool LinuxAudioDriver::isPlaying() const +bool AudioMidiManager::isPlaying() const { return playbackController()->isPlaying(); } -float LinuxAudioDriver::playbackPositionInSeconds() const +float AudioMidiManager::playbackPositionInSeconds() const { return playbackController()->playbackPositionInSeconds(); } -void LinuxAudioDriver::remotePlayOrStop(bool ps) const +void AudioMidiManager::remotePlayOrStop(bool ps) const { playbackController()->remotePlayOrStop(ps); } -void LinuxAudioDriver::remoteSeek(msecs_t millis) const +void AudioMidiManager::remoteSeek(msecs_t millis) const { playbackController()->remoteSeek(millis); } -int LinuxAudioDriver::audioDelayCompensate() const +int AudioMidiManager::audioDelayCompensate() const { return m_audioDelayCompensate; } -void LinuxAudioDriver::setAudioDelayCompensate(const int frames) +void AudioMidiManager::setAudioDelayCompensate(const int frames) { m_audioDelayCompensate = frames; } -unsigned int LinuxAudioDriver::outputDeviceBufferSize() const +unsigned int AudioMidiManager::outputDeviceBufferSize() const { return m_current_audioDriverState->m_spec.samples; } -bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) +bool AudioMidiManager::setOutputDeviceBufferSize(unsigned int bufferSize) { if (m_spec.samples == (int)bufferSize) { return true; @@ -272,12 +272,12 @@ bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize) return true; } -async::Notification LinuxAudioDriver::outputDeviceBufferSizeChanged() const +async::Notification AudioMidiManager::outputDeviceBufferSizeChanged() const { return m_bufferSizeChanged; } -std::vector LinuxAudioDriver::availableOutputDeviceBufferSizes() const +std::vector AudioMidiManager::availableOutputDeviceBufferSizes() const { std::vector result; @@ -294,13 +294,13 @@ std::vector LinuxAudioDriver::availableOutputDeviceBufferSizes() c // FIX-JACK-20240823: change api callers, WAS: // unsigned int LinuxAudioDriver::sampleRate() const -unsigned int LinuxAudioDriver::outputDeviceSampleRate() const +unsigned int AudioMidiManager::outputDeviceSampleRate() const { return m_current_audioDriverState->m_spec.sampleRate; } // FIX-JACK-20240823: merge this code -bool LinuxAudioDriver::setOutputDeviceSampleRate(unsigned int sampleRate) +bool AudioMidiManager::setOutputDeviceSampleRate(unsigned int sampleRate) { LOGE("------ setSamplerate: %u", sampleRate); if (m_spec.sampleRate == (int)sampleRate) { @@ -336,12 +336,12 @@ bool LinuxAudioDriver::setOutputDeviceSampleRate(unsigned int sampleRate) #endif } -async::Notification LinuxAudioDriver::outputDeviceSampleRateChanged() const +async::Notification AudioMidiManager::outputDeviceSampleRateChanged() const { return m_sampleRateChanged; } -std::vector LinuxAudioDriver::availableOutputDeviceSampleRates() const +std::vector AudioMidiManager::availableOutputDeviceSampleRates() const { // ALSA API is not of any help to get sample rates supported by the driver. // (snd_pcm_hw_params_get_rate_[min|max] will return 1 to 384000 Hz) @@ -353,7 +353,7 @@ std::vector LinuxAudioDriver::availableOutputDeviceSampleRates() c 96000, }; -bool LinuxAudioDriver::pushMidiEvent(muse::midi::Event& e) +bool AudioMidiManager::pushMidiEvent(muse::midi::Event& e) { if (m_current_audioDriverState) { m_current_audioDriverState->pushMidiEvent(e); @@ -362,7 +362,7 @@ bool LinuxAudioDriver::pushMidiEvent(muse::midi::Event& e) return false; } -std::vector LinuxAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection direction) const +std::vector AudioMidiManager::availableMidiDevices(muse::midi::MidiPortDirection direction) const { if (m_current_audioDriverState) { return m_current_audioDriverState->availableMidiDevices(direction); @@ -371,10 +371,10 @@ std::vector LinuxAudioDriver::availableMidiDevices(muse: return x; } -void LinuxAudioDriver::resume() +void AudioMidiManager::resume() { } -void LinuxAudioDriver::suspend() +void AudioMidiManager::suspend() { } diff --git a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h b/src/framework/audio/internal/audiomidimanager.h similarity index 95% rename from src/framework/audio/internal/platform/lin/linuxaudiodriver.h rename to src/framework/audio/internal/audiomidimanager.h index b90a98e39b889..b00fb3d0e683a 100644 --- a/src/framework/audio/internal/platform/lin/linuxaudiodriver.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -29,17 +29,17 @@ #include "framework/midi/midimodule.h" #include "iaudiodriver.h" -#include "audiodeviceslistener.h" +#include "platform/lin/audiodeviceslistener.h" #include "playback/iplaybackcontroller.h" namespace muse::audio { -class LinuxAudioDriver : public IAudioDriver, public async::Asyncable +class AudioMidiManager : public IAudioDriver, public async::Asyncable { Inject playbackController; Inject midiInPort; public: - LinuxAudioDriver(); - ~LinuxAudioDriver(); + AudioMidiManager(); + ~AudioMidiManager(); void init() override; From 6082e613f9d5273b80b2212375e60a78d4e48729 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 27 Apr 2024 14:28:45 +0200 Subject: [PATCH 32/60] cleanup private member naming --- src/framework/audio/iaudiodriver.h | 4 +- .../audio/internal/audiomidimanager.cpp | 6 +- .../platform/alsa/alsaaudiodriver.cpp | 60 ++++++------- .../internal/platform/alsa/alsaaudiodriver.h | 12 +-- .../platform/jack/jackaudiodriver.cpp | 86 +++++++++---------- .../internal/platform/jack/jackaudiodriver.h | 18 ++-- 6 files changed, 94 insertions(+), 92 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 1a1a86bc165ed..1b3c1dd906ddc 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -120,8 +120,8 @@ class AudioDriverState virtual void changedPlaying() const = 0; virtual void changedPosition() const = 0; - IAudioDriver::Spec m_spec; // current running spec - std::string m_deviceId; + IAudioDriver::Spec deviceSpec; // current running spec + std::string deviceId; }; } diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index 7af7c3fe0d993..a4a0ce820951f 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -109,7 +109,7 @@ const AudioMidiManager::Spec& AudioMidiManager::activeSpec() const AudioDeviceID AudioMidiManager::outputDevice() const { if (m_current_audioDriverState != nullptr) { - return m_current_audioDriverState->m_deviceId; + return m_current_audioDriverState->deviceId; } else { LOGE() << "device is not opened, deviceId: " << m_deviceId; return m_deviceId; // FIX: should return optional type @@ -256,7 +256,7 @@ void AudioMidiManager::setAudioDelayCompensate(const int frames) unsigned int AudioMidiManager::outputDeviceBufferSize() const { - return m_current_audioDriverState->m_spec.samples; + return m_current_audioDriverState->deviceSpec.samples; } bool AudioMidiManager::setOutputDeviceBufferSize(unsigned int bufferSize) @@ -296,7 +296,7 @@ std::vector AudioMidiManager::availableOutputDeviceBufferSizes() c // unsigned int LinuxAudioDriver::sampleRate() const unsigned int AudioMidiManager::outputDeviceSampleRate() const { - return m_current_audioDriverState->m_spec.sampleRate; + return m_current_audioDriverState->deviceSpec.sampleRate; } // FIX-JACK-20240823: merge this code diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 0ab04415c5167..3fe6f9c89a3d4 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -43,22 +43,22 @@ static void* alsaThread(void* aParam) muse::runtime::setThreadName("audio_driver"); AlsaDriverState* state = static_cast(aParam); - int ret = snd_pcm_wait(static_cast(state->m_alsaDeviceHandle), 1000); + int ret = snd_pcm_wait(static_cast(state->alsaDeviceHandle), 1000); IF_ASSERT_FAILED(ret > 0) { return nullptr; } - while (!state->m_audioProcessingDone) + while (!state->audioProcessingDone) { - uint8_t* stream = (uint8_t*)state->m_buffer; - int len = state->m_spec.samples * state->m_spec.channels * sizeof(float); + uint8_t* stream = (uint8_t*)state->buffer; + int len = state->deviceSpec.samples * state->deviceSpec.channels * sizeof(float); - state->m_spec.callback(state->m_spec.userdata, stream, len); + state->deviceSpec.callback(state->deviceSpec.userdata, stream, len); - snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(state->m_alsaDeviceHandle), state->m_buffer, state->m_spec.samples); + snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast(state->alsaDeviceHandle), state->buffer, state->deviceSpec.samples); if (pcm != -EPIPE) { } else { - snd_pcm_prepare(static_cast(state->m_alsaDeviceHandle)); + snd_pcm_prepare(static_cast(state->alsaDeviceHandle)); } } @@ -68,7 +68,7 @@ static void* alsaThread(void* aParam) AlsaDriverState::AlsaDriverState() { - m_deviceId = "alsa"; + deviceId = "alsa"; m_deviceName = ALSA_DEFAULT_DEVICE_ID; } @@ -79,25 +79,25 @@ AlsaDriverState::~AlsaDriverState() void AlsaDriverState::alsaCleanup() { - m_audioProcessingDone = true; + audioProcessingDone = true; if (m_threadHandle) { pthread_join(m_threadHandle, nullptr); } - if (m_alsaDeviceHandle != nullptr) { - snd_pcm_t* aDevice = static_cast(m_alsaDeviceHandle); + if (alsaDeviceHandle != nullptr) { + snd_pcm_t* aDevice = static_cast(alsaDeviceHandle); snd_pcm_drain(aDevice); snd_pcm_close(aDevice); - m_alsaDeviceHandle = nullptr; + alsaDeviceHandle = nullptr; } - if (m_buffer) { - delete[] m_buffer; + if (buffer) { + delete[] buffer; } - m_buffer = nullptr; + buffer = nullptr; } std::string AlsaDriverState::name() const { - return m_deviceId; + return deviceId; } std::string AlsaDriverState::deviceName() const @@ -116,10 +116,10 @@ void AlsaDriverState::setAudioDelayCompensate([[maybe_unused]] const int frames) bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { - m_spec.samples = spec.samples; - m_spec.channels = spec.channels; - m_spec.callback = spec.callback; - m_spec.userdata = spec.userdata; + deviceSpec.samples = spec.samples; + deviceSpec.channels = spec.channels; + deviceSpec.callback = spec.callback; + deviceSpec.userdata = spec.userdata; snd_pcm_t* handle; int rc = snd_pcm_open(&handle, m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0); @@ -128,7 +128,7 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } - m_alsaDeviceHandle = handle; + alsaDeviceHandle = handle; snd_pcm_hw_params_t* params; snd_pcm_hw_params_alloca(¶ms); @@ -147,12 +147,12 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } - long unsigned int samples = m_spec.samples; + long unsigned int samples = deviceSpec.samples; rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &samples); if (rc < 0) { LOGE() << "Unable to set buffer size: " << samples << ", err code: " << rc; } - m_spec.samples = (int)samples; + deviceSpec.samples = (int)samples; rc = snd_pcm_hw_params(handle, params); if (rc < 0) { @@ -161,21 +161,21 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a snd_pcm_hw_params_get_rate(params, &val, &dir); aSamplerate = val; - m_spec.sampleRate = aSamplerate; + deviceSpec.sampleRate = aSamplerate; - if (m_buffer != nullptr) { + if (buffer != nullptr) { LOGW() << "open before close"; - delete[] m_buffer; - m_buffer = nullptr; + delete[] buffer; + buffer = nullptr; } - m_buffer = new float[m_spec.samples * m_spec.channels]; + buffer = new float[deviceSpec.samples * deviceSpec.channels]; if (activeSpec) { *activeSpec = spec; activeSpec->format = IAudioDriver::Format::AudioF32; activeSpec->sampleRate = aSamplerate; - m_spec = *activeSpec; + deviceSpec = *activeSpec; } m_threadHandle = 0; @@ -195,7 +195,7 @@ void AlsaDriverState::close() bool AlsaDriverState::isOpened() const { - return m_alsaDeviceHandle != nullptr; + return alsaDeviceHandle != nullptr; } void AlsaDriverState::changedPlaying() const diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 0f5a0e6968028..94f718b90ff2f 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -45,15 +45,17 @@ class AlsaDriverState : public AudioDriverState void changedPlaying() const override; void changedPosition() const override; - void* m_alsaDeviceHandle = nullptr; + void* alsaDeviceHandle = nullptr; + float* buffer = nullptr; + bool audioProcessingDone = false; - float* m_buffer = nullptr; - bool m_audioProcessingDone = false; - pthread_t m_threadHandle = 0; private: + void alsaCleanup(); + + pthread_t m_threadHandle = 0; + async::Channel m_eventReceived; std::string m_deviceName = "default"; - void alsaCleanup(); }; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 537522ef38900..3468ebe840ff0 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -165,7 +165,7 @@ bool musescore_seek(unsigned int pos) void JackDriverState::changedPlaying() const { - jack_client_t* client = static_cast(m_jackDeviceHandle); + jack_client_t* client = static_cast(jackDeviceHandle); if (s_jackDriver->isPlaying()) { jack_nframes_t frames = static_cast(s_jackDriver->playbackPositionInSeconds() * g_samplerate); @@ -180,7 +180,7 @@ void JackDriverState::changedPlaying() const void JackDriverState::changedPosition() const { - jack_client_t* client = static_cast(m_jackDeviceHandle); + jack_client_t* client = static_cast(jackDeviceHandle); jack_nframes_t frames = static_cast(s_jackDriver->playbackPositionInSeconds() * g_samplerate); // worker thread is updating muse_frame (which runs every 100ms) @@ -312,7 +312,7 @@ static int framecnt = 0; void check_jack_midi_transport(JackDriverState* state, jack_nframes_t nframes) { - jack_client_t* client = static_cast(state->m_jackDeviceHandle); + jack_client_t* client = static_cast(state->jackDeviceHandle); jack_muse_update_verify_sync(state, client); @@ -399,17 +399,17 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) { JackDriverState* state = static_cast(args); - jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(state->m_outputPorts[0], nframes); - jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(state->m_outputPorts[1], nframes); + jack_default_audio_sample_t* l = (float*)jack_port_get_buffer(state->outputPorts[0], nframes); + jack_default_audio_sample_t* r = (float*)jack_port_get_buffer(state->outputPorts[1], nframes); - uint8_t* stream = (uint8_t*)state->m_buffer; - state->m_spec.callback(state->m_spec.userdata, stream, nframes * state->m_spec.channels * sizeof(float)); - float* sp = state->m_buffer; + uint8_t* stream = (uint8_t*)state->buffer; + state->deviceSpec.callback(state->deviceSpec.userdata, stream, nframes * state->deviceSpec.channels * sizeof(float)); + float* sp = state->buffer; for (size_t i = 0; i < nframes; i++) { *l++ = *sp++; *r++ = *sp++; } - jack_client_t* client = static_cast(state->m_jackDeviceHandle); + jack_client_t* client = static_cast(state->jackDeviceHandle); // if (!isConnected()) { // LOGI() << "---- JACK-midi output sendEvent SORRY, not connected"; // return make_ret(Err::MidiNotConnected); @@ -420,8 +420,8 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) } check_jack_midi_transport(state, nframes); - if (!state->m_midiOutputPorts.empty()) { - jack_port_t* port = state->m_midiOutputPorts.front(); + if (!state->midiOutputPorts.empty()) { + jack_port_t* port = state->midiOutputPorts.front(); if (port) { int segmentSize = jack_get_buffer_size(client); void* pb = jack_port_get_buffer(port, segmentSize); @@ -429,7 +429,7 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) // FIX: can portBuffer be nullptr? muse::midi::Event e; while (1) { - if (state->m_midiQueue.pop(e)) { + if (state->midiQueue.pop(e)) { sendEvent(e, pb); } else { break; @@ -439,7 +439,7 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) } else { muse::midi::Event e; while (1) { - if (state->m_midiQueue.pop(e)) { + if (state->midiQueue.pop(e)) { LOGW() << "no jack-midi-outport, consumed unused Event: " << e.to_string(); } else { break; @@ -447,8 +447,8 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) } } - if (!state->m_midiInputPorts.empty()) { - jack_port_t* port = state->m_midiInputPorts.front(); + if (!state->midiInputPorts.empty()) { + jack_port_t* port = state->midiInputPorts.front(); if (port) { int segmentSize = jack_get_buffer_size(client); void* pb = jack_port_get_buffer(port, segmentSize); @@ -475,7 +475,7 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) event.buffer[1], event.buffer[2], event.buffer[0]); - state->m_eventReceived.send(static_cast(0), e); + state->eventReceived.send(static_cast(0), e); } } } @@ -500,22 +500,22 @@ static void jack_cleanup_callback(void*) JackDriverState::JackDriverState(IAudioDriver* amm) { s_jackDriver = this; - m_deviceId = JACK_DEFAULT_DEVICE_ID; + deviceId = JACK_DEFAULT_DEVICE_ID; m_deviceName = JACK_DEFAULT_IDENTIFY_AS; m_audiomidiManager = amm; } JackDriverState::~JackDriverState() { - if (m_jackDeviceHandle != nullptr) { - jack_client_close(static_cast(m_jackDeviceHandle)); + if (jackDeviceHandle != nullptr) { + jack_client_close(static_cast(jackDeviceHandle)); } - delete[] m_buffer; + delete[] buffer; } std::string JackDriverState::name() const { - return m_deviceId; + return deviceId; } std::string JackDriverState::deviceName() const @@ -552,10 +552,10 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return true; } - // m_spec.samples = spec.samples; // client doesn't set sample-rate - m_spec.channels = spec.channels; - m_spec.callback = spec.callback; - m_spec.userdata = spec.userdata; + deviceSpec.samples = spec.samples; // client doesn't set sample-rate + deviceSpec.channels = spec.channels; + deviceSpec.callback = spec.callback; + deviceSpec.userdata = spec.userdata; const char* clientName = m_deviceName.c_str(); jack_status_t status; @@ -564,10 +564,10 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a LOGE() << "jack_client_open() failed: " << status; return false; } - m_jackDeviceHandle = handle; + jackDeviceHandle = handle; unsigned int jackSamplerate = jack_get_sample_rate(handle); - m_spec.sampleRate = jackSamplerate; + deviceSpec.sampleRate = jackSamplerate; g_samplerate = jackSamplerate; // FIX: at samplerate change, this need to be adjusted g_frameslimit = static_cast((double)g_samplerate * (double)FRAMESLIMIT / 1000.0d); @@ -586,20 +586,20 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a //threadv.push_back(std::move(thread_musescore_state)); //threads = std::move(threadv); - jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&m_spec); + jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&deviceSpec); jack_port_t* output_port_left = jack_port_register(handle, "audio_out_left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - m_outputPorts.push_back(output_port_left); + outputPorts.push_back(output_port_left); jack_port_t* output_port_right = jack_port_register(handle, "audio_out_right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - m_outputPorts.push_back(output_port_right); - m_spec.samples = jack_get_buffer_size(handle); - m_buffer = new float[m_spec.samples * m_spec.channels]; + outputPorts.push_back(output_port_right); + deviceSpec.samples = jack_get_buffer_size(handle); + buffer = new float[deviceSpec.samples * deviceSpec.channels]; if (activeSpec) { *activeSpec = spec; activeSpec->format = IAudioDriver::Format::AudioF32; activeSpec->sampleRate = jackSamplerate; - m_spec = *activeSpec; + deviceSpec = *activeSpec; } jack_on_shutdown(handle, jack_cleanup_callback, (void*)this); @@ -613,13 +613,13 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a // midi input jack_port_t* midi_input_port = jack_port_register(handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - m_midiInputPorts.push_back(midi_input_port); + midiInputPorts.push_back(midi_input_port); // midi output int portFlag = JackPortIsOutput; const char* portType = JACK_DEFAULT_MIDI_TYPE; jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); - m_midiOutputPorts.push_back(port); + midiOutputPorts.push_back(port); muse_seek_requested = 0; mpos_frame = muse_frame = static_cast(s_jackDriver->playbackPositionInSeconds() * jackSamplerate); @@ -638,15 +638,15 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a void JackDriverState::close() { - jack_client_close(static_cast(m_jackDeviceHandle)); - m_jackDeviceHandle = nullptr; - delete[] m_buffer; - m_buffer = nullptr; + jack_client_close(static_cast(jackDeviceHandle)); + jackDeviceHandle = nullptr; + delete[] buffer; + buffer = nullptr; } bool JackDriverState::isOpened() const { - return m_jackDeviceHandle != nullptr; + return jackDeviceHandle != nullptr; } bool JackDriverState::isPlaying() const @@ -675,20 +675,20 @@ void JackDriverState::remoteSeek(msecs_t millis) const bool JackDriverState::pushMidiEvent(muse::midi::Event& e) { - m_midiQueue.push(e); + midiQueue.push(e); return true; } void JackDriverState::registerMidiInputQueue(async::Channel midiInputQueue) { - m_eventReceived = midiInputQueue; + eventReceived = midiInputQueue; } std::vector JackDriverState::availableMidiDevices(muse::midi::MidiPortDirection direction) const { std::vector ports; std::vector ret; - jack_client_t* client = static_cast(m_jackDeviceHandle); + jack_client_t* client = static_cast(jackDeviceHandle); const char** prts = jack_get_ports(client, 0, "midi", 0); if (!prts) { return ports; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index e8e3ca2235094..a4a8f69ca2097 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -48,15 +48,6 @@ class JackDriverState : public AudioDriverState, public async::Asyncable void deviceName(const std::string newDeviceName); std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const; - void* m_jackDeviceHandle = nullptr; - float* m_buffer = nullptr; - std::vector m_outputPorts; - std::vector m_midiInputPorts; - std::vector m_midiOutputPorts; - ThreadSafeQueue m_midiQueue; - async::Channel m_eventReceived; - mu::playback::IPlaybackController* m_playbackController; - void changedPlaying() const override; void changedPosition() const override; @@ -65,6 +56,15 @@ class JackDriverState : public AudioDriverState, public async::Asyncable void remotePlayOrStop(bool) const; void remoteSeek(msecs_t) const; + void* jackDeviceHandle = nullptr; + float* buffer = nullptr; + std::vector outputPorts; + std::vector midiInputPorts; + std::vector midiOutputPorts; + ThreadSafeQueue midiQueue; + async::Channel eventReceived; + mu::playback::IPlaybackController* playbackController; + private: IAudioDriver* m_audiomidiManager; std::string m_deviceName; From 892497418b709b50196ffe22ebdf1371dad88720 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 1 May 2024 18:18:47 +0200 Subject: [PATCH 33/60] GUI jack-transport enable checkbox --- src/appshell/appshell.qrc | 1 + .../Preferences/AudioMidiPreferencesPage.qml | 13 +++++ .../qml/Preferences/internal/JackSection.qml | 50 +++++++++++++++++++ .../preferences/audiomidipreferencesmodel.cpp | 18 +++++++ .../preferences/audiomidipreferencesmodel.h | 8 +++ .../audio/internal/audiomidimanager.cpp | 3 +- .../audio/internal/audiomidimanager.h | 3 ++ .../platform/jack/jackaudiodriver.cpp | 36 ++++++++----- .../internal/platform/jack/jackaudiodriver.h | 2 +- .../internal/playbackconfiguration.cpp | 22 ++++++++ src/playback/internal/playbackconfiguration.h | 6 +++ src/playback/iplaybackconfiguration.h | 4 ++ .../playback/playbackconfigurationstub.cpp | 15 ++++++ .../playback/playbackconfigurationstub.h | 4 ++ 14 files changed, 171 insertions(+), 14 deletions(-) create mode 100644 src/appshell/qml/Preferences/internal/JackSection.qml diff --git a/src/appshell/appshell.qrc b/src/appshell/appshell.qrc index 0c0c867273700..7f289f119e92b 100644 --- a/src/appshell/appshell.qrc +++ b/src/appshell/appshell.qrc @@ -103,6 +103,7 @@ qml/Preferences/internal/MeiSection.qml qml/Preferences/internal/PublishMuseScoreComSection.qml qml/Preferences/internal/MixerSection.qml + qml/Preferences/internal/JackSection.qml qml/DevTools/Extensions/ExtensionsListView.qml qml/platform/PlatformMenuBar.qml qml/Preferences/PercussionPreferencesPage.qml diff --git a/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml b/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml index 8724cccb6dbd0..616b53793d064 100644 --- a/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml +++ b/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml @@ -82,6 +82,19 @@ PreferencesPage { SeparatorLine {} + JackSection { + jackTransportEnable: playbackModel.jackTransportEnable + + navigation.section: root.navigationSection + navigation.order: root.navigationOrderStart + 3 + + onJackTransportEnableChangeRequested: function(enable) { + playbackModel.jackTransportEnable = enable + } + } + + SeparatorLine {} + MixerSection { muteHiddenInstruments: audioMidiModel.muteHiddenInstruments diff --git a/src/appshell/qml/Preferences/internal/JackSection.qml b/src/appshell/qml/Preferences/internal/JackSection.qml new file mode 100644 index 0000000000000..f31ad7b21568b --- /dev/null +++ b/src/appshell/qml/Preferences/internal/JackSection.qml @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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, see . + */ +import QtQuick 2.15 + +import Muse.Ui 1.0 +import Muse.UiComponents 1.0 + +BaseSection { + id: root + + title: qsTrc("appshell/preferences", "Jack") + + property alias jackTransportEnable: jackTransportEnableCheckBox.checked + + signal jackTransportEnableChangeRequested(bool enable) + + CheckBox { + id: jackTransportEnableCheckBox + + width: parent.width + + text: qsTrc("appshell/preferences", "Enable Jack Transport") + + navigation.name: "JackTransportEnableCheckbox" + navigation.panel: root.navigation + + onClicked: { + root.jackTransportEnableChangeRequested(!checked) + } + } +} diff --git a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp index 9be02db3429c6..a065b9862c7e9 100644 --- a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp +++ b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp @@ -99,6 +99,10 @@ void AudioMidiPreferencesModel::init() playbackConfiguration()->muteHiddenInstrumentsChanged().onReceive(this, [this](bool mute) { emit muteHiddenInstrumentsChanged(mute); }); + + playbackConfiguration()->jackTransportEnableChanged().onReceive(this, [this](bool mute) { + emit jackTransportEnableChanged(mute); + }); } QStringList AudioMidiPreferencesModel::audioApiList() const @@ -188,3 +192,17 @@ void AudioMidiPreferencesModel::setMuteHiddenInstruments(bool mute) playbackConfiguration()->setMuteHiddenInstruments(mute); } + +bool PlaybackPreferencesModel::jackTransportEnable() const +{ + return playbackConfiguration()->jackTransportEnable(); +} + +void PlaybackPreferencesModel::setJackTransportEnable(bool enable) +{ + if (enable == jackTransportEnable()) { + return; + } + + playbackConfiguration()->setJackTransportEnable(enable); +} diff --git a/src/appshell/view/preferences/audiomidipreferencesmodel.h b/src/appshell/view/preferences/audiomidipreferencesmodel.h index 5538d5e2c50e6..d2bc1e031fc8b 100644 --- a/src/appshell/view/preferences/audiomidipreferencesmodel.h +++ b/src/appshell/view/preferences/audiomidipreferencesmodel.h @@ -50,6 +50,8 @@ class AudioMidiPreferencesModel : public QObject, public muse::Injectable, publi Q_PROPERTY(bool muteHiddenInstruments READ muteHiddenInstruments WRITE setMuteHiddenInstruments NOTIFY muteHiddenInstrumentsChanged) + Q_PROPERTY(bool jackTransportEnable READ jackTransportEnable WRITE setJackTransportEnable NOTIFY jackTransportEnableChanged) + muse::Inject audioConfiguration = { this }; muse::Inject midiConfiguration = { this }; muse::Inject midiOutPort = { this }; @@ -81,6 +83,8 @@ class AudioMidiPreferencesModel : public QObject, public muse::Injectable, publi bool muteHiddenInstruments() const; + bool jackTransportEnable() const; + public slots: void setCurrentAudioApiIndex(int index); @@ -88,6 +92,8 @@ public slots: void setMuteHiddenInstruments(bool mute); + void setJackTransportEnable(bool enable); + signals: void currentAudioApiIndexChanged(int index); void midiInputDeviceIdChanged(); @@ -100,6 +106,8 @@ public slots: void muteHiddenInstrumentsChanged(bool mute); + void jackTransportEnableChanged(bool enable); + private: muse::midi::MidiDeviceID midiInputDeviceId(int index) const; muse::midi::MidiDeviceID midiOutputDeviceId(int index) const; diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index a4a0ce820951f..cf057d0e44d1c 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -120,7 +120,8 @@ bool AudioMidiManager::makeDevice(const AudioDeviceID& deviceId) { #if defined(JACK_AUDIO) if (deviceId == "jack") { - m_current_audioDriverState = std::make_unique(this); + bool transportEnable = playbackConfiguration()->jackTransportEnable(); + m_current_audioDriverState = std::make_unique(this, transportEnable); #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) } else if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index b00fb3d0e683a..2cff1f0b8cef1 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -30,12 +30,15 @@ #include "iaudiodriver.h" #include "platform/lin/audiodeviceslistener.h" +#include "playback/iplaybackconfiguration.h" #include "playback/iplaybackcontroller.h" namespace muse::audio { class AudioMidiManager : public IAudioDriver, public async::Asyncable { + Inject playbackConfiguration; Inject playbackController; + Inject midiInPort; public: AudioMidiManager(); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 3468ebe840ff0..d977e3840ee9b 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -48,6 +48,7 @@ static int g_jackTransportDelay = 0; using namespace muse::audio; using namespace muse::midi; namespace muse::audio { +static bool g_transportEnable = false; // variables to communicate between soft-realtime jack thread and musescore static msecs_t mpos_frame; // musescore frame and state static jack_nframes_t muse_frame; // musescore frame and state @@ -165,6 +166,9 @@ bool musescore_seek(unsigned int pos) void JackDriverState::changedPlaying() const { + if (!g_transportEnable) { + return; + } jack_client_t* client = static_cast(jackDeviceHandle); if (s_jackDriver->isPlaying()) { @@ -180,6 +184,9 @@ void JackDriverState::changedPlaying() const void JackDriverState::changedPosition() const { + if (!g_transportEnable) { + return; + } jack_client_t* client = static_cast(jackDeviceHandle); jack_nframes_t frames = static_cast(s_jackDriver->playbackPositionInSeconds() * g_samplerate); @@ -415,10 +422,12 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) // return make_ret(Err::MidiNotConnected); // } - if (muse_state == JackTransportRolling) { - mpos_frame += nframes; + if (g_transportEnable) { + if (muse_state == JackTransportRolling) { + mpos_frame += nframes; + } + check_jack_midi_transport(state, nframes); } - check_jack_midi_transport(state, nframes); if (!state->midiOutputPorts.empty()) { jack_port_t* port = state->midiOutputPorts.front(); @@ -497,12 +506,13 @@ static void jack_cleanup_callback(void*) } } -JackDriverState::JackDriverState(IAudioDriver* amm) +JackDriverState::JackDriverState(IAudioDriver* amm, bool transportEnable) { s_jackDriver = this; deviceId = JACK_DEFAULT_DEVICE_ID; m_deviceName = JACK_DEFAULT_IDENTIFY_AS; m_audiomidiManager = amm; + g_transportEnable = transportEnable; } JackDriverState::~JackDriverState() @@ -546,7 +556,7 @@ void JackDriverState::setAudioDelayCompensate(const int frames) bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) { - LOGI("using jackTransportDelay: %i", g_jackTransportDelay); + LOGI("using jack-transport: %b, jackTransportDelay: %i", g_transportEnable, g_jackTransportDelay); if (isOpened()) { LOGW() << "Jack is already opened"; return true; @@ -578,13 +588,15 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a //return false; } - // start musescore state thread - running_musescore_state = true; - std::thread thread_musescore_state(musescore_state); - thread_musescore_state.detach(); - //std::vector threadv; - //threadv.push_back(std::move(thread_musescore_state)); - //threads = std::move(threadv); + if (g_transportEnable) { + // start musescore state thread + running_musescore_state = true; + std::thread thread_musescore_state(musescore_state); + thread_musescore_state.detach(); + //std::vector threadv; + //threadv.push_back(std::move(thread_musescore_state)); + //threads = std::move(threadv); + } jack_set_sample_rate_callback(handle, jack_srate_callback, (void*)&deviceSpec); diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index a4a8f69ca2097..2a0b759c5bd96 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -33,7 +33,7 @@ namespace muse::audio { class JackDriverState : public AudioDriverState, public async::Asyncable { public: - JackDriverState(IAudioDriver* amm); + JackDriverState(IAudioDriver* amm, bool transportEnable); ~JackDriverState(); std::string name() const override; diff --git a/src/playback/internal/playbackconfiguration.cpp b/src/playback/internal/playbackconfiguration.cpp index 4932da6a6a87c..f0c7af3f0af69 100644 --- a/src/playback/internal/playbackconfiguration.cpp +++ b/src/playback/internal/playbackconfiguration.cpp @@ -58,6 +58,8 @@ static const Settings::Key MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_PLAYBACK_PROFILE_ static const Settings::Key MUTE_HIDDEN_INSTRUMENTS(moduleName, "playback/mixer/muteHiddenInstruments"); +static const Settings::Key JACK_TRANSPORT_ENABLE(moduleName, "playback/jack/transportEnable"); + static const Settings::Key DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS(moduleName, "playback/profiles/defaultProfileName"); static const SoundProfileName BASIC_PROFILE_NAME(u"MuseScore Basic"); static const SoundProfileName MUSE_PROFILE_NAME(u"Muse Sounds"); @@ -121,6 +123,11 @@ void PlaybackConfiguration::init() m_muteHiddenInstrumentsChanged.send(mute.toBool()); }); + settings()->setDefaultValue(JACK_TRANSPORT_ENABLE, Val(true)); + settings()->valueChanged(JACK_TRANSPORT_ENABLE).onReceive(nullptr, [this](const Val& enable) { + m_jackTransportEnableChanged.send(enable.toBool()); + }); + settings()->setDefaultValue(DEFAULT_SOUND_PROFILE_FOR_NEW_PROJECTS, Val(fallbackSoundProfileStr().toStdString())); for (aux_channel_idx_t idx = 0; idx < AUX_CHANNEL_NUM; ++idx) { @@ -269,6 +276,21 @@ muse::async::Channel PlaybackConfiguration::muteHiddenInstrumentsChanged() return m_muteHiddenInstrumentsChanged; } +bool PlaybackConfiguration::jackTransportEnable() const +{ + return settings()->value(JACK_TRANSPORT_ENABLE).toBool(); +} + +void PlaybackConfiguration::setJackTransportEnable(bool enable) +{ + settings()->setSharedValue(JACK_TRANSPORT_ENABLE, Val(enable)); +} + +muse::async::Channel PlaybackConfiguration::jackTransportEnableChanged() const +{ + return m_jackTransportEnableChanged; +} + const SoundProfileName& PlaybackConfiguration::basicSoundProfileName() const { return BASIC_PROFILE_NAME; diff --git a/src/playback/internal/playbackconfiguration.h b/src/playback/internal/playbackconfiguration.h index 1c13bcc328afb..d96e9081f7609 100644 --- a/src/playback/internal/playbackconfiguration.h +++ b/src/playback/internal/playbackconfiguration.h @@ -71,6 +71,10 @@ class PlaybackConfiguration : public IPlaybackConfiguration, public muse::async: void setMuteHiddenInstruments(bool mute) override; muse::async::Channel muteHiddenInstrumentsChanged() const override; + bool jackTransportEnable() const override; + void setJackTransportEnable(bool mute) override; + muse::async::Channel jackTransportEnableChanged() const override; + const SoundProfileName& basicSoundProfileName() const override; const SoundProfileName& museSoundProfileName() const override; SoundProfileName defaultProfileForNewProjects() const override; @@ -98,6 +102,8 @@ class PlaybackConfiguration : public IPlaybackConfiguration, public muse::async: muse::async::Channel m_isMixerSectionVisibleChanged; muse::async::Channel m_muteHiddenInstrumentsChanged; + + muse::async::Channel m_jackTransportEnableChanged; }; } diff --git a/src/playback/iplaybackconfiguration.h b/src/playback/iplaybackconfiguration.h index e58fec07a4b8b..348c5a463fcfa 100644 --- a/src/playback/iplaybackconfiguration.h +++ b/src/playback/iplaybackconfiguration.h @@ -67,6 +67,10 @@ class IPlaybackConfiguration : MODULE_EXPORT_INTERFACE virtual void setMuteHiddenInstruments(bool mute) = 0; virtual muse::async::Channel muteHiddenInstrumentsChanged() const = 0; + virtual bool jackTransportEnable() const = 0; + virtual void setJackTransportEnable(bool enable) = 0; + virtual muse::async::Channel jackTransportEnableChanged() const = 0; + virtual const SoundProfileName& basicSoundProfileName() const = 0; virtual const SoundProfileName& museSoundProfileName() const = 0; diff --git a/src/stubs/playback/playbackconfigurationstub.cpp b/src/stubs/playback/playbackconfigurationstub.cpp index 61f069f9ad221..9351ee9da4337 100644 --- a/src/stubs/playback/playbackconfigurationstub.cpp +++ b/src/stubs/playback/playbackconfigurationstub.cpp @@ -135,6 +135,21 @@ muse::async::Channel PlaybackConfigurationStub::muteHiddenInstrumentsChang return ch; } +bool PlaybackConfigurationStub::jackTransportEnable() const +{ + return false; +} + +void PlaybackConfigurationStub::setJackTransportEnable(bool) +{ +} + +muse::async::Channel PlaybackConfigurationStub::jackTransportEnableChanged() const +{ + static muse::async::Channel ch; + return ch; +} + const SoundProfileName& PlaybackConfigurationStub::basicSoundProfileName() const { static const SoundProfileName basic; diff --git a/src/stubs/playback/playbackconfigurationstub.h b/src/stubs/playback/playbackconfigurationstub.h index 9059819e6a5dd..db38a5fc388ee 100644 --- a/src/stubs/playback/playbackconfigurationstub.h +++ b/src/stubs/playback/playbackconfigurationstub.h @@ -61,6 +61,10 @@ class PlaybackConfigurationStub : public IPlaybackConfiguration void setMuteHiddenInstruments(bool mute) override; muse::async::Channel muteHiddenInstrumentsChanged() const override; + bool jackTransportEnable() const override; + void setJackTransportEnable(bool enable) override; + muse::async::Channel jackTransportEnableChanged() const override; + const SoundProfileName& basicSoundProfileName() const override; const SoundProfileName& museSoundProfileName() const override; From 5b5d1fae842fc57ed6a80b197450106e3b11ca4b Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 31 Aug 2024 19:25:09 +0200 Subject: [PATCH 34/60] (squash) audiomidipreferencesmodel --- src/appshell/view/preferences/audiomidipreferencesmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp index a065b9862c7e9..13bfe05e29b96 100644 --- a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp +++ b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp @@ -193,12 +193,12 @@ void AudioMidiPreferencesModel::setMuteHiddenInstruments(bool mute) playbackConfiguration()->setMuteHiddenInstruments(mute); } -bool PlaybackPreferencesModel::jackTransportEnable() const +bool AudioMidiPreferencesModel::jackTransportEnable() const { return playbackConfiguration()->jackTransportEnable(); } -void PlaybackPreferencesModel::setJackTransportEnable(bool enable) +void AudioMidiPreferencesModel::setJackTransportEnable(bool enable) { if (enable == jackTransportEnable()) { return; From a1e7fcc2155e9392e623526e07bb9575644e13ec Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 09:54:12 +0200 Subject: [PATCH 35/60] (squash) rebase --- .../commonaudioapiconfigurationmodel.cpp | 21 +------------------ src/playback/internal/playbackcontroller.cpp | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp index 7821cb8ac6eaf..50496c4ec682c 100644 --- a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp +++ b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp @@ -46,10 +46,6 @@ void CommonAudioApiConfigurationModel::load() emit sampleRateChanged(); emit bufferSizeListChanged(); emit bufferSizeChanged(); - - audioDriver()->sampleRateChanged().onNotify(this, [this]() { - LOGE("---- emit sampleRateChanged ----"); - emit sampleRateChanged(); }); audioDriver()->outputDeviceSampleRateChanged().onNotify(this, [this]() { @@ -87,22 +83,6 @@ void CommonAudioApiConfigurationModel::deviceSelected(const QString& deviceId) audioConfiguration()->setAudioOutputDeviceId(deviceId.toStdString()); } -int CommonAudioApiConfigurationModel::sampleRate() const -{ - return audioDriver()->sampleRate(); -} - -QList CommonAudioApiConfigurationModel::sampleRateList() const -{ - return { 16000, 32000, 44100, 48000 }; -} - -void CommonAudioApiConfigurationModel::sampleRateSelected(const QString& sampleRateStr) -{ - LOGE("------- selected samplerate: %s ------", qPrintable(sampleRateStr)); - audioConfiguration()->setSampleRate(sampleRateStr.toInt()); // FIX: setDriverSampleRate ? -} - unsigned int CommonAudioApiConfigurationModel::bufferSize() const { return audioDriver()->outputDeviceBufferSize(); @@ -146,5 +126,6 @@ QList CommonAudioApiConfigurationModel::sampleRateList() const void CommonAudioApiConfigurationModel::sampleRateSelected(const QString& sampleRateStr) { + LOGE("------- selected samplerate: %s ------", qPrintable(sampleRateStr)); audioConfiguration()->setSampleRate(sampleRateStr.toInt()); } diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 5ef29c1e97ed7..5db39c75cd157 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -140,7 +140,7 @@ void PlaybackController::init() m_measureInputLag = configuration()->shouldMeasureInputLag(); - m_playbackPositionChanged.onNotify(this, [this]() { + m_currentPlaybackPositionChanged.onNotify(this, [this]() { updateCurrentTempo(); msecs_t endMsecs = playbackEndMsecs(); From 34da2fc0c3b05fa409783c6f03f16b68ba0dfb2b Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 15:50:46 +0200 Subject: [PATCH 36/60] (squash) compile errors --- src/framework/audio/iaudiodriver.h | 4 ++-- .../audio/internal/audiomidimanager.cpp | 19 ++++++++++--------- .../audio/internal/audiomidimanager.h | 8 ++------ .../internal/audiooutputdevicecontroller.cpp | 7 +++---- .../platform/alsa/alsaaudiodriver.cpp | 2 +- .../internal/platform/alsa/alsaaudiodriver.h | 2 +- .../platform/jack/jackaudiodriver.cpp | 12 ++++++++++-- .../internal/platform/jack/jackaudiodriver.h | 2 +- src/playback/internal/playbackcontroller.cpp | 10 ---------- 9 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 1b3c1dd906ddc..2500de39afe6f 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -91,7 +91,7 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual std::vector availableOutputDeviceSampleRates() const = 0; virtual bool isPlaying() const = 0; - virtual float playbackPositionInSeconds() const = 0; + //virtual float playbackPositionInSeconds() const = 0; virtual void remotePlayOrStop(bool) const = 0; virtual void remoteSeek(msecs_t) const = 0; @@ -118,7 +118,7 @@ class AudioDriverState virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; virtual void changedPlaying() const = 0; - virtual void changedPosition() const = 0; + virtual void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const = 0; IAudioDriver::Spec deviceSpec; // current running spec std::string deviceId; diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index cf057d0e44d1c..004ad3948bb5a 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -57,8 +57,8 @@ void AudioMidiManager::init() }); // HELP: is playbackPositionChanged notified for incremental changes too? - playbackController()->playbackPositionChanged().onNotify(this, [this]() { - positionChanged(); + playbackController()->currentPlaybackPositionChanged().onReceive(this, [this](audio::secs_t secs, midi::tick_t tick) { + positionChanged(secs, tick); }); } @@ -103,7 +103,7 @@ bool AudioMidiManager::isOpened() const const AudioMidiManager::Spec& AudioMidiManager::activeSpec() const { - return s_format; + return m_current_audioDriverState->deviceSpec; } AudioDeviceID AudioMidiManager::outputDevice() const @@ -218,10 +218,10 @@ void AudioMidiManager::isPlayingChanged() } } -void AudioMidiManager::positionChanged() +void AudioMidiManager::positionChanged(muse::audio::secs_t secs, muse::midi::tick_t tick) { if (m_current_audioDriverState) { - m_current_audioDriverState->changedPosition(); + m_current_audioDriverState->changedPosition(secs, tick); } } @@ -230,10 +230,10 @@ bool AudioMidiManager::isPlaying() const return playbackController()->isPlaying(); } -float AudioMidiManager::playbackPositionInSeconds() const -{ - return playbackController()->playbackPositionInSeconds(); -} +//float AudioMidiManager::playbackPositionInSeconds() const +//{ +// return playbackController()->playbackPositionInSeconds(); +//} void AudioMidiManager::remotePlayOrStop(bool ps) const { @@ -353,6 +353,7 @@ std::vector AudioMidiManager::availableOutputDeviceSampleRates() c 88200, 96000, }; +} bool AudioMidiManager::pushMidiEvent(muse::midi::Event& e) { diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index 2cff1f0b8cef1..eebdcdd0e376f 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -65,10 +65,6 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; - unsigned int sampleRate() const override; - bool setSampleRate(unsigned int sampleRate) override; - async::Notification sampleRateChanged() const override; - std::vector availableOutputDeviceBufferSizes() const override; int audioDelayCompensate() const override; @@ -84,10 +80,10 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceSampleRates() const override; void isPlayingChanged(); - void positionChanged(); + void positionChanged(muse::audio::secs_t secs, muse::midi::tick_t tick); bool isPlaying() const override; - float playbackPositionInSeconds() const override; + //float playbackPositionInSeconds() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; diff --git a/src/framework/audio/internal/audiooutputdevicecontroller.cpp b/src/framework/audio/internal/audiooutputdevicecontroller.cpp index 22ddeb35ce1e9..ba2888dbfd136 100644 --- a/src/framework/audio/internal/audiooutputdevicecontroller.cpp +++ b/src/framework/audio/internal/audiooutputdevicecontroller.cpp @@ -47,13 +47,12 @@ void AudioOutputDeviceController::init() onOutputDeviceChanged(); } }); - configuration()->sampleRateChanged().onNotify(this, [this]() { unsigned int sampleRate = configuration()->sampleRate(); - bool ok = audioDriver()->setSampleRate(sampleRate); + bool ok = audioDriver()->setOutputDeviceSampleRate(sampleRate); if (ok) { - async::Async::call(this, [sampleRate](){ - AudioEngine::instance()->setSampleRate(sampleRate); + async::Async::call(this, [this, sampleRate](){ + audioEngine()->setSampleRate(sampleRate); }, AudioThread::ID); } }); diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 3fe6f9c89a3d4..4e31b457f6217 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -202,7 +202,7 @@ void AlsaDriverState::changedPlaying() const { } -void AlsaDriverState::changedPosition() const +void AlsaDriverState::changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const { } diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index 94f718b90ff2f..c2109258b7b9e 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -43,7 +43,7 @@ class AlsaDriverState : public AudioDriverState std::string deviceName() const; void deviceName(const std::string newDeviceName); void changedPlaying() const override; - void changedPosition() const override; + void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const override; void* alsaDeviceHandle = nullptr; float* buffer = nullptr; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index d977e3840ee9b..c59cc884aee0e 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -69,6 +69,9 @@ static bool running_musescore_state; //static std::vector threads; static JackDriverState* s_jackDriver; +muse::audio::secs_t g_secs = 0; +muse::midi::tick_t g_tick = 0; + void musescore_state_check_musescore() { jack_nframes_t pos = mpos_frame; @@ -182,8 +185,12 @@ void JackDriverState::changedPlaying() const } } -void JackDriverState::changedPosition() const +void JackDriverState::changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const { + // ugly, but provide position to playbackPositionInSeconds + g_secs = secs; + g_tick = tick; + if (!g_transportEnable) { return; } @@ -668,7 +675,8 @@ bool JackDriverState::isPlaying() const float JackDriverState::playbackPositionInSeconds() const { - return m_audiomidiManager->playbackPositionInSeconds(); + // this round-trip could be avoided if the caller uses info from changedposition + return g_secs; } void JackDriverState::remotePlayOrStop(bool ps) const diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 2a0b759c5bd96..0558af8f972fb 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -49,7 +49,7 @@ class JackDriverState : public AudioDriverState, public async::Asyncable std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const; void changedPlaying() const override; - void changedPosition() const override; + void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const override; bool isPlaying() const; float playbackPositionInSeconds() const; diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 5db39c75cd157..8d0e8c6cce9fd 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -140,16 +140,6 @@ void PlaybackController::init() m_measureInputLag = configuration()->shouldMeasureInputLag(); - m_currentPlaybackPositionChanged.onNotify(this, [this]() { - updateCurrentTempo(); - - msecs_t endMsecs = playbackEndMsecs(); - const LoopBoundaries& loop = notationPlayback()->loopBoundaries(); - if (m_currentPlaybackTimeMsecs == endMsecs && m_currentPlaybackTimeMsecs != loop.loopOutTick) { - stop(); - } - }); - m_remoteSeek.onReceive(this, [this](const muse::audio::msecs_t msecs) { seek(msecs); }); From a47e5553e2c14dbde8d977bd7d83a465ca7150be Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 16:38:39 +0200 Subject: [PATCH 37/60] (squash) api fixes --- src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml | 4 ++-- src/playback/internal/playbackcontroller.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml b/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml index 616b53793d064..00989d7f5d514 100644 --- a/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml +++ b/src/appshell/qml/Preferences/AudioMidiPreferencesPage.qml @@ -83,13 +83,13 @@ PreferencesPage { SeparatorLine {} JackSection { - jackTransportEnable: playbackModel.jackTransportEnable + jackTransportEnable: audioMidiModel.jackTransportEnable navigation.section: root.navigationSection navigation.order: root.navigationOrderStart + 3 onJackTransportEnableChangeRequested: function(enable) { - playbackModel.jackTransportEnable = enable + audioMidiModel.jackTransportEnable = enable } } diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 8d0e8c6cce9fd..2963be29daab1 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -254,6 +254,7 @@ void PlaybackController::seek(const audio::secs_t secs) void PlaybackController::remoteSeek(const msecs_t msecs) { + if (!currentPlayer() || !playback()) return; IF_ASSERT_FAILED(playback()) { return; } From caff8e9a8dc3b7606f44bb69e60f0684449c35bc Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 16:39:12 +0200 Subject: [PATCH 38/60] playbackStatus not ONLY_AUDIO_MAIN_THREAD --- src/framework/audio/internal/worker/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/audio/internal/worker/player.cpp b/src/framework/audio/internal/worker/player.cpp index ccd6842fe17d0..941b02d03c007 100644 --- a/src/framework/audio/internal/worker/player.cpp +++ b/src/framework/audio/internal/worker/player.cpp @@ -215,7 +215,7 @@ async::Channel Player::playbackPositionChanged() const PlaybackStatus Player::playbackStatus() const { - ONLY_AUDIO_MAIN_THREAD; + //ONLY_AUDIO_MAIN_THREAD; return m_playbackStatus; } From 763e8d829f68a367cbe884f879196ec0791e41a1 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 18:29:59 +0200 Subject: [PATCH 39/60] (sqash) code-style --- .../audio/internal/platform/win/wasapiaudiodriver.cpp | 1 + src/playback/internal/playbackcontroller.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index fd57180661ce3..dceeab3ca721b 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -409,6 +409,7 @@ unsigned int WasapiAudioDriver::minSupportedBufferSize() const } return closestBufferSize; +} bool WasapiAudioDriver::pushMidiEvent(muse::midi::Event&) { diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 2963be29daab1..69b1e12d0933e 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -254,7 +254,9 @@ void PlaybackController::seek(const audio::secs_t secs) void PlaybackController::remoteSeek(const msecs_t msecs) { - if (!currentPlayer() || !playback()) return; + if (!currentPlayer() || !playback()) { + return; + } IF_ASSERT_FAILED(playback()) { return; } From 1ae4b9098e03ae5e9a6200c1d4dd89513e839131 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 1 Sep 2024 18:38:12 +0200 Subject: [PATCH 40/60] (squash) rebase cleanups --- src/framework/audio/iaudiodriver.h | 1 - .../audio/internal/audiomidimanager.cpp | 5 ----- .../audio/internal/audiomidimanager.h | 1 - .../internal/platform/osx/osxaudiodriver.h | 5 ----- .../internal/platform/osx/osxaudiodriver.mm | 20 ------------------- .../platform/win/wasapiaudiodriver.cpp | 20 ------------------- .../internal/platform/win/wasapiaudiodriver.h | 7 ------- src/framework/stubs/audio/audiodriverstub.cpp | 5 ----- src/framework/stubs/audio/audiodriverstub.h | 1 - 9 files changed, 65 deletions(-) diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 2500de39afe6f..814b8d9b27f00 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -91,7 +91,6 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual std::vector availableOutputDeviceSampleRates() const = 0; virtual bool isPlaying() const = 0; - //virtual float playbackPositionInSeconds() const = 0; virtual void remotePlayOrStop(bool) const = 0; virtual void remoteSeek(msecs_t) const = 0; diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index 004ad3948bb5a..c13b5d26153e5 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -230,11 +230,6 @@ bool AudioMidiManager::isPlaying() const return playbackController()->isPlaying(); } -//float AudioMidiManager::playbackPositionInSeconds() const -//{ -// return playbackController()->playbackPositionInSeconds(); -//} - void AudioMidiManager::remotePlayOrStop(bool ps) const { playbackController()->remotePlayOrStop(ps); diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index eebdcdd0e376f..0ef3a110c7ad4 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -83,7 +83,6 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable void positionChanged(muse::audio::secs_t secs, muse::midi::tick_t tick); bool isPlaying() const override; - //float playbackPositionInSeconds() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 5c5313a7f9a9b..94d6972c8a7f6 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -66,14 +66,9 @@ class OSXAudioDriver : public IAudioDriver bool setOutputDeviceBufferSize(unsigned int bufferSize) override; async::Notification outputDeviceBufferSizeChanged() const override; - unsigned int sampleRate() const override; - bool setSampleRate(unsigned int sampleRate) override; - async::Notification sampleRateChanged() const override; - int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; bool isPlaying() const override; - float playbackPositionInSeconds() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index b2e9883e44c2c..66dc58fe21eaa 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -335,21 +335,6 @@ return m_bufferSizeChanged; } -unsigned int OSXAudioDriver::sampleRate() const -{ - return 0; -} - -bool OSXAudioDriver::setSampleRate(unsigned int sampleRate) -{ - return true; -} - -async::Notification OSXAudioDriver::sampleRateChanged() const -{ - return m_sampleRateChanged; -} - std::vector OSXAudioDriver::availableOutputDeviceBufferSizes() const { OSXAudioDeviceID osxDeviceId = this->osxDeviceId(); @@ -441,11 +426,6 @@ return false; } -float OSXAudioDriver::playbackPositionInSeconds() const -{ - return 0; -} - void OSXAudioDriver::remotePlayOrStop([[maybe_unused]] bool ps) const { } diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index dceeab3ca721b..8b225eba18cef 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -242,21 +242,6 @@ async::Notification WasapiAudioDriver::availableOutputDevicesChanged() const return m_availableOutputDevicesChanged; } -unsigned int WasapiAudioDriver::sampleRate() const -{ - return 0; -} - -bool WasapiAudioDriver::setSampleRate(unsigned int sampleRate) -{ - return true; -} - -async::Notification WasapiAudioDriver::sampleRateChanged() const -{ - return m_sampleRateChanged; -} - unsigned int WasapiAudioDriver::outputDeviceBufferSize() const { return m_activeSpec.samples; @@ -367,11 +352,6 @@ bool WasapiAudioDriver::isPlaying() const return false; } -float WasapiAudioDriver::playbackPositionInSeconds() const -{ - return 0; -} - void WasapiAudioDriver::remotePlayOrStop(bool ps) const { } diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index c753a7df7fbe1..34aad24c8a2b2 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -59,22 +59,15 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable std::vector availableOutputDeviceBufferSizes() const override; - // ------------------------------------------------------------------- - // FIX-JACK: api-change, WAS: - // unsigned int sampleRate() const override; - // bool setSampleRate(unsigned int sampleRate) override; - // async::Notification sampleRateChanged() const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; async::Notification outputDeviceSampleRateChanged() const override; - // ------------------------------------------------------------------- std::vector availableOutputDeviceSampleRates() const override; int audioDelayCompensate(void) const override; void setAudioDelayCompensate(const int frames) override; bool isPlaying() const override; - float playbackPositionInSeconds() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; bool pushMidiEvent(muse::midi::Event& e) override; diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index 7d88007be8424..cddc8fee97169 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -97,11 +97,6 @@ bool AudioDriverStub::isPlaying() const return false; } -float AudioDriverStub::playbackPositionInSeconds() const -{ - return 0; -} - unsigned int AudioDriverStub::sampleRate() const { return 0; diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index 09bf78e7e6d12..61ffcce256901 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -50,7 +50,6 @@ class AudioDriverStub : public IAudioDriver int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; bool isPlaying() const override; - float playbackPositionInSeconds() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; From 00062b4ff7e33e627badbbb4ce5fba5ff370f06a Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Thu, 3 Oct 2024 21:37:30 +0200 Subject: [PATCH 41/60] bugfix: millisecs and secs conflation --- .../audio/internal/platform/jack/jackaudiodriver.cpp | 7 ++++--- src/playback/internal/playbackcontroller.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index c59cc884aee0e..8394fafd15522 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -200,10 +200,10 @@ void JackDriverState::changedPosition(muse::audio::secs_t secs, muse::midi::tick // worker thread is updating muse_frame (which runs every 100ms) // thats why we can get out of sync with "ourself" if (labs((long int)muse_frame - (long int)frames) > g_frameslimit) { - LOGW("musescore tell transport to LOCATE mf=%u, fr=%u diff: %i (lim: %i)", + LOGW("musescore tell transport to LOCATE mf=%u, fr=%u diff: %i (lim: %li) g_secs: %f", muse_frame, frames, muse_frame - frames, - g_frameslimit); + g_frameslimit, g_secs.to_double()); jack_transport_locate(client, frames); muse_frame = mpos_frame = frames; muse_seek_countdown = 10; // KLUDGE: avoid transport seeking musescore for some time @@ -673,10 +673,11 @@ bool JackDriverState::isPlaying() const return m_audiomidiManager->isPlaying(); } +// FIX: return type double float JackDriverState::playbackPositionInSeconds() const { // this round-trip could be avoided if the caller uses info from changedposition - return g_secs; + return g_secs.to_double(); } void JackDriverState::remotePlayOrStop(bool ps) const diff --git a/src/playback/internal/playbackcontroller.cpp b/src/playback/internal/playbackcontroller.cpp index 69b1e12d0933e..d6e61d3565743 100644 --- a/src/playback/internal/playbackcontroller.cpp +++ b/src/playback/internal/playbackcontroller.cpp @@ -141,7 +141,7 @@ void PlaybackController::init() m_measureInputLag = configuration()->shouldMeasureInputLag(); m_remoteSeek.onReceive(this, [this](const muse::audio::msecs_t msecs) { - seek(msecs); + seek(msecs / 1000L); //FIX: dont do scaling here }); m_remotePlayOrStop.onReceive(this, [this](const bool playOrStop) { From ad36c8588654f9f09c40888c965c637bdb93ac71 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sun, 20 Oct 2024 12:55:27 +0200 Subject: [PATCH 42/60] (squash) wrong membername --- src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 4e31b457f6217..85ad5d78c06a4 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -124,7 +124,7 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a snd_pcm_t* handle; int rc = snd_pcm_open(&handle, m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { - LOGE() << "Unable to open device: " << outputDevice() << ", err code: " << rc; + LOGE() << "Unable to open device: " << name() << ", err code: " << rc; return false; } From efd6860debf6c61d328e8193b3e4c1067e7bd887 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Mon, 21 Oct 2024 22:47:18 +0200 Subject: [PATCH 43/60] mac-jack: cmake --- src/framework/audio/CMakeLists.txt | 14 ++++++++++++++ src/framework/midi/CMakeLists.txt | 1 + 2 files changed, 15 insertions(+) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index 4e50a6bf105a9..fa32007bed17c 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -55,7 +55,16 @@ elseif(OS_IS_LIN OR OS_IS_FBSD OR MINGW) ${JACK_SRC} ) elseif(OS_IS_MAC) + set(JACK_SRC "") + if (MUSE_MODULE_AUDIO_JACK) + set(JACK_SRC + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.h + ) + endif(MUSE_MODULE_AUDIO_JACK) set(DRIVER_SRC + ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.mm ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.h ) @@ -275,6 +284,11 @@ else () endif() if (OS_IS_MAC) + if (MUSE_MODULE_AUDIO_JACK) + find_package(Jack REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) + endif() find_library(AudioToolbox NAMES AudioToolbox) find_library(CoreAudio NAMES CoreAudio) set(MODULE_LINK ${MODULE_LINK} ${AudioToolbox} ${CoreAudio}) diff --git a/src/framework/midi/CMakeLists.txt b/src/framework/midi/CMakeLists.txt index 0336818e98246..30924be0cfd4a 100644 --- a/src/framework/midi/CMakeLists.txt +++ b/src/framework/midi/CMakeLists.txt @@ -66,6 +66,7 @@ elseif(OS_IS_FBSD) ) elseif(OS_IS_MAC) set(DRIVER_SRC + ${JACK_SRC} ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidioutport.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidioutport.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidiinport.cpp From 27be4c1c0462d064709d68910d8a2067774c2f09 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Mon, 21 Oct 2024 22:55:53 +0200 Subject: [PATCH 44/60] mac-jack: CI install jack --- buildscripts/ci/macos/setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildscripts/ci/macos/setup.sh b/buildscripts/ci/macos/setup.sh index 2cc0215d93450..e8f4865288f0f 100644 --- a/buildscripts/ci/macos/setup.sh +++ b/buildscripts/ci/macos/setup.sh @@ -27,6 +27,8 @@ export MACOSX_DEPLOYMENT_TARGET=10.14 # Install build tools echo "Install build tools" brew install cmake ninja --formula --quiet +brew install cmake --formula --quiet +brew install jack --formula --quiet # Download dependencies echo "Download dependencies" From 3b96d14f7fc47bba9acd1e732873ef36a6c8b4ee Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 09:48:15 +0200 Subject: [PATCH 45/60] (squash) fix compile errors on mac --- .../audio/internal/audiomidimanager.cpp | 8 ++++---- src/framework/audio/internal/audiomidimanager.h | 16 ++++++++-------- .../internal/platform/jack/jackaudiodriver.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index c13b5d26153e5..3e652829b8091 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -189,7 +189,7 @@ bool AudioMidiManager::resetToDefaultOutputDevice() #endif } -async::Notification AudioMidiManager::outputDeviceChanged() const +muse::async::Notification AudioMidiManager::outputDeviceChanged() const { return m_outputDeviceChanged; } @@ -206,7 +206,7 @@ AudioDeviceList AudioMidiManager::availableOutputDevices() const return devices; } -async::Notification AudioMidiManager::availableOutputDevicesChanged() const +muse::async::Notification AudioMidiManager::availableOutputDevicesChanged() const { return m_availableOutputDevicesChanged; } @@ -268,7 +268,7 @@ bool AudioMidiManager::setOutputDeviceBufferSize(unsigned int bufferSize) return true; } -async::Notification AudioMidiManager::outputDeviceBufferSizeChanged() const +muse::async::Notification AudioMidiManager::outputDeviceBufferSizeChanged() const { return m_bufferSizeChanged; } @@ -332,7 +332,7 @@ bool AudioMidiManager::setOutputDeviceSampleRate(unsigned int sampleRate) #endif } -async::Notification AudioMidiManager::outputDeviceSampleRateChanged() const +muse::async::Notification AudioMidiManager::outputDeviceSampleRateChanged() const { return m_sampleRateChanged; } diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index 0ef3a110c7ad4..f3cf56c0a5855 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -56,14 +56,14 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable AudioDeviceID outputDevice() const override; bool selectOutputDevice(const AudioDeviceID& deviceId) override; bool resetToDefaultOutputDevice() override; - async::Notification outputDeviceChanged() const override; + muse::async::Notification outputDeviceChanged() const override; AudioDeviceList availableOutputDevices() const override; - async::Notification availableOutputDevicesChanged() const override; + muse::async::Notification availableOutputDevicesChanged() const override; unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; - async::Notification outputDeviceBufferSizeChanged() const override; + muse::async::Notification outputDeviceBufferSizeChanged() const override; std::vector availableOutputDeviceBufferSizes() const override; @@ -75,7 +75,7 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; - async::Notification outputDeviceSampleRateChanged() const override; + muse::async::Notification outputDeviceSampleRateChanged() const override; std::vector availableOutputDeviceSampleRates() const override; @@ -92,16 +92,16 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable private: bool makeDevice(const AudioDeviceID& deviceId); bool reopen(const AudioDeviceID& deviceId, Spec newSpec); - async::Notification m_outputDeviceChanged; + muse::async::Notification m_outputDeviceChanged; mutable std::mutex m_devicesMutex; AudioDevicesListener m_devicesListener; - async::Notification m_availableOutputDevicesChanged; + muse::async::Notification m_availableOutputDevicesChanged; std::string m_deviceId; - async::Notification m_bufferSizeChanged; - async::Notification m_sampleRateChanged; + muse::async::Notification m_bufferSizeChanged; + muse::async::Notification m_sampleRateChanged; int m_audioDelayCompensate; struct IAudioDriver::Spec m_spec; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 0558af8f972fb..366008152a516 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -46,7 +46,7 @@ class JackDriverState : public AudioDriverState, public async::Asyncable std::string deviceName() const; void deviceName(const std::string newDeviceName); - std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const; + std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; void changedPlaying() const override; void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const override; From 0d5b5400fbef80f058f9e9173212be3b1724b45b Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 11:11:10 +0200 Subject: [PATCH 46/60] mac-jack: cmake --- src/framework/audio/CMakeLists.txt | 23 +++++++++-------------- src/framework/midi/CMakeLists.txt | 7 ++++++- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index fa32007bed17c..b8703b946c314 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -23,6 +23,14 @@ set(MODULE_ALIAS muse::audio) include(GetPlatformInfo) +set(JACK_SRC "") +if (MUSE_MODULE_AUDIO_JACK) + set(JACK_SRC + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.h + ) +endif(MUSE_MODULE_AUDIO_JACK) + if (OS_IS_WIN AND (NOT MINGW)) set(DRIVER_SRC #${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.cpp @@ -38,13 +46,6 @@ if (OS_IS_WIN AND (NOT MINGW)) ${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/audiodeviceslistener.h ) elseif(OS_IS_LIN OR OS_IS_FBSD OR MINGW) - set(JACK_SRC "") - if (MUSE_MODULE_AUDIO_JACK) - set(JACK_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.h - ) - endif(MUSE_MODULE_AUDIO_JACK) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h @@ -55,18 +56,12 @@ elseif(OS_IS_LIN OR OS_IS_FBSD OR MINGW) ${JACK_SRC} ) elseif(OS_IS_MAC) - set(JACK_SRC "") - if (MUSE_MODULE_AUDIO_JACK) - set(JACK_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackaudiodriver.h - ) - endif(MUSE_MODULE_AUDIO_JACK) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.mm ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.h + ${JACK_SRC} ) set_source_files_properties( diff --git a/src/framework/midi/CMakeLists.txt b/src/framework/midi/CMakeLists.txt index 30924be0cfd4a..592033abc0bd3 100644 --- a/src/framework/midi/CMakeLists.txt +++ b/src/framework/midi/CMakeLists.txt @@ -74,7 +74,6 @@ elseif(OS_IS_MAC) ) endif() - set(MODULE_SRC ${DRIVER_SRC} ${CMAKE_CURRENT_LIST_DIR}/midimodule.cpp @@ -101,9 +100,15 @@ if (OS_IS_MAC) find_library(CoreMIDI NAMES CoreMIDI) find_library(CoreAudio NAMES CoreAudio) set(MODULE_LINK ${MODULE_LINK} ${CoreMIDI} ${CoreAudio}) + if (MUSE_MODULE_AUDIO_JACK) + find_package(Jack REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) + endif() elseif (OS_IS_WIN) set(MODULE_LINK ${MODULE_LINK} winmm) elseif (OS_IS_LIN) + # FIX: why does jack sources compile without a find_library here? find_package(ALSA REQUIRED) set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS} ) set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread ) From 23f4316a1a200ee6a23c5587f25b396d5ee6b0e9 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 11:46:09 +0200 Subject: [PATCH 47/60] fix compiler errors and warnings --- src/framework/audio/internal/audiomidimanager.cpp | 2 +- src/framework/audio/internal/platform/jack/jackaudiodriver.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index 3e652829b8091..a70f7974549fd 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -299,7 +299,7 @@ unsigned int AudioMidiManager::outputDeviceSampleRate() const bool AudioMidiManager::setOutputDeviceSampleRate(unsigned int sampleRate) { LOGE("------ setSamplerate: %u", sampleRate); - if (m_spec.sampleRate == (int)sampleRate) { + if (m_spec.sampleRate == sampleRate) { LOGE("------ SAME setSamplerate, doing nothing ------"); return true; } diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 8394fafd15522..3a7e677c29fe8 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -587,7 +588,7 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a deviceSpec.sampleRate = jackSamplerate; g_samplerate = jackSamplerate; // FIX: at samplerate change, this need to be adjusted - g_frameslimit = static_cast((double)g_samplerate * (double)FRAMESLIMIT / 1000.0d); + g_frameslimit = static_cast((double)g_samplerate * (double)FRAMESLIMIT / 1000.0L); if (spec.sampleRate != jackSamplerate) { LOGW() << "Musescores samplerate: " << spec.sampleRate << ", is NOT the same as jack's: " << jackSamplerate; // FIX: enable this if it is possible for user to adjust samplerate (AUDIO_SAMPLE_RATE_KEY) From 90b302de11a3eafa02836d5b7359fe2e1b758a77 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 12:13:05 +0200 Subject: [PATCH 48/60] welcome to c++ --- src/framework/audio/internal/platform/jack/jackaudiodriver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 3a7e677c29fe8..6e40c258542f0 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -94,7 +94,8 @@ void musescore_state_do_seek() auto diff = std::chrono::duration_cast(now - musescore_act_time); auto ms = static_cast(diff.count()); auto millis = static_cast((double)musescore_act_seek * 1000 / (double)g_samplerate); - millis = std::max(millis - ms, 0L); + + millis = static_cast(std::max(static_cast(millis - ms), 0L)); LOGW("Jack mst: really do musescore-seek to %lu (%lims) (diff: %i) mf=%u/%li jf=%u lag: %lims", musescore_act_seek, millis, muse_frame - jack_frame, muse_frame, mpos_frame, jack_frame, ms); s_jackDriver->remoteSeek(millis); From 20768aceecb40952e965c7f119d99387450e388e Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 13:04:47 +0200 Subject: [PATCH 49/60] audiomidimanager needs audiodeviceslistener --- src/framework/audio/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index b8703b946c314..7dca71fde3ef0 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -59,6 +59,8 @@ elseif(OS_IS_MAC) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.mm ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.h ${JACK_SRC} From 759842c4f971de1cb4475d4886efc20c23efe43d Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 13:49:02 +0200 Subject: [PATCH 50/60] try to download and install jack universal library --- buildscripts/ci/macos/setup.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/buildscripts/ci/macos/setup.sh b/buildscripts/ci/macos/setup.sh index e8f4865288f0f..f16e6b11da42c 100644 --- a/buildscripts/ci/macos/setup.sh +++ b/buildscripts/ci/macos/setup.sh @@ -28,7 +28,13 @@ export MACOSX_DEPLOYMENT_TARGET=10.14 echo "Install build tools" brew install cmake ninja --formula --quiet brew install cmake --formula --quiet -brew install jack --formula --quiet + +#brew install jack --formula --quiet + +wget -q https://github.com/jackaudio/jack2-releases/releases/download/v1.9.22/jack2-macOS-universal-v1.9.22.tar.gz +tar xvf jack2-macOS-universal-v1.9.22.tar.gz +ls -ltr +installer -pkg ./jack2-osx-1.9.22.pkg -target / # Download dependencies echo "Download dependencies" From ba51b17466afc9a2fe35ef72f9ae4b6faedc8d82 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Sat, 26 Oct 2024 15:42:45 +0200 Subject: [PATCH 51/60] run installer for jack as root --- buildscripts/ci/macos/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/ci/macos/setup.sh b/buildscripts/ci/macos/setup.sh index f16e6b11da42c..ea5d359cd6b19 100644 --- a/buildscripts/ci/macos/setup.sh +++ b/buildscripts/ci/macos/setup.sh @@ -34,7 +34,7 @@ brew install cmake --formula --quiet wget -q https://github.com/jackaudio/jack2-releases/releases/download/v1.9.22/jack2-macOS-universal-v1.9.22.tar.gz tar xvf jack2-macOS-universal-v1.9.22.tar.gz ls -ltr -installer -pkg ./jack2-osx-1.9.22.pkg -target / +sudo installer -pkg ./jack2-osx-1.9.22.pkg -target / # Download dependencies echo "Download dependencies" From d04f628042cce30c1037414487a211b68b8efd90 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 30 Oct 2024 08:22:53 +0100 Subject: [PATCH 52/60] (squash) cleanup src/framework/audio/CMakeLists.txt --- src/framework/audio/CMakeLists.txt | 33 +++++++++--------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index 7dca71fde3ef0..d568be278c550 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -280,37 +280,24 @@ else () ) endif() +if (MUSE_MODULE_AUDIO_JACK) + find_package(Jack REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) +endif() + if (OS_IS_MAC) - if (MUSE_MODULE_AUDIO_JACK) - find_package(Jack REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) - set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) - endif() find_library(AudioToolbox NAMES AudioToolbox) find_library(CoreAudio NAMES CoreAudio) set(MODULE_LINK ${MODULE_LINK} ${AudioToolbox} ${CoreAudio}) elseif (OS_IS_WIN AND (NOT (MINGW))) set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) elseif (OS_IS_LIN) - if (MUSE_MODULE_AUDIO_JACK) - find_package(ALSA REQUIRED) - find_package(Jack REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS}) - set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} ${ALSA_LIBRARIES} pthread) - else() - find_package(ALSA REQUIRED) - set(MODULE_INCLUDE ${MODULE_INCLUDE} ${ALSA_INCLUDE_DIRS}) - set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread) - endif() + find_package(ALSA REQUIRED) + set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${ALSA_INCLUDE_DIRS}) + set(MODULE_LINK ${MODULE_LINK} ${ALSA_LIBRARIES} pthread) elseif (MINGW) - if (MUSE_MODULE_AUDIO_JACK) - find_package(Jack REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) - set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) - else() - set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) - endif() + set(MODULE_LINK ${MODULE_LINK} winmm mmdevapi mfplat) endif() set(MODULE_QRC audio.qrc) From 2d8f86bdb592b16ec45877ba14bd5985209f6e4f Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 30 Oct 2024 21:23:07 +0100 Subject: [PATCH 53/60] audiomidimanager osx stubs --- src/framework/audio/audiomodule.cpp | 12 ++---------- src/framework/audio/internal/audiomidimanager.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/framework/audio/audiomodule.cpp b/src/framework/audio/audiomodule.cpp index 6214ec9c98936..70d9e31f19895 100644 --- a/src/framework/audio/audiomodule.cpp +++ b/src/framework/audio/audiomodule.cpp @@ -55,7 +55,7 @@ using namespace muse::audio; using namespace muse::audio::synth; using namespace muse::audio::fx; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) +#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) #include "internal/audiomidimanager.h" #endif @@ -65,10 +65,6 @@ using namespace muse::audio::fx; #include "internal/platform/win/wasapiaudiodriver.h" #endif -#ifdef Q_OS_MACOS -#include "internal/platform/osx/osxaudiodriver.h" -#endif - #ifdef Q_OS_WASM #include "internal/platform/web/webaudiodriver.h" #endif @@ -112,7 +108,7 @@ void AudioModule::registerExports() m_playbackFacade = std::make_shared(iocContext()); m_soundFontRepository = std::make_shared(iocContext()); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) +#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(MINGW) m_audioDriver = std::shared_ptr(new AudioMidiManager()); #endif @@ -122,10 +118,6 @@ void AudioModule::registerExports() m_audioDriver = std::shared_ptr(new WasapiAudioDriver()); #endif -#ifdef Q_OS_MACOS - m_audioDriver = std::shared_ptr(new OSXAudioDriver()); -#endif - #ifdef Q_OS_WASM m_audioDriver = std::shared_ptr(new WebAudioDriver()); #endif diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index a70f7974549fd..f3239c6c7ffcb 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -21,11 +21,19 @@ */ #include "framework/audio/midiqueue.h" #include "audiomidimanager.h" + +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) #include "platform/alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists +#endif + #if JACK_AUDIO #include "platform/jack/jackaudiodriver.h" //FIX: relative path, set path in CMakeLists #endif +#ifdef Q_OS_MACOS +#include "internal/platform/osx/osxaudiodriver.h" +#endif + #include "translation.h" #include "log.h" #include "runtime.h" @@ -126,11 +134,18 @@ bool AudioMidiManager::makeDevice(const AudioDeviceID& deviceId) } else if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); #endif +//#ifdef Q_OS_MACOS +// } else if (deviceId == "osx") { +// m_current_audioDriverState = std::make_unique(); +//#endif #else #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); #endif +//#ifdef Q_OS_MACOS +// m_current_audioDriverState = std::make_unique(); +//#endif #endif } else { LOGE() << "Unknown device name: " << deviceId; From aeb9ee00fe72232551293dabef6d093766fb6a41 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Fri, 1 Nov 2024 22:44:59 +0100 Subject: [PATCH 54/60] remove midi --- src/app/CMakeLists.txt | 6 - .../commonaudioapiconfigurationmodel.cpp | 2 - src/engraving/dom/note.cpp | 6 +- src/framework/audio/iaudiodriver.h | 7 - .../audio/internal/audiomidimanager.cpp | 29 --- .../audio/internal/audiomidimanager.h | 6 - .../internal/fx/reverb/reverbprocessor.cpp | 6 +- .../internal/fx/reverb/reverbprocessor.h | 3 - .../platform/alsa/alsaaudiodriver.cpp | 16 -- .../internal/platform/alsa/alsaaudiodriver.h | 3 - .../platform/jack/jackaudiodriver.cpp | 216 ------------------ .../internal/platform/jack/jackaudiodriver.h | 8 - .../internal/platform/osx/osxaudiodriver.h | 2 - .../internal/platform/osx/osxaudiodriver.mm | 11 - .../platform/win/wasapiaudiodriver.cpp | 11 - .../internal/platform/win/wasapiaudiodriver.h | 2 - src/framework/audio/midiqueue.h | 45 ---- src/framework/midi/CMakeLists.txt | 18 -- .../internal/platform/jack/jackmidiinport.cpp | 93 -------- .../internal/platform/jack/jackmidiinport.h | 58 ----- .../platform/jack/jackmidioutport.cpp | 116 ---------- .../internal/platform/jack/jackmidioutport.h | 61 ----- .../internal/platform/lin/linuxmidiinport.cpp | 5 +- .../internal/platform/lin/linuxmidiinport.h | 7 - .../platform/lin/linuxmidioutport.cpp | 14 +- .../internal/platform/lin/linuxmidioutport.h | 7 - 26 files changed, 9 insertions(+), 749 deletions(-) delete mode 100644 src/framework/audio/midiqueue.h delete mode 100644 src/framework/midi/internal/platform/jack/jackmidiinport.cpp delete mode 100644 src/framework/midi/internal/platform/jack/jackmidiinport.h delete mode 100644 src/framework/midi/internal/platform/jack/jackmidioutport.cpp delete mode 100644 src/framework/midi/internal/platform/jack/jackmidioutport.h diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 97690674c5298..9824cb9fd06e9 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -239,12 +239,6 @@ if (CC_IS_EMSCRIPTEN) list(APPEND MSCORE_APPEND_SRC $) endif() -# if any above modules are using dynamic-library loading (musesampler) -# then if mingw, use dl-lib which emulates unix-dl -if (MINGW) - list(APPEND LINK_LIB "-ldl -fstack-protector") -endif (MINGW) - ########################################### # Resources ########################################### diff --git a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp index 50496c4ec682c..f5b3b394c16b4 100644 --- a/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp +++ b/src/appshell/view/preferences/commonaudioapiconfigurationmodel.cpp @@ -41,7 +41,6 @@ void CommonAudioApiConfigurationModel::load() }); audioDriver()->outputDeviceChanged().onNotify(this, [this]() { - LOGE("---- emit currentDeviceIdChanged ----"); emit currentDeviceIdChanged(); emit sampleRateChanged(); emit bufferSizeListChanged(); @@ -126,6 +125,5 @@ QList CommonAudioApiConfigurationModel::sampleRateList() const void CommonAudioApiConfigurationModel::sampleRateSelected(const QString& sampleRateStr) { - LOGE("------- selected samplerate: %s ------", qPrintable(sampleRateStr)); audioConfiguration()->setSampleRate(sampleRateStr.toInt()); } diff --git a/src/engraving/dom/note.cpp b/src/engraving/dom/note.cpp index 736c836a62f22..dbe4b4cfe793c 100644 --- a/src/engraving/dom/note.cpp +++ b/src/engraving/dom/note.cpp @@ -876,9 +876,9 @@ String Note::tpcUserName(const bool explicitAccidental, bool full) const String pitchOffset; if (tuning() != 0) { - static constexpr size_t maxLen = 50; - char buffer[maxLen]; - snprintf(buffer, maxLen, "%+.3f", tuning()); + static constexpr size_t bufferSize = 50; + char buffer[bufferSize]; + snprintf(buffer, bufferSize, "%+.3f", tuning()); pitchOffset = String::fromAscii(buffer); } diff --git a/src/framework/audio/iaudiodriver.h b/src/framework/audio/iaudiodriver.h index 814b8d9b27f00..a7ff9b74df93a 100644 --- a/src/framework/audio/iaudiodriver.h +++ b/src/framework/audio/iaudiodriver.h @@ -33,7 +33,6 @@ #include "audiotypes.h" #include "framework/midi/miditypes.h" -#include "framework/audio/midiqueue.h" namespace muse::audio { class AudioDriverState; @@ -97,9 +96,6 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE virtual int audioDelayCompensate() const = 0; virtual void setAudioDelayCompensate(const int frames) = 0; - virtual bool pushMidiEvent(muse::midi::Event&) = 0; - virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; - virtual void resume() = 0; virtual void suspend() = 0; }; @@ -112,9 +108,6 @@ class AudioDriverState virtual void close() = 0; virtual bool isOpened() const = 0; virtual void setAudioDelayCompensate(const int frames) = 0; - virtual bool pushMidiEvent(muse::midi::Event&) = 0; - virtual void registerMidiInputQueue(async::Channel) = 0; - virtual std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const = 0; virtual void changedPlaying() const = 0; virtual void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const = 0; diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index f3239c6c7ffcb..a5dc56dc0ae9b 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -19,7 +19,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "framework/audio/midiqueue.h" #include "audiomidimanager.h" #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) @@ -77,16 +76,6 @@ std::string AudioMidiManager::name() const bool AudioMidiManager::open(const Spec& spec, Spec* activeSpec) { - /**************************************************************************/ - // a bit lazy registering the midi-input-queue here, but midimodule isn't - // available at audiomodule init, because midimodule starts after audiomodule - // not sure we got the identity of eventQueue (ie, passed by reference) -#if defined(JACK_AUDIO) - muse::async::Channel queue = midiInPort()->eventReceived(); - m_current_audioDriverState->registerMidiInputQueue(queue); -#endif - /**************************************************************************/ - // re-initialize devide m_current_audioDriverState->setAudioDelayCompensate(m_audioDelayCompensate); @@ -365,24 +354,6 @@ std::vector AudioMidiManager::availableOutputDeviceSampleRates() c }; } -bool AudioMidiManager::pushMidiEvent(muse::midi::Event& e) -{ - if (m_current_audioDriverState) { - m_current_audioDriverState->pushMidiEvent(e); - return true; - } - return false; -} - -std::vector AudioMidiManager::availableMidiDevices(muse::midi::MidiPortDirection direction) const -{ - if (m_current_audioDriverState) { - return m_current_audioDriverState->availableMidiDevices(direction); - } - std::vector x; - return x; -} - void AudioMidiManager::resume() { } diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index f3cf56c0a5855..e63315eaf6d89 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -25,8 +25,6 @@ #include "async/asyncable.h" -#include "framework/midi/imidiinport.h" -#include "framework/midi/midimodule.h" #include "iaudiodriver.h" #include "platform/lin/audiodeviceslistener.h" @@ -39,7 +37,6 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable Inject playbackConfiguration; Inject playbackController; - Inject midiInPort; public: AudioMidiManager(); ~AudioMidiManager(); @@ -70,9 +67,6 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable int audioDelayCompensate() const override; void setAudioDelayCompensate(const int frames) override; - bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; - unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; muse::async::Notification outputDeviceSampleRateChanged() const override; diff --git a/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp b/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp index a8974d81c1fc1..5e42df6c95177 100644 --- a/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp +++ b/src/framework/audio/internal/fx/reverb/reverbprocessor.cpp @@ -287,7 +287,7 @@ ReverbProcessor::ReverbProcessor(const AudioFxParams& params, audioch_t audioCha setParameter(Params::PreDelayMs, getParameter(Params::PreDelayMs)); setParameter(Params::FeedbackTop, getParameter(Params::FeedbackTop)); - setFormat(audioChannelsCount, audioConfiguration()->sampleRate(), 512 /*maximumBlockSize*/); + setFormat(audioChannelsCount, 44100.0 /*sampleRate*/, 512 /*maximumBlockSize*/); } ReverbProcessor::~ReverbProcessor() @@ -380,7 +380,7 @@ float ReverbProcessor::getParameter(int32_t index) void ReverbProcessor::calculateTailParams() { const int* delayTimes = _delayTimesForN(m_delays); - float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / static_cast(audioConfiguration()->sampleRate())); + float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / 44100.); const float log_db60 = std::log(fromDecibel(-60.f)); @@ -438,7 +438,7 @@ void ReverbProcessor::calculateModParams() float modDepthSmp = float(depthMs * 0.001f * m_processor._sampleRate); d->sinLfo.setup(m_delays, freqHz * d->modStep, modDepthSmp, m_processor._sampleRate); - float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / static_cast(audioConfiguration()->sampleRate())); + float scale = float(getParameter(LateRoomScale) * m_processor._sampleRate / 44100.); for (int i = 0; i < m_delays; ++i) { d->modDelay[i].setBaseDelay(delayTimes[i] * scale, modDepthSmp * 2.f); } diff --git a/src/framework/audio/internal/fx/reverb/reverbprocessor.h b/src/framework/audio/internal/fx/reverb/reverbprocessor.h index 2c7deca03cb7d..b84f9bfced4f5 100644 --- a/src/framework/audio/internal/fx/reverb/reverbprocessor.h +++ b/src/framework/audio/internal/fx/reverb/reverbprocessor.h @@ -28,14 +28,11 @@ #include #include -#include "modularity/ioc.h" -#include "iaudioconfiguration.h" #include "ifxprocessor.h" namespace muse::audio::fx { class ReverbProcessor : public IFxProcessor { - Inject audioConfiguration; public: ReverbProcessor(const audio::AudioFxParams& params, audioch_t audioChannelsCount = 2); ~ReverbProcessor() override; diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp index 85ad5d78c06a4..3121f46efb86c 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp @@ -205,19 +205,3 @@ void AlsaDriverState::changedPlaying() const void AlsaDriverState::changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const { } - -bool AlsaDriverState::pushMidiEvent(muse::midi::Event&) -{ - return true; // dummy -} - -void AlsaDriverState::registerMidiInputQueue(async::Channel midiInputQueue) -{ - m_eventReceived = midiInputQueue; -} - -std::vector AlsaDriverState::availableMidiDevices([[maybe_unused]] muse::midi::MidiPortDirection direction) const -{ - std::vector x; - return x; // dummy -} diff --git a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h index c2109258b7b9e..1eaeb0bb9a403 100644 --- a/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h +++ b/src/framework/audio/internal/platform/alsa/alsaaudiodriver.h @@ -37,9 +37,6 @@ class AlsaDriverState : public AudioDriverState void close() override; bool isOpened() const override; void setAudioDelayCompensate(const int frames) override; - bool pushMidiEvent(muse::midi::Event& e) override; - void registerMidiInputQueue(async::Channel) override; - std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; std::string deviceName() const; void deviceName(const std::string newDeviceName); void changedPlaying() const override; diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp index 6e40c258542f0..e0ae70a63289a 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.cpp @@ -21,9 +21,6 @@ */ #include "jackaudiodriver.h" #include -#include "framework/midi/miditypes.h" -#include "framework/midi/midierrors.h" -#include "framework/midi/imidiinport.h" #include #include @@ -47,7 +44,6 @@ static int g_jackTransportDelay = 0; using namespace muse::audio; -using namespace muse::midi; namespace muse::audio { static bool g_transportEnable = false; // variables to communicate between soft-realtime jack thread and musescore @@ -212,89 +208,6 @@ void JackDriverState::changedPosition(muse::audio::secs_t secs, muse::midi::tick } } -/* - * MIDI - */ - -muse::Ret sendEvent_noteonoff(void* pb, int framePos, const muse::midi::Event& e) -{ - unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); - if (p == 0) { - LOGE("JackMidi: buffer overflow, event lost"); - return muse::Ret(false); - } - // FIX: is opcode an compatible MIDI enumeration? - if (e.opcode() == muse::midi::Event::Opcode::NoteOn) { - p[0] = /* e.opcode() */ 0x90 | e.channel(); - } else { - p[0] = /* e.opcode() */ 0x80 | e.channel(); - } - p[1] = e.note(); - p[2] = e.velocity(); - return muse::Ret(true); -} - -muse::Ret sendEvent_control(void* pb, int framePos, const Event& e) -{ - unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); - if (p == 0) { - LOGE("JackMidi: buffer overflow, event lost"); - return muse::Ret(false); - } - p[0] = /* e.opcode() */ 0xb0 | e.channel(); - p[1] = e.index(); - p[2] = e.data(); - return muse::Ret(true); -} - -muse::Ret sendEvent_program(void* pb, int framePos, const Event& e) -{ - unsigned char* p = jack_midi_event_reserve(pb, framePos, 2); - if (p == 0) { - LOGE("JackMidiOutput: buffer overflow, event lost"); - return muse::Ret(false); - } - p[0] = /* e.opcode() */ 0xc0 | e.channel(); - p[1] = e.program(); - return muse::Ret(true); -} - -muse::Ret sendEvent_pitchbend(void* pb, int framePos, const Event& e) -{ - unsigned char* p = jack_midi_event_reserve(pb, framePos, 3); - if (p == 0) { - LOGE("JackMidiOutput: buffer overflow, event lost"); - return muse::Ret(false); - } - p[0] = /* e.opcode() */ 0xe0 | e.channel(); - p[1] = e.data(); // dataA - p[2] = e.velocity(); // dataB - return muse::Ret(true); -} - -muse::Ret sendEvent(const Event& e, void* pb) -{ - int framePos = 0; - switch (e.opcode()) { - // FIX: Event::Opcode::POLYAFTER ? - case Event::Opcode::NoteOn: - return sendEvent_noteonoff(pb, framePos, e); - case Event::Opcode::NoteOff: - return sendEvent_noteonoff(pb, framePos, e); - case Event::Opcode::ControlChange: - return sendEvent_control(pb, framePos, e); - case Event::Opcode::ProgramChange: - return sendEvent_control(pb, framePos, e); - case Event::Opcode::PitchBend: - return sendEvent_pitchbend(pb, framePos, e); - default: - NOT_SUPPORTED << "event: " << e.to_string(); - return make_ret(muse::midi::Err::MidiNotSupported); - } - - return Ret(true); -} - // musescore has around 200ms inaccuracy in playbackPositionInSeconds bool is_muse_jack_frame_sync(jack_nframes_t mf, jack_nframes_t jf) { @@ -438,69 +351,6 @@ static int jack_process_callback(jack_nframes_t nframes, void* args) check_jack_midi_transport(state, nframes); } - if (!state->midiOutputPorts.empty()) { - jack_port_t* port = state->midiOutputPorts.front(); - if (port) { - int segmentSize = jack_get_buffer_size(client); - void* pb = jack_port_get_buffer(port, segmentSize); - // handle midi - // FIX: can portBuffer be nullptr? - muse::midi::Event e; - while (1) { - if (state->midiQueue.pop(e)) { - sendEvent(e, pb); - } else { - break; - } - } - } - } else { - muse::midi::Event e; - while (1) { - if (state->midiQueue.pop(e)) { - LOGW() << "no jack-midi-outport, consumed unused Event: " << e.to_string(); - } else { - break; - } - } - } - - if (!state->midiInputPorts.empty()) { - jack_port_t* port = state->midiInputPorts.front(); - if (port) { - int segmentSize = jack_get_buffer_size(client); - void* pb = jack_port_get_buffer(port, segmentSize); - if (pb) { - muse::midi::Event ev; - jack_nframes_t n = jack_midi_get_event_count(pb); - for (jack_nframes_t i = 0; i < n; ++i) { - jack_midi_event_t event; - if (jack_midi_event_get(&event, pb, i) != 0) { - continue; - } - int type = event.buffer[0]; - uint32_t data = 0; - if ((type & 0xf0) == 0x90 - || (type & 0xf0) == 0x90) { - data = 0x90 - | (type & 0x0f) - | ((event.buffer[1] & 0x7F) << 8) - | ((event.buffer[2] & 0x7F) << 16); - Event e = Event::fromMIDI10Package(data); - e = e.toMIDI20(); - if (e) { - LOGI("-- jack midi-input-port send %i,%i,%i", - event.buffer[1], - event.buffer[2], - event.buffer[0]); - state->eventReceived.send(static_cast(0), e); - } - } - } - } - } - } - return 0; } @@ -632,16 +482,6 @@ bool JackDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a return false; } - // midi input - jack_port_t* midi_input_port = jack_port_register(handle, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - midiInputPorts.push_back(midi_input_port); - - // midi output - int portFlag = JackPortIsOutput; - const char* portType = JACK_DEFAULT_MIDI_TYPE; - jack_port_t* port = jack_port_register(handle, "Musescore", portType, portFlag, 0); - midiOutputPorts.push_back(port); - muse_seek_requested = 0; mpos_frame = muse_frame = static_cast(s_jackDriver->playbackPositionInSeconds() * jackSamplerate); if (muse_frame >= g_jackTransportDelay) { @@ -691,59 +531,3 @@ void JackDriverState::remoteSeek(msecs_t millis) const { m_audiomidiManager->remoteSeek(millis); } - -/* - * MIDI - */ - -bool JackDriverState::pushMidiEvent(muse::midi::Event& e) -{ - midiQueue.push(e); - return true; -} - -void JackDriverState::registerMidiInputQueue(async::Channel midiInputQueue) -{ - eventReceived = midiInputQueue; -} - -std::vector JackDriverState::availableMidiDevices(muse::midi::MidiPortDirection direction) const -{ - std::vector ports; - std::vector ret; - jack_client_t* client = static_cast(jackDeviceHandle); - const char** prts = jack_get_ports(client, 0, "midi", 0); - if (!prts) { - return ports; - } - int devIndex = 0; - for (const char** p = prts; p && *p; ++p) { - jack_port_t* port = jack_port_by_name(client, *p); - int flags = jack_port_flags(port); - - if ((flags & JackPortIsInput) - && direction == muse::midi::MidiPortDirection::Output) { - continue; - } - if ((flags & JackPortIsOutput) - && direction == muse::midi::MidiPortDirection::Input) { - continue; - } - - char buffer[128]; - strncpy(buffer, *p, sizeof(buffer) - 1); - buffer[sizeof(buffer) - 1] = 0; - - if (strncmp(buffer, "MuseScore", 9) == 0) { - continue; - } - muse::midi::MidiDevice dev; - dev.name = buffer; - dev.id = makeUniqueDeviceId(devIndex++, 0, 0); - ports.push_back(std::move(dev)); - } - - free(prts); - - return ports; -} diff --git a/src/framework/audio/internal/platform/jack/jackaudiodriver.h b/src/framework/audio/internal/platform/jack/jackaudiodriver.h index 366008152a516..b75ffd5c7378d 100644 --- a/src/framework/audio/internal/platform/jack/jackaudiodriver.h +++ b/src/framework/audio/internal/platform/jack/jackaudiodriver.h @@ -25,7 +25,6 @@ #include -#include "framework/midi/miditypes.h" #include "iaudiodriver.h" #include "playback/iplaybackcontroller.h" @@ -40,13 +39,10 @@ class JackDriverState : public AudioDriverState, public async::Asyncable bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override; void close() override; bool isOpened() const override; - bool pushMidiEvent(muse::midi::Event& e) override; - void registerMidiInputQueue(async::Channel) override; void setAudioDelayCompensate(const int frames) override; std::string deviceName() const; void deviceName(const std::string newDeviceName); - std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; void changedPlaying() const override; void changedPosition(muse::audio::secs_t secs, muse::midi::tick_t tick) const override; @@ -59,10 +55,6 @@ class JackDriverState : public AudioDriverState, public async::Asyncable void* jackDeviceHandle = nullptr; float* buffer = nullptr; std::vector outputPorts; - std::vector midiInputPorts; - std::vector midiOutputPorts; - ThreadSafeQueue midiQueue; - async::Channel eventReceived; mu::playback::IPlaybackController* playbackController; private: diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.h b/src/framework/audio/internal/platform/osx/osxaudiodriver.h index 94d6972c8a7f6..d5d9b0e16ad9b 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.h +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.h @@ -73,8 +73,6 @@ class OSXAudioDriver : public IAudioDriver void remoteSeek(msecs_t) const override; std::vector availableOutputDeviceBufferSizes() const override; - bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; unsigned int outputDeviceSampleRate() const override; bool setOutputDeviceSampleRate(unsigned int sampleRate) override; diff --git a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm index 66dc58fe21eaa..a11423c5304b1 100644 --- a/src/framework/audio/internal/platform/osx/osxaudiodriver.mm +++ b/src/framework/audio/internal/platform/osx/osxaudiodriver.mm @@ -597,14 +597,3 @@ static OSStatus onDeviceListChanged(AudioObjectID inObjectID, UInt32 inNumberAdd pData->callback(pData->mUserData, (uint8_t*)buffer->mAudioData, buffer->mAudioDataByteSize); AudioQueueEnqueueBuffer(pData->audioQueue, buffer, 0, NULL); } - -bool OSXAudioDriver::pushMidiEvent(muse::midi::Event&) -{ - return true; // dummy -} - -std::vector OSXAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection dir) const -{ - std::vector x; - return x; // dummy -} diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index 8b225eba18cef..56fbb9e6726b5 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -390,14 +390,3 @@ unsigned int WasapiAudioDriver::minSupportedBufferSize() const return closestBufferSize; } - -bool WasapiAudioDriver::pushMidiEvent(muse::midi::Event&) -{ - return true; -} - -std::vector WasapiAudioDriver::availableMidiDevices(muse::midi::MidiPortDirection dir) const -{ - std::vector x; - return x; // dummy -} diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h index 34aad24c8a2b2..d0d2d7e142c2a 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.h +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.h @@ -70,8 +70,6 @@ class WasapiAudioDriver : public IAudioDriver, public async::Asyncable bool isPlaying() const override; void remotePlayOrStop(bool) const override; void remoteSeek(msecs_t) const override; - bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices(muse::midi::MidiPortDirection dir) const override; void resume() override; void suspend() override; diff --git a/src/framework/audio/midiqueue.h b/src/framework/audio/midiqueue.h deleted file mode 100644 index 6d890e3dbfa81..0000000000000 --- a/src/framework/audio/midiqueue.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MUSE_MIDI_MIDIQUEUE_H -#define MUSE_MIDI_MIDIQUEUE_H - -#include -#include -#include - -template -class ThreadSafeQueue -{ -private: - std::queue queue_; - mutable std::mutex mtx_; - -public: - void push(const T& item) - { - std::lock_guard lock(mtx_); - queue_.push(item); - } - - bool pop(T& item) - { - std::lock_guard lock(mtx_); - if (queue_.empty()) { - return false; - } - //T* ptr = queue_.front(); - //item = *ptr; - //delete ptr; - //queue_.pop(); - //return true; - item = queue_.front(); - queue_.pop(); - return true; - } - - bool empty() const - { - std::lock_guard lock(mtx_); - return queue_.empty(); - } -}; - -#endif // MUSE_MIDI_MIDIQUEUE_H diff --git a/src/framework/midi/CMakeLists.txt b/src/framework/midi/CMakeLists.txt index 592033abc0bd3..cdc9041ddb815 100644 --- a/src/framework/midi/CMakeLists.txt +++ b/src/framework/midi/CMakeLists.txt @@ -23,16 +23,6 @@ set(MODULE_ALIAS muse::midi) include(GetPlatformInfo) -set(JACK_SRC "") -if (MUSE_MODULE_AUDIO_JACK) - set(JACK_SRC - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidioutport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidioutport.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidiinport.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/jack/jackmidiinport.h - ) -endif() - if (OS_IS_WIN) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmidioutport.cpp @@ -42,7 +32,6 @@ if (OS_IS_WIN) ) elseif(OS_IS_LIN) set(DRIVER_SRC - ${JACK_SRC} ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.cpp @@ -54,7 +43,6 @@ elseif(OS_IS_LIN) ) elseif(OS_IS_FBSD) set(DRIVER_SRC - ${JACK_SRC} ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidioutport.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/alsa/alsamidiinport.cpp @@ -66,7 +54,6 @@ elseif(OS_IS_FBSD) ) elseif(OS_IS_MAC) set(DRIVER_SRC - ${JACK_SRC} ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidioutport.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidioutport.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/coremidiinport.cpp @@ -100,11 +87,6 @@ if (OS_IS_MAC) find_library(CoreMIDI NAMES CoreMIDI) find_library(CoreAudio NAMES CoreAudio) set(MODULE_LINK ${MODULE_LINK} ${CoreMIDI} ${CoreAudio}) - if (MUSE_MODULE_AUDIO_JACK) - find_package(Jack REQUIRED) - set(MODULE_INCLUDE_PRIVATE ${MODULE_INCLUDE_PRIVATE} ${JACK_INCLUDE_DIRS}) - set(MODULE_LINK ${MODULE_LINK} ${JACK_LDFLAGS} pthread) - endif() elseif (OS_IS_WIN) set(MODULE_LINK ${MODULE_LINK} winmm) elseif (OS_IS_LIN) diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp b/src/framework/midi/internal/platform/jack/jackmidiinport.cpp deleted file mode 100644 index 21541ded15eea..0000000000000 --- a/src/framework/midi/internal/platform/jack/jackmidiinport.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -//#include "linuxmidiinport.h" -#include "jackmidiinport.h" - -#include -#include - -#include "midierrors.h" -#include "stringutils.h" -#include "translation.h" -#include "defer.h" -#include "log.h" - -using namespace muse::midi; - -void JackMidiInPort::init() -{ - m_jack = std::make_unique(); -} - -void JackMidiInPort::deinit() -{ - if (isConnected()) { - disconnect(); - } -} - -muse::Ret JackMidiInPort::connect(const MidiDeviceID&) -{ - return muse::Ret(true); -} - -void JackMidiInPort::disconnect() -{ -} - -bool JackMidiInPort::isConnected() const -{ - return m_jack && m_jack->midiIn && !m_deviceID.empty(); -} - -MidiDeviceID JackMidiInPort::deviceID() const -{ - return m_deviceID; -} - -bool JackMidiInPort::deviceExists(const MidiDeviceID& deviceId) const -{ - for (const MidiDevice& device : availableDevices()) { - if (device.id == deviceId) { - return true; - } - } - - return false; -} - -bool JackMidiInPort::supportsMIDI20Output() const -{ - return false; -} - -// dummy -muse::Ret JackMidiInPort::sendEvent(const Event&) -{ - return muse::make_ok(); -} - -std::vector JackMidiInPort::availableDevices() const -{ - std::vector x; - return x; // dummy -} diff --git a/src/framework/midi/internal/platform/jack/jackmidiinport.h b/src/framework/midi/internal/platform/jack/jackmidiinport.h deleted file mode 100644 index cdb00af0717c2..0000000000000 --- a/src/framework/midi/internal/platform/jack/jackmidiinport.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -#ifndef MU_MIDI_JACKMIDIINPORT_H -#define MU_MIDI_JACKMIDIINPORT_H - -#include -#include "midi/midiportstate.h" - -namespace muse::midi { -class JackMidiInPort : public MidiPortState -{ -public: - JackMidiInPort() = default; - ~JackMidiInPort() = default; - void init(); - void deinit(); - - std::vector availableDevices() const override; - Ret connect(const MidiDeviceID& deviceID) override; - void disconnect() override; - bool isConnected() const override; - MidiDeviceID deviceID() const override; - bool supportsMIDI20Output() const override; - Ret sendEvent(const Event& e) override; - -private: - bool deviceExists(const MidiDeviceID& deviceId) const; - struct Jack { - void* midiIn = nullptr; - void* client = nullptr; - int port = -1; - int segmentSize; - }; - std::unique_ptr m_jack; - MidiDeviceID m_deviceID; -}; -} - -#endif // MU_MIDI_JACKMIDIINPORT_H diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp b/src/framework/midi/internal/platform/jack/jackmidioutport.cpp deleted file mode 100644 index 926ecccef8f67..0000000000000 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -#include "framework/audio/audiomodule.h" -#include "jackmidioutport.h" - -#include -#include - -#include "midierrors.h" -#include "translation.h" -#include "log.h" - -using namespace muse::midi; - -void JackMidiOutPort::init() -{ - m_jack = std::make_unique(); -} - -void JackMidiOutPort::deinit() -{ - if (isConnected()) { - disconnect(); - } -} - -std::vector JackMidiOutPort::availableDevices() const -{ - std::vector ret; - MidiDevice dev; - dev.name = "JACK"; - dev.id = makeUniqueDeviceId(0, 9999, 0); - ret.push_back(std::move(dev)); - return ret; -} - -muse::Ret JackMidiOutPort::connect(const MidiDeviceID& deviceID) -{ - if (!m_jack->client) { - return make_ret(Err::MidiInvalidDeviceID, "jack-open fail, device: " + deviceID); - } - return muse::Ret(true); -} - -void JackMidiOutPort::disconnect() -{ - if (!isConnected()) { - return; - } - if (!m_jack->client) { - return; - } - jack_client_t* client = static_cast(m_jack->client); - - //FIX: - //const char* sn = jack_port_name((jack_port_t*) src); - //const char* dn = jack_port_name((jack_port_t*) dst); - //jackdisconnect(m_jack->midiOut, 0, m_jack->client, m_jack->port); - if (jack_deactivate(client)) { - LOGE() << "failed to deactive jack"; - } - m_jack->port = -1; - m_jack->midiOut = nullptr; - m_deviceID.clear(); -} - -bool JackMidiOutPort::isConnected() const -{ - return !(m_jack.get() && m_jack->midiOut && !m_deviceID.empty()); -} - -MidiDeviceID JackMidiOutPort::deviceID() const -{ - return m_deviceID; -} - -bool JackMidiOutPort::supportsMIDI20Output() const -{ - return false; -} - -bool JackMidiOutPort::deviceExists(const MidiDeviceID& deviceId) const -{ - for (const MidiDevice& device : availableDevices()) { - if (device.id == deviceId) { - return true; - } - } - - return false; -} - -// Not used -muse::Ret JackMidiOutPort::sendEvent(const Event&) -{ - return muse::Ret(true); -} diff --git a/src/framework/midi/internal/platform/jack/jackmidioutport.h b/src/framework/midi/internal/platform/jack/jackmidioutport.h deleted file mode 100644 index 70fc45aecc9bb..0000000000000 --- a/src/framework/midi/internal/platform/jack/jackmidioutport.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-only - * MuseScore-CLA-applies - * - * MuseScore - * Music Composition & Notation - * - * Copyright (C) MuseScore BVBA 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 3 as - * published by the Free Software Foundation. - * - * 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, see . - */ -#ifndef MU_MIDI_JACKMIDIOUTPORT_H -#define MU_MIDI_JACKMIDIOUTPORT_H - -#include -#include "framework/audio/midiqueue.h" -#include "framework/audio/audiomodule.h" -#include "midi/midiportstate.h" - -namespace muse::midi { -class JackMidiOutPort : public MidiPortState -{ -public: - JackMidiOutPort() = default; - ~JackMidiOutPort() = default; - void init(); - void deinit(); - - std::vector availableDevices() const override; - Ret connect(const MidiDeviceID& deviceID) override; - void disconnect() override; - bool isConnected() const override; - MidiDeviceID deviceID() const override; - bool supportsMIDI20Output() const override; - Ret sendEvent(const Event& e) override; - -private: - bool deviceExists(const MidiDeviceID& deviceId) const; - std::shared_ptr > m_midiQueue; - struct Jack { - void* midiOut = nullptr; - void* client = nullptr; - int port = -1; - int segmentSize; - }; - std::unique_ptr m_jack; - MidiDeviceID m_deviceID; -}; -} - -#endif // MU_MIDI_JACKMIDIOUTPORT_H diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp index 5d03888dde83f..377d3a3933750 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.cpp @@ -33,7 +33,6 @@ using namespace muse::midi; void LinuxMidiInPort::init() { #if defined(JACK_AUDIO) - m_midiInPortJack = std::make_unique(); #else m_midiInPortAlsa = std::make_unique(); #endif @@ -50,8 +49,8 @@ std::vector LinuxMidiInPort::availableDevices() const { // FIX: this is compile-time, change so that we call availableMidiDevices if jack is selected #if defined(JACK_AUDIO) - // the external jack-midi-ports that are connecing to Musescore are of output type - return audioDriver()->availableMidiDevices(muse::midi::MidiPortDirection::Output); + std::vector ret; + return ret; #else std::lock_guard lock(m_devicesMutex); std::vector ret; diff --git a/src/framework/midi/internal/platform/lin/linuxmidiinport.h b/src/framework/midi/internal/platform/lin/linuxmidiinport.h index 878016bedd91f..5cbea936e8ce1 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidiinport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidiinport.h @@ -33,10 +33,6 @@ #include "imidiinport.h" #include "internal/midideviceslistener.h" -#if defined(JACK_AUDIO) -#include "internal/platform/jack/jackmidiinport.h" -#endif - #include "internal/platform/alsa/alsamidiinport.h" namespace muse::midi { @@ -82,9 +78,6 @@ class LinuxMidiInPort : public IMidiInPort, public async::Asyncable async::Channel m_eventReceived; -#if defined(JACK_AUDIO) - std::unique_ptr m_midiInPortJack; -#endif std::unique_ptr m_midiInPortAlsa; }; } diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp index 3e4b9dfc8739a..99fad06ac6198 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.cpp @@ -34,10 +34,6 @@ using namespace muse::midi; void LinuxMidiOutPort::init() { -#if JACK_AUDIO - m_midiOutPortJack = std::make_unique(); - m_midiOutPortJack->init(); -#endif m_midiOutPortAlsa = std::make_unique(); m_midiOutPortAlsa->init(); @@ -73,10 +69,6 @@ std::vector LinuxMidiOutPort::availableDevices() const std::lock_guard lock(m_devicesMutex); std::vector ret; -#if JACK_AUDIO - auto vj = m_midiOutPortJack->availableDevices(); - ret.insert(ret.end(), vj.begin(), vj.end()); -#endif auto va = m_midiOutPortAlsa->availableDevices(); ret.insert(ret.end(), va.begin(), va.end()); @@ -107,9 +99,6 @@ muse::Ret LinuxMidiOutPort::connect(const MidiDeviceID& deviceID) } if (deviceParams.at(1) == 9999) { // This is an jack device -#if JACK_AUDIO - m_midiOutPortCurrent = /* JackMidiOutPort */ m_midiOutPortJack.get(); -#endif } else { m_midiOutPortCurrent = /* AlsaMidiOutPort */ m_midiOutPortAlsa.get(); } @@ -175,8 +164,7 @@ muse::Ret LinuxMidiOutPort::sendEvent(const Event& e) } #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - Event e2(e); - return muse::Ret(audioDriver()->pushMidiEvent(e2)); + return muse::Ret(true); #else // alsa return m_midiOutPortCurrent->sendEvent(e); #endif diff --git a/src/framework/midi/internal/platform/lin/linuxmidioutport.h b/src/framework/midi/internal/platform/lin/linuxmidioutport.h index dd7be182637a5..fbc2bc90dddbd 100644 --- a/src/framework/midi/internal/platform/lin/linuxmidioutport.h +++ b/src/framework/midi/internal/platform/lin/linuxmidioutport.h @@ -30,10 +30,6 @@ #include "midi/imidioutport.h" #include "internal/midideviceslistener.h" -#if defined(JACK_AUDIO) -#include "internal/platform/jack/jackmidioutport.h" -#endif - #include "internal/platform/alsa/alsamidioutport.h" namespace muse::midi { @@ -72,9 +68,6 @@ class LinuxMidiOutPort : public IMidiOutPort, public async::Asyncable mutable std::mutex m_devicesMutex; MidiPortState* m_midiOutPortCurrent; -#if defined(JACK_AUDIO) - std::unique_ptr m_midiOutPortJack; -#endif std::unique_ptr m_midiOutPortAlsa; }; } From 242a767123b13b3b3d50e618033599a82d3ce638 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Mon, 10 Feb 2025 20:59:50 +0100 Subject: [PATCH 55/60] (squash) rebase fix --- buildscripts/ci/macos/setup.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/buildscripts/ci/macos/setup.sh b/buildscripts/ci/macos/setup.sh index ea5d359cd6b19..0a125cc8c88de 100644 --- a/buildscripts/ci/macos/setup.sh +++ b/buildscripts/ci/macos/setup.sh @@ -27,9 +27,6 @@ export MACOSX_DEPLOYMENT_TARGET=10.14 # Install build tools echo "Install build tools" brew install cmake ninja --formula --quiet -brew install cmake --formula --quiet - -#brew install jack --formula --quiet wget -q https://github.com/jackaudio/jack2-releases/releases/download/v1.9.22/jack2-macOS-universal-v1.9.22.tar.gz tar xvf jack2-macOS-universal-v1.9.22.tar.gz From 66e210f675a55da9d027eb2c01c9b743ad83be7c Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Mon, 10 Feb 2025 21:21:04 +0100 Subject: [PATCH 56/60] (squash) audio stub fixes --- .../stubs/audio/audioconfigurationstub.cpp | 2 +- src/framework/stubs/audio/audiodriverstub.cpp | 28 +------------------ src/framework/stubs/audio/audiodriverstub.h | 18 ++++-------- 3 files changed, 8 insertions(+), 40 deletions(-) diff --git a/src/framework/stubs/audio/audioconfigurationstub.cpp b/src/framework/stubs/audio/audioconfigurationstub.cpp index 2262c85e447db..828af251c2e49 100644 --- a/src/framework/stubs/audio/audioconfigurationstub.cpp +++ b/src/framework/stubs/audio/audioconfigurationstub.cpp @@ -57,7 +57,7 @@ int AudioConfigurationStub::audioDelayCompensate() const return 0; } -void AudioConfigurationStub::setAudioDelayCompensate(const int frames) +void AudioConfigurationStub::setAudioDelayCompensate(const int) { } diff --git a/src/framework/stubs/audio/audiodriverstub.cpp b/src/framework/stubs/audio/audiodriverstub.cpp index cddc8fee97169..13f1ba44618c0 100644 --- a/src/framework/stubs/audio/audiodriverstub.cpp +++ b/src/framework/stubs/audio/audiodriverstub.cpp @@ -88,7 +88,7 @@ int AudioDriverStub::audioDelayCompensate() const return 0; } -void AudioDriverStub::setAudioDelayCompensate(const int frames) +void AudioDriverStub::setAudioDelayCompensate(const int) { } @@ -97,21 +97,6 @@ bool AudioDriverStub::isPlaying() const return false; } -unsigned int AudioDriverStub::sampleRate() const -{ - return 0; -} - -bool AudioDriverStub::setSampleRate(unsigned int sampleRate) -{ - return true; -} - -async::Notification AudioDriverStub::sampleRateChanged() const -{ - return async::Notification(); -} - void AudioDriverStub::remotePlayOrStop([[maybe_unused]] bool ps) const { } @@ -167,14 +152,3 @@ void AudioDriverStub::resume() void AudioDriverStub::suspend() { } - -bool AudioDriverStub::pushMidiEvent(muse::midi::Event&) -{ - return true; -} - -std::vector AudioDriverStub::availableMidiDevices(muse::midi::MidiPortDirection direction) const -{ - std::vector x; - return x; // dummy -} diff --git a/src/framework/stubs/audio/audiodriverstub.h b/src/framework/stubs/audio/audiodriverstub.h index 61ffcce256901..c657e10b9300c 100644 --- a/src/framework/stubs/audio/audiodriverstub.h +++ b/src/framework/stubs/audio/audiodriverstub.h @@ -44,18 +44,6 @@ class AudioDriverStub : public IAudioDriver AudioDeviceList availableOutputDevices() const override; async::Notification availableOutputDevicesChanged() const override; - bool pushMidiEvent(muse::midi::Event& e) override; - std::vector availableMidiDevices(muse::midi::MidiPortDirection direction) const override; - - int audioDelayCompensate() const override; - void setAudioDelayCompensate(const int frames) override; - bool isPlaying() const override; - void remotePlayOrStop(bool) const override; - void remoteSeek(msecs_t) const override; - - unsigned int sampleRate() const override; - bool setSampleRate(unsigned int sampleRate) override; - async::Notification sampleRateChanged() const override; unsigned int outputDeviceBufferSize() const override; bool setOutputDeviceBufferSize(unsigned int bufferSize) override; @@ -68,6 +56,12 @@ class AudioDriverStub : public IAudioDriver async::Notification outputDeviceSampleRateChanged() const override; std::vector availableOutputDeviceSampleRates() const override; + bool isPlaying() const override; + void remotePlayOrStop(bool) const override; + void remoteSeek(msecs_t) const override; + + int audioDelayCompensate() const override; + void setAudioDelayCompensate(const int frames) override; void resume() override; void suspend() override; From 8df6c227909f62412cb76f84f97468502a11ace8 Mon Sep 17 00:00:00 2001 From: Larry Date: Wed, 12 Feb 2025 18:34:34 +0100 Subject: [PATCH 57/60] cleanup audiomidimanager Co-authored-by: Casper Jeukendrup <48658420+cbjeukendrup@users.noreply.github.com> --- .../audio/internal/audiomidimanager.cpp | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index a5dc56dc0ae9b..ac228dc42a881 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -119,28 +119,23 @@ bool AudioMidiManager::makeDevice(const AudioDeviceID& deviceId) if (deviceId == "jack") { bool transportEnable = playbackConfiguration()->jackTransportEnable(); m_current_audioDriverState = std::make_unique(this, transportEnable); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - } else if (deviceId == "alsa") { - m_current_audioDriverState = std::make_unique(); + return true; + } #endif -//#ifdef Q_OS_MACOS -// } else if (deviceId == "osx") { -// m_current_audioDriverState = std::make_unique(); -//#endif -#else #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) if (deviceId == "alsa") { m_current_audioDriverState = std::make_unique(); + return true; + } #endif //#ifdef Q_OS_MACOS -// m_current_audioDriverState = std::make_unique(); +// if (deviceId == "osx") { +// m_current_audioDriverState = std::make_unique(); +// return true; +// } //#endif -#endif - } else { - LOGE() << "Unknown device name: " << deviceId; - return false; - } - return true; + LOGE() << "Unknown device name: " << deviceId; + return false; } // reopens the same device (if m_spec has changed) From be8770a086c7889d63035adb4edfb4fb94674bef Mon Sep 17 00:00:00 2001 From: Larry Date: Wed, 12 Feb 2025 18:39:20 +0100 Subject: [PATCH 58/60] squash? typo Co-authored-by: Casper Jeukendrup <48658420+cbjeukendrup@users.noreply.github.com> --- src/framework/audio/internal/audiomidimanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index ac228dc42a881..d3fd9b19e75d5 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -76,7 +76,7 @@ std::string AudioMidiManager::name() const bool AudioMidiManager::open(const Spec& spec, Spec* activeSpec) { - // re-initialize devide + // re-initialize device m_current_audioDriverState->setAudioDelayCompensate(m_audioDelayCompensate); if (!m_current_audioDriverState->open(spec, activeSpec)) { From b45295439e4b08200ace1a98b2731bb12e9ecdc8 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 12 Feb 2025 21:32:01 +0100 Subject: [PATCH 59/60] (squash) move audioConfig from console to gui is guiapp a good place though? it seems to do high-level gui init only --- src/app/internal/consoleapp.cpp | 2 -- src/app/internal/consoleapp.h | 2 -- src/app/internal/guiapp.cpp | 2 ++ src/app/internal/guiapp.h | 2 ++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/internal/consoleapp.cpp b/src/app/internal/consoleapp.cpp index 46e1edaf3f7b8..b6fbea94992e7 100644 --- a/src/app/internal/consoleapp.cpp +++ b/src/app/internal/consoleapp.cpp @@ -211,8 +211,6 @@ void ConsoleApp::applyCommandLineOptions(const CmdOptions& options, IApplication notationConfiguration()->setTemplateModeEnabled(options.notation.templateModeEnabled); notationConfiguration()->setTestModeEnabled(options.notation.testModeEnabled); - audioConfiguration()->setAudioDelayCompensate(options.audio.audioDelayCompensate.value_or(1024)); // FIX: equal to buffer-size - if (runMode == IApplication::RunMode::ConsoleApp) { project::MigrationOptions migration; migration.appVersion = mu::engraving::Constants::MSC_VERSION; diff --git a/src/app/internal/consoleapp.h b/src/app/internal/consoleapp.h index d8d4614420911..024254b705e1c 100644 --- a/src/app/internal/consoleapp.h +++ b/src/app/internal/consoleapp.h @@ -38,7 +38,6 @@ #include "engraving/devtools/drawdata/idiagnosticdrawprovider.h" #include "autobot/iautobot.h" #include "audioplugins/iregisteraudiopluginsscenario.h" -#include "audio/iaudioconfiguration.h" #include "multiinstances/imultiinstancesprovider.h" #include "ui/iuiconfiguration.h" @@ -69,7 +68,6 @@ class ConsoleApp : public muse::BaseApplication, public std::enable_shared_from_ muse::Inject notationConfiguration; muse::Inject projectConfiguration; muse::Inject soundProfilesRepository; - muse::Inject audioConfiguration; muse::Inject imagesExportConfiguration; muse::Inject midiImportExportConfiguration; muse::Inject audioExportConfiguration; diff --git a/src/app/internal/guiapp.cpp b/src/app/internal/guiapp.cpp index 615c0dfdfdb98..57b1e4a3323b7 100644 --- a/src/app/internal/guiapp.cpp +++ b/src/app/internal/guiapp.cpp @@ -314,4 +314,6 @@ void GuiApp::applyCommandLineOptions(const CmdOptions& options) if (options.app.loggerLevel) { m_globalModule.setLoggerLevel(options.app.loggerLevel.value()); } + + audioConfiguration()->setAudioDelayCompensate(options.audio.audioDelayCompensate.value_or(1024)); // FIX: equal to buffer-size } diff --git a/src/app/internal/guiapp.h b/src/app/internal/guiapp.h index 8c3943f0940eb..d3a516618e3dc 100644 --- a/src/app/internal/guiapp.h +++ b/src/app/internal/guiapp.h @@ -16,6 +16,7 @@ #include "appshell/iappshellconfiguration.h" #include "appshell/internal/istartupscenario.h" #include "importexport/guitarpro/iguitarproconfiguration.h" +#include "audio/iaudioconfiguration.h" namespace mu::app { class GuiApp : public muse::BaseApplication, public std::enable_shared_from_this @@ -25,6 +26,7 @@ class GuiApp : public muse::BaseApplication, public std::enable_shared_from_this muse::Inject appshellConfiguration; muse::Inject startupScenario; muse::Inject guitarProConfiguration; + muse::Inject audioConfiguration; public: GuiApp(const CmdOptions& options, const muse::modularity::ContextPtr& ctx); From 77ee6664db420e52977dbe1385fd7778e675b339 Mon Sep 17 00:00:00 2001 From: Larry Valkama Date: Wed, 12 Feb 2025 21:50:19 +0100 Subject: [PATCH 60/60] osx no audiodevicelistener --- src/framework/audio/CMakeLists.txt | 2 -- src/framework/audio/internal/audiomidimanager.cpp | 2 ++ src/framework/audio/internal/audiomidimanager.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/framework/audio/CMakeLists.txt b/src/framework/audio/CMakeLists.txt index d568be278c550..bd69e3c53ce29 100644 --- a/src/framework/audio/CMakeLists.txt +++ b/src/framework/audio/CMakeLists.txt @@ -59,8 +59,6 @@ elseif(OS_IS_MAC) set(DRIVER_SRC ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.cpp ${CMAKE_CURRENT_LIST_DIR}/internal/audiomidimanager.h - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.cpp - ${CMAKE_CURRENT_LIST_DIR}/internal/platform/lin/audiodeviceslistener.h ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.mm ${CMAKE_CURRENT_LIST_DIR}/internal/platform/osx/osxaudiodriver.h ${JACK_SRC} diff --git a/src/framework/audio/internal/audiomidimanager.cpp b/src/framework/audio/internal/audiomidimanager.cpp index d3fd9b19e75d5..4c4b64ab026c6 100644 --- a/src/framework/audio/internal/audiomidimanager.cpp +++ b/src/framework/audio/internal/audiomidimanager.cpp @@ -50,6 +50,7 @@ AudioMidiManager::~AudioMidiManager() void AudioMidiManager::init() { +#ifndef Q_OS_MACOS m_devicesListener.startWithCallback([this]() { return availableOutputDevices(); }); @@ -57,6 +58,7 @@ void AudioMidiManager::init() m_devicesListener.devicesChanged().onNotify(this, [this]() { m_availableOutputDevicesChanged.notify(); }); +#endif // notify driver if when musescore changes play-position or play/pause playbackController()->isPlayingChanged().onNotify(this, [this]() { diff --git a/src/framework/audio/internal/audiomidimanager.h b/src/framework/audio/internal/audiomidimanager.h index e63315eaf6d89..06c923a0627c8 100644 --- a/src/framework/audio/internal/audiomidimanager.h +++ b/src/framework/audio/internal/audiomidimanager.h @@ -89,7 +89,9 @@ class AudioMidiManager : public IAudioDriver, public async::Asyncable muse::async::Notification m_outputDeviceChanged; mutable std::mutex m_devicesMutex; +#ifndef Q_OS_MACOS AudioDevicesListener m_devicesListener; +#endif muse::async::Notification m_availableOutputDevicesChanged; std::string m_deviceId;