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.
Try out the web demo to get started!
This repository includes build targets for Windows, macOS, Linux, Android, WebAssembly, and Daisy platforms, along with a native Unity game engine plugin and a VST instrument plugin.
To use in a project, simply include barelymusician.h.
To use in Unity, download the latest version of barelymusician.unitypackage.
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, /*max_frame_count=*/512);
// Set the global tempo.
engine.SetTempo(/*tempo=*/124.0);
// Create a new instrument.
auto instrument = engine.CreateInstrument();
// Set the instrument to use full oscillator mix.
instrument.SetControl(barely::InstrumentControlType::kOscMix, /*value=*/1.0f);
// Set an instrument note on.
//
// The note pitch is expressed in octaves relative to middle C as the center frequency. Fractional
// note values adjust the frequency logarithmically to ensure equally perceived pitch intervals
// within each octave.
constexpr float kC4Pitch = 0.0f;
instrument.SetNoteOn(kC4Pitch);
// Check if the instrument note is on.
const bool is_note_on = instrument.IsNoteOn(kC4Pitch); // will return true.
// Create a new performer.
auto performer = engine.CreatePerformer();
// Set the performer to looping.
performer.SetLooping(/*is_looping=*/true);
// Create a new 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 with the respective timestamps.
// Otherwise, `Process` calls may be *late* in receiving relevant changes to the engine. To address
// this, `Update` should typically be called from the main thread update callback using 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` should typically be
// called from an audio thread process callback 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