package llama_core

All checked builds pass
  1. Overview
  2. Docs
Core types and operations for the Llama synthesizer library

Install

dune-project
 Dependency

Authors

Maintainers

Sources

0.1.0.tar.gz
sha256=320b997e202b053c1529a70b4fae97b2de4f2d750f26fda199aa3d24c9be7cba
sha512=6a53edfed78ca496009a5b34efbf9b10ed7055ce536ceb7bb0c194090aaa6d103598e5b177260e49c4be9305511f26140db864ed28cdad937ff2da209b5dfbda

Description

Core types and operations for Llama. This is separate from the llama package so that other packages can be written which define new synthesizer modules based on llama without needing to depend on additional packages required by llama to interact with the sound card.

Added to opam-repository:

README

Language for Live Audio Module Arrangement

test status

The llama is a domesticated South American camelid.

About

llama is a library for building software-defined modular synthesizers in a declarative style. It can be used to implement programs that generate audio using components commonly found in synthesizers such as oscillators, envelope generators, and low/high pass filters. It can also be used from utop or other ocaml repl environments to perform music live.

Llama in Action

Videos showing off some of the example programs:

Getting Started

You will need to install rust to build the low level library that reads wav files and talks to the sound card. These parts are written in rust because rust has really good libraries for wav decoding (hound) and sound card interaction (cpal).

Then you should be able to build and some example programs:

$ dune exec ./examples/polyphonic_events.exe
$ dune exec ./examples/random_pentatonic.exe
$ dune exec ./examples/echo_effect.exe

Interactive Demo

Screenshot showing an oscilloscope rendering of an audio waveform

Run dune exec examples/interactive.exe and then use your computer's keyboard to play music. The top and bottom rows of letters are the white keys and the number row and middle row of letters are the black keys. The mouse position controls the frequency cutoff and resonance of a low-pass filter. Hack examples/interactive.ml to change how it sounds!

Concepts

The 'a Signal.t type represents a buffered stream of values of type 'a and is central to the API of llama. These are used to send audio and control signals through a network of components. For example:

(* This is a complete example. Paste this into a file and run it to see what
   it does, or just run:

   $ dune exec ./examples/from_readme.exe
*)

open Llama
open Dsl

(* [osc] represents a signal whose value varies between -1 and 1 according
   to a 440Hz sine wave. *)
let osc : float Signal.t = oscillator (const Sine) (const 440.0)

(* [note_gate] represents a signal whose value is either [true] or [false]
   which changes from [false] to [true] twice per second, and spends 30% of the
   time on. This is often used to communicate the fact that a key is pressed to
   a module that responds to such events. The [Signal.Gate.t] type is a wrapper
   of [bool Signal.t]. *)
let note_gate : Signal.Gate.t =
  periodic_gate ~frequency_hz:(const 2.0) ~duty_01:(const 0.3)

(* [envelope] is a signal which is 0 while its [gate] argument is producing
   [false] values, but which raises to 1 over the course of [attack_s] seconds
   when [gate] transitions to [true], and transitions back to [false] when
   [gate] transitions to [false]. Note that even though it is also a [float
   Signal.t] like [osc] is, it doesn't contain audio data. Instead an envelope
   is typically used to modulate a signal in response to a key press, which we
   are simulating here with [note_clock]. *)
let envelope : float Signal.t =
  ar_linear ~gate:note_gate ~attack_s:(const 0.01) ~release_s:(const 0.2)

(* Multiply the oscillator with the envelope to produce a repeating
   burst of volume which gradually tapers off twice per second. *)
let output : float Signal.t = osc *.. envelope

(* Play the sound! *)
let () = play_signal (output |> scale 0.1)

Example Live Session

Start a utop session with the Llama module available by running dune utop, then enter this into the utop repl.

open Llama.Live;;

(* Define a sequence of frequencies and durations. *)
let steps = [ Some (110.0, 0.1); Some (123.47, 0.1); Some (98.0, 0.2); None ]
|> List.map (Option.map (fun (freq, period) -> { value = const freq; period_s = const period }));;

(* Create a sequencer to play the notes. *)
let { value = freq; gate } = sustained_step_sequencer steps (clock (const 4.0));;

(* Create an oscillator to buzz at the frequency selected by the sequencer. *)
let osc = oscillator (const Saw) freq;;

(* Create an envelope generator to shape the volume according to the gate. *)
let env = ar_linear ~gate ~attack_s:(const 0.01) ~release_s:(const 0.2);;

(* Use the envelope to control the volume of the oscillator. *)
let amp = osc *.. env

(* Create a player returning a `float t ref` which can be set to the signal we want to play. *)
let out = go ();;

(* Play! *)
out := amp;;

(* To silence playback you can change the output to [silence]. *)
out := silence;;

Dependencies (3)

  1. llama_midi = version
  2. ocaml >= "4.13"
  3. dune >= "3.0"

Dev Dependencies (1)

  1. odoc with-doc

Optional Dependencies

None

Used by (1)

  1. llama >= "0.1.0"

Conflicts (1)

  1. result < "1.5"

Build status

Results of building llama_core with each compiler on check.ci.ocaml.org, run of against opam-repository 8a77e58. All results for this package.

Each result links to its build log. To keep crawlers from overloading the site, build logs require a GitHub sign-in (see ocurrent/opam-health-check). On your first log, GitHub asks you to “Authorize opam-health-check”, the OCurrent app that runs these checks; it sees only your public profile, not your repositories. The sign-in lasts 30 days.

Version OCaml 4.11 OCaml 4.14 OCaml 5.2 OCaml 5.4 OCaml 5.5
0.1.0 (this version) n/a good good good good
  • good Package successfully built
  • partial One of the dependencies failed to build
  • bad Package failed to build
  • n/a Package is not available in this environment
  • internal Internal failure