├── .circleci └── config.yml ├── .flowconfig ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── flow-typed └── npm │ └── jest_v21.x.x.js ├── gallium-live ├── .babelrc ├── .gitignore ├── package.json ├── scripts │ └── publish.sh ├── src │ ├── App.js │ ├── BPMSelector.js │ ├── BPMSelector.test.js │ ├── Editor.js │ ├── Editor.test.js │ ├── Editor_test_utils.js │ ├── OutputSelector.js │ ├── OutputSelector.test.js │ ├── ToggleInvert.js │ ├── ToggleInvert.test.js │ ├── __tests__ │ │ ├── initialization.test.js │ │ └── persistence.test.js │ ├── app_actions.js │ ├── efx.js │ ├── index.html │ ├── index.js │ ├── local_storage.js │ ├── midi.js │ ├── midi.test.js │ ├── midi_actions.js │ ├── playback.js │ ├── playback.test.js │ ├── playback_test_utils.js │ ├── shim.js │ ├── static │ │ └── gallium_logo.svg │ ├── styles.js │ └── test_utils.js ├── webpack.config.js └── yarn.lock ├── gallium ├── .babelrc ├── README.md ├── package.json └── src │ ├── AST.js │ ├── __snapshots__ │ └── parser.test.js.snap │ ├── interpreter.js │ ├── interpreter.test.js │ ├── midi_utils.js │ ├── parser.js │ ├── parser.test.js │ ├── parser_combinators.js │ ├── pretty.js │ ├── pretty.test.js │ ├── printer.js │ ├── printer.test.js │ ├── resolver.js │ ├── resolver.test.js │ ├── semantics.js │ ├── semantics.test.js │ ├── top_level.js │ ├── top_level.test.js │ ├── type_checker.js │ └── types.js ├── lerna.json ├── package.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: node:8.7.0 6 | steps: 7 | - checkout 8 | - run: 9 | name: Install Dependencies 10 | command: yarn 11 | - run: 12 | name: Build packages 13 | command: yarn build 14 | - run: 15 | name: Run checks 16 | command: yarn check-all 17 | - run: 18 | name: Initialize workspace 19 | command: cp -R . /tmp/project 20 | - persist_to_workspace: 21 | root: /tmp/project 22 | paths: . 23 | 24 | publish-site: 25 | docker: 26 | - image: node:8.7.0 27 | steps: 28 | - run: 29 | name: Install awscli 30 | command: | 31 | apt-get -y -qq update 32 | apt-get -y -qq install awscli 33 | - attach_workspace: 34 | at: /tmp/project 35 | - run: 36 | name: Build and Publish gallium.live 37 | command: cd /tmp/project/gallium-live && ./scripts/publish.sh 38 | 39 | workflows: 40 | version: 2 41 | build-publish: 42 | jobs: 43 | - build 44 | - publish-site: 45 | requires: 46 | - build 47 | filters: 48 | branches: 49 | only: 50 | - master 51 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/styled-components/src/.* 3 | 4 | [include] 5 | 6 | [libs] 7 | 8 | [lints] 9 | 10 | [options] 11 | suppress_comment=\\(.\\|\n\\)*\\$ExpectError 12 | include_warnings=true 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | yarn-error.log 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Have a bug or a feature request? 2 | Look in the [issue tracker](https://github.com/sleexyz/gallium/issues) for your issue. If it isn't already there, feel free to create one. 3 | 4 | Bugs should include steps to reproduce. If you can, please link to a branch with a failing test. 5 | 6 | ## Want to contribute to development? 7 | Feel free to take on issues in the issue tracker. If you don't know what to work on, issues are prioritized on the [project board](https://github.com/sleexyz/gallium/projects/1). 8 | 9 | Then fork the repo and make a pull-request when you're ready! In-progress PRs are encouraged. 10 | 11 | 12 | ## [Code of Conduct](./CODE_OF_CONDUCT) 13 | 14 | ## Directories 15 | - [`./gallium`](./gallium) – language implementation 16 | - [`./gallium-live`](./gallium-live) – web based live coding environment 17 | - [`./gallium-relay`](./gallium-relay) - experimental server for collaboration 18 | 19 | ## Development Guide 20 | 21 | The following commands run in the root of the repo: 22 | 23 | ### Prequisites 24 | Install: 25 | - yarn 1.3.2 26 | - node v8.7.0 27 | 28 | Install package dependencies: 29 | ``` 30 | yarn 31 | ``` 32 | 33 | ### Building and Testing 34 | 35 | Build packages: 36 | 37 | ``` 38 | yarn build 39 | ``` 40 | 41 | 42 | To run all checks: 43 | 44 | ``` 45 | yarn check-all 46 | ``` 47 | 48 | 49 | To start a local development server for [gallium.live](http://gallium.live): 50 | 51 | ``` 52 | yarn start 53 | ``` 54 | 55 | A useful shell one-liner that checks your code as it changes. Uses [ag](https://github.com/ggreer/the_silver_searcher) and [entr](http://entrproject.org/): 56 | 57 | ``` 58 | ag -l | grep '.js' | entr -cdrs 'yarn flow && yarn test && yarn format' 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sean Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 |  4 | 5 |
6 |
7 |
8 |
9 |
16 | A web-based environment for live coding music. 17 |
18 | 19 |20 | 21 | http://gallium.live 22 | 23 |
24 | 25 | 26 |  27 | 28 |  29 | 30 | 31 | * [Setup](#setup) 32 | * [Tutorial](#tutorial) 33 | * [Basics](#basics) 34 | * [Multiple Channels](#multiple-channels) 35 | * [Advanced: Contextual Numeric Interpretation](#advanced-contextual-numeric-interpretation) 36 | * [Advanced: Polyphony via Stack-Inversion](#advanced-polyphony-via-stack-inversion) 37 | 38 | * [Reference](#reference) 39 | * [Basic operators](#basic-operators) 40 | * [MIDI operators](#midi-operators) 41 | * [Time operators](#time-operators) 42 | * [Contributing](#contributing) 43 | * [Acknowledgements](#acknowledgements) 44 | 45 |  46 | 47 |  48 | 49 | ## Setup 50 | You'll need two things: 51 | - A browser with WebMIDI support, like Google Chrome, open to *[gallium.live](http://gallium.live)*. 52 | - A MIDI output device. 53 | 54 | Want to send MIDI to a DAW like Ableton or Garageband? Here are instructions for setting up a virtual MIDI device: 55 | - *OSX* — [Set up an IAC bus](https://help.ableton.com/hc/en-us/articles/209774225-Using-virtual-MIDI-buses) 56 | - *Windows* — [Install loopMIDI](http://www.tobias-erichsen.de/software/loopmidi.html) 57 | - *Linux* — [Enable snd-virmidi](https://jazz-soft.net/download/Jazz-Plugin/LinuxSynth.html) 58 | 59 | You can also use Gallium directly with a hardware MIDI synth with something like a USB-MIDI cable. 60 | 61 | Don'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/). 62 | 63 | 64 | ## Tutorial 65 | ### Basics 66 | Use `note` to start a stream of MIDI notes. 67 | ``` 68 | note 60 69 | ``` 70 | 71 | `note` can take multiple arguments. The following plays a C-major arpeggio with a cycle of 4 beats: 72 | 73 | ``` 74 | note 60 64 67 72 75 | ``` 76 | 77 | --- 78 | 79 | You can also write the previous arpeggio with `add`: 80 | 81 | ``` 82 | note 60 83 | add 0 4 7 12 84 | ``` 85 | 86 | What if we want the entire arpeggio to occur all within a beat? We can speed up the stream with `fast`: 87 | 88 | ``` 89 | note 60 90 | add 0 4 7 12 91 | fast 4 92 | ``` 93 | 94 | --- 95 | 96 | Transformers can run in parallel with `stack`. For example, the following plays a C-major *chord* on every beat: 97 | 98 | ``` 99 | note 60 100 | stack 101 | add 0 102 | add 4 103 | add 7 104 | ``` 105 | 106 | --- 107 | 108 | Pipes are connected together with `do`. 109 | 110 | Use `do` in conjunction with `stack` to do more complex things in parallel. For example: 111 | ``` 112 | note 60 113 | stack 114 | do 115 | fast 2 116 | add 12 117 | do 118 | fast 3 119 | add 24 120 | ``` 121 | 122 | will play a basic polyrhythm of `72`'s and `84`'s. 123 | 124 | --- 125 | 126 | In Gallium, inputs are supplied to operators either with indentation or with spacing. 127 | 128 | For example, we can write the previous expression in fewer lines of code by using parentheses: 129 | 130 | ``` 131 | note 60 132 | stack 133 | do (fast 2) (add 12) 134 | do (fast 3) (add 24) 135 | ``` 136 | 137 | We can even write the whole thing in one line! 138 | 139 | ``` 140 | do (note 60) (stack (do (fast 2) (add 12)) (do (fast 3) (add 24))) 141 | ``` 142 | --- 143 | 144 | By default, all expressions in gallium with zero indentation are chained together with an implicit `do`. In other words, 145 | ``` 146 | note 60 147 | fast 2 148 | add 3 149 | ``` 150 | with no indentation, really just means: 151 | ``` 152 | do 153 | note 60 154 | fast 2 155 | add 3 156 | ``` 157 | 158 | ### Multiple Channels 159 | 160 | You can send data to up to 16 different MIDI channels with `chan`. Channels are numbered from 0 to 15. 161 | 162 | For example, the following alternates between sending middle C to channel 0 and channel 1: 163 | 164 | 165 | ``` 166 | note 60 167 | chan 0 1 168 | ``` 169 | 170 | If you want control two channels separately, use it in conjunction with `stack`. For example: 171 | 172 | ``` 173 | stack 174 | do 175 | note 60 176 | sub 24 177 | chan 0 178 | do 179 | note 60 180 | add 0 2 5 7 181 | chan 1 182 | ``` 183 | 184 | 185 | ### Advanced: Contextual Numeric Interpretation 186 | 187 | In Gallium, numbers are interpreted differently depending on the context. 188 | 189 | What does that mean? Let's go through a practical example. Suppose we have a pattern that alternates between two notes: 190 | 191 | ``` 192 | note 60 80 193 | ``` 194 | 195 | What if we want to play the 80 twice? We can wrap the 80 in a `do` and simply add a `fast 2`: 196 | 197 | ``` 198 | note 60 (do 80 (fast 2)) 199 | ``` 200 | 201 | This is exactly equivalent to: 202 | 203 | ``` 204 | alt (note 60) (do (note 80) (fast 2)) 205 | ``` 206 | 207 | where [`alt`](./alt) is the operator that switches between pipes. 208 | 209 | --- 210 | 211 | What's going on? 212 | 213 | `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`. 214 | 215 | 216 | ---- 217 | 218 | All 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. 219 | 220 | 221 | ### Advanced: Polyphony via Stack-Inversion 222 | 223 | We can exploit contextual numeric interpretation to introduce a useful technique called *stack-inversion*, which allows concise ways to do variations on polyphony. 224 | 225 | Here is a stream of C-major triads: 226 | 227 | ``` 228 | note 60 229 | stack (add 0) (add 4) (add 7) 230 | ``` 231 | 232 | Writing the `add` three times can get a bit cumbersome. Stack-inversion allows us to write `add` just once: 233 | 234 | ``` 235 | note 60 236 | add (stack 0 4 7) 237 | ``` 238 | 239 | 240 | --- 241 | 242 | With stack-inversion, we can whip up a delay effect, which simulataneously plays a stream of notes and then shifted copies of itself: 243 | 244 | ``` 245 | shift (stack 0 0.5) 246 | ``` 247 | 248 | where [`shift`](./shift) is an operator that shifts notes in time by an offset in beats. 249 | 250 | 251 | ## Reference 252 | 253 | ### Basic operators 254 | 255 | #### i 256 | ``` 257 | i : P 258 | ``` 259 | 260 | The identity pipe. Takes the input and simply returns it. 261 | 262 | #### m 263 | ``` 264 | m : P 265 | ``` 266 | 267 | The mute pipe. Takes the input and returns nothing. 268 | 269 | #### do 270 | ``` 271 | do : ...P -> P 272 | ``` 273 | Connects pipes together. 274 | 275 | #### stack 276 | ``` 277 | stack : ...P -> P 278 | ``` 279 | Runs pipes in parallel. 280 | 281 | #### alt 282 | 283 | ``` 284 | alt : ...P -> P 285 | ``` 286 | 287 | Alternates between pipes on every beat. 288 | 289 | ### alt0, alt1, alt2, alt3, alt4, alt5, alt6 290 | 291 | ``` 292 | alt(n) : ...P -> P 293 | ``` 294 | 295 | Alternates between pipes every 2^n beats. 296 | 297 | Note alt0 is equivalent to alt. 298 | 299 | ### out0, out1, out2, out3, out4, out5, out6 300 | 301 | ``` 302 | out(n) : ...P -> P 303 | ``` 304 | 305 | Alternates between pipes every 2^n beats. Pipes perceive time 2^n times slower. 306 | 307 | Note out0 is equivalent to alt. 308 | 309 | ### in0, in1, in2, in3, in4, in5, in6 310 | 311 | ``` 312 | in(n) : ...P -> P 313 | ``` 314 | 315 | Alternates between pipes every (1/2)^n beats. Pipes perceive time 2^n times faster. 316 | 317 | Note in0 is equivalent to alt. 318 | 319 | 320 | ### MIDI Operators 321 | 322 | #### note 323 | ``` 324 | note : ...P -> P 325 | (note): Number -> P 326 | ```` 327 | 328 | Starts a new stream of MIDI notes. `note` will ignore data from the previous pipe and overwrite it with a new stream. 329 | 330 | *Alternates between pipes on every beat.* 331 | 332 | #### add 333 | ``` 334 | add: ...P -> P 335 | (add): Number -> P 336 | ```` 337 | 338 | Transposes a stream of MIDI notes up a given number of semitones. 339 | 340 | *Alternates between pipes on every beat.* 341 | 342 | #### sub 343 | ``` 344 | sub: ...P -> P 345 | (sub): Number -> P 346 | ```` 347 | 348 | Transposes a stream of MIDI notes down a given number of semitones. 349 | 350 | *Alternates between pipes on every beat.* 351 | 352 | 353 | #### chan 354 | 355 | ``` 356 | chan : ...P -> P 357 | (chan): Number -> P 358 | ```` 359 | 360 | Sets the MIDI channel. 361 | 362 | *Alternates between pipes on every beat.* 363 | 364 | 365 | #### len 366 | 367 | ``` 368 | len : ...P -> P 369 | (len): Number -> P 370 | ```` 371 | 372 | Sets the note lengths in beats. Default length is 1. 373 | 374 | *Alternates between pipes on every beat.* 375 | 376 | 377 | ### Time Operators 378 | 379 | #### fast 380 | 381 | ``` 382 | fast : ...P -> P 383 | (fast): Number -> P 384 | ```` 385 | 386 | *Alternates between pipes on every beat.* 387 | 388 | Speeds up the pattern by a given multiplier. 389 | 390 | #### slow 391 | 392 | ``` 393 | slow : ...P -> P 394 | (slow): Number -> P 395 | ```` 396 | 397 | *Alternates between pipes on every beat.* 398 | 399 | Slows down the pattern by a given multiplier. 400 | 401 | 402 | #### shift 403 | 404 | ``` 405 | shift : ...P -> P 406 | (shift): Number -> P 407 | ```` 408 | 409 | *Alternates between pipes on every beat.* 410 | 411 | Shifts the pattern forward by an offset in beats. 412 | 413 | 414 | 415 | ## Contributing 416 | Found a bug? Missing something? Want to make things happen? Please read the [Contributing](./CONTRIBUTING.md) document for more information. 417 | 418 | ## Acknowledgements 419 | 420 | Inspired by [Tidal](https://tidalcycles.org/). 421 | 422 | Thanks to [Originate](http://www.originate.com/) for sponsoring this as a 20% project! 423 | -------------------------------------------------------------------------------- /flow-typed/npm/jest_v21.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 107cf7068b8835594e97f938e8848244 2 | // flow-typed version: 8b4dd96654/jest_v21.x.x/flow_>=v0.39.x 3 | 4 | type JestMockFn