gitlab.com/fioravera/synth

Realtime Keyboard Instrument

Project synth implements a real-time keyboard instrument in C, with a WebAssembly/JS wrapper for browser usage, and keeps a legacy version for reference.

Project Structure

/realtime_keyboard_instrument/       <- Root folder of the project
├─ /legacy/                          <- Historical / initial prototypes
│   └─ pianola.c                     <- First prototype C code (no libraries, basic realtime keyboard)
├─ /src/                             <- Official C library implementation
│   ├─ instrument.h                  <- Public API header
│   ├─ instrument.c                  <- Implementation of the fast realtime synth
│   └─ native_example.c              <- Minimal example for native compilation (stdout -> aplay)
├─ /emscripten/                      <- Emscripten wrapper + WASM example
│   └─ emscripten_wrapper.c          <- Exports functions to JS (ems_init, ems_generate, etc.)
└─ synth.xhtml                       <- Browser-ready offline demo with clickable keyboard

Notes

Compilation Tips

Playback in the terminal through ./native_synth (a..k notes, z/x octave, space=bellows, q quit).

Playback in the browser through synth.xhtml.

Compiling and Running the Native Synth

Note: Requires gcc installed and configured in your environment.

Compile the C sources into a native executable:

gcc src/native_example.c src/instrument.c -O3 -lm -o native_synth

Explanation:

Run the synth and pipe audio to a player:

./native_synth | aplay -f S16\_LE -r 48000

Breakdown:

Summary:

./native_synth | ffplay -f s16le -ar 48000 -ac 2 -

This achieves the same effect, playing the PCM audio directly in real time.

Compiling the Synth for WebAssembly with Emscripten

Note: Requires Emscripten installed and configured in your environment.

The following command compiles the C library and wrapper into WebAssembly (.wasm) and JavaScript (synth.js) for use in a browser:

emcc -I./src emscripten/emscripten_wrapper.c src/instrument.c -O3 -s WASM=1 \
  -s EXPORTED_FUNCTIONS='["_ems_init","_ems_shutdown","_ems_set_wave","_ems_set_bellows","_ems_note_on","_ems_note_off","_ems_generate"]' \
  -s EXPORTED_RUNTIME_METHODS='["cwrap","getValue","setValue","HEAP16"]' \
  -o synth.js

Breakdown:

Result: