diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-03-13 15:36:57 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-03-13 15:36:57 +0000 |
| commit | 563c6cb1a4f589db59f5241e6e1f78d46477601c (patch) | |
| tree | c51a05011e44d11afffca6267fbe4d8ade53a45a /docs | |
| parent | add Result spec (diff) | |
| download | alive-563c6cb1a4f589db59f5241e6e1f78d46477601c.tar.gz alive-563c6cb1a4f589db59f5241e6e1f78d46477601c.zip | |
docs/guide: runtime description
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/guide.md | 195 |
1 files changed, 149 insertions, 46 deletions
diff --git a/docs/guide.md b/docs/guide.md index 34fdcab..4b1fc64 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -2,13 +2,14 @@ % - % - # getting started with alive -`alive` is a language for creating and changing programs that continuously -run. `alive` can be used to create music, visuals or installations, but by -itself does creates neither sound nor video. Rather, `alive` is used -together with other tools and synthesizers like [SuperCollider][supercollider], -[Pilot][pilot] and many more. `alive` takes the role of a 'conductor', telling -the other tools what to play when by sending commands to them using a variety -of protocols (such as OSC and MIDI). +`alive` is a language for creating and changing realtime programs while they +are running continuously. `alive` can be used to create music, visuals or +installations, but by itself creates neither sound nor video. Rather, `alive` is +used together with other tools and synthesizers (for example +[SuperCollider][supercollider] or [Pilot][pilot]). In such an ensemble of +tools, `alive` takes the role of a 'conductor', telling the other tools what to +play when by sending commands to them using a variety of protocols, such as OSC +and MIDI. Before we get to making sound though, we should learn a bit about the `alive` programming language, and how to install and use it. @@ -20,16 +21,21 @@ used, follow [this link][luarocks] for instructions on setting it up. Once you have luarocks, you can install the dependencies for `alive`: $ luarocks install moonscript + $ luarocks install luasystem $ luarocks install osc $ luarocks install luasocket - $ luarocks install luasystem $ luarocks install https://raw.githubusercontent.com/s-ol/lua-rtmidi/master/lua-rtmidi-dev-1.rockspec -If you have trouble installing some of the dependencies, note that `osc`, -`luasocket` and `lua-rtmidi` are optional, however, you will not be able to use -the corresponding modules of the `alive` standard library if you do not install -them. To follow the later parts of this guide at least `osc` and `luasocket` -are required. +While `moonscript` and `luasystem` are required by the core of `alive`, the +other packages (`osc`, `luasocket` and `lua-rtmidi`) are specific to some +modules of the alive language, and as long as you don't need to use these +modules installation is optional. + +In a later part of this guide, we will be using modules that require `osc` and +`luasocket`, so it is recommended to install at least these two. However it is +possible to follow a large portion of the guide without any of the three. There +will be a note marking the parts of the guide where specific dependencies are +required. After installing the dependencies, you can clone the [`alivecoding` repository][git] using git: @@ -49,7 +55,7 @@ file. From now on, whenever you change `hello.alv` and save the file, `alive` will reload it and execute your new code. When you are done, you can stop the copilot at any time using `^C` (control-C). -## `alive` basics +## evaluating code `alive`'s syntax is very similar to Lisp. Expressions take the form of parenthesized lists like `(head a b c...)`, where the first element of the list (`head`) is the name of an operator or function, which defines what the @@ -60,7 +66,7 @@ following in your file and save it: (trace "hello world") -You should notice two things happening: +As soon as you save the file, you should notice two things happening: 1. The copilot should print two new lines to the terminal: @@ -71,16 +77,18 @@ You should notice two things happening: line, we can see the output from [trace][]: it lets us know that our input `"hello world"` evaluated to a `Value` with the type `str` (string) and contents `hello world`. -2. Your editor may notify you that `hello.alv` has changed, or reload the file - for you. If there is an option like `always reload`, you might want to use - it, since this will happen every time you make a change. +2. The copilot will make a small modification to your file. Depending on the + editor you are using, this may either result in you seeing the modification + immediately, or a notice appearing that offers the option to reload the + file. If it is the latter, confirm the notification to accept the changes. + If there is an option to do so, you may want to configure your editor to + always reload the file automatically. -After reloading the file, you should see that the code has changed slightly: -It now looks like this: +The code should now look like this: ([1]trace "hello world") -The [1] that the copilot added to our expression is that expression's `tag`. +The `[1]` that the copilot added to our expression is that expression's `tag`. In `alive`, every expression has a tag that helps the copilot to identify the individual expressions as you make changes to your code. The copilot will make sure that all expressions are tagged by adding missing tags when you save the @@ -91,19 +99,6 @@ square brackets) and let the copilot generate a new one for you the next time you save the file. ### basic types -Aside from strings, there are two more types of values that you can use when -writing alive programs: numbers and booleans. Numbers use the digits 0-9 and -can be integers, contain a decimal point, or start or end with a decimal point. -Numbers can start with a negetive sign. The following are all valid numbers: - - 0 - 12 - -7 - 0.1 - 10. - .1 - 123. - Strings can be written in two ways: using double quotes (`"`), as we did above, or using single quotes (`'`). In both types of strings, you can escape a quote that otherwise would signify the end of the string by adding a single backslash @@ -119,6 +114,19 @@ The following are all valid strings: "" '' +Aside from strings, there are two more types of values that you can use when +writing alive programs: numbers and booleans. Numbers use the digits 0-9 and +can be integers, contain a decimal point, or start or end with a decimal point. +Numbers can start with a negetive sign. The following are all valid numbers: + + 0 + 12 + -7 + 0.1 + 10. + .1 + 123. + There are only two boolean values, `true` and `false`: true @@ -127,6 +135,21 @@ There are only two boolean values, `true` and `false`: You can try using [trace][] with all of these values to get used to how they are printed. +### comments +To annotate your code, you can use comments. In `alive`, comments begin with +`#(` and end on a matching `)`. This way you can comment out a complete +expression simply by adding a `#` character in front. + + #(this is a comment) + + #(this is a long, + multi-line comment, + (and it also has nested parentheses). + It ends after this sentence.) + +You can put comments anywhere in your program where whitespace is allowed and +it will simply be ignored by `alive`. + ### importing modules Apart from [trace][], there are only very little builtin operators in `alive` - you can see all of them in the *builtins* section of the [reference][:/:]. @@ -155,18 +178,6 @@ it with a prefix. This is what the [import][] builtin is for: (import math) (trace (math/+ 1 2)) -### comments -To annotate your code, you can use comments. In `alive`, comments begin with -`#(` and end on a matching `)`. This way you can uncomment a complete -expression simply by adding a `#` character in front. - - #(this is a comment) - - #(this is a long, - multi-line comment, - (and it also has nested parentheses). - It ends after this sentence.) - ### defining symbols Both [import][] and [import*][] are actually shorthands for other builtins: [def][] and [use][]. [def][] is used to *define a symbol* in the @@ -328,6 +339,49 @@ builtins into a single expression. Compare this equivalent definition of the (defn add-and-trace (a b) (trace (+ a b))) +### evaltime and runtime +So far, `alive` may seem a lot like any other programming language - you write +some code, save the file, and it runs, printing some output. "What about the +'continuously running' aspect from the introduction?", you may ask yourself. + +So far, we have only seen *evaltime* execution in alive - but there is also +*runtime* behavior. At *evaltime*, that is whenever there is change to the +source code, `alive` behaves similar to a Lisp. This is the part we have seen +so far. But once one such *eval cycle* has executed, *runtime* starts, and +`alive` behaves like a dataflow system like [PureData][pd], [Max/MSP][max] or +[vvvv][vvvv]. + +What looked so far like static constants are actually *streams* of values. +Whenever an input to an operator changes, the operator (may) update and respond +with a change to its output as well. To see this in action, we need to start +with a changing value. Number literals like `1` and `2`, which we used so far, +are *evaltime constant*, which means simply that they will never update. Since +all inputs to our [math/+][] operator are *evaltime constant*, the result is +constant as well. To get some *runtime* activity, we have to introduce a +side-effect input from somewhere outside the system. + +The [time/][] module contains a number of operators whose outputs update +over time. Lets take a look at [time/tick][]: + + (import* time) + (trace (tick 1)) + +This will print a series of numbers, incrementing by 1 every second. The +parameter to [time/tick][] controls how quickly it counts - try changing it to `0.5` +or `2`. As you can see, we can change [time/tick][] *while it is running*, but it +doesn't lose track of where it was! + +All of the other things we learned above apply to streams of values as well - +we can use [def][] to store them in the scope, transform them using the ops +from the [math/][] module and so on: + + (import* time math) + (def tik (tick 0.25)) + (trace (/ tik 4)) + +Note that if you leave the [time/tick][]'s *tag* in place when you move it into +the [def][] expression, it will keep on running steadily even then. + ## making sound As mentioned earlier, `alive` doesn't produce sound by itself. Instead, it is paired with other tools, and takes the role of a 'Conductor', sending commands @@ -340,8 +394,57 @@ command line at the bottom. To verify that everything is working so far, try typing in `84c` and hitting enter. This should play a short sound (the note 4C, played by the 8th default synthesizer voice in Pilot). +To talk to Pilot from `alive`, we will use the [pilot/][] module. Note that for +this module to work, you have to have the `osc` and `luasocket` dependencies +installed. To play the same sound we played by entering `84c` above every 0.5 +seconds, we can use [time/every][] to send a `bang` to [pilot/play][]: + + (import* time) + (import pilot) + (pilot/play (every 0.5) 8 4 'c') + +You can play with the voice, octave and note values a bit. To add a simple +melody, we can use [util/switch][], which will cycle through a list of +parameters when used together with [time/tick][]: + + (import* time util) + (import pilot) + (pilot/play (every 0.5) 8 4 + (switch (tick 0.5) 'c' 'd' 'a' 'f')) + +Now we can have the voice change every other loop as well: + + (import* time util) + (import pilot) + (pilot/play (every 0.5) + (switch (tick 4) 8 9) + 4 (switch (tick 0.5) 'c' 'd' 'a' 'f')) + +To round off the sound a bit, we can turn on Pilot's reverb using +[pilot/effect][]. Add the following somewhere in your file: + + (pilot/effect "REV" 2 8) + +Now it's time to add some rhythm. The kick drum is voice 12 by default, +and we can also add something like a snare on channel 3: + + (pilot/play (every 0.75) + 12 2 'd' 3) + (pilot/play (every 2) + 13 4 'a' 4) + +Note that since we are using multiple individual [time/every][] instances, +the timing of our voices relative to each other is not aligned - each voice +started playing when the file was first saved with it added, and kept the +rhythmn since. By deleting all their tags and re-saving the file, we can force +`alive` to re-instantiate them all at the same time, thereby synchronising +them. + [supercollider]: https://supercollider.github.io/ [pilot]: https://github.com/hundredrabbits/Pilot +[pd]: http://puredata.info/ +[max]: https://cycling74.com/products/max +[vvvv]: https://vvvv.org/ [luarocks]: https://github.com/luarocks/luarocks/#installing [git]: https://git.s-ol.nu/alivecoding [reference]: reference/ |
