barelymusician is a real-time music engine for interactive systems.
It provides a modern C/C++ API to generate and perform musical sounds from scratch with sample accurate timing.
This repository includes build targets for Windows, macOS, Linux, Android, WebAssembly, and Daisy, as well as a Godot GDExtension, a native Unity plugin, and a VST instrument plugin.
To use in a C/C++ project, include barelymusician.h.
To use in Godot, download the latest version of barelymusiciangodot.zip.
To use in Unity, download the latest version of barelymusician.unitypackage.
Just curious? Try the experimental web toy at barelymusician.com.
For background about this project, see the original research paper here, and the legacy Unity implementation here.
#include <barelymusician.h>
// Create the engine.
barely::Engine engine(/*sample_rate=*/48000);
// Create an oscillator instrument.
auto instrument = engine.CreateInstrument();
instrument.SetControl(barely::InstrumentControlType::kOscMix, /*value=*/1.0f);
// Set an instrument note on.
// Notes are expressed as octaves relative to middle C. Fractional values adjust the frequency
// logarithmically for equal-tempered pitch intervals within each octave.
constexpr float kC4Pitch = 0.0f;
instrument.SetNoteOn(kC4Pitch);
// Create a looping performer.
auto performer = engine.CreatePerformer()
performer.SetLooping(/*is_looping=*/true);
// Create a task that plays an instrument note every beat.
auto task = performer.CreateTask(/*position=*/0.0, /*duration=*/1.0, /*priority=*/0,
[&](barely::TaskEventType type) {
constexpr float kC3Pitch = -1.0f;
if (type == barely::TaskEventType::kBegin) {
instrument.SetNoteOn(kC3Pitch);
} else if (type == barely::TaskEventType::kEnd) {
instrument.SetNoteOff(kC3Pitch);
}
});
// Start the performer playback.
performer.Start();
// Update the engine timestamp.
// Timestamp updates must occur before processing the engine at the respective timestamp. Otherwise,
// process calls may receive relevant engine changes too late. To avoid this, the engine must be
// updated from the main thread with a lookahead to prevent potential thread synchronization issues
// in real-time audio applications.
constexpr double kLookahead = 0.1;
double timestamp = 0.0;
engine.Update(timestamp + kLookahead);
// Process the next output samples of the engine.
// The engine processes output samples synchronously. Therefore, process must be called from the
// audio thread in real-time audio applications.
constexpr int kChannelCount = 2;
constexpr int kFrameCount = 512;
float output_samples[kChannelCount * kFrameCount];
engine.Process(output_samples, kChannelCount, kFrameCount, timestamp);Further examples can be found in examples/demo, e.g. to run the instrument_demo.cpp:
python build.py --run_demo instrument_demo