{"id":18465303,"url":"https://github.com/sleexyz/gallium","last_synced_at":"2026-03-08T10:31:26.497Z","repository":{"id":147692826,"uuid":"112759677","full_name":"sleexyz/gallium","owner":"sleexyz","description":"Web-based environment for livecoding MIDI","archived":false,"fork":false,"pushed_at":"2018-05-22T03:50:38.000Z","size":319,"stargazers_count":19,"open_issues_count":33,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-23T09:24:35.514Z","etag":null,"topics":["livecoding"],"latest_commit_sha":null,"homepage":"http://gallium.live","language":"JavaScript","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/sleexyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2017-12-01T16:09:34.000Z","updated_at":"2023-03-13T01:50:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"b264a0c0-441d-4beb-b28c-52885dbce0f3","html_url":"https://github.com/sleexyz/gallium","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sleexyz%2Fgallium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sleexyz%2Fgallium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sleexyz%2Fgallium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sleexyz%2Fgallium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sleexyz","download_url":"https://codeload.github.com/sleexyz/gallium/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247804554,"owners_count":20999011,"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","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":["livecoding"],"created_at":"2024-11-06T09:12:41.423Z","updated_at":"2026-03-08T10:31:26.469Z","avatar_url":"https://github.com/sleexyz.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://gallium.live\"\u003e\n    \u003cimg alt=\"GALLIUM\" src=\"http://gallium.live/static/gallium_logo.svg\" width=\"75%\"\u003e\u003c/img\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n\u003cp align=\"center\"\u003e\n  A web-based environment for live coding music.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ci\u003e\n  \u003ca href=\"http://gallium.live\"\u003ehttp://gallium.live\u003c/a\u003e\n  \u003c/i\u003e\n\u003c/p\u003e\n\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n\n  * [Setup](#setup)\n  * [Tutorial](#tutorial)\n     * [Basics](#basics)\n     * [Multiple Channels](#multiple-channels)\n     * [Advanced: Contextual Numeric Interpretation](#advanced-contextual-numeric-interpretation)\n     * [Advanced: Polyphony via Stack-Inversion](#advanced-polyphony-via-stack-inversion)\n\n  * [Reference](#reference)\n     * [Basic operators](#basic-operators)\n     * [MIDI operators](#midi-operators)\n     * [Time operators](#time-operators)\n  * [Contributing](#contributing)\n  * [Acknowledgements](#acknowledgements)\n  \n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n![](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)\n\n## Setup\nYou'll need two things:\n- A browser with WebMIDI support, like Google Chrome, open to *[gallium.live](http://gallium.live)*.\n- A MIDI output device.\n\nWant to send MIDI to a DAW like Ableton or Garageband? Here are instructions for setting up a virtual MIDI device:\n  - *OSX* —  [Set up an IAC bus](https://help.ableton.com/hc/en-us/articles/209774225-Using-virtual-MIDI-buses)\n  - *Windows* — [Install loopMIDI](http://www.tobias-erichsen.de/software/loopmidi.html)\n  - *Linux* — [Enable snd-virmidi](https://jazz-soft.net/download/Jazz-Plugin/LinuxSynth.html)\n  \nYou can also use Gallium directly with a hardware MIDI synth with something like a USB-MIDI cable.\n\nDon't have a DAW or synth? There are great free and open source ones, like [TiMidity++](http://timidity.sourceforge.net/) or [PureData](https://puredata.info/).\n\n\n## Tutorial\n### Basics\nUse `note` to start a stream of MIDI notes.\n```\nnote 60\n```\n\n`note` can take multiple arguments. The following plays a C-major arpeggio with a cycle of 4 beats:\n\n```\nnote 60 64 67 72\n```\n\n---\n\nYou can also write the previous arpeggio with `add`:\n\n```\nnote 60\nadd 0 4 7 12\n```\n\nWhat if we want the entire arpeggio to occur all within a beat? We can speed up the stream with `fast`:\n\n```\nnote 60\nadd 0 4 7 12\nfast 4\n```\n\n---\n\nTransformers can run in parallel with `stack`. For example, the following plays a C-major *chord* on every beat:\n\n```\nnote 60\nstack\n  add 0\n  add 4\n  add 7\n```\n\n---\n\nPipes are connected together with `do`.\n\nUse `do` in conjunction with `stack` to do more complex things in parallel. For example:\n```\nnote 60\nstack\n  do\n    fast 2\n    add 12\n  do\n    fast 3\n    add 24\n```\n\nwill play a basic polyrhythm of `72`'s and `84`'s.\n\n---\n\nIn Gallium, inputs are supplied to operators either with indentation or with spacing.\n\nFor example, we can write the previous expression in fewer lines of code by using parentheses:\n\n```\nnote 60\nstack\n  do (fast 2) (add 12)\n  do (fast 3) (add 24)\n```\n\nWe can even write the whole thing in one line!\n\n```\ndo (note 60) (stack (do (fast 2) (add 12)) (do (fast 3) (add 24)))\n```\n---\n\nBy default, all expressions in gallium with zero indentation are chained together with an implicit `do`. In other words,\n```\nnote 60\nfast 2\nadd 3\n```\nwith no indentation, really just means:\n```\ndo\n  note 60\n  fast 2\n  add 3\n```\n\n### Multiple Channels\n\nYou can send data to up to 16 different MIDI channels with `chan`. Channels are numbered from 0 to 15.\n\nFor example, the following alternates between sending middle C to channel 0 and channel 1:\n\n\n```\nnote 60\nchan 0 1\n```\n\nIf you want control two channels separately, use it in conjunction with `stack`. For example:\n\n```\nstack\n  do\n    note 60\n    sub 24\n    chan 0\n  do\n    note 60\n    add 0 2 5 7\n    chan 1\n```\n\n\n### Advanced: Contextual Numeric Interpretation\n\nIn Gallium, numbers are interpreted differently depending on the context.\n\nWhat does that mean? Let's go through a practical example. Suppose we have a pattern that alternates between two notes:\n\n```\nnote 60 80\n```\n\nWhat if we want to play the 80 twice? We can wrap the 80 in a `do` and simply add a `fast 2`:\n\n```\nnote 60 (do 80 (fast 2))\n```\n\nThis is exactly equivalent to:\n\n```\nalt (note 60) (do (note 80) (fast 2))\n```\n\nwhere [`alt`](./alt) is the operator that switches between pipes. \n\n---\n\nWhat's going on? \n\n`note` sets an interpretation for numbers in all its subexpressions. Unless another operator overrides this interpretation (like `fast`, in our case), all numbers get interpreted with `note`. \n\n\n----\n\nAll operators in Gallium that work with numbers behave similarly, including [`fast`](./fast) and [`add`](./add). See the [Reference](./Reference) section for a complete list of operators.\n\n\n### Advanced: Polyphony via Stack-Inversion\n\nWe can exploit contextual numeric interpretation to introduce a useful technique called *stack-inversion*, which allows concise ways to do variations on polyphony.\n\nHere is a stream of C-major triads:\n\n```\nnote 60\nstack (add 0) (add 4) (add 7)\n```\n\nWriting the `add` three times can get a bit cumbersome. Stack-inversion allows us to write `add` just once:\n\n```\nnote 60\nadd (stack 0 4 7)\n```\n\n\n---\n\nWith stack-inversion, we can whip up a delay effect, which simulataneously plays a stream of notes and then shifted copies of itself:\n\n```\nshift (stack 0 0.5)\n```\n\nwhere [`shift`](./shift) is an operator that shifts notes in time by an offset in beats.\n\n\n## Reference\n\n### Basic operators\n\n#### i\n```\ni : P\n```\n\nThe identity pipe. Takes the input and simply returns it.\n\n#### m\n```\nm : P\n```\n\nThe mute pipe. Takes the input and returns nothing.\n\n#### do\n```\ndo : ...P -\u003e P\n```\nConnects pipes together.\n\n#### stack\n```\nstack : ...P -\u003e P\n```\nRuns pipes in parallel.\n\n#### alt\n\n```\nalt : ...P -\u003e P\n```\n\nAlternates between pipes on every beat.\n\n### alt0, alt1, alt2, alt3, alt4, alt5, alt6\n\n```\nalt(n) : ...P -\u003e P\n```\n\nAlternates between pipes every 2^n beats.\n\nNote alt0 is equivalent to alt.\n\n### out0, out1, out2, out3, out4, out5, out6\n\n```\nout(n) : ...P -\u003e P\n```\n\nAlternates between pipes every 2^n beats. Pipes perceive time 2^n times slower.\n\nNote out0 is equivalent to alt.\n\n### in0, in1, in2, in3, in4, in5, in6\n\n```\nin(n) : ...P -\u003e P\n```\n\nAlternates between pipes every (1/2)^n beats. Pipes perceive time 2^n times faster.\n\nNote in0 is equivalent to alt.\n\n\n### MIDI Operators\n\n#### note\n```\n note : ...P -\u003e P\n(note): Number -\u003e P\n````\n\nStarts a new stream of MIDI notes. `note` will ignore data from the previous pipe and overwrite it with a new stream.\n\n*Alternates between pipes on every beat.*\n\n#### add\n```\n add: ...P -\u003e P\n(add): Number -\u003e P\n````\n\nTransposes a stream of MIDI notes up a given number of semitones.\n\n*Alternates between pipes on every beat.*\n\n#### sub\n```\n sub: ...P -\u003e P\n(sub): Number -\u003e P\n````\n\nTransposes a stream of MIDI notes down a given number of semitones.\n\n*Alternates between pipes on every beat.*\n\n\n#### chan\n\n```\n chan : ...P -\u003e P\n(chan): Number -\u003e P\n````\n\nSets the MIDI channel.\n\n*Alternates between pipes on every beat.*\n\n\n#### len\n\n```\n len : ...P -\u003e P\n(len): Number -\u003e P\n````\n\nSets the note lengths in beats. Default length is 1.\n\n*Alternates between pipes on every beat.*\n\n\n### Time Operators\n\n#### fast\n\n```\n fast : ...P -\u003e P\n(fast): Number -\u003e P\n````\n\n*Alternates between pipes on every beat.*\n\nSpeeds up the pattern by a given multiplier.\n\n#### slow\n\n```\n slow : ...P -\u003e P\n(slow): Number -\u003e P\n````\n\n*Alternates between pipes on every beat.*\n\nSlows down the pattern by a given multiplier.\n\n\n#### shift\n\n```\n shift : ...P -\u003e P\n(shift): Number -\u003e P\n````\n\n*Alternates between pipes on every beat.*\n\nShifts the pattern forward by an offset in beats.\n\n\n\n## Contributing\nFound a bug? Missing something? Want to make things happen? Please read the [Contributing](./CONTRIBUTING.md) document for more information.\n\n## Acknowledgements\n\nInspired by [Tidal](https://tidalcycles.org/).\n\nThanks to [Originate](http://www.originate.com/) for sponsoring this as a 20% project!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsleexyz%2Fgallium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsleexyz%2Fgallium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsleexyz%2Fgallium/lists"}