Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions 3rdparty/3rdparty.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ endfunction()
include(3rdparty/dspfilters.cmake)
include(3rdparty/eigen.cmake)
include(3rdparty/gamma.cmake)
include(3rdparty/sndfile.cmake)
include(3rdparty/xtensor.cmake)
include(3rdparty/r8brain.cmake)

if(NOT EMSCRIPTEN)
include(3rdparty/libsimpleio.cmake)
include(3rdparty/mimalloc.cmake)
include(3rdparty/r8brain.cmake)
include(3rdparty/sh4lt.cmake)
include(3rdparty/shmdata.cmake)
include(3rdparty/snappy.cmake)
include(3rdparty/sndfile.cmake)
include(3rdparty/xtensor.cmake)
endif()
2 changes: 1 addition & 1 deletion cmake/Configurations/all-plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Emscripten)

score-plugin-media

# score-plugin-gfx
score-plugin-gfx
score-plugin-js
score-plugin-midi
score-plugin-recording
Expand Down
27 changes: 19 additions & 8 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ if(CMAKE_SYSTEM_NAME MATCHES Emscripten)
add_link_options("SHELL:-sSTACK_OVERFLOW_CHECK=0")
#add_link_options("SHELL:--source-map-base http://127.0.0.1:8000/")
add_link_options("SHELL:-sFETCH=1")
add_link_options("SHELL:-sWASM=1")
add_link_options("SHELL:-sFULL_ES2=1")
add_link_options("SHELL:-sFULL_ES3=1")
add_link_options("SHELL:-sUSE_WEBGL2=1")
# OLD add_link_options("SHELL:-sWASM=1")
# OLD add_link_options("SHELL:-sFULL_ES2=1")
# OLd add_link_options("SHELL:-sFULL_ES3=1")
# OLD add_link_options("SHELL:-sUSE_WEBGL2=1")
#add_link_options("SHELL:-s EXIT_RUNTIME=1")
add_link_options("SHELL:-sERROR_ON_UNDEFINED_SYMBOLS=1")
#add_link_options("SHELL:-s PTHREAD_POOL_SIZE=16")
Expand All @@ -37,14 +37,19 @@ if(CMAKE_SYSTEM_NAME MATCHES Emscripten)
# add_link_options("SHELL:-s EXTRA_EXPORTED_RUNTIME_METHODS=[\"UTF16ToString\",\"stringToUTF16\"]")

## Qt 6
add_link_options("SHELL:-sUSE_PTHREADS=1")
add_link_options("-pthread")
add_compile_options("-fwasm-exceptions")
add_link_options("-fwasm-exceptions")
add_link_options("SHELL:-sJSPI")

# OLD add_link_options("SHELL:-sUSE_PTHREADS=1")
# add_link_options("SHELL:-s FETCH=1")
add_link_options("SHELL:-sWASM_BIGINT=1")
add_link_options("SHELL:-sMODULARIZE=1")
add_link_options("SHELL:-sMAX_WEBGL_VERSION=2")
add_link_options("SHELL:-sWEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1")
# add_link_options("SHELL:-sMAX_WEBGL_VERSION=2")
# add_link_options("SHELL:-sWEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1")
# add_link_options("SHELL:-pthread")
add_link_options("SHELL:-sASYNCIFY" "-s" "ASYNCIFY_IMPORTS=[qt_asyncify_suspend_js, qt_asyncify_resume_js]")
# add_link_options("SHELL:-sASYNCIFY" "-s" "ASYNCIFY_IMPORTS=[qt_asyncify_suspend_js, qt_asyncify_resume_js]")

add_link_options("SHELL:-sABORTING_MALLOC=1")
# add_link_options("SHELL:-sJS_MATH=1")
Expand Down Expand Up @@ -81,6 +86,7 @@ target_link_libraries(${APPNAME}
PUBLIC
score_lib_base
${QT_PREFIX}::CorePrivate
${QT_PREFIX}::Gui
)

if(SCORE_STATIC_PLUGINS)
Expand Down Expand Up @@ -253,7 +259,12 @@ endif()
include(ScoreDeployment)

if(EMSCRIPTEN)
qt_import_plugins(${APPNAME}
INCLUDE Qt6::QWasmIntegrationPlugin
EXCLUDE Qt6::QMinimalIntegrationPlugin
)
qt_finalize_executable(${APPNAME})
enable_minimal_qt_plugins(${APPNAME} 1)
else()
disable_qt_plugins(${APPNAME})
enable_minimal_qt_plugins(${APPNAME} 1)
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/score-plugin-audio/Audio/Settings/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ SETTINGS_PARAMETER_IMPL(Driver)
"687d49cf-b58d-430f-8358-ec02cb50be36")} // PipeWire
#elif defined(__EMSCRIPTEN__)
Audio::AudioFactory::ConcreteKey{score::uuids::string_generator::compute(
"28b88e91-c5f0-4f13-834f-aa333d14aa81")} // SDL
"a2e8b688-521c-4755-b0b2-4e3d01807b8e")} // Web Audio (MiniAudio)
#else
Audio::AudioFactory::ConcreteKey
{
Expand Down
48 changes: 48 additions & 0 deletions src/plugins/score-plugin-audio/Audio/WASMMiniAudioInterface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once
#if defined(__EMSCRIPTEN__)
#include <Audio/AudioInterface.hpp>
#include <Audio/Settings/Model.hpp>

#include <ossia/audio/miniaudio_protocol.hpp>

#if OSSIA_ENABLE_MINIAUDIO

namespace Audio
{

class WASMMiniAudioFactory final : public AudioFactory
{
SCORE_CONCRETE("a2e8b688-521c-4755-b0b2-4e3d01807b8e")
public:
~WASMMiniAudioFactory() override { }
bool available() const noexcept override { return true; }
void
initialize(Audio::Settings::Model& set, const score::ApplicationContext& ctx) override
{
}

QString prettyName() const override { return QObject::tr("Web Audio (MiniAudio)"); }

std::shared_ptr<ossia::audio_engine> make_engine(
const Audio::Settings::Model& set, const score::ApplicationContext& ctx) override
{
auto context = std::make_shared<ossia::miniaudio_context>();
auto cfg = ma_context_config_init();
ma_context_init(nullptr, 0, &cfg, &context->context);

ma_device_id in_id{}, out_id{};
return std::make_shared<ossia::miniaudio_engine>(
std::move(context), "ossia score", in_id, out_id, 0, 2, 48000, 1024);
}

QWidget* make_settings(
Audio::Settings::Model& m, Audio::Settings::View& v,
score::SettingsCommandDispatcher& m_disp, QWidget* parent) override
{
return nullptr;
}
};

}
#endif
#endif
7 changes: 6 additions & 1 deletion src/plugins/score-plugin-audio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ set(HDRS
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/PipeWireInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/PortAudioInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/SDLInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/WASMMiniAudioInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/WASAPIPortAudioInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/WDMKSPortAudioInterface.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Audio/AudioApplicationPlugin.hpp"
Expand Down Expand Up @@ -94,10 +95,14 @@ if(OSSIA_ENABLE_SDL)
list(APPEND SCORE_FEATURES_LIST sdl)
endif()

if(LINUX OR BSD OR APPLE)
if(LINUX OR BSD OR APPLE OR EMSCRIPTEN)
target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE "${OSSIA_3RDPARTY_FOLDER}/miniaudio")
if(APPLE)
target_link_libraries(${PROJECT_NAME} PRIVATE "-framework AudioUnit" "$<BUILD_INTERFACE:kfr>")
endif()
if(EMSCRIPTEN)
target_compile_definitions(${PROJECT_NAME} PRIVATE MA_ENABLE_AUDIO_WORKLETS MA_ENABLE_WEBAUDIO)
target_link_options(${PROJECT_NAME} PUBLIC -sAUDIO_WORKLET=1 -sWASM_WORKERS=1)
endif()
endif()
setup_score_plugin(${PROJECT_NAME})
5 changes: 5 additions & 0 deletions src/plugins/score-plugin-audio/score_plugin_audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <Audio/SDLInterface.hpp>
#include <Audio/Settings/Factory.hpp>
#include <Audio/WASAPIPortAudioInterface.hpp>
#include <Audio/WASMMiniAudioInterface.hpp>
#include <Audio/WDMKSPortAudioInterface.hpp>

#include <score/plugins/FactorySetup.hpp>
Expand Down Expand Up @@ -220,6 +221,10 @@ std::vector<score::InterfaceBase*> score_plugin_audio::factories(
#if defined(__APPLE__) && defined(OSSIA_AUDIO_MINIAUDIO)
,
Audio::CoreAudioFactory
#endif
#if defined(__EMSCRIPTEN__) && defined(OSSIA_AUDIO_MINIAUDIO)
,
Audio::WASMMiniAudioFactory
#endif
>>(vec, ctx, key);

Expand Down
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-gfx/Gfx/Graph/VideoNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,4 +439,6 @@ AVFrame* VideoFrameReader::nextFrame(

}

#if !defined(__EMSCRIPTEN__)
#include <hap/source/hap.c>
#endif
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-gfx/Gfx/Graph/decoders/DXV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cstring>

#if !defined(__EMSCRIPTEN__)
namespace score::gfx
{

Expand Down Expand Up @@ -396,3 +397,4 @@ void DXVYCoCgDecoder::exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& f
}

}
#endif
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-gfx/Gfx/Graph/decoders/DXV.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>

#if !defined(__EMSCRIPTEN__)
extern "C" {
#include <libavformat/avformat.h>
#include <dxv.h>
Expand Down Expand Up @@ -81,3 +82,4 @@ struct DXVYCoCgDecoder : GPUVideoDecoder
};

}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ std::unique_ptr<GPUVideoDecoder> createGPUVideoDecoder(
// Try fourcc-based formats (HAP, DXV)
std::string_view fourcc{(const char*)&format.pixel_format, 4};

#if !defined(__EMSCRIPTEN__)
if(fourcc == "Hap1")
return std::make_unique<HAPDefaultDecoder>(
QRhiTexture::BC1, format, f);
Expand Down Expand Up @@ -299,7 +300,7 @@ std::unique_ptr<GPUVideoDecoder> createGPUVideoDecoder(
return std::make_unique<DXVYCoCgDecoder>(false, format, f);
else if(fourcc == "DxvA")
return std::make_unique<DXVYCoCgDecoder>(true, format, f);

#endif
return nullptr;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/score-plugin-gfx/Gfx/Graph/decoders/HAP.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <Gfx/Graph/decoders/HAP.hpp>

#if !defined(__EMSCRIPTEN__)
namespace score::gfx
{
HAPDecoder::HAPSection HAPDecoder::HAPSection::read(const uint8_t* bytes)
Expand Down Expand Up @@ -83,6 +84,7 @@ void HAPDecoder::setPixels_noEncoding(
void HAPDecoder::setPixels_snappy(
QRhiResourceUpdateBatch& res, const uint8_t* data_start, std::size_t size)
{
#if !defined(__EMSCRIPTEN__)
size_t uncomp_size{};
snappy::GetUncompressedLength((const char*)data_start, size, &uncomp_size);

Expand All @@ -97,6 +99,7 @@ void HAPDecoder::setPixels_snappy(

auto y_tex = samplers[0].texture;
res.uploadTexture(y_tex, desc);
#endif
}

HAPDefaultDecoder::HAPDefaultDecoder(
Expand Down Expand Up @@ -221,3 +224,4 @@ void HAPMDecoder::setPixels(
}

}
#endif
3 changes: 3 additions & 0 deletions src/plugins/score-plugin-gfx/Gfx/Graph/decoders/HAP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <hap/source/hap.h>

#if !defined(__EMSCRIPTEN__)
#include <snappy.h>

extern "C" {
Expand Down Expand Up @@ -141,3 +142,5 @@ void main ()
};

}

#endif
3 changes: 3 additions & 0 deletions src/plugins/score-plugin-js/JS/Qml/QmlProcess.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "QmlProcess.hpp"

#if !defined(__EMSCRIPTEN__)

#include <QTimer>

#include <wobjectimpl.h>
Expand Down Expand Up @@ -174,3 +176,4 @@ void QmlProcess::setWorkingDirectory(const QString& dir)
workingDirectoryChanged();
}
}
#endif
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-js/JS/Qml/QmlProcess.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <QProcess>
#include <QQmlEngine>

#if !defined(__EMSCRIPTEN__)
#include <verdigris>

namespace JS
Expand Down Expand Up @@ -110,3 +111,4 @@ class QmlProcess : public QProcess
W_REGISTER_ARGTYPE(QProcess::ProcessError)
W_REGISTER_ARGTYPE(QProcess::ExitStatus)
W_REGISTER_ARGTYPE(QProcess::ProcessState)
#endif
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-js/score_plugin_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ score_plugin_js::score_plugin_js()
qmlRegisterType<JS::GlobalDeviceEnumerator>("Score.UI", 1, 0, "DeviceEnumerator");
qmlRegisterType<JS::DeviceListener>("Score.UI", 1, 0, "DeviceListener");

#if !defined(__EMSCRIPTEN__)
qmlRegisterType<JS::QmlProcess>("Score.UI", 1, 0, "Process");
#endif

qRegisterMetaType<QVector<JS::MidiMessage>>();

Expand Down
1 change: 0 additions & 1 deletion src/plugins/score-plugin-media/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ if(EMSCRIPTEN)
/opt/ossia-sdk-wasm/ffmpeg/lib/libavutil.a
/opt/ossia-sdk-wasm/ffmpeg/lib/libswscale.a
/opt/ossia-sdk-wasm/ffmpeg/lib/libswresample.a
/opt/ossia-sdk-wasm/ffmpeg/lib/libpostproc.a
-Wl,--end-group
)
elseif(TARGET avcodec)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ namespace
{
static int defaultEditorRefreshRate()
{
#if defined(__EMSCRIPTEN__)
return 50; // ~20fps — WASM single-thread can't handle higher rates
#else
const auto tcount = QThread::idealThreadCount();
if(tcount <= 4)
return 30;
else if(tcount <= 8)
return 16;
else
return 8;
#endif
}
}
ProcessGraphicsView::ProcessGraphicsView(
Expand Down Expand Up @@ -704,6 +708,10 @@ void ScenarioDocumentView::updateBackgroundMode()
if(rate > 0)
refreshRate = 1000. / rate;
}
#if defined(__EMSCRIPTEN__)
// Cap the refresh rate on WASM to avoid starving the single-threaded event loop
refreshRate = std::max(refreshRate, (double)defaultEditorRefreshRate());
#endif

if(!wantsFullUpdates)
{
Expand Down Expand Up @@ -733,8 +741,15 @@ void ScenarioDocumentView::updateBackgroundMode()
}
else
{
#if defined(__EMSCRIPTEN__)
// On WASM, FullViewportUpdate at high rates starves the single-threaded event loop.
// Use MinimalViewportUpdate and let the background renderer request updates explicitly.
m_view.setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
m_timer = startTimer(refreshRate, Qt::CoarseTimer);
#else
m_view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
m_timer = startTimer(refreshRate, Qt::PreciseTimer);
#endif
}
m_view.update();
}
Expand Down