asm-vm
is a light-weight virtual machine that executes a very simple language, that captures some essential concepts for a musical live coding context, such as playing notes and looping patterns. It is intentionally limited to make it fairly easy to learn, yet also intentionally designed to make it possible to express a wide variety of ideas.
Idea and code by @grrrwaaa, extracted from: https://worldmaking.github.io/workshop_nime_2017/vm.html
Currently it works with the aswesome Gibberish by @charlieroberts
The current distribution is 13Kb minified and 4.5Kb minified and gzipped.
Node
Via npm: npm i -S ash-vm
or with yarn: yarn add ash-vm
ES6:
import * as AshVM from "ash-vm"
ES5:
const AshVM = require("ash-vm")
Browser
You can use the ash-vm.js file. Here's an example of use with Gibberish:
<script src="https://oramics.github.io/ash-vm/js/gibberish.min.js"></script>
<script src="https://oramics.github.io/ash-vm/dist/ash-vm.js"></script>
<script>
const vm = AshVM.initGibberish(Gibberish)
vm.run(["@loop", [440, "freq", "@set", "@pluck", 0.5, "@wait"]])
</script>
AshVM can be used with different audio libraries:
You can use the Web Audio API directly, but you have to add your own sounds:
// ES5
const AshVM = require("ash-vm")
// ES6
import * as AshVM from "ash-vm"
const vm = AshVM.initWebAudio(new AudioContext(), { bpm: 120 })
// create your own voices
vm.addVoices({
"bass": (ctx, when) => {
const freq = ctx.get("freq")
const amp = ctx.get("amp")
...
}
})
AshVM is originally developed to use [Gibberish]. It comes with nice sounding instruments:
import * as AshVM from "ash-vm"
import * as Gibberish from "gibberish-dsp"
const vm = AshVM.initGibberish(Gibberish, { bpm: 100 })
The initXXX
function receives an audio driver and returns a virtual machine:
const Gibberish = require("gibberish-dsp")
const AshVM = require("ash-vm")
const vm = AshVM.initGibberish(Gibberish, { bpm: 100 })
It accepts an optional object with one or more of the following parameters:
bpm
: the initial tempo. It uses120
by default.random
: a random function. It usesMath.random
by default.
Run a program. If sync
is true, the program will start in the next beat.
const notes = [60, 62, 64, 78, 98, 100]
vm.run(["@loop", ["@pick", notes, "@mtof", "freq", "@set", "@pluck"]])
You can extend the instruction set by adding commands. You can, for example, add more instruments:
const bang = new Gibberish.FMSynth({ cmRatio:5, index:3 }).connect()
vm.addCommands({
"@bang!": ({ context }) => bang.note(context.get("freq"))
})
vm.run(["@loop", ["@bang!", 1, "@wait"]])
You can extend the instruments by adding instruments. An instrument is a function that receives a Context and trigger a sound:
const synth = Gibberish.Monosynth().connect()
vm.addInstruments({
"synth": (ctx) => {
synth.freq = ctx.get("freq")
synth.note()
}
})
- An introduction to the language with lot of examples (by @grrrwaaa and @charlieroberts): https://oramics.github.io/ash-vm/
- Annotated source code: https://oramics.github.io/ash-vm/literate/
Name | Description | Example |
---|---|---|
@+, @add | Add two values | [1, 2, "@+"] |
@-, @sub | Subtract two values | [2, 1, "@-"] |
@*, @mul | Multiply two values | [2, 4, "@*"] |
@/, @div | Divide two values | [4, 2, "@*"] |
@%, @wrap | Modulo for positive and negative numbers | [4, -2, "@%"] |
@mod | Standard modulo operation | [4, 2, "@mod"] |
@neg | The negative of a value | [4, "@neg"] |
Name | Description | Example |
---|---|---|
@cond | Conditional execution | condition, "@cond", executed-if-true, executed-if-false |
@> | a > b | a, b, "@>" |
@>= | a >= b | a, b, "@>=" |
@< | a < b | a, b, "@<" |
@<= | a <= b | a, b, "@<=" |
@== | a == b | a, b, "@==" |
@!= | a != b | a, b, "@!=" |
@!, @!not | not a | a, "@not" |
@&, @and | a and b | a, b, "@and" |
@or | a or b | a, b, "@or" |
Name | Description | Example |
---|---|---|
@fork | Fork | @fork, [0.5, "@wait", "@kick"] |
@spawn | Spawn | "melody", "@spawn", [0.5, "@wait", "@kick"] |
@stop | Stop current process | @stop |
@stop-all | Stop all processes | @stop-all |
Every process has a context, a time and rate.
Name | Description | Example |
---|---|---|
@let | Assign a value to the local context | 10,"repetitions",@let |
@set | Assign a value to the global context | 10,"parts",@set |
@get | Push the value of a variable into the stack | "repetitions",@get |
Name | Description | Example |
---|---|---|
@wait | Wait an amount of time (in beats) | 1,@wait |
@sync | Wait until next beat | @sync |
@scale-rate | Scale the time rate by a factor | 1.5, "@scale-rate" |
@set-bpm | Set the global tempo in beats per minute | 120, "@set-bpm" |
@scale-tempo | Scale the global tempo by a factor | 0.75 , "@scale-tempo" |
Name | Description | Example |
---|---|---|
@execute | Execute an instruction | 10,"dup","@execute" |
@dup | Duplicate item (so you can use it twice) | 10,@dup |
@repeat | Repeat | 4, "@repeat", ["@kick", 0.5, "@wait"] |
@forever | Repeat forever | "@forever", ["@kick", 0.5, "@wait"] |
Name | Description | Example |
---|---|---|
@iter | Iterate a pattern | [["@iter", [0.3, 1]], "amp", "@set"] |
@rotate | Rotate a pattern | 3, "@rotate", [1, 2, 3, 4] |
Name | Description | Example |
---|---|---|
@random, @rand | Generate a random number between 0 and 1 | ["@random", "amp", "@set"] |
@srandom, @srand | Generate a random number between -1 and 1 | ["@srandom", "phase", "@set"] |
@randi | Generate a random integer between 0 and n | [60, "@randi", "midi", "@set"] |
@pick | Pick a random element from a list | ["@pick", [1, 2, 3, 4]] |
@chance | Probabilistic execution | probability, "@chance", executed-if-true, executed-if-false |
@shuffle | Shuffle a list | "@shuffle", [1, 2, 3] |
Name | Description | Example |
---|---|---|
@play-note | Trigger a note with params | { inst: "pluck", amp: 0.5}, "@note-params" |
@play | Trigger a note | "@note" |
Name | Description | Example |
---|---|---|
Print the last value of the stack | 10,"@print" |
|
@log | Log the name with the last value of the stack | "@random", "amp", "@log" |
You need node and npm installed. Yarn recommended.
- Fork and clone this repository
- Install dependencies:
yarn
ornpm install
- Run tests:
npm test
- Make changes
- Create a pull request
MIT License