supercollider-with-plugins: fix plugin discovery

Assisted-by: Codex (GPT-6)
This commit is contained in:
crertel
2026-09-23 17:07:19 -05:00
parent db477a3f36
commit fab8bd8cf9
3 changed files with 88 additions and 17 deletions

View File

@@ -21,7 +21,6 @@
gitUpdater,
supercollider-with-plugins,
supercolliderPlugins,
writeText,
runCommand,
}:
@@ -87,25 +86,29 @@ stdenv.mkDerivation rec {
};
tests = {
# test to make sure sclang runs and included plugins are successfully found
# Check both language classes and server UGens, without an audio device.
sclang-sc3-plugins =
let
supercollider-with-test-plugins = supercollider-with-plugins.override {
plugins = with supercolliderPlugins; [ sc3-plugins ];
};
testsc = writeText "test.sc" ''
var err = 0;
try {
MdaPiano.name.postln;
} {
err = 1;
};
err.exit;
'';
in
runCommand "sclang-sc3-plugins-test" { } ''
timeout 60s env XDG_CONFIG_HOME="$(mktemp -d)" QT_QPA_PLATFORM=minimal ${supercollider-with-test-plugins}/bin/sclang ${testsc} >$out
'';
runCommand "sclang-sc3-plugins-test"
{
QT_QPA_PLATFORM = "offscreen";
}
''
export XDG_CONFIG_HOME="$TMPDIR/config"
export XDG_DATA_HOME="$TMPDIR/data"
export XDG_CACHE_HOME="$TMPDIR/cache"
mkdir -p "$out"
timeout 60s ${supercollider-with-test-plugins}/bin/sclang \
${./tests/sc3-plugins.scd} "$out" 2>&1 | tee "$out/log"
grep -Fq 'SC3 plugins rendered successfully' "$out/log"
if grep -E 'ERROR|FAILURE|duplicate' "$out/log"; then
exit 1
fi
'';
};
};

View File

@@ -0,0 +1,58 @@
var output = thisProcess.argv[0];
var definition, score;
try {
// Resolve symbols at runtime: an undefined class literal prevents the entire
// script (including its error handler and exit) from being compiled.
[\MembraneHexagon, \MdaPiano].do { |name|
if(name.asClass.isNil) {
Error("Missing SC3 class: " ++ name).throw;
};
};
definition = SynthDef(\sc3PluginsTest, {
// Give each UGen its own output channel so neither can mask a failure.
Out.ar(0, \MembraneHexagon.asClass.ar(Impulse.ar(0)));
Out.ar(1, \MdaPiano.asClass.ar.sum);
});
score = Score([
[0, [\d_recv, definition.asBytes]],
[0, [\s_new, definition.name, 1000, 0, 0]],
[1, [\n_free, 1000]]
]);
score.recordNRT(
oscFilePath: output +/+ "score.osc",
outputFilePath: output +/+ "sc3.wav",
headerFormat: "WAV",
sampleFormat: "float",
options: ServerOptions.new.numInputBusChannels_(0).numOutputBusChannels_(2),
action: { |exitCode|
var file, samples;
try {
if(exitCode != 0) { Error("scsynth exited with " ++ exitCode).throw };
file = SoundFile.openRead(output +/+ "sc3.wav");
if(file.isNil) { Error("No rendered audio").throw };
if(file.numChannels != 2) { Error("Expected two audio channels").throw };
if(file.numFrames < 44100) { Error("Incomplete rendered audio").throw };
samples = FloatArray.newClear(file.numFrames * file.numChannels);
file.readData(samples);
file.close;
samples.clump(2).flop.do { |channel|
if(channel.any { |sample| sample.isNaN or: { sample.abs == inf } }) {
Error("Invalid SC3 UGen output").throw;
};
if(channel.abs.maxItem <= 0.00001) { Error("Silent SC3 UGen output").throw };
};
"SC3 plugins rendered successfully".postln;
0.exit;
} { |error|
error.reportError;
1.exit;
};
}
);
} { |error|
error.reportError;
1.exit;
};

View File

@@ -1,4 +1,5 @@
{
lib,
symlinkJoin,
makeWrapper,
supercollider,
@@ -12,10 +13,19 @@ symlinkJoin {
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
# --include-path adds to the paths from the user's language configuration,
# including an explicit -l configuration (as used by tidal-cycles-full).
if [ -d "$out/share/SuperCollider/Extensions" ]; then
wrapProgram "$out/bin/sclang" \
--add-flags "--include-path $out/share/SuperCollider/Extensions"
fi
for exe in $out/bin/*; do
wrapProgram $exe \
--set SC_PLUGIN_DIR "$out/lib/SuperCollider/plugins" \
--set SC_DATA_DIR "$out/share/SuperCollider"
# scide launches sclang, and sclang launches scsynth, through PATH.
# The server already loads its core UGens from its compiled-in path.
wrapProgram "$exe" \
--prefix PATH : "$out/bin" \
--prefix SC_PLUGIN_PATH : "${lib.makeSearchPath "lib/SuperCollider/plugins" plugins}"
done
'';