OK. FOSC is usable when certain conditions are met. Based on my tests (In summary, based on my tests, FOSC functions reliably on Intel‑based macOS and Linux systems. On ARM64 hardware, it works only under macOS. On Windows, it fails to operate on both Intel and ARM64 architectures.):
- macOS
- Intel, macOS 10.14.6, SC3.13.0:
(Unfortunately this is the latest macOS version available for my Intel machine.)
Works perfectly without any strange error messages.- LilyPond 2.24.4
(downloaded from the macOS section on Download (LilyPond – Music notation for everyone)) - LilyPond 2.25.81
(downloaded from https://gitlab.com/lilypond/lilypond/-/release)
- LilyPond 2.24.4
- ARM, macOS 15.7.5 & 26.3, SC3.15.0-dev:
Works with strange error messages; need to be fixed (see below)- LilyPond 2.24.4
(downloded from macOS section on Download (LilyPond – Music notation for everyone)) - LilyPond 2.25.81
(ARM64 version downloaded from https://gitlab.com/lilypond/lilypond/-/release)
- LilyPond 2.24.4
- Intel, macOS 10.14.6, SC3.13.0:
- Intel, Linux, SC3.15.0-dev:
- Ubuntu 22.04, LilyPond 2.24.4 & 2.25.81
works with strange error messages; need to be fixed (see below)
- Ubuntu 22.04, LilyPond 2.24.4 & 2.25.81
With SC3.13.0 and SC3.14.1 on macOS 15.7.5 (ARM64), I could not get FOSC to work with either LilyPond version due to the following error:
SC3.13.0 and SC3.14.1 on macOS 15.7.5, error when using FOSC
-> Fosc
ERROR: Message 'alterations' not understood.
RECEIVER:
nil
ARGS:
KEYWORD ARGUMENTS:
CALL STACK:
DoesNotUnderstandError:reportError
arg this = <instance of DoesNotUnderstandError>
Nil:handleError
arg this = nil
arg error = <instance of DoesNotUnderstandError>
Thread:handleError
arg this = <instance of Thread>
arg error = <instance of DoesNotUnderstandError>
Object:throw
arg this = <instance of DoesNotUnderstandError>
Object:doesNotUnderstand
arg this = nil
arg selector = 'alterations'
arg args = [*0]
arg kwargs = [*0]
Meta_FoscPitchManager:pitchClassNumberToPitchClassName
arg this = <instance of Meta_FoscPitchManager>
arg number = 60
arg accidental = nil
var integer = 0
var frac = 0
var alterations = nil
var index = nil
var accidentalName = nil
var diatonicPitchClassName = nil
var result = nil
Meta_FoscPitchManager:midinoteToPitchName
arg this = <instance of Meta_FoscPitchManager>
arg midinote = 60
arg accidental = nil
var pitchClassName = nil
var octaveNumber = nil
var octaveName = nil
var result = nil
FoscPitch:init
arg this = <instance of FoscPitch>
arg argName = 60
FoscNoteHead:writtenPitch_
arg this = <instance of FoscNoteHead>
arg pitch = 60
FoscNoteHead:init
arg this = <instance of FoscNoteHead>
arg writtenPitch = 60
arg argClient = <instance of FoscNote>
arg argIsCautionary = false
arg argIsForced = false
arg argIsParenthesized = false
arg argTweaks = nil
var noteHead = nil
var key = nil
var val = nil
FoscNote:initFoscNote
arg this = <instance of FoscNote>
arg writtenPitch = 60
arg isCautionary = false
arg isForced = false
arg isParenthesized = false
< closed FunctionDef > (no arguments or variables)
Interpreter:interpretPrintCmdLine
arg this = <instance of Interpreter>
var res = nil
var func = <instance of Function>
var code = "(
a = FoscNote(60, 1/4);
a.s..."
var doc = nil
var ideClass = <instance of Meta_ScIDE>
Process:interpretPrintCmdLine
arg this = <instance of Main>
^^ ERROR: Message 'alterations' not understood.
RECEIVER: nil
On Linux (ARM64) and Windows (Intel, ARM64), I could not find a way to resolve the problems yet.
Ubuntu 24.04.3, ARM64
Fosc.lilypondPath = "/home/parallels/Downloads/lilypond-2.25.81-linux-x86_64/lilypond-2.25.81/bin/lilypond"
returns:
-> Fosc
However,
Fosc.lilypondVersion;
returns:
ERROR: /bin/sh: 1: /home/parallels/Downloads/lilypond-2.25.81-linux-x86_64/lilypond-2.25.81/bin/lilypond: Exec format error
ERROR: Message 'at' not understood.
RECEIVER:
nil
ARGS:
Integer 0
KEYWORD ARGUMENTS:
CALL STACK:
DoesNotUnderstandError:reportError
arg this = <instance of DoesNotUnderstandError>
Nil:handleError
arg this = nil
arg error = <instance of DoesNotUnderstandError>
Thread:handleError
arg this = <instance of Thread>
arg error = <instance of DoesNotUnderstandError>
Object:throw
arg this = <instance of DoesNotUnderstandError>
Object:doesNotUnderstand
arg this = nil
arg selector = 'at'
arg args = [*1]
arg kwargs = [*0]
Meta_Fosc:lilypondVersion
arg this = <instance of Meta_Fosc>
var str = ""
Interpreter:interpretPrintCmdLine
arg this = <instance of Interpreter>
var res = nil
var func = <instance of Function>
var code = "Fosc.lilypondVersion;"
var doc = nil
var ideClass = <instance of Meta_ScIDE>
Process:interpretPrintCmdLine
arg this = <instance of Main>
^^ ERROR: Message 'at' not understood.
RECEIVER: nil
Messages with a similar name understood by the receiver:
as
rate
halt
Many other objects respond to the message 'at' (found 36 superclasses).
“Exec format error” indicates the binary is not compatible with ARM64. You cannot run the x86_64 LilyPond binary on ARM64.
Windows 11 (ARM64 & Intel)
LilyPond itself runs and returns the version correctly, but FOSC fails when trying to open the generated PDF:
Fosc.lilypondPath = "C:/Users/prko/Downloads/lilypond-2.25.81/bin/lilypond.exe"
returns:
-> Fosc
Fosc.lilypondVersion;
returns:
-> 2.25.81
However,
(
a = FoscNote(60, 1/4);
a.show
)
returns:
ERROR: Changing working directory to: `'C:/Users/prko/AppData/Local/SuperCollider/fosc-output'
fatal error: unable to change directory to: `'C:/Users/prko/AppData/Local/SuperCollider/fosc-output'
ERROR: FoscIOManager:openFile: path does not exist: C:\Users\prko\AppData\Local\SuperCollider/fosc-output/0005.pdf.
CALL STACK:
Object:reportError
arg this = "FoscIOManager:openFile: path..."
Nil:handleError
arg this = nil
arg error = "FoscIOManager:openFile: path..."
Thread:handleError
arg this = <instance of Thread>
arg error = "FoscIOManager:openFile: path..."
Object:throw
arg this = "FoscIOManager:openFile: path..."
Fosc:show
arg this = <instance of FoscNote>
arg paperSize = nil
arg staffSize = nil
arg includes = nil
var illustrateEnvir = <instance of Event>
var path = "C:\Users\prko\AppData\Local\..."
Interpreter:interpretPrintCmdLine
arg this = <instance of Interpreter>
var res = nil
var func = <instance of Function>
var code = "(
a = FoscNote(60, 1/4);
a.s..."
var doc = nil
var ideClass = <instance of Meta_ScIDE>
Process:interpretPrintCmdLine
arg this = <instance of Main>
The folder does exist:
"C:/Users/prko/AppData/Local/SuperCollider/fosc-output".openOS
So this seems to be a path-handling issue in FOSC on Windows.
Where the error messages come from
The relevant code is here:
A simple implementation
Changing line 147 as follows suppresses the error messages on macOS 15.7.5, Ubuntu 22.04.5, and Ubuntu 24.04.3:
exitCode = systemCmd(
command +
Platform.case(
\osx, { "2>/dev/null" },
\linux, { "2>/dev/null" },
\windows, { "2>NUL" }
)
);
However, this also hides important LilyPond warnings and errors, such as:
ERROR: warning: g_spawn_sync failed (-1): gs: Failed to execute child process “gs” (No such file or directory)
ERROR: warning: `(gs -q -dNODISPLAY -dNOSAFER -dNOPAUSE -dBATCH -dAutoRotatePages=/None -dPrinted=false /var/folders/2_/hdf9s2tx6kg7_yqv0bwqtlcm0000gn/T//lilypond-tmp-372811)' failed (-1)
ERROR: /opt/homebrew/Cellar/lilypond/2.24.4/share/lilypond/2.24.4/ly/init.ly:65:2: error: Guile signaled an error for the expression beginning here
#
(let ((book-handler (if (defined? 'default-toplevel-book-handler)
ERROR: Throw to key `ly-file-failed' with args `()'.
ERROR: FoscIOManager:openFile: path does not exist: /Users/prko/Library/Application Support/SuperCollider/fosc-output/0028.pdf.
CALL STACK:
Object:reportError
arg this = "FoscIOManager:openFile: path..."
Nil:handleError
arg this = nil
arg error = "FoscIOManager:openFile: path..."
Thread:handleError
arg this = <instance of Thread>
arg error = "FoscIOManager:openFile: path..."
Object:throw
arg this = "FoscIOManager:openFile: path..."
Fosc:show
arg this = <instance of FoscNote>
arg paperSize = nil
arg staffSize = nil
arg includes = nil
var illustrateEnvir = <instance of Event>
var path = "/Users/prko/Library/Applicat..."
Interpreter:interpretPrintCmdLine
arg this = <instance of Interpreter>
var res = nil
var func = <instance of Function>
var code = "(
a = FoscNote(60, 1/4);
a.s..."
var doc = nil
var ideClass = <instance of Meta_ScIDE>
Process:interpretPrintCmdLine
arg this = <instance of Main>
So suppressing stderr entirely is not ideal.
A more appropriate implementation
Filtering only the “noise” while keeping real errors visible seems better:
*runLilypond { |path, flags, outputPath, executablePath, clean=false|
var lilypondBase, filterText, command, exitCode, success;
executablePath = executablePath ?? { Fosc.lilypondPath };
lilypondBase = path.splitext[0];
outputPath = outputPath ? lilypondBase;
flags = ((flags ? "") ++ " %").format("-dno-point-and-click -o");
command = "% % % %".format(executablePath, flags, outputPath.shellQuote, path.shellQuote);
filterText = " 2>&1 | grep -vE " ++
"'^(Processing|Parsing\\.\\.\\.|Interpreting music\\.\\.\\.|Preprocessing graphical objects\\.\\.\\.|Finding the ideal number of pages\\.\\.\\.|Fitting music on [0-9]+ page[s]?\\.\\.\\.|Drawing systems\\.\\.\\.|Converting to .+)$' | " ++
"grep -vE '^$'";
exitCode = systemCmd(
command +
Platform.case(
\osx, { filterText },
\linux, { filterText },
\windows, { " 2>NUL" }
)
);
success = (exitCode == 0);
if (success && clean) { File.delete(path) };
^success;
}
I don’t use LilyPond regularly, but whenever I test it, it often breaks due to architecture mismatches (PowerBook → MacBook, Intel → ARM). This has been the main reason I haven’t been able to adopt LilyPond more fully.