|
Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
|
A native C++20 implementation of the Roland Sound Canvas VA synth voice. It reads the wave ROM and synth tables out of SCCore.dll as a data file — the DLL is never loaded as code — so the engine is portable and has no Windows dependency at all.
MIDI file in, audio out, on one core.
result.left and result.right are the finished mix at ts::ToneGenerator::sample_rate.
| Getting started | Supplying the DLL, the first render, driving the engine live |
| Architecture | How a note becomes sound, and where the clock domains sit |
| In the browser | The engine compiled to WebAssembly, and the app around it |
| Verification | What is proven, how, and against which oracle |
| Specification | The normative specification this engine is built to |
| API reference | Every public type |
Or hear it first. The same engine is live at tabula-sonora.kddlb.cl — a player for Standard MIDI Files and a live instrument, running in the browser with nothing to build. It needs the same DLL this library does, and reads it in the page.
The headers under include/tabulasonora divide the way the engine does. Everything is in namespace ts.
| area | what it does | start at |
|---|---|---|
| ROM | Opens the DLL as data and slices the tables out of it | ts::RomImage, ts::TableManifest, ts::TableSet, ts::WaveRom |
| Patches | Turns a program change into a tone, and a note into a wave | ts::PatchDirectory, ts::Tone, ts::DrumKitTable, ts::WaveDescriptor |
| DSP | The per-voice signal path | ts::Sampler, ts::Interpolator, ts::StateVariableFilter, ts::PitchChain, ts::TvaChain, ts::TvfChain, ts::LfoEngine |
| Modulation | What the stream can move while a note sounds | ts::ControlMatrix, ts::PartModifiers, ts::PitchRamp, ts::ControlDecode |
| Effects | The three send effects, the part EQ, and their coefficient tables | ts::Reverb, ts::Chorus, ts::SystemDelay, ts::Equalizer, ts::EffectPresets, ts::EffectProgrammer |
| MIDI | Reading a Standard MIDI File into something renderable | ts::MidiEvent, ts::Sequence |
| The engine | The block loop, 32 samples at a time, and the parts it drives | ts::ToneGenerator, ts::Part, ts::VoicePool, ts::FrameRing |
| Render | Playing a file through it, live or into a buffer | ts::SequencePlayer, ts::RenderOptions, ts::NoteRenderer, ts::wav::write |
This engine is inert on its own. Roland's wave ROM and tables are not redistributed here — see NOTICE.md, which also covers what little is. You need a legally obtained SCCore.dll from a Sound Canvas VA installation you have licensed, pinned to one exact build: the one shipped in SOUND Canvas VA 1.1.6.
| field | value |
|---|---|
| SCVA release | 1.1.6 |
| size | 27,347,456 bytes |
| SHA-256 | 117e6aa147a96fbde5e10d2caf16c89965acc1e44235fd245992216cc620bdb1 |
| PE timestamp | 2019-10-30 |
A different build moves every table offset, so ts::RomImage refuses to open one.
The release number tells you which installer to look in and nothing more. The DLL has no version resource, so 1.1.6 cannot be read from the file and is not verified; ts::DllIdentity records it as provenance while the hash does the identifying.
Nothing Roland-derived is committed to this repository. assets/manifest.json is the offset map, not the data. The effect coefficients are no exception: the reverb and chorus numbers, once thought to exist only in the running engine's state, are encoded in the DLL, and ts::EffectProgrammer decodes them from your own copy.
Sound Canvas VA was withdrawn from sale in September 2024. This is a preservation and interoperability effort: music written for the Sound Canvas should keep playing after the software that played it stops being available, on platforms the original plugin never supported.
This repository is the reference implementation. It began as a port of the C# engine, which is now archived and kept as a record; both are built to the specification recovered from the DLL. Being C++ with a BSD 3-Clause licence means a host that cannot take a .NET runtime — including GPL software such as Cog — can embed it directly.
And the plugin is itself a port: SCCore.dll carries the SC-8820's own mask ROMs and reproduces its voice down to the fixed-point arithmetic. The lineage runs hardware → plugin → here, and this end of it is not confined to what the previous two could do — it will run 64 parts over four ports where the module has 32 and the shipped DLL reaches 16, and will grow its voice pool past the hardware's 64 rather than steal. Everything of that kind is opt-in, because the default has a job: match the module, and exceed it only on request.
The bulk of this code was generated by large language models, working from the specification and under review. That is not a footnote: it is how every commit in the repository was made, and git log is the record — each one carries a Co-Authored-By trailer naming the model that wrote it, so git blame answers the question for any particular line. Claude Fable 5 and Claude Opus 5, to date.
What makes that acceptable is the property the rest of these pages are about: nothing in this engine is trusted because it looks right. A port whose bar is a SHA-256 match against another implementation's output is checkable by machine, and the phases were gated that way — a phase did not start until the previous one was byte-exact. Verification sets out what is proven, against which oracle, and where this engine knowingly differs. The constants were recovered by measurement, and the claims resting on thin evidence are tagged as such rather than smoothed over.