Skip to content

anokta/barelymusician

Repository files navigation

barelymusician ci sponsor

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 in a sample accurate way.

This repository includes the build targets for Linux, macOS, Windows, Android, and Daisy platforms, in addition to a native Unity game engine 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.

Example usage

#include "barelymusician.h"

// Create the musician.
barely::Musician musician(/*sample_rate=*/48000);

// Set the global tempo.
musician.SetTempo(/*tempo=*/124.0);

// Create a new instrument.
auto instrument = musician.CreateInstrument();

// Set the instrument gain.
instrument.SetControl(barely::ControlType::kGain, /*value=*/-6.0f);

// Set an instrument note on.
//
// The note pitch is centered around the reference frequency and measured in octaves. Fractional
// note values adjust the frequency logarithmically to ensure equally perceived pitch intervals
// within each octave.
constexpr float kC4Pitch = 0.0f;
instrument.SetNoteOn(kC4Pitch, /*intensity=*/0.25f);

// Check if the instrument note is on.
const bool is_note_on = instrument.IsNoteOn(kC4Pitch);  // will return true.

// Create a new performer.
auto performer = musician.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, [&](barely::TaskState state) {
  constexpr float kC3Pitch = -1.0f;
  if (state == barely::TaskState::kBegin) {
    instrument.SetNoteOn(kC3Pitch);
  } else if (state == barely::TaskState::kEnd) {
    instrument.SetNoteOff(kC3Pitch);
  }
});

// Start the performer.
performer.Start();

// Update the musician timestamp in seconds.
//
// Timestamp updates must occur before processing instruments with their respective timestamps.
// Otherwise, `Process` calls may be *late* in receiving the relevant changes to the instruments. 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;
musician.Update(timestamp + kLookahead);

// Process the next output samples of the instrument.
//
// Instruments process raw PCM audio samples in a synchronous call. Therefore, `Process` should
// typically be called from an audio thread process callback in real-time audio applications.
float output_samples[1024];
instrument.Process(output_samples, timestamp);

Further examples can be found in examples/demo, e.g. to run the instrument_demo.cpp:

python build.py --run_demo instrument_demo