From 8a1688f7eb40030156e3a1ef7ffdde160d3f525d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Sun, 25 Oct 2026 11:17:40 +0200 Subject: [PATCH 1/2] fix: support the Csound 7 plugin API Keep the const type descriptor returned by GetTypeForArg in Fluid. Export csoundModuleInfo from Chua and linear algebra so Csound 7 can validate their ABI and load them. Add native loader tests and update Csound 7 CI to the stable release. Assisted-by: Codex (GPT-6) --- .github/workflows/plugins_build_7.yml | 2 +- 7.x/CMakeLists.txt | 26 +++++++++ 7.x/src/chua/ChuaOscillator.cpp | 2 + 7.x/src/fluidOpcodes/fluidOpcodes.cpp | 2 +- 7.x/src/linear_algebra/linear_algebra.cpp | 2 + 7.x/tests/plugin_load_test.cpp | 65 +++++++++++++++++++++++ 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 7.x/tests/plugin_load_test.cpp diff --git a/.github/workflows/plugins_build_7.yml b/.github/workflows/plugins_build_7.yml index 989c4e05..b118242c 100644 --- a/.github/workflows/plugins_build_7.yml +++ b/.github/workflows/plugins_build_7.yml @@ -19,7 +19,7 @@ on: workflow_dispatch: env: - CSOUND_VERSION: 7.0.0-beta.18 + CSOUND_VERSION: 7.0.0 FAUST_VERSION: 2.88.0 VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/vcpkg-cache,readwrite" diff --git a/7.x/CMakeLists.txt b/7.x/CMakeLists.txt index 734f933d..07eb007c 100644 --- a/7.x/CMakeLists.txt +++ b/7.x/CMakeLists.txt @@ -335,3 +335,29 @@ add_subdirectory(./src/CUDA) add_subdirectory(./src/OpenCL) add_subdirectory(./src/stk) add_subdirectory(./src/faustcsound) + +# Exercise the native loader as well as compilation against the Csound headers. +if(NOT WASM AND (TARGET chua OR TARGET linear_algebra OR TARGET fluidOpcodes)) + find_package(GTest QUIET) + if(GTest_FOUND) + add_executable(plugin_load_tests tests/plugin_load_test.cpp) + set_target_properties(plugin_load_tests PROPERTIES + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON) + target_include_directories(plugin_load_tests PRIVATE ${CSOUND_INCLUDE_DIRS}) + target_link_libraries(plugin_load_tests PRIVATE GTest::gtest_main ${CSOUND_LIBRARY}) + foreach(plugin IN ITEMS chua linear_algebra fluidOpcodes) + if(TARGET ${plugin}) + if(plugin STREQUAL "fluidOpcodes") + set(test_name FLUID) + else() + string(TOUPPER "${plugin}" test_name) + endif() + target_compile_definitions(plugin_load_tests PRIVATE + CSOUND_TEST_${test_name}="$") + add_dependencies(plugin_load_tests ${plugin}) + endif() + endforeach() + add_test(NAME plugin_load_tests COMMAND plugin_load_tests) + endif() +endif() diff --git a/7.x/src/chua/ChuaOscillator.cpp b/7.x/src/chua/ChuaOscillator.cpp index 9d7a42ce..1da760c4 100644 --- a/7.x/src/chua/ChuaOscillator.cpp +++ b/7.x/src/chua/ChuaOscillator.cpp @@ -611,6 +611,8 @@ OENTRY oentries[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }}; +PUBLIC int32_t csoundModuleInfo(void) { return CSOUND_MODULE_INFO; } + PUBLIC int32_t csoundModuleCreate(CSOUND *csound) { return 0; } PUBLIC int32_t csoundModuleInit(CSOUND *csound) { diff --git a/7.x/src/fluidOpcodes/fluidOpcodes.cpp b/7.x/src/fluidOpcodes/fluidOpcodes.cpp index 666f76ee..4cf568b4 100644 --- a/7.x/src/fluidOpcodes/fluidOpcodes.cpp +++ b/7.x/src/fluidOpcodes/fluidOpcodes.cpp @@ -283,7 +283,7 @@ class FluidLoad : public csound::OpcodeBase { soundFontId = -1; toa(csound, iFluidSynth, fluidSynth); listPresets = (int32_t)*iListPresets; - CS_TYPE *argType = GetTypeForArg(iFilename); + const CS_TYPE *argType = GetTypeForArg(iFilename); if (strcmp("S", argType->varTypeName) == 0) { filename = csound->Strdup(csound, ((STRINGDAT *)iFilename)->data); } else { diff --git a/7.x/src/linear_algebra/linear_algebra.cpp b/7.x/src/linear_algebra/linear_algebra.cpp index ca9dfa82..ac6eaea4 100644 --- a/7.x/src/linear_algebra/linear_algebra.cpp +++ b/7.x/src/linear_algebra/linear_algebra.cpp @@ -3926,6 +3926,8 @@ class la_k_qr_sym_eigen_mc_t : public OpcodeBase { extern "C" { +PUBLIC int32_t csoundModuleInfo(void) { return CSOUND_MODULE_INFO; } + PUBLIC int32_t csoundModuleCreate(CSOUND *csound) { return 0; } PUBLIC int32_t csoundModuleInit(CSOUND *csound) { diff --git a/7.x/tests/plugin_load_test.cpp b/7.x/tests/plugin_load_test.cpp new file mode 100644 index 00000000..1260dc4a --- /dev/null +++ b/7.x/tests/plugin_load_test.cpp @@ -0,0 +1,65 @@ +#include "csound.h" +#include "gtest/gtest.h" +#include + +class PluginLoadTests : public ::testing::Test { +protected: + CSOUND *csound = nullptr; + + void SetUp() override { + // Load the selected library, without scanning installed plugins. + csound = csoundCreate(nullptr, ""); + ASSERT_NE(csound, nullptr); + csoundCreateMessageBuffer(csound, 0); + } + + void TearDown() override { + csoundDestroy(csound); + } + + std::string messages() { + std::string result; + while (csoundGetMessageCnt(csound)) { + result += csoundGetFirstMessage(csound); + csoundPopFirstMessage(csound); + } + return result; + } + + void compile(const char *plugin, const char *orchestra) { + std::string option = std::string("--opcode-lib=") + plugin; + ASSERT_EQ(csoundSetOption(csound, option.c_str()), 0); + EXPECT_EQ(csoundCompileOrc(csound, orchestra, 0), 0) << messages(); + } +}; + +#ifdef CSOUND_TEST_CHUA +TEST_F(PluginLoadTests, ChuaRegistersItsOpcode) { + compile(CSOUND_TEST_CHUA, R"( + instr 1 + a1, a2, a3 chuap 0.00945, 7.5, 2e-7, 0.00105, 0, -0.00121, 1.76e-5, 1.5e-8, 0, -0.1, 0.1, 5e-6 + endin + )"); +} +#endif + +#ifdef CSOUND_TEST_LINEAR_ALGEBRA +TEST_F(PluginLoadTests, LinearAlgebraRegistersItsOpcodes) { + compile(CSOUND_TEST_LINEAR_ALGEBRA, R"( + instr 1 + ivector la_i_vr_create 3 + endin + )"); +} +#endif + +#ifdef CSOUND_TEST_FLUID +TEST_F(PluginLoadTests, FluidRegistersItsOpcodes) { + compile(CSOUND_TEST_FLUID, R"( + instr 1 + iengine fluidEngine + aleft, aright fluidOut iengine + endin + )"); +} +#endif From 3b5337cb526754b3bea595902ed5ee23b2dc2aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hl=C3=B6=C3=B0ver=20Sigur=C3=B0sson?= Date: Sun, 25 Oct 2026 11:43:07 +0200 Subject: [PATCH 2/2] test: verify the requested Csound plugin loads Quote opcode library paths so build directories can contain spaces. Check the exact load message as well as orchestra compilation: an rc file can load an installed copy and hide a failed load of the build artifact. Assisted-by: Codex (GPT-6) --- 7.x/tests/plugin_load_test.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/7.x/tests/plugin_load_test.cpp b/7.x/tests/plugin_load_test.cpp index 1260dc4a..88711d4f 100644 --- a/7.x/tests/plugin_load_test.cpp +++ b/7.x/tests/plugin_load_test.cpp @@ -7,7 +7,7 @@ class PluginLoadTests : public ::testing::Test { CSOUND *csound = nullptr; void SetUp() override { - // Load the selected library, without scanning installed plugins. + // Skip the default plugin directories; rc files may still add libraries. csound = csoundCreate(nullptr, ""); ASSERT_NE(csound, nullptr); csoundCreateMessageBuffer(csound, 0); @@ -27,9 +27,14 @@ class PluginLoadTests : public ::testing::Test { } void compile(const char *plugin, const char *orchestra) { - std::string option = std::string("--opcode-lib=") + plugin; + std::string option = std::string("--opcode-lib=\"") + plugin + "\""; ASSERT_EQ(csoundSetOption(csound, option.c_str()), 0); - EXPECT_EQ(csoundCompileOrc(csound, orchestra, 0), 0) << messages(); + const int result = csoundCompileOrc(csound, orchestra, 0); + const std::string log = messages(); + EXPECT_EQ(result, 0) << log; + // An installed copy can supply the opcodes if the requested library fails. + const std::string loaded = std::string("\nloaded ") + plugin + "\n"; + EXPECT_NE(("\n" + log).find(loaded), std::string::npos) << log; } };