SedaiAudio4Delphi
A thin, flat-C DLL bridge that lets you use the **Sedai Audio Foundation** (a Free Pascal / Object Pascal audio synthesis library) from **Delphi 11.3** (or any Delphi version that supports `external 'sedaiaudio.dll'`).
- Active · last change 11-4-2026
- ★ 2 on GitHub
README
Sedai Audio 4 Delphi v0.1

SedaiAudio https://github.com/camauri/SedaiAudio
A thin, flat-C DLL bridge that lets you use the Sedai Audio Foundation
(a Free Pascal / Object Pascal audio synthesis library) from Delphi 11.3
(or any Delphi version that supports external 'sedaiaudio.dll').
The Sedai Audio Foundation is a complete synth engine: classic subtractive,
FM, additive, wavetable, Karplus-Strong, sample playback, MIDI voice
management, modulation matrix, multi-effect filters, and more. It is
written in Free Pascal and ships as a Delphi-incompatible Object Pascal
unit. This project re-packages it as a native Win64 DLL with a flat
cdecl C-API, and ships a Delphi import unit so you can call every
function directly from your Delphi engine.
Features
- Flat C-API,
cdecl— every public function ofSedaiAudioFoundationis exported under its original name (e.g.InitAudio,PlaySine,PlayWavetable,MIDIPlayNote, …). 128 original exports + one helper for array returns = 129 DLL exports. - Static Delphi imports — no
LoadLibrary/GetProcAddressboiler- plate. AddSedaiAudio4Delphi.pasto yourusesclause and call. - Five synthesis engines in one DLL:
- Classic subtractive (sine / square / saw / triangle / pulse / noise, plus lead / bass / pad presets)
- FM synthesis (e-piano / brass / bell / organ / lead / bass)
- Additive synthesis (up to 64 harmonics, organ / bell / strings)
- Karplus-Strong plucked string (guitar / bass)
- Wavetable synthesis (basic / supersaw / PWM / Serum / Wasp / PPG)
- Sample playback — register in-memory buffers or load WAV files, repitched relative to a configurable root note, loop mode supported.
- Wavetable loading — load single files or scan whole directories, on-disk cache, list/count/query loaded wavetables, custom in-memory wavetables.
- Advanced voice control — per-voice frequency / amplitude / pan / pulse-width / ADSR / retrigger, per-voice filter (type, cutoff, Q, slope 12/24/36/48 dB).
- Instrument modulation matrix — unlimited LFOs per instrument, fixed sources (envelope / velocity / key-track / pitch-bend) routed to pitch / cutoff / amplitude, one-call helpers for vibrato / tremolo / filter-LFO.
- Instrument oscillators — three-oscillator mix, ring-mod, hard-sync, sub-oscillator.
- MIDI utilities — note↔frequency conversion, velocity↔amplitude, pan conversion, note name + octave lookup.
- MIDI voice pool — 256-voice pool with allocate / set / on / off / release, frequency / amplitude / wavetable / pan per voice.
- MIDI integration callback — register a
cdeclcallback to be invoked from the audio thread for external sequencer updates. - Chord and scale helpers — one call for a triad or a major scale across any synth type.
- Win64 native — built with Free Pascal (
-Twin64), links against the Microsoft x64 ABI, socdeclon both sides is ABI-identical. - Console-safe — the DLL redirects FPC's
stdout/stderrtoNULon load, soWriteLncalls inside the engine do not raiseEInOutErrorin GUI hosts (no more External Exception E0465043). - Exception-safe
Init/Shutdown— both are wrapped intry-exceptso a backend failure returnsFalseinstead of crashing the Delphi host.
Project layout
| File | Purpose |
|---|---|
sedaiaudio.lpr |
Free Pascal DLL project. Compile this to produce sedaiaudio.dll. |
SedaiAudio4Delphi.pas |
Delphi import unit. Add to your uses clause. |
SedaiAudioSample.pas |
Delphi VCL sample form. 32 buttons, one per sound, no DFM changes. |
SedaiAudioFoundation.pas |
The original FPC engine unit (drop-in, not modified by this project). |
Building the DLL yourself
You need:
- Free Pascal 3.2.2 or newer (
fpcon PATH) - The full Sedai Audio Foundation source tree (all
Sedai*.pasunits), in the same directory assedaiaudio.lpror on the FPC unit search path - Audio backend dependencies: SDL2.dll and SDL3.dll must be
available to the compiled DLL at runtime (place them next to your
.exe). The Sedai backend currently pulls in both, so both are needed.
From the directory that contains sedaiaudio.lpr and the Sedai units:
fpc -Twin64 -O2 -XSs -Xt sedaiaudio.lprFlags:
-Twin64target Windows 64-bit-O2optimizer level 2-XSssmart-linkable (smaller DLL)-Xtstrip symbols
The output is sedaiaudio.dll. Copy it (together with SDL2.dll and
SDL3.dll) next to your Delphi .exe or onto the system PATH.
The DLL's
begin…end.block redirects FPC'sOutputandErrOutputtext files toNUL. This is required because the Sedai engine usesWriteLnfor status messages, and in a Delphi GUI host there is no console attached tostdout— without the redirect, FPC raisesEInOutError, which Delphi cannot decode and surfaces as External Exception E0465043. The DLL also wrapsInitAudioandShutdownAudiointry-except, so any other FPC exception during init/shutdown returnsFalse/ is swallowed instead of crashing the host.
Using the DLL from Delphi
- Copy
sedaiaudio.dll,SDL2.dll, andSDL3.dllinto your Delphi project's output directory (next to the.exe). - Add
SedaiAudio4Delphi.pasto your project. - Add
SedaiAudio4Delphito theusesclause where you want to call the engine. - Initialize, play, shut down:
uses
SedaiAudio4Delphi;
if not InitAudio(64) then
raise Exception.Create('Sedai Audio backend failed to initialize');
try
PlaySine(440.0, 0.5);
PlayEPiano(440.0);
PlayWavetable(440.0); // nil -> DLL uses 'basic'
PlayWavetable(440.0, PAnsiChar(AnsiString('supersaw')));
// Advanced: get a voice handle and shape it
var V := PlayClassicAdv(440.0, PAnsiChar(AnsiString('lead')));
if V >= 0 then
begin
SetVoicePan(V, -0.5);
SetVoiceADSR(V, 0.01, 0.2, 0.6, 0.4);
SetVoiceFilter(V, True, FT_LOWPASS, 2000.0, 0.7, FS_24DB);
NoteOff(V); // releases the envelopes
end;
// MIDI note pool
var MV := MIDIPlayNote(60, 100, PAnsiChar(AnsiString('basic')));
// ... later
MIDIReleaseAllVoices;
finally
ShutdownAudio;
end;A full, runnable demo form is in SedaiAudioSample.pas — every button
calls one engine function, and a TTimer shows live sample rate / active
voice count / master volume in the form's status label.
Calling-convention & ABI notes
-
cdeclthroughout. On Win64 the FPCregisterandcdeclconventions are ABI-identical (both use the Microsoft x64 calling convention), so callback registration is transparent. -
String parameters are
PAnsiChar(null-terminated ANSI strings). Delphi's defaultstringis UnicodeString — convert explicitly:PlayClassic(440.0, PAnsiChar(AnsiString('sine')));For routines that had a default preset in the original API (
PlayClassic,PlayFM,PlayWavetable,PlayKarplus,PlayAdditive,MIDIPlayNote, …), passnilto use the default. The DLL substitutes the original default value ('sine','epiano','basic', …). Note:PAnsiChar(AnsiString(''))in Delphi returnsnil, so passing an empty Delphi string is the same as passingnil. -
String return values (
GetLoadedWavetableName,GetWavetableCacheInfo,MIDINoteToName,MIDIGetVoiceWavetable,GetWavetableFormatByIndex) returnPAnsiCharpointing into a thread-local static buffer inside the DLL. The buffer is overwritten by the next string-returning call on the same thread. Copy the result to a Delphi string immediately:var NoteName: string := string(MIDINoteToName(60)); -
Array returns (
GetLoadedWavetables,GetWavetableFormats): the original routines returnedTStringArray, which cannot cross the ABI boundary. They are exported asInteger(the element count). Use the indexed getters to retrieve individual items:var Count := GetLoadedWavetables; for var I := 0 to Count - 1 do Memo.Lines.Add(string(GetLoadedWavetableName(I))); -
Enum parameters are passed as
Integer(32-bit) to keep the ABI independent of FPC enum packing. The constantsSAF_*,WT_*,FT_*,FS_*,MS_*,MDT_*,VOM_*are declared inSedaiAudio4Delphi.pas.SAF_*(synth type) andMDT_*(modulation destination) are confirmed against the FPC source; the others (WT_*,FT_*,FS_*,MS_*,VOM_*) are inferred from usage — verify against the FPC source if you need the full set:SedaiAudioTypes,SedaiOscillator,SedaiFilter,SedaiModulationMatrix,SedaiVoice. -
Opaque pointer parameters (
RegisterSample.ABuffer,PlayCustomWavetable.ACustomWavetable,PlayCustomWavetableAdv.ACustomWavetable) take FPC-internal types that have no Delphi counterpart in this unit:TSedaiAudioBufferis a class → pass the object reference asPointerTWavetableis a record → pass the address of the record asPointer(the DLL dereferences it)
The memory layout must match the FPC type. Most Delphi callers will use
LoadSampleFile+PlaySample/PlayLoadedWavetableinstead, which cover the typical workflows without exposing those types. -
Callbacks (
RegisterMidiUpdateCallback) expect acdeclprocedure ofprocedure(ADeltaTimeSeconds: Single); cdecl. The DLL stores it and invokes it from the audio thread — keep the callback body short and non-blocking.
Requirements
| Component | Required for |
|---|---|
| Free Pascal 3.2.2+ | Building sedaiaudio.dll |
| Sedai Audio Foundation source | Building sedaiaudio.dll |
SDL2.dll |
Runtime, next to your .exe |
SDL3.dll |
Runtime, next to your .exe |
| Delphi 11.3 (or compatible) | Compiling the sample + your app |
Windows 64-bit only. Other targets would require recompiling the DLL
and updating the external 'sedaiaudio.dll' references in the wrapper
unit.
Sample project, exe and dlls included
License
The Sedai Audio Foundation is © 2025 Artiforge, licensed under
GPL-3.0. The bridge files in this repository (sedaiaudio.lpr,
SedaiAudio4Delphi.pas, SedaiAudioSample.pas) are provided under the
same license to keep the combined work distributable.

