{"id":18662885,"url":"https://github.com/gridbugs/llama","last_synced_at":"2025-08-27T07:11:39.274Z","repository":{"id":177093106,"uuid":"659865767","full_name":"gridbugs/llama","owner":"gridbugs","description":"Library for declaratively building software-defined modular synthesizers in OCaml","archived":false,"fork":false,"pushed_at":"2025-06-24T06:35:08.000Z","size":295,"stargazers_count":53,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-24T06:35:19.269Z","etag":null,"topics":["dsl","music","ocaml","synthesizer"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gridbugs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-06-28T18:26:18.000Z","updated_at":"2025-06-24T05:44:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"48e9ff9a-4d3c-4e23-98b2-5a396210faba","html_url":"https://github.com/gridbugs/llama","commit_stats":{"total_commits":176,"total_committers":2,"mean_commits":88.0,"dds":"0.011363636363636354","last_synced_commit":"96d1c96c31ff136f465b5f37c981fff591bac6fd"},"previous_names":["gridbugs/llama"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/gridbugs/llama","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gridbugs%2Fllama","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gridbugs%2Fllama/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gridbugs%2Fllama/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gridbugs%2Fllama/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gridbugs","download_url":"https://codeload.github.com/gridbugs/llama/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gridbugs%2Fllama/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272302896,"owners_count":24910291,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsl","music","ocaml","synthesizer"],"created_at":"2024-11-07T08:14:17.934Z","updated_at":"2025-08-27T07:11:39.262Z","avatar_url":"https://github.com/gridbugs.png","language":"OCaml","readme":"# Language for Live Audio Module Arrangement\n\n[![test status](https://github.com/gridbugs/llama/actions/workflows/test.yml/badge.svg)](https://github.com/gridbugs/llama/actions/workflows/test.yml)\n\n*The llama is a domesticated South American camelid.*\n\n\n## About\n\n`llama` is a library for building software-defined modular synthesizers in a\ndeclarative style. It can be used to implement programs that generate audio\nusing components commonly found in synthesizers such as oscillators, envelope\ngenerators, and low/high pass filters. It can also be used from `utop` or other\nocaml repl environments to perform music live.\n\n\n## Llama in Action\n\nVideos showing off some of the example programs:\n- [polyphonic_events](https://youtu.be/o-XPH1j0NqE)\n- [random_pentatonic](https://youtu.be/wfmmdRo_ytU)\n- [echo_effect](https://youtu.be/1ndhPlvDBH8)\n- [interactive](https://youtu.be/O8oc7MhG4uE)\n- [midi_player](https://youtu.be/A8a1Dem2eKs)\n\n## Getting Started\n\nThis project depends on the external dependency `libao` to get access to your\nsoundcard. Install it with your package manager. Then you should be able to\nbuild and some example programs:\n```\n$ dune exec ./examples/polyphonic_events.exe\n$ dune exec ./examples/echo_effect.exe\n```\n\n\n## Interactive Demo\n\n![Screenshot showing an oscilloscope rendering of an audio waveform](img/screenshot.png)\n\nRun `dune exec examples/interactive.exe` and then use your computer's keyboard\nto play music. The top and bottom rows of letters are the white keys and the\nnumber row and middle row of letters are the black keys. The mouse position\ncontrols the frequency cutoff and resonance of a low-pass filter. Hack\nexamples/interactive.ml to change how it sounds!\n\n\n## Concepts\n\nThe `'a Signal.t` type represents a buffered stream of values of type `'a` and\nis central to the API of `llama`. These are used to send audio and control\nsignals through a network of components. For example:\n\n```ocaml\n(* This is a complete example. Paste this into a file and run it to see what\n   it does, or just run:\n\n   $ dune exec ./examples/from_readme.exe\n*)\n\nopen Llama\nopen Dsl\n\n(* [osc] represents a signal whose value varies between -1 and 1 according\n   to a 440Hz sine wave. *)\nlet osc : float Signal.t = oscillator (const Sine) (const 440.0)\n\n(* [note_gate] represents a signal whose value is either [true] or [false]\n   which changes from [false] to [true] twice per second, and spends 30% of the\n   time on. This is often used to communicate the fact that a key is pressed to\n   a module that responds to such events. The [Signal.Gate.t] type is a wrapper\n   of [bool Signal.t]. *)\nlet note_gate : Signal.Gate.t =\n  periodic_gate ~frequency_hz:(const 2.0) ~duty_01:(const 0.3)\n\n(* [envelope] is a signal which is 0 while its [gate] argument is producing\n   [false] values, but which raises to 1 over the course of [attack_s] seconds\n   when [gate] transitions to [true], and transitions back to [false] when\n   [gate] transitions to [false]. Note that even though it is also a [float\n   Signal.t] like [osc] is, it doesn't contain audio data. Instead an envelope\n   is typically used to modulate a signal in response to a key press, which we\n   are simulating here with [note_clock]. *)\nlet envelope : float Signal.t =\n  ar_linear ~gate:note_gate ~attack_s:(const 0.01) ~release_s:(const 0.2)\n\n(* Multiply the oscillator with the envelope to produce a repeating\n   burst of volume which gradually tapers off twice per second. *)\nlet output : float Signal.t = osc *.. envelope\n\n(* Play the sound! *)\nlet () = play_signal (output |\u003e scale 0.1)\n```\n\n\n## Example Live Session\n\nStart a utop session with the `Llama` module available by running `dune utop`,\nthen enter this into the utop repl.\n\n```ocaml\nopen Llama.Live;;\n\n(* Define a sequence of frequencies and durations. *)\nlet steps = [ Some (110.0, 0.1); Some (123.47, 0.1); Some (98.0, 0.2); None ]\n|\u003e List.map (Option.map (fun (freq, period) -\u003e { value = const freq; period_s = const period }));;\n\n(* Create a sequencer to play the notes. *)\nlet { value = freq; gate } = sustained_step_sequencer steps (clock (const 4.0));;\n\n(* Create an oscillator to buzz at the frequency selected by the sequencer. *)\nlet osc = oscillator (const Saw) freq;;\n\n(* Create an envelope generator to shape the volume according to the gate. *)\nlet env = ar_linear ~gate ~attack_s:(const 0.01) ~release_s:(const 0.2);;\n\n(* Use the envelope to control the volume of the oscillator. *)\nlet amp = osc *.. env\n\n(* Create a player returning a `float t ref` which can be set to the signal we want to play. *)\nlet out = go ();;\n\n(* Play! *)\nout := amp;;\n\n(* To silence playback you can change the output to [silence]. *)\nout := silence;;\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgridbugs%2Fllama","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgridbugs%2Fllama","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgridbugs%2Fllama/lists"}