{"id":27261967,"url":"https://github.com/syntelang/syntelang","last_synced_at":"2025-04-11T05:48:45.978Z","repository":{"id":40689392,"uuid":"496784356","full_name":"SynteLang/SynteLang","owner":"SynteLang","description":"Public repository for the Syntə live-coding language","archived":false,"fork":false,"pushed_at":"2025-04-06T18:33:09.000Z","size":1515,"stargazers_count":22,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T05:48:39.477Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SynteLang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2022-05-26T22:04:03.000Z","updated_at":"2025-04-06T18:33:13.000Z","dependencies_parsed_at":"2023-02-15T10:47:01.471Z","dependency_job_id":"babfd5ac-93a3-40d1-9654-91a6d881691f","html_url":"https://github.com/SynteLang/SynteLang","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/SynteLang%2FSynteLang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SynteLang%2FSynteLang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SynteLang%2FSynteLang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SynteLang%2FSynteLang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SynteLang","download_url":"https://codeload.github.com/SynteLang/SynteLang/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248351459,"owners_count":21089271,"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":[],"created_at":"2025-04-11T05:48:45.270Z","updated_at":"2025-04-11T05:48:45.962Z","avatar_url":"https://github.com/SynteLang.png","language":"Go","funding_links":[],"categories":["Languages"],"sub_categories":[],"readme":"\u003cTestTag\u003e\n\n# ◌ Syntə\n\nis an audio live coding language and environment\n\u003cbr\u003e\n\nThe name is pronounced '*sinter*', which means to create something by\nfusing many tiny elements together under intense heat.  \nIt is also a portmanteau of 'synth' and 'byte', which is a reference to the stream of bytes that are generated and sent to the soundcard by Syntə.  \n\nProtect your hearing when listening to *any* audio on a system capable of more than 85dB SPL  \n\n**Motivation:**  \n\u003eFun  \n\n**Intended purpose:**  \n\u003eTo compose and perform music using algorithms\n\n**Author:** Dan Arves  \n\u003eAvailable for workshops, talks and performances: synte@proton.me  \n\n**YouTube:**\n\u003e [Syntə Lang Channel](https://www.youtube.com/channel/UCRj9_B6P9T0bQSwCL3yOkyw)  \n\n**Features:**  \n\u003eAudio synthesis    \nWav playback  \nMouse control  \nTelemetry / code display  \nAnything can be connected to anything else  \nFeedback permitted (see above)  \nGroups of operators can be defined, named and instantiated as functions (extensible)  \nUseful predefined functions  \nStandalone - built-in sound engine\n\nThis work and associated code is licensed for non-commercial use, see associated [`licence.md`](https://github.com/SynteLang/SynteLang/blob/main/licence.md) file  \n© 2022  \n\nFor now this document also serves as a specification of the syntə language and may be viewed as a paper on the topic.  \n\nThis document has been written to be accessible to the widest audience as a deliberate aim. Some prior knowledge of unix-like systems and sound synthesis will be useful, and you can build up some knowledge about them alongside this document.  \nSyntə is designed to be both capable as a serious sonic tool and a good entry point for beginners, although inevitably there is a tradeoff and so some patience and learning may be required if you are starting from scratch.  \n\nThe ◊ symbol indicates a sentence or section that may need updating in future.  \n\n\u003ca name=\"top\"\u003e\u003c/a\u003e\n-------------------------------------------------------------------------------------\n\n+ [Examples](#eg)  \n+ [Reference](#ref)\n+ [Details](#det)\n\n## How to use syntə\n\n**Requirements:**  \n\u003eComputer with a soundcard (internal or external)  \n\u003eOSS or ALSA sound driver (FreeBSD / Linux) ◊  \n\u003eGo programming language installed - requires at minimum version 1.18 ◊  \n\u003eDesire to learn about audio synthesis  \n\u003eUnicode support\n\nLinux with ALSA driver should work without modifications, but latest commits may not be tested. You may need to install `osspd` on your Linux distribution. \nIt is not known at present what the performance will be on other systems. ◊ The terminal emulator that has been used for development and testing is Alacritty. It works well on cool-retro-term. You may experience flickering in some terminal emulators due to the incomplete UI.  \n\n**Getting Started**\n\nTo download the files use `git clone` on this repo or click on the green code link above this doc on the main page of the github repository (which you are probably looking at right now) and download as a zip file. As the software is under continuous development it is a good idea to update the code regularly.  \nYou should end up with a directory (folder) containing the following files and directories:  \n\n\u003e\t\n\tREADME.md (this file)\n\tsynte.go  \n\tbsd-linux.go \n\tfunctions.json  \n\ttools/info.go (optional, recommended)  \n\ttools/listing.go (optional, recommended)  \n\ttools/functions.go (optional) \n\ta directory named 'wavs' containing wav files (optional, can contain a README.md)\n\tan empty directory named '.temp' (can contain a README file) \n\tan empty directory named 'recordings' (can contain a README.md) \n\nOpen a terminal, navigate to the directory and type `go run synte.go bsd-linux.go` to begin. ◊ Open another terminal and run `info.go` similarly. This will display useful information and feedback as you input and run code, if you run this before synte.go it will display details of any loaded wavs.  \nOpen another terminal and run `listing.go` to view currently running code, this will also show mute status in italics. You may wish to arrange these using a tiling window manager, terminal multiplexer, or equivalent.\n\nYou will be prompted to write your first syntə listing, a program that will make sounds.  \nThe listing is input one line at a time. You must write the name of an operator or function, usually followed by a space and a number or signal name. The first character of a name cannot be either a number, plus, minus or dot, to avoid confusion.  \nSome names have special meaning, such as ones beginning with the `@` or `^` characters.\n\nPress enter to complete each line.\n\nTry this example to test everything is working ok:\n\n\u003cTest\u003e\n\n\tin 330hz  \n\tosc  \n\tsine  \n\tmix  \n\n\u003c/Test\u003e\n\nThis should output a single sine tone.  \n\nTo mute it, type `mute 0`  \nTo delete it, type `del 0`  \n(where zero is the index of the listing)  \n\nTo pause playback, type `: pause` and `: play` to resume.  \nTo exit from syntə type `: exit`  \n(The `:` operator is used for mode commands to Syntə)  \n\nA function is a predefined list of operations that you can use in your code as if they are operators. These are indicated by a different colour once you have typed them in.\n\nThe result of each operation is fed to the input of the next. You can call this a necklace, or listing of operations. One link of the necklace looks like this in schematic form:\n\u003e\n\tinput (from previous)\n\t↓\n\t[operator] [operand]\n\t↓\n\toutput (to next)\n\nA number represents an input value that could be used to set, for example, a frequency.  \nA number can be input as a frequency, time, or bpm or just a plain number. Eg. `in 1/3`, `in 330hz`, `in 2s`, `in 500ms`, `in 120bpm`, `mul 6db`.   \nA name represents a signal, Signals are used to store or share values using the `in` and `out` operators. Another way to think of them is as registers, like in a CPU.  \nYou can only output to a unique signal once in a listing, but you can input multiple times from the same signal.  \nThink of it as a confluence of rivers flowing into one another to reach the sea. Many inputs, one output.  \nIf you want to send two values to the same signal, either add them or combine them in other ways using operators first.    \n\nSome operators and functions do not need an operand, simply press enter after the name.\n\nCommon operations are `+`, `mul`, `in`, `out`.\n\nThe `osc` function outputs a ramp wave (increasing series of values up to 1, then restarts.)  \n`osc` accepts a frequency in hertz (from the preceding operation.)\n\nMost values apart from frequencies are between -1 and 1 for audio and 0 to 1 for control/modulation. This might seem like a limited range; however, incredibly small fractions down to a number with over 300 zeros after the decimal place are possible. You won't need to handle such numbers, but if you want to experiment they can be input using the syntax `1e-3` which would represent one thousandth, or 3 millionths would be `3e-6` etc. You may also input a number as a fraction such as `in 1/3.14` etc.  \nAny values greater than 1 or less than -1 will be clipped by the output resulting in distortion. Think of this as slicing off the tops of waveforms that are too loud. Most of the time you won't need to worry about keeping within range though.\n\nIn the syntə code example above, the output of the `osc` function is *shaped* by the sine operator. The sine operator does not produce a sound tone by itself.\n\n`dac` is a special signal name which sends the output to the soundcard of your computer. Typing `out dac` ends a listing and sends it to the sound engine to perform computations.  \nMost listings end in `out dac`, so it can only be used once. `dac` stands for digital audio converter, which is the technical name for anything that takes a series of digitally represented numbers and converts them into audio. A listing that generates signals for other listings but no sound directly can end with the `.out` operator.\n\nYou will probably want to use the function `mix` which contains `out dac` and so will also end a necklace. `mix` will set the level based on the frequency of the most recent osc function within the listing to ensure output limiting doesn't take place (which may reduce the bass response). However, for listings that pass through using `from` it is better to use `out dac`.\n\nThe `sino` function combines `osc` and `sine` so can be used in their place.\n\nOnce you have added one listing in this way, you can add more.  \nIn the code display window (running `tools/listing.go`), each listing has a number indicated at the beginning of the first line.  This is used to reference the listing for operators like `del` which silences a listing and removes all its code. When inputting a new listing, typing `: erase` removes all operations input so far and starts again from the top. Once a listing has been launched it will be saved in the `.temp/` directory and will relaunch if edited and saved.  \n\nYou don't need to understand all of this right away. Everyone learns at different rates, and has a different learning style. Some need to experiment, some need a lot of detail, some by example etc. In future you may be able to find a workshop to attend if that is helpful too. If you want you can skip to the [Examples](#eg) section below to try out some listings directly.  \n\n**Great, but what do I actually type in?**\n\nTo decide what code to write, it's helpful to think about the functions or shapes that represent the sounds that you want.  \n\nAny number that increases and decreases periodically in some way will produce an audible sound if the frequency is in the range of 20 to 20,000 hertz. (1 hertz is one cycle per second.) In practice most frequencies will be between around 200 to 2000 hertz. Anything below that takes quite a lot of power and size for a speaker to produce clearly and anything above that is rarely used directly (as a fundamental or root note) and will usually only appear as overtones of other lower frequencies. A discussion of overtones and harmonics is beyond the scope of this document, doing your own research will be useful for future if they are new to you.  \n\nThe `osc` function is actually a group of operators that are added to your listing. They are:\n\n\u003e\t\n\tout ^freq  \n\t+ a  \n\tmod 1  \n\tout a  \n\n`out ^freq` sends the input frequency to a mix function (if you use one) for help in setting a sensible level.\n`+` adds the input to a signal called `a` .\n`mod 1` allows through any number between 0 and 1. Any numbers larger have 1 subtracted until within that range, eg. 2.3 → 0.3\n`out a` sends the result of `mod 1` to the signal `a`, this forms a loop.\n\nSo `osc` is always adding to itself, yet keeping between 0 and 1.\nIn ASCII it looks like: /|/|/| etc, you can see why it is called a ramp wave. In the study of digital signal processing it is known as a phase accumulator or numerically controlled oscillator and in mathematics it is an overflowing integrator, but you don't need to know that. Another way of looking at it is that it counts up and then starts again to generate a repeating cycle. It is one of the most useful and basic functions in producing sounds. In fact, unless you do something really fiddly, nearly all of your necklaces will contain osc somewhere. (For functional programming aficionados: the register in `osc` forms a closure which holds the current value of the output. Any register that is read from (with `in`) before writing to (with `out`) will form a closure, if this is allowed to change while being constrained within a certain range it will form an oscillator.)\n\nNow what happens if you want a *decreasing* wave form? i.e one that counts down instead of up. What you can do is take an `osc` and flip it upside down with `mul -1`. Now it is also negative so you can `+ 1` to shift it to between 0 and 1 again. This is also what the `flip` function does. This upside down ramp can be called a sawtooth wave (although they're kind of interchangeable terms.) Interestingly you wouldn't be able to tell an audible difference between a ramp and a sawtooth wave if output directly to your speakers, that is to say they sound the same. However for low frequency modulation, like periodically changing the volume, you would definitely tell the difference. Modulation just means changing one aspect of something else, such as the volume or filtering or pitch.\n\n**Signal chains**\n\nIf you are not familiar with the concepts of synthesis don't worry, with a little time and patience you can build up confidence and understanding bit by bit.\n\nTo understand signal chains, visualise how a traditional electric guitarist makes music. They connect their equipment like so:\n\nGuitar → fx pedal → amplifier\n\nThis is the equivalent to a necklace in syntə, for example something like:\n\nfrequency → osc → lpf → mix\n\nBut in this case syntə is the guitar and the guitarist too. So in code `in 330, osc, osc, mix` would be a frequency controlling the frequency of another oscillator.\nIn this case the frequency of the second oscillator will only change from 0 to 1, so we can:\n\n`in 330hz, osc, mul f, osc, mix`\n\nwhere f is now the maximum frequency we span to. You can use a number such as 200 instead, or feed in a value by sending to f from somewhere else. The listing input display indicates where a result is passed down the chain by a curly arrow on the left. The operators `in`, `pop`, and `tap` break the chain and start a with value which is either the operand, the top of the stack, or the specified delay tap, respectively.\n\nIf we examine the guitarist example more closely , we realise that the fx pedal will likely contain modulators such as LFOs, along with filters, wave shapers etc.\nSo we can extend our analogous model to something like:\n\n`in 2.5hz, osc, flip, out a, tri, out c, in 330hz, osc, mul a, osc, lpf c, mix`\n\nNotice that the first oscillator is now generating a 2.5 hertz low frequency modulation. It is inverted before being send to a, and then shaped into a triangle wave and send to c. The second osc now operates at a fixed frequency of 330 hertz and is multiplied by a (acting like a VCA to control the volume) and filtered by c before being mixed and send to the output.\n\nWhich leads us to \n\n**Heuristics**\n\nTo assist in writing necklaces of operations here are some useful heuristics/suggestions:\n\n- Low to high. Start from low frequencies (less than 20 hertz) for modulation and combine them and/or outputting to signals with `out` for later use, before progressing to high (audible) frequencies.  \n\n- name each signal by the next available letter of the alphabet. Another approach, which is good for beginners is semantic naming, which is a clever way of saying to give a name that describes what the value represents - what it *means*. For example: OscPitch, modulatorA, lfo, env1 etc.\n\n- if you realise that you need to add in further modulation or adjust values, you can use `push` to break the necklace and then `pop` to resume later.\n\n\u003ca name=\"eg\"\u003e\u003c/a\u003e\n## Examples ◊\nTo help get your creative juices flowing, try typing in these example necklaces of operations:\n\n**Surf**  \nAdd two or three separate listings of this code for a relaxing beach experience.\n\n\u003cTest\u003e\n\n\tin 4hz\n\tnoise\n\t+ 0.05hz\n\tosc\n\ttri\n\tout a\n\tnoise\n\tmul a\n\tmix\n\n\u003c/Test\u003e\n\n**Kick and hihat**\n\n\u003cTest\u003e\n\n\tin 2hz\n\tposc 0\n\tmul 8\n\tclip 0\n\tflip\n\tmul 165hz\n\tosc\n\tsine\n\tmul 2\n\ttanh\n\tlpf 200hz\n\tmix\n\n\u003c/Test\u003e\n\nThe kick will play on every beat. For once per bar of four beats use `in 120bpm, / 4` before `posc`\n\n\u003cTest\u003e\n\n\tin 2hz\n\tposc 0.5\n\tmul 4\n\tclip 0\n\tflip\n\tnoise\n\tmix\n\n\u003c/Test\u003e\n\n\u003cTest\u003e\n\n\t.\u003esync\n\n\u003c/Test\u003e\n\nHere the clip operator is used to shape the VCA envelope of the hi-hat and the listings are synchronised together with a phase offset.\n\n**Sample and hold melody**\n\n\u003cTest\u003e\n\n\tin 3.5hz\n\tramp\n\tout a\n\tin 8hz\n\tosc\n\ts/h a\n\tmul 3.5\n\tmul 8\n\tmod 3\n\tmul ln3\n\tmod ln2\n\tbase E\n\tmul 440hz\n\tosc\n\tsine\n\tmix\n\n\u003c/Test\u003e\n\nHere the pitch is calculated exponentially, mixing powers of 3 ≡ MOD 2 to produce a scale. You are not expected to understand this straightaway!\nThe bpm could be interpreted as quarter notes at 120bpm, because 8 / 4 = 2 and 2 x 60 = 120.\n\n**Pulse sequencing**\n\n\u003cTest\u003e\n\n\tin 120bpm\n\tmul 1/4\n\tout tempo\n\tpulse 2/4\n\tout pitch\n\tin tempo\n\tpulse 1/4\n\tout+ pitch\n\tin tempo\n\tpulse 3/4\n\t+ pitch\n\tbase 2\n\tmul 330hz\n\tsino\n\tmix\n\n\u003c/Test\u003e\n\nThis sequence will play a descending series of quarter notes spaced by an octave.\n\n**Wobble bass**\n\n\u003cTest\u003e\n\n\tin 135bpm\n\tosc\n\ttri\n\tout a\n\tin 55hz\n\tosc\n\tsine\n\tmul 5\n\ttanh\n\tmul a\n\tlpf a\n\tmix\n\n\u003c/Test\u003e\n\n**Siren** (note similarity to wobble)\n\n\u003cTest\u003e\n\n\tin 0.2hz\n\tosc\n\ttri\n\tmul 440hz\n\t+ 110hz\n\tosc\n\tsine\n\tmul 2\n\ttanh\n\tmix\n\n\u003c/Test\u003e\n\n**Algo-rhythm**\n\n\u003cTest\u003e\n\n\tin 120bpm\n\tmul 8\n\tosc\n\tgt 0.5\n\tout a\n\tin 5hz\n\tosc\n\tgt 0.9\n\tmul a\n\tnoise\n\tmix\n\n\u003c/Test\u003e\n\nNote that the operator `gt` (greater than or equal) shapes the `osc` into a pulse wave where threshold is the operand and so sets the pulse width.\n\n**Basic Sample manipulations**\n\u003e\n\u003cTest\u003e\n\n\tin wavR\n\tosc\n\twav [name of wav file]\n\tout dac\n\n\u003c/Test\u003e\n\n\u003cTest\u003e\n\n\tin mousex\n\tlpf 0.1hz\n\twav [name of wav file]\n\tout dac\n\n\u003c/Test\u003e\n\n\u003cTest\u003e\n\n\tin wavR\n\tosc\n\tmod 0.1\n\twav [name of wav file]\n\tout dac\n\n\u003c/Test\u003e\n\nThe `mousex` register supplies the relative X co-ordinate motion transmitted by the mouse. The second example simulates vinyl and the third controls the sample length. `out dac` is used here instead of `mix` assuming the sample is already pre-mixed.\n\n**Simple time-stretch algorithm**\n\n\u003cTest\u003e\n\n\tin 50hz\n\tosc\n\tmul 0.25/50\n\tmul 0.9\n\tout a\n\tin wavR\n\tmul 0.1\n\tosc\n\t+ a\n\twav [name of wav file]\n\tout dac\n\n\u003c/Test\u003e\n\nThe values 0.9 and 0.1 should sum to 1 to maintain original pitch. 0.25 is the frequency given by wavR for a sample length of 4 seconds\n\n**Basic reverb**  ◊\n\n\u003cTest\u003e\n\n\tin 0.5hz\n\tosc\n\tlt 1/20\n\tout a\n\tin 440hz\n\tosc\n\tsine\n\tmul a\n\t+ c\n\tpush\n\tmul 0.25\n\ttape 100ms\n\ttap 300ms\n\ttap 70ms\n\tlpf 1200hz\n\tout c\n\tpop\n\tmix\n\n\u003c/Test\u003e\n\nThe reverb begins at the `+ c` line. the output is pushed onto the stack before being fed into `tape`. The feedback is from multiple taps which are attenuated by `mul 0.3` before being fed back via the register c. The listing preceding the reverb generates a 440Hz sine wave gated by a pulse every 3⅓ seconds.\n\n**FM Bell**\n\n\u003cTest\u003e\n\n\tin 0.5hz\n\tosc\n\tflip\n\texp 5\n\tlpf 120hz\n\tout a\n\tin 280hz\n\tosc\n\tsine\n\tmul 190hz\n\t+ 105hz\n\tosc\n\tsine\n\tmul a\n\tmix\n\n\u003c/Test\u003e\n\nHere, we use the `exp` function to shape the inverted ramp wave from osc into an exponential decay to control the amplitude of the bell. Feeding the output of the second `osc` into a third one results in FM synthesis, that is the output of one oscillator controls or modulates the frequency of the next. The `lpf` smoothes out the amplitude envelope, `a` which helps avoid limiting on the output (slower attack reduces higher frequencies, which the limiter is more sensitive to).\n\n**Dialling tone**\n\n\u003cTest\u003e\n\n\tin 1/6hz\n\tosc\n\tlt 1/3\n\tlpf 120hz\n\tout a\n\tin 480hz\n\tsino\n\tout c\n\tin 440hz\n\tsino\n\t+ c\n\tmul a\n\tmix\n\n\u003c/Test\u003e\n\nAlthough not particularly musical, this simple necklace illustrates mixing two signals and gating them (turning on and off) with a third signal which is a pulse wave. The `pulse` function can be used instead to gate a signal by a variable width. `slew 150hz` could be added before `out a` instead of `lpf 120hz`, both smoothen the pulse for a less clicky sound.\n\n**Euclidean Rhythm**\n\n\u003cTest\u003e\n\n\tin 120bpm  \n\tmul 1/4  \n\teuclid 3,8,0  \n\tdecay 0.999\n\tnoise  \n\tmix  \n\n\u003c/Test\u003e\n\u003c/TestTag\u003e\n\nFunctions can have up to three operands separated by commas with no spaces. Refer to the function reference below for how many each one takes. The third argument of `euclid` is the phase offset of the internal oscillators.  \nEuclidean rhythms can also be generated by using `grid`.  \n\nYou can find more examples in the `.saved` directory.\n\n---\n\n\u003ca name=\"ref\"\u003e\u003c/a\u003e\n## Reference\n\n+ [Sample playback](#sp)  \n+ [Tape loop](#tl)\n+ [Arithmetic operations](#ao)\n+ [Type system](#ts)\n+ [Signals](#sigs)\n+ [CV and audio signal ranges](#CV)\n+ [Channels](#ch)\n+ [Synchronisation](#syn)\n+ [Setting levels](#sl)\n+ [Adding functions](#af)\n+ [info.go and listing.go](#il)\n+ [Hot tips](#ht)\n+ [Performing with Synte](#ps)\n+ [Editing running listings](#ed)\n+ [Exported signals](#ex)\n\n**List of operators**\n\n|  Operator\t|Requires operand?| Notes                           |\n|-----------|---------------|-----------------------------------|\n|    in\t\t|\t\tyes\t\t|  \t\tinput from signal or fixed value|\n|\tout\t\t|\t\tyes\t\t|\t\toutput to signal  \n|\tout+\t|\t\tyes\t\t|\t\tadd to signal\n|\t+\t\t|\t\tyes\t\t|\t\tadd previous result to operand, negate operand to subtract instead eg. `+ -1`  \n|\tsine\t|\t\tno\t\t|\t\tapply sine mathematical function. Output = sine(2·Pi·input)  \n| \tmod\t\t|\t\tyes\t\t|\t\tmodulo operator. Output is the remainder on division by operand\n|\tgt\t\t|\t\tyes\t\t|\t\tresult is 1 if greater than or equal to operand, 0 otherwise. For strictly greater than, use `lt` followed by `flip`  \n|\tlt\t\t|\t\tyes\t\t|\t\tresult is 1 if less than or equal to operand, 0 otherwise. For strictly less than, use `gt` followed by `flip`\n|\tmul\t\t|\t\tyes\t\t|\t\tmultiply operator\n|\tabs\t\t|\t\tno\t\t|\t\tabsolute value, all inputs become positive (removes negative sign)\n|\ttanh\t|\t\tno\t\t|\t\thyperbolic tangent, useful for 'soft clipping'\n|\tclip\t|\t\tno\t\t|\t\trestrict input between symmetrical thresholds ±operand value. 0 is a special case resulting in thresholds of 0 and 1\n|\tnois\t|\t\tno\t\t|\t\tresult is a pseudo-random series of numbers in range ( [-1, 1] * input ). Use `noise` for audio\n|\tpow\t\t|\t\tyes\t\t|\t\tresult is operand raised to the power of input, for convenience the sign of both input and operand is ignored (always positive, |n|)\n|\tbase\t|\t\tyes\t\t|\t\tresult is input raised to the power of operand. Sign of operand (±) is ignored\n|\t\\\u003csync\t|\t\tyes\t\t|\t\treceive sync pulse which zeros whatever is passed through. Operand adds phase offset on pulse\n|\t\\\u003esync\t|\t\tyes\t\t|\t\tsend one sync pulse to all listings when input ≤ 0. Latches off until input \u003e 0\n|\t.\u003esync\t|\t\tyes\t\t|\t\tequivalent to \u003esync but will end listing and launch, like `out dac`\n|\tpush\t|\t\tno\t\t|\t\tmove result to the stack of that listing\n|\tpop\t\t|\t\tno\t\t|\t\ttake most recently pushed result from stack of that listing\n|\tbuff\t|\t\tyes\t\t|\t\trecord and playback from a rotating buffer, analogous to a tape loop. Operand is the offset in seconds/milliseconds (use types).\n|\ttap\t\t|\t\tyes\t\t|\t\tresult drawn from buff and added to input from preceding listing, operand is the offset in seconds/milliseconds (use types)\n|\tf2c\t\t|\t\tno\t\t|\t\tconvert frequency to filter coefficient. Numbers less than than 0 will be multiplied by -1 (sign removed, become positive)\n|\twav\t\t|\t\tyes   \t|\t\twill play the corresponding sample of a loaded WAV file given by the operand. Expects an input in range [0, 1], values outside this range will wrap around this interval. See section below for more information\n|\t8bit\t|\t\tyes   \t|\t\tquantises input to 8 bits of resolution (-128 to +127). The operand is the size of quantisation steps. So to quantise a ±1 signal, use 127 as the operand. Alternatively, quantise to integers with an operand of 1.\n|\tlevel\t|\t\tyes   \t|\t\tchanges the output level of the listing at the index given by operand, which must be a number (not a signal). The preceding input sets the level. Capable of modulation up to 1100Hz, but because of this sudden large changes in level may produce clicks. Filter with eg. `lpf 50hz` or `smooth` to avoid this. Operation independent of mute. Indexes out of range are silently ignored\n|\tx\t\t|\t\tyes   \t|\t\talias of `mul`\n|\t*\t\t|\t\tyes   \t|\t\talias of `x`\n|\tfrom\t|\t\tyes   \t|\t\treceives mono output of listing given by operand. By design operand must be a number not a named signal. Indexes out of range are silently ignored\n|\tsgn\t\t|\t\tno   \t|\t\toutputs is 1 if the input is positive and -1 if negative\n|\t/\t\t|\t\tyes   \t|\t\tsubtracts the operand from the input repeatedly until zero and outputs the number of subtractions as a fraction. AKA divide. output = input / operand\n|\t\\\t\t|\t\tyes   \t|\t\toutput = operand / input\n|\tsub\t\t|\t\tyes   \t|\t\tsubtracts the operand from the input\n|\tsetmix \t| \t\tyes\t\t|\t\tused internally for mix function\n|\t.level\t|\t\tyes   \t|\t\tequivalent to `level` except will end input and launch listing. Operation not affected by mute\n|\tprint\t|\t\tno   \t|\t\tprints value of input to info display and passes through unchanged to next operation. Timing is a random point in an interval approximately 341ms to 682ms\n|\tindex\t|\t\tno   \t|\t\toutputs index of current listing\n|\t//\t\t|\t\tyes   \t|\t\tdoes nothing, use to display comments. Separate words with underscores like_this_etc. Remainder of listing will be skipped, use as a single line listing\n|\tall\t\t|\t\tno   \t|\t\toutput is sum of all listings including preceding listing, but not including its own output. Not affected by mutes\n|\t.out\t|\t\tyes   \t|\t\tuse to end silent listing, for use with signals `tempo`, `pitch`, `grid`, or Exported signals.\n|\tjl0\t\t|\t\tyes   \t|\t\tjump if less than zero. The next n number of operations are skipped if input is less than or equal to zero, where n is given by operand.  Bear in mind that this number of skips includes all the operations within any functions within the listing. The final operation in a listing will always execute. An operand of zero is no jump. Added for fun in a vague attempt to make syntə turing-complete\n|\tpan\t\t|\t\tyes   \t|\t\tinput (limited to ±1) sets the stereo pan of the listing given by operand (which must be a number, similarly to `level`). Positive input pans right and negative input pans left. The pan curve chosen ensures neither channel is boosted at full pan, while centrally panned sounds remain at unity gain in both channels. This is achieved by turning down the mono channel while pan increases. Because of this a sound with modulated (changing) pan summed to mono will fluctuate in volume, so we recommend modulating with a signal `pan` on stereo playback systems only. That is to say - for full mono compatibility only apply static `pan` (input is unchanging) at most. But don't worry as this is somewhat of a niche concern\n|\t--\t\t|\t\tyes   \t|\t\toutput = operand - input. Useful for r = 1-r in particular\n|\tfft\t\t|\t\tno\t\t|\t\tapplies a fast fourier transform to the input, which is registered internally (on a per-listing basis) for use by related operators below. This is quite a rudementary implementation that works best on sustained sounds\n|\tifft\t|\t\tno\t\t|\t\toutput is an inverse fast fourier transform applied to the internal frequency domain representation\n|\tffrz\t|\t\tyes\t\t|\t\twhen operand is zero, freeze the process in `fft`\n|\tgafft\t|\t\tyes\t\t|\t\tgating in the frequency domain. All frequencies in magnitude below the given operand are zeroed when the operand is positive, frequencies above absolute value of operand are zeroed when it is negative\n|\tfftrnc\t|\t\tyes\t\t|\t\ta proportion of the frequency spectrum given by operand is zeroed, creating a brickwall filter. Positive operands create low-pass, negative operands create high-pass\n|\tshfft\t|\t\tyes\t\t|\t\tfrequency spectrum is rotated by amount given by operand\n|\trev\t\t|\t\tno\t\t|\t\treverse order of internal frequency representation\n|\tffzy\t|\t\tno\t\t|\t\trandomise phases of internal representation\n|\tffltr\t|\t\tyes\t\t|\t\tsmear multiple windows, suggest operand in range 2s to 50s\n|\tffaze\t|\t\tyes\t\t|\t\trotate phases by operand [-1. 1]\n|\tindex\t|\t\tyes\t\t|\t\taccess index of listing\n|\tlog\t    |\t\tno\t\t|\t\toutput is base-2 logarithm of input. Negative inputs are treated as if they are positive\n|   4lp     |       no      |       four concatenated all-pass filters with delays of between 4ms and 20ms, useful to create diffuse reverbs within a tape echo loop. This may be re-implemented as a function using `buff` ◊\n|\t       \t| \t\t       \t|\n|\tfma\t\t|\t\tyes  \t|\t\tfused multiply add, the result of the input multiplied by the operand is stored in a special register `fma` (not implemented yet) ◊  \n\n**List of commands (won't appear in listing, `rld` and `del` will remove any unlaunched input)**\n\n|  Command\t|Requires operand?| Notes                           |\n|-----------|---------------|-----------------------------------|\n|\t[\t\t|\t\tyes\t\t|  \t\tbegin function definition, operand is name                                 |\n|\t]\t\t|\t\tno \t\t|  \t\tend function definition. Listing input is cleared                          |\n|\t:\t\t|   \tyes\t\t|   \tperform mode command: exit, erase, play, pause, fon, foff, clear, verbose, mc |\n|\tfade\t|\t\tyes\t\t|\t\tchanges fade out time after exit. Default is 325e-3 (unit is seconds, maximum 130s)\n|\tdel\t\t|\t\tyes\t\t|\t\tdelete an entire compiled and running listing numbered by operand. Play will be resumed if paused. On deletion the `.temp/*.syt` file remains intact so the listing can be reloaded with `rld`. If you wish to delete all listings simply exit from Syntə and restart\n|\tmute \t|\t\tyes\t\t|\t\tmute  or un-mute listing at index given by operand. Muting won't affect sync operations sent by a listing\n|\tm\t \t|\t\tyes\t\t|\t\talias of `mute`\n|\tm+\t \t|\t\tyes\t\t|\t\tlike mute but simply adds to mute group, the whole group is launched (and reset) at once by a final invocation of `mute` or `m`\n|\tunmute \t|\t\tno\t\t|\t\tun-mute all muted listings\n|\tsolo\t|\t\tyes\t\t|\t\tsolo listing at index given by operand (all other listings are muted). Solo-ing the same listing twice will reinstate prior mutes, including if a previous solo state\n|\ts\t\t|\t\tyes\t\t|\t\talias of `solo`\n|\trelease\t|\t\tyes\t\t|\t\tset the release constant of the built in limiter. The limiter VCA envelope will decay by approximately 70dB in the operand time given in milliseconds. Default is 1s. Times of less than ~200ms may result in audible distortion or pumping. Times greater than ~2s will have a slow response to a decrease in level. The limiter has absolute peak detection (non-interpolated) and the attack (onset) is instantaneous. The decay curve is not strictly exponential as it has a slow onset to avoid distortion. Any listings that are much louder than the others will bring down the volume of all listings.  \n|\t.mute \t|\t\tyes\t\t|\t\tequivalent to `mute` except will insert 'out dac' to launch listing. Play will be resumed if paused\n|\t.del \t|\t\tyes\t\t|\t\tequivalent to `del` except will insert 'out dac' to launch listing. Used in effect to replace a listing, play will be resumed if paused\n|\t.solo \t|\t\tyes\t\t|\t\tequivalent to `solo` except will insert 'out dac' to launch listing. Play will be resumed if paused\n|\terase \t|\t\tyes\t\t|\t\terase preceding number of lines given by operand. For erase all use `: erase`. \n|\te\t \t|\t\tyes\t\t|\t\talias of `erase`\n|\trld \t|\t\tyes\t\t|\t\treload edited listing, file in `.temp/` is not updated. if index not extant, will append to listings, but won't overwrite that particular `.temp/` file\n|\tr \t\t|\t\tyes\t\t|\t\talias of `rld`\n|\tdo \t\t|\t\tyes\t\t|\t\trepeat next operation or function n times, where n is given by the operand. Define a function for this purpose if needs be. any instance of the string \"{i}\" will be replaced by index of do loop number i.e. 0 to 9, for `do 9`. Alternatively, \"{i+1}\" will produce 1 to 10 in that instance. Multiple listings can be reloaded with eg. `do 3, r {i}`\n\n**List of built-in functions**\n\n|  Function\t|Requires operand?| Notes                           |\n|-----------|---------------|-----------------------------------|\n|\tflip\t|\t\tno\t\t|\t\tturn a value between [0, 1] 'upside down', the input is flipped around y=½. Not suitable for negative values |\n|\ttri\t\t|\t\tno\t\t|\t\tshape a value in range [0, 1] from saw/ramp to triangle. (mul 2, + -1, abs)\n|\tosc\t\t|\t\tno\t\t|\t\tramp wave, (phase accumulator). Output in range [0,1]. Has DC offset of ½\n|\tsaw\t\t|\t\tno\t\t|\t\tsaw wave, descending ramp. Output in range ±1\n|\tmix\t\t|\t\tyes\t\t|\t\toutput adjusted level to soundcard and end listing\n|\ts/h\t\t|\t\tyes\t\t|\t\tsamples and holds input when operand moves greater than zero from less than or equal to zero. Use ramp or square to supply operand. See 'Sample and hold melody' example above. Feed a `pulse` to operand of `lpf` for track and hold\n|\tdist\t|\t\tyes\t\t|\t\tdistortion, operand controls amount\n|\tsino\t|\t\tno\t\t|\t\tsine wave oscillator\n|\tlpf\t\t|\t\tyes\t\t|\t\t6dB per octave low-pass filter. Operand is cutoff frequency in Hertz. Cascade (repeat) for steeper cutoff\n|\theat\t|\t\tyes\t\t|\t\t'bulb-element' emulator (untested) ◊  \n|\tcv2a\t|\t\tno\t\t|\t\tconvert range [0, 1] to [-1, 1]\n|\ttest\t|\t\tyes\t\t|\t\toutput a sine test tone at the frequency of the given operand. Output at full scale, so may be much louder than other listings and engage the limiter\n|\tdecay\t|\t\tyes\t\t|\t\twill decay away to nothing from 1. 0.9997 is approx 20s, lower is quicker decay. Resets when input goes from 0 to 1. Using `down` and `exp` usually easier\n|\thalf\t|\t\tyes\t\t|\t\tlike `decay` but accepts an operand in seconds that defines the 'half-life' of the decay. Input will override decay.\n|\tonce\t|\t\tno\t\t|\t\tlike `osc` but only completes one cycle and output remains at 1\n|\tpulse\t|\t\tyes\t\t|\t\tpulse generator with duty cycle (pulse width) set by operand. Output is between 0 and 1, follow by `cv2a` for audio out. `pulse 0` will give a one sample pulse, any operand greater than or equal to 1 will be silent, i.e. output continuous zero. `pulse 0.5` is a square wave like `sq`\n|\tramp\t|\t\tno\t\t|\t\tlike `osc` but with an output suitable for audio, i.e. spans -1 to 1\n|\tposc\t|\t\tyes\t\t|\t\tlike `osc` but will retrigger on a sync pulse. Operand sets phase offset. Can also use `out ^z` to control the phase independently of sync.\n|\tslew\t|\t\tyes\t\t|\t\tswings to the input at a rate given by operand. Intended for pulses/square waves.  Maximum slew rate is 1% of the sample rate, typically this would be less than 500hz\n|\tT2\t\t|\t\tno\t\t|\t\timplements Chebyshev polynomial of the first kind. In plain english this means it will double the frequency of anything passed through it\n|\tzx\t\t|\t\tno\t\t|\t\tdetects negative-going zero-crossing of input. A preceding `ramp` will generate a single pulse of 1 at the end of its cycle.\n|\tlmap\t|\t\tyes\t\t|\t\timplements the Logistic Map, modified to constrain the output to range [0,1] using `mod` (to prevent divergence at high values of r). Iterates on zero-crossing of the input. Operand is the r value, suggested between 3 and 4. Precede with `ramp` and follow with `cv2a` for audio output\n|\teuclid\t|\t\t3\t\t|\t\toutputs euclidean rhythms at the frequency given by input as a series of pulses. Eg. output for (3,8) = \"X..X..X.\" the X will be 1 and the rests 0\n|\texp\t\t|\t\tyes\t\t|\t\tconverts linear ramps on interval [0,1] to exponential. Operand is the number of times one is halved for an input of zero, eg. three would be ½ x ½ x ½ = ⅛, the greater the number the steeper the curve. Typically useful to shape a descending ramp. Negative operands will double instead of halve\n|\tdial\t|\t\tno\t\t|\t\tplays uk telephone ringing tone\n|\tdirac\t|\t\tno\t\t|\t\toutputs a single sample pulse when input goes from 0 to 1. Will trigger on first run of listing if input is 1\n|\trange\t|\t\t2\t\t|\t\tspreads input from 0 to ±1 across a range of values from the first operand to the second. Eg. `range 220hz,440hz`. If the second operand is smaller the range will be negative. Operands should be in order of slow to fast, eg. 2s,1s\n|\tbd909\t|\t\t2\t\t|\t\tunfinished '909' kick drum. first operand is decay and second is pitch. ◊  \n|\tdown\t|\t\tyes\t\t|\t\tslews downwards for decreasing signals, jumps immediately to an increasing or static (unchanging) signal value. Use with a narrow pulse to make a linear decay envelope. Descends at rate given by operand\n|\techo\t|\t\t2\t\t|\t\trepeated echo of input using `buff` internally. First operand is repeat interval (time), second operand is loop/feedback gain, \u003e1 is infinite repeats (may distort), 0 is no repeats and no output. Use in conjunction with `from` or mix in with original input\n|\tstep\t|\t\tyes\t\t|\t\tgenerates a rising staircase of values with the operand number of steps within input time interval, eg `120bpm` or `2hz`. Output is between [0,1]. This implementation is not precise due to overflows (low frequency aliasing). Uses `s/h` internally. For precision use `osc` or `posc p` followed by `8bit n`, where p is the phase offset from sync and n is the equivalent of the `step` operand\n|\ttempo\t|\t\tyes\t\t|\t\toperand sets the tempo across all listings, subsequent invocations will set tempo for subsequent listings\n|\tgrid\t|\t\tno\t\t|\t\tgenerates a square wave at frequency of input and sends out to grid, accessible across all listings in ascending order like tempo. The grid signal can be used to gate audio using `mul`. Euclidean rhythms can be generated by `s/h`-ing other gate signals at different frequencies. Contains `\u003esync`\n|\tcount\t|\t\tyes\t\t|\t\tgenerates a rising staircase of values from 1 up to and including operand. Use a pulse or square wave [0,1] as input. Uses `dirac` to detect edge transitions internally. Can be used with `in \u003ctempo\u003e, osc, lt 0.5, count n` as a more precise equivalent to `step`\n|\thpf\t\t|\t\tyes\t\t|\t\t6dB per octave high-pass filter. Operand is cutoff frequency in Hertz\n|\ttape\t|\t\tyes\t\t|\t\trecord and playback from a rotating buffer, analogous to a tape loop. Operand is the offset in seconds/milliseconds (use types). Contains a high-pass filter internally\n|\talp\t\t|\t\t2\t\t|\t\tfirst-order all-pass delay line using `buff`. First operand is delay time, second operand is damping coefficient [0,1]\n|\tpink\t|\t\tno\t\t|\t\tapproximation of pinkening filter, low pass at -3db per octave\n|\tplay\t|\t\tyes\t\t|\t\tplays wav given by operand once when input goes from 0 to 1\n|\tsqr\t\t|\t\tno\t\t|\t\tsquare wave at audio levels, output is in range [-1,1]\n|\tsq\t\t|\t\tno\t\t|\t\tsquare wave, equivalent to `pulse 0.5`, output is in range [0,1], contains `\u003csync`\n|\txvr\t\t|\t\tno\t\t|\t\temulates class-B crossover distortion\n|\tsclp\t|\t\tno\t\t|\t\tsoft clipping, harsher than tanh\n|\tevery\t|\t\tyes\t\t|\t\tfor a pulse (or square) input [0,1], outputs a pulse ending at second rising edge of input every n input pulses, where n is the operand. Uses `count` internally\n|\tintfr\t|\t\tyes\t\t|\t\tnon-linear feedback leads to radio-interference sounding patterns\n|\tfractal\t|\t\tyes\t\t|\t\tfractal inspired non-linear feedback mangles input in interesting ways\n|\tcatch\t|\t\tno\t\t|\t\toutput is zero until first sync pulse received, input is passed through to output thereafter. Use before last operation of a listing containing `posc` for a smooth launch\n|\tsmooth\t|\t\tno\t\t|\t\talias of `lpf 150hz`, use to smoothen vca signals or other below audio rate CV's\n|\tCB\t\t|\t\tyes\t\t|\t\tan 808-like cowbell, triggered like `dirac`. Operand multiplies pitch\n|\t.grid\t|\t\tno\t\t|\t\tan experimental alternative to `grid`, will terminate listing. Not synced\n|\tfor\t\t|\t\tyes\t\t|\t\tinput sets frequency of pulse which stays high for time interval given by operand, output is [0, 1]\n|\t/b\t\t|\t\t2\t\t|\t\tcreates a rising ramp in sync with a ramp sent to `sync` signal\n|\tdef\t\t|\t\t2\t\t|\t\tsends tempo and sync to other listings, first argument is tempo, second is number of beats which the sync wave spans. Launches listing\n|\tdef_\t|\t\t2\t\t|\t\tlike `def` but can be followed by other operators (doesn't launch)\n|\tnoise\t|\t\tno\t\t|\t\toutput 'white' noise, input controls volume\n|           |               |\n\n**List of pre-defined constants**\t\n\n|  Name\t|\tDescription\t\t|\n|-----------|---------------|\n|\tln2\t\t|\t\tnatural logarithm of 2    \t|  \n|   ln3\t\t|       \"\t\t\"\t\t\t 3\t\t|\n|\tln5     |       \" \t\t\"\t\t\t 5\t\t|  \n|\tE\t\t|\t\tthe mathematical constant e\t|  \n|\tPi\t\t|\t\tπ, ratio of diameter to circumference of an ideal circle |\n|\tPhi\t\t|\t\tφ, the golden ratio = (1+√5)/2 \t\t|  \n|\tinvSR\t|\t\t1 / SampleRate   \t\t\t|  \n|\tSR\t\t|\t\tSampleRate\t\t\t\t\t|  \n|\tEpsilon\t|\t\tEpsilon, smallest possible number within Syntə |\n|\twavR\t|\t\tFrequency for wav playback at SampleRate, 0.25Hz at 4s sample time. Will need to be adjusted for samples with a different rate\t|  \n|\tsemitone|\t\tThe twelfth root of 2, ratio of one semitone interval |  \n|\tTau\t\t|\t\tτ, = 2π\t\t\t\t\t\t|  \n|\tln7\t\t|\t\tnatural logarithm of 7\t\t|  \n|\tnull\t|\t\t0\t\t\t\t\t\t\t|  \n|\tfifth\t|\t\tequal temperament = 2^(7/12) ≈ 1.5 (2:3)\t|  \n|\tthird\t|\t\tmajor, equal temperament = 2^(1/3) ≈ 1.25 (4:5)\t|  \n|\tseventh\t|\t\tmajor, equal temperament = 2^(11/12) ≈ 1.875 (8:15)\t|  \n|\t\t\t|\t\t\t\t\t\t\t\t\t|\n**List of reserved signals**\n|\tdac\t\t|\t\tsignal represents output to soundcard. For use as `out dac` only\t|\n|\ttempo\t|\t\tsignal is daisy chained between listings, can be set with `out`. Will be zero until set by an `out` or `.out`, value will persist if this is deleted |\n|\tpitch\t|\t\tacts the same as tempo\t|\n|\tmousex\t|\t\tvalue of mousepad X-coordinate |\n|\tmousey\t|\t\tvalue of mousepad Y-coordinate |\n|\tbutt1\t|\t\tvalue of left mouse button, 0 or 1\t|\n|\tbutt2\t|\t\tvalue of centre mouse button, 0 or 1\t|\n|\tbutt3\t|\t\tvalue of right mouse button, 0 or 1\t|\n|\tgrid\t|\t\tacts the same as tempo and pitch |\n\n**List of modes** (preceded by `:` operator)\n\n|  mode\t| Description                           |\n|-----------|---------------|\n| exit\t\t| shutdown Syntə\n| q\t\t\t| alias of `exit`\n| erase\t\t| erase entire listing input \n| e\t\t\t| alias of `erase`\n| pause\t\t| pause playback\n| play\t\t| resume playback\n| clear\t\t| clear info message display\n| verbose\t| show verbose listings in listing display, type again to toggle off\n| mc\t\t| switch mouse curve to linear (default is exponential). Toggles\n| stats\t\t| display Go's automatic memory management pause times in info display\n\n\nThe notation [a,b] is a closed interval, which means the numbers between a and b, including a and b.\n\nThe input syntax is in EBNF:  \n\t`operator \" \" [ [\",\"] operand [\",\"] \" \" ]`  \nAn operand can be a name or a number where:  \n\t`name = letter { letter | digit }`  \n\t`number = float [ ( \"/\" | \"\\*\" ) float ] [type`]  \nA letter is defined as any UTF-8 character excluding `+ - . 0 1 2 3 4 5 6 7 8 9`  \nA float matches the floating point literal in the Go language specification.  \nA type can be one of the following tokens:  \n\t`\"hz\", \"khz\", \"m\", \"s\", \"ms\", \"bpm\", \"!\", or \"db\"`    \nLists of operations may be composed into functions with multiple arguments.  \nThe function syntax is:  \n\t`function [ \" \" operand [ \",\" operand ] [ \",\" operand ] ]` .  \n\n---\n\n\u003cbr\u003e\n\u003ca name=\"det\"\u003e\u003c/a\u003e\n\n## Exposition  \nAlthough theoretically possible, Syntə is not primarily designed for making 'normal' music. A suggested use is the composition of waves, frequencies, shapes and combinations thereof to express a feeling or to dance to.  \nThe ideal aspect of Syntə is using the full power of a modern computer to produce musical structures that would otherwise be difficult to materialise. The simple building blocks help gain insight into the workings and provide almost orthogonal flexibility. (If something is orthogonal it means the smallest number of parts to realise the full possibilities of a concept space.)  \nSyntə enables detailed specification of sounds because it is built from small atomic operations. This gives a lot of freedom, which in turn requires some learning and practice. If you are new to synthesis you will need to learn that to, the program itself won't teach you. However, in the opinion of the author the concepts and maths of audio are a delight to uncover and play with. Most of the time simple arithmetic is all that is required for a deeper understanding. Take small steps and be surprised at what you achieve in time.  \nThe language is intended to expand and supplement the existing live-coding space to offer other possibilities and benefit the ecosystem as a whole.  \n\nListings are asynchronous and will start immediately on submission to the sound engine. A `\u003esync` operation can be used to synchronise listings using `posc`, with any offset. \n\n\u003ca name=\"sp\"\u003e\u003c/a\u003e\n## Sample Playback ◊  \nAny wav files placed in a folder named `wavs` will be loaded on startup. They need to be either 16, 24 or 32bit resolution and either stereo or mono PCM format files. You will need to adjust the frequency of playback for wavs with non-standard sample rates. The nominal playback frequency is given by the pre-defined constant `wavR` which you can use for normal playback like so:  \n\u003e\n\tin wavR  \n\tosc  \n\twav [name of wav file, indicated above listings]  \n\tout dac  \n\nIn the necklace above `in` sets the frequency of playback which is passed to osc to generate a rising ramp wave at that frequency. This 'scans' through the sample using the wav operator. Another way to look at it is that the output of osc, which repeats every 4 seconds, is 'shaped' into a sample waveform by `wav`. Any number between 0 and 1 will play the corresponding value of the sample at that point. Eg. 0.1 will play the sample at 400ms in. A continuous stream of values from `osc` will play the entire wav file. A decreasing series of numbers produced by, for example, `osc, flip` will play the sample backwards. `flip` turns the values of osc upside-down so they count down instead of up.  \nDifferent frequencies fed to `osc` will change the speed of playback and adding a fixed number will offset the starting point of playback. So  \n\u003e\n\tin wavR  \n\tosc  \n\t+ 0.5  \n\twav [name]  \n\tout dac  \n\nwill playback starting halfway through the sample. You don't need to worry if the input value exceeds 1 as it will automatically wrap around so eg. 2.37 will become 0.37 and remain in range. As the default wav length is 4 seconds, 1 second of the wav corresponds to input of 0.25, 2s to 0.5 etc.   Different rules apply for samples shorter than 4s. ◊  \nBy increasing the frequency and decreasing the amplitude of osc, a shorter section of the wav will be played.  \n\nwavR is a pre-defined constant which gives the playback speed for a sample recorded at the same rate as the internal sample rate, which is typically 48kHz. To adjust to playback speed for samples recorded at a different rate simply `mul 44100/48000` for example, where the desired rate is 44.1kHz. This could be put more simply as `mul 441/480`, which is equivalent. To show this in a working necklace for clarity:\n\u003e\n\tin wavR\n\tmul 441/480\n\tosc\n\twav [name]\n\tout dac\n\n\nBy design only the first 4 seconds of any wav file will be loaded. Two reasons for this are fast-loading times and to encourage creativity. You can manually edit any wav file in a free program such as Audacity to ensure the part you want to play is within the first 4 seconds, ideally starting at the beginning of the sample. Samples less then 4 seconds long are fine.\n\nLater on, the intention is to provide more flexibility in synchronising other necklaces to wav files using `l.wavname` signals. This has been partially implemented and would provide the possibility to sync to exact loop length samples. Likewise, you can use `r.wavname` in place of wavR. ◊  \n\n\u003ca name=\"tl\"\u003e\u003c/a\u003e\n## Tape loop ◊  \nEach listing has a tape loop available which is accessed by the `buff` operator. The tape loop is a rolling buffer of 1 second in length. The operand given sets the delay time of the initial tap. The loop can be additionally accessed by the tap operator, which will sum the new tap to its input. Multiple `tap` operators can be used. The use of multiple `buff` operators is undefined. Bear in mind that for modulating tap times (eg. for chorusing/detuning) only a small amount is required, and as time is inversely proportional to frequency this leads to large modulation times. For example `in 3hz, osc, sine, mul 30s, + 100ms, out t, ... buff t ...` An easier formulation is `in 3hz, osc, sine, mul 0.01, + 1, mul 100ms, out t, ... buff t ...`  \n\n\u003ca name=\"ao\"\u003e\u003c/a\u003e\n## Arithmetic operations\nAn operand may be added in a listing of the form a/b or a\\*b where a and b are valid numbers and the result is division and multiplication respectively. For example: typing  \n\u003e\n\tin 2/3  \nwill result in  \n\u003e\n\tin 0.666666666...  \nbeing added to the listing \n\n\u003ca name=\"ts\"\u003e\u003c/a\u003e\n## Type system\nThis is a fancy term for inputting numerical values with a unit of measurement. If you tell someone a duration you might say: \"it will take three hours\", you don't just say \"it will take three\". In a similar way Syntə expects to be told what the number you have input means. A number can be a frequency expressed in Hertz, a bpm (beats per minute), a time in seconds or milliseconds, or a decibel level (negative numbers reduce signal level, positive increases). For example:\n\n\t440hz   \u003c= this is the approximate frequency of the note A\n\n\t135bpm  \u003c= a typical house music tempo\n\n\t10s     \u003c= ten seconds, equivalent to 0.1hz\n\n\t50ms    \u003c= 50 milliseconds, equivalent to 20hz - the lowest audible frequency\n\n\t6db     \u003c= double the magnitude (by multiplying the signal)\n\t-6db    \u003c= halve the magnitude (by multiplying the signal)\n\nInternally all these numbers are converted to a unitless number within Syntə which is typically between zero and one, except in the case of 6db which is 2, 12db is 4 etc. The calculation to convert frequencies is:  \n\tinput / sample rate  \nAnd for seconds is:  \n\t1 / ( input \\* sample rate )  \n\nThe types available are:\n\thz khz, m, s, ms, bpm, db\nCorresponding to: Hertz, Kilohertz, minutes, seconds, milliseconds, beats per minute, and decibels\n\nIn future this type system may be developed further to require a specific type for input to each operator, which will be converted on-the-fly. This will also enable the possibility of reducing the sample rate under heavy load, which has not been needed so far.  \n\n\u003ca name=\"sigs\"\u003e\u003c/a\u003e\n## Signals\nSignals are the way of passing values around outside of the main flow through the necklace. Signals which are named and not just numbers can be referred to as registers, because they *register* a value. Usually the initial value of a named signal is 0. If you want it to begin as 1, add ' to the name. So `a` becomes `'a`. Likewise you can use the double quotation mark \" to have a default value of one half. If you want to be able to overwrite the value of a signal with `out` (more than once in a necklace), which is not normally possible, you can add ^ to the name. So `a` becomes `^a`. You can use both of these special symbols with a single signal, but the circumflex ^ must come first or it will be ignored.\n\n\u003ca name=\"CV\"\u003e\u003c/a\u003e\n## CV and audio signal ranges\nVarying numbers intended for output to the soundcard usually span the range [-1,+1]. CVs, or control voltages, which are used to control other parts of the signal chain and not produce sound directly typically span the range [0,1]. For instance the output of `ramp`, `saw` and `sine` which are intended to produce frequencies at audible rates (20 - 20,000Hz) all go between ±1, whereas `osc` which can be used to control a vca or the pitch of another oscillator spans between zero and 1. To make `osc` suitable for direct audio output you can use the cv2a function, which is exactly what `ramp` does. CV signals are generally slower and more rounded than audio signals. The `flip` function can be used to turn a CV upside-down, use `mul -1` to do the same for an audio signal (essentially what `saw` does).  \n\n\u003ca name=\"ch\"\u003e\u003c/a\u003e\n## Channels  \nSyntə produces the same audio on two channels (Left and Right) by default. Panning of a specific listing can be adjusted or modulated using the `pan` operator. The signal sent via `pan` is fed directly without any filtering - so smooth inputs are recommended. If in doubt, precede `pan` by `lpf 10hz`.  \nFor those interested, the panning is facilitated by a mid-sides configuration internally. Each pan signal is passed though the limiter vca (the part that turns the sound down if too loud) but not through the limiter detection (the part that decides if the audio is too loud), thus the limiter may modulate the stereo width, but the stereo image should remain stable. As noted above, in the event you require full mono-compatibility it is best to avoid modulating the pan of any listing; however, static pans (eg. `in 1/2, pan 0`)should be ok.  \n\n\u003ca name=\"syn\"\u003e\u003c/a\u003e\n## Synchronisation    \nBy default (and by design) when a listing is sent to the sound engine it starts immediately. The synchronisation operators `\u003esync` and `\u003csync` can be used to co-ordinate listings to play in time with one another. First, for a rhythmic element use the phase synchronised oscillator `posc` instead of osc. This contains a `\u003csync` operation which will reset the waveform when it receives a sync pulse. The `posc` operator requires a number between 0 and 1 to offset the phase, you can use 0 to start with and experiment later. For reference 0.5 would result in a phase shift of 180°, 1 would be 360° etc. Phase will only be set once a sync pulse is received.  \nTo send a sync pulse you can use `\u003esync` to synchronise all listings containing a `posc`. For `\u003esync` you can either simply:\n\u003e\n\t.\u003esync\n\nwhich will send one pulse. The `.` allows `.\u003esync` to end a listing and send it to the sound engine. The listings containing posc will remain in sync, even if you then delete this listing. Or, for periodic syncing you can:\n\u003e\n\tin 120bpm\n\tramp\n\t.\u003esync\n\nwhich will send pulses at the frequency given, in this case 120bpm. `osc, gt 0.5` can be also be used in place of `ramp`, in general any signal which transitions to zero or less than zero (from greater than zero) at the desired sync point will work. `sq` begins at 1, so will trigger sync halfway through its cycle.  \nMuting a sync listing will have no effect on the synchronisation, as it is send via a separate channel.  \nA listing can be synced on launch by adding \u003esync at the top.  \n\nIf you wish to launch a listing that only starts playing when the next `\u003csync` is received, use the `catch` function prior to the last operation, eg. `catch, mix`.  \n\nSync pulses transmitted will be indicated by a yellow dot at the top of the info display.  \n\nThe synchronisation is somewhat rudimentary, a world away from DAW/midi sequencers, yet it has been designed to be raw and flexible in keeping with the Syntə philosophy. It also allows for a modicum of 'musicianship' as it is possible to submit listings in time with one another by hand (without sync) if you are that way inclined. Of course this is live coding which only intersects with music in general :)\n\nUPDATE:\nA new synchronisation paradigm has been introduced for smoother DAW-like capabilities where required. There is a new built-in signal `sync` that can be used to send a varying waveform such as a ramp from `osc`. This can be received using `/b` which is similar to `posc`. `/b` takes two arguments - the first is the number of cycles in a given `sync` cycle, and the second is the phase offset of each. The output of `/b` is a ramp like `osc` which can be further shaped using eg. `flip, exp 5` or `trn 4`. The `b` in `/b` stands for bars or beats, the slash echoes a rising ramp waveform passed to `sync`. Synchronise listings using for example: `in 135bpm, / 8, osc, .out sync` and then something like `/b 8,0, ...` - where 8 is the number of beats in 2 bars of 4/4 time. The function `def` can be used instead to specify tempo and number of beats that the sync loop will span. ◊\n\n\u003ca name=\"sl\"\u003e\u003c/a\u003e\n## Setting levels\n\nThe `level` operator is used to adjust the audio level of a running listing, like so: `in 0.5 level 2` which would set listing two to half the available level, which is -6dB. This level-setting listing may be deleted straightaway and the level will persist once set. Although intended for automation of listings' level, you may modulate the level at rates up to 1200Hz. This is an arbitrary limit set to reduce clicks produced by immediate large changes in volume, while still allowing frequency modulation. You need to use `.level` to end a necklace.\n\n\u003ca name=\"af\"\u003e\u003c/a\u003e\n## Adding functions\nIf you find yourself reusing the same chunk of code multiple times, it is possible to define a named function which will instantiate that chunk of code. To begin, type `[` followed by the new name. Then type the listing as normal and at the end type `]` (no operand) which will complete the function add, the listing will then be restarted blank. The function will be saved for future use. You can delete functions by removing them from the `functions.json` file.  \nYou may overwrite functions by typing in the same name.  \nN.B. No signals are exported from inside functions except `tempo`, `pitch, `sync` and `grid`.  \nThe ability to make functions like this makes the language *extensible*, which means you are able to extend the language beyond what is written in this document. One of the project aims is to build up a library of abstractions in this way to make performance easier for beginners. However there is a limit to this, as just typing 'music' and stopping there would be quite boring!  \nAn *abstraction* means wrapping up a bit of code into something simple to make it easier to use, for example the term 'global apartheid' is an abstraction of a system and history that involves many many processes, interconnections, organisations, trade-misinvoicing etc.\n\n\u003ca name=\"il\"\u003e\u003c/a\u003e\n## info.go and listing.go\n`info.go` is intended to run alongside Syntə to display useful information and error messages. The layout is as follows:\n```\nSyntə info *press enter to quit*                0s      \u003c-- elapsed running time in seconds. Also, a yellow dot indicates a sync event\n╭───────────────────────────────────────────────────╮\n\n                                    Load: 0.00          \u003c-- If the sound engine is overloaded, the sound quality will degrade\n\n\n\n\n\n                                                        \u003c-- info and error messages will appear here\n\n\n\n\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(the top line of the audio meter will flicker red if clipping occurs internally)\n        0.00    |||||||             |                   \u003c-- peak audio meter, approx 50dB of range, will display 'GR' if limiting takes place on the output.\n      Mouse-X: 0\t\t\t\tMouse-Y: 0              \u003c-- value of mouse X and Y\n╰───────────────────────────────────────────────────╯\n```\n\nInfo display won't display the same message sent more than once in succession.  \n`listing.go` displays the currently running necklaces. Any that are muted will show in italics. In verbose mode the functions within a listing are 'unrolled', that is to say they are shown in terms of their atomic operations.\n\n\u003ca name=\"ht\"\u003e\u003c/a\u003e\n## Hot tips\n\n+ use `slew 150hz` or `lpf 150hz` to smoothen a signal used for modulating volume with `mul`\n+ trim samples of music to be an exact number of bars (look for repetition in the waveform of around ~2 seconds)\n+ use the \"!\" type to use a number outside of the expected range if you need to. This is not a factorial operation\n+ had a moment of inspiration and can't remember what you did? All listings accepted by the sound engine are saved by timestamp to the recordings folder in json format\n+ pipe the output of `functions.go` through `less` using the `-r` flag, like this: `go run functions.go | less -r`. You can then search the contents using `/`, refer to `man less` \n+ want to fade in a listing? Use `in 10s, once, level n, in 0, .mute n` where n is the index of the particular listing (that has previously been muted)\n+ want a long fade out on exit? Type `fade 30s` before you type `: exit`\n+ want to purge the .temp folder of old listings? Type `rm -v .temp/*.syt` from inside the project directory\n+ reset the phase of the `sino` function by adding `push, dirac, flip, out ^'z, pop` after the pulse you want to sync to\n+ unsure which value/number to use? type `mousex` or `mousey` and experiment. Once you have settled on something that you can edit the relevant file in the `.temp/` directory and replace the mouse value with a number directly\n+ other tips tba... ◊  \n\n\u003ca name=\"ps\"\u003e\u003c/a\u003e\n## Performing with Syntə\nTo prepare the audio system:\n1. Set up the equipment and verify sound from Syntə is reaching the speakers using `in 440hz, osc, sine, mul 0.1, out dac`\n2. Turn the system volume down to zero\n3. Type `test 2khz`\n4. Increase volume until an acceptable level\n\nYou will probably need to go above this level for performance once you have an audience in the room and are playing full range sounds, but this gives a good starting point that you probably don't want to go too far over. Please ensure the audience has access to hearing protection if the system is capable of more than 85dBSPL.\nTo specifically test the bass level and evenness try:\n\u003e\n\tin 10s\n\tosc\n\tmul 4\n\tbase 2\n\tmul 20hz\n\tsino\n\tout dac\n\nIf the bass level fluctuates a lot at different frequencies and at different listing positions you should consider some using some bass trapping. This is because sound reflections between the walls will interfere and cancel out at low frequencies.\n\n\u003ca name=\"ed\"\u003e\u003c/a\u003e\n## Editing running listings\nAll currently running listings can be found in the `.temp/` folder in the root directory (main project folder). The name of the file will be the index (a non-negative integer) with the file extension .syt, eg. `0.syt` , this file can be opened in any text editor. Once you have saved your edits the listing will be reloaded automatically on saving. It is best to do this with nothing typed in main Syntə input, as reload will be appended to current input and partially entered operations will cause confusion for the next line input once reload complete.  \nA TUI library or headless mode may replace this feature in future. No files are purged from `.temp/` on exit, so will remain indefinitely until overwritten one-by-one when each new listing is launched. ◊  \n\n\u003ca name=\"ex\"\u003e\u003c/a\u003e\n## Exported signals\nUp to 12 signals may be exported for input to other listings. Indicate this by capitalising the initial letter, eg. `out Env1`. This can then be used like any other signal, in the same manner as `tempo`, `pitch` and `grid`. These exported signals are daisy-chained in the same manner, so will propagate between listings in ascending order. This means that the signal will correspond to the preceding `out` in another listing.\n\n---\n\n\u003cbr\u003e\n\n## The Sound Engine\nAlthough it is not necessary to know how the sound engine works to perform or play with Syntə, it can be helpful to learn more about it so we'll give a brief outline here.  \nWhen a listing is send to the sound engine an internal copy is generated and added to the sequence of listings. The sound engine takes each listing in turn from 0 onwards and runs through it once to produce the value of the next sample, then it moves on to the next listing. Once it has computed all the listings the resulting samples are summed together and sent through the built-in limiter to ensure no loud surprises and the peak amplitude of the output is also sent to the info display. The resulting signal is converted to the correct format and sent to the soundcard in your computer, after which the whole process repeats.  \nThe terms 'listing' and 'necklace' are interchangeable. Necklace also illustrates the point that the listing is computed in a continuous loop.  \nAll values in the sound engine are represented by 64-bit floating point numbers which represent a nominal value within Syntə of between -1 and 1 inclusive. At the end of each cycle of the sound engine this is converted to a 32, 24 or 16 bit number to be sent to the soundcard, depending on the format it accepts. Within a listing a value can be anywhere in the range of the 64-bit float (approx ±1.8x10^308 with an precision of about 15 decimal places.) These numbers will be limited or clipped to ±1 before audio conversion.  \nEach listing has its own frequency dependent limiter to prevent obliteration of other listings under the limiting on the output, they are then added together. The result is then passed through a high-pass filter before the limiter. This is to remove any DC offsets, which means a consistent average signal other than 0, or another way to think of it is attenuating (reducing) frequencies below 4.6Hz. If my calculations are correct, any DC signal will fade below -33db after seven seconds. DC signals can still be passed between listings using `from`, `all` or Exported signals.  \nThe limiter reduces the level of audio above a peak value of 1 to avoid the possibility of clipping the main output, which would produce distortion. The detection algorithm of the limiter is progressively more sensitive to higher frequencies, it expects audio to have a spectrum approximately equivalent to 'pink noise'.  \nThe density distribution of pink noise is a good general approximation to expected frequency levels in audio (*Barrow, 1995*). The `mix` function also uses this as a guiding principle in setting a sensible level. Some adjustment may be required; however, the limiter will always kick in if internal levels are exceeded.   \nBecause of the frequency dependent nature of the limiter detection, gain reduction may occur before the info display shows a high VU level. This is normal and you can adjust listings via the `level` operator to prevent higher frequencies from dominating the playback, or more simply by adding eg. `mul -4dB` before `mix`.  \nBetween the limiter and the clipping stage before conversion, what is known as triangular dither is applied to the signal. This is a tiny amount of noise to mask rounding errors, but is probably overkill, especially at higher bitrates. Before the dither any envelopes associated with pausing or exiting are applied. These reduce the chances of pops or clicks.  \nThe whole main loop of the sound engine has a timer to produce the 'load' value that shows how much work it is doing to create each sample for the soundcard. See info display section above. If enough listings are added and the sound engine is unable to perform all calculations in time before the next sample is due, the sound quality and pitch accuracy will degrade. In future if type conversions are added back in as part of making the language strongly typed, the sample rate will be able to dynamically adjust to avoid overloading. The sound engine will also restart if a runtime or other error occurs and in this case will remove the previously added listing, as this is most likely to have caused the error. The listing will still be available in the `.temp/` directory to be amended and reloaded as desired.\n\n## Synthesis and levels  \n\nThe design of Syntə has from inception included sufficient control of sound levels as a core aim. The open possibilities of Syntə are deliberately constrained in two main ways. A limiter is built-in to the sound engine, which controls levels on a frequency dependent basis. Also, listings can use the `mix` function to set a reasonable level based on simple heuristics that follow a similar principle to the limiter. The upper limit of potential hearing damage is defined by the capabilities of your sound playback system - the amplifier(s) and speakers; however, we have applied our best efforts to ensure loud frequencies do not leave Syntə. More details in the Sound Engine section above.\n\n## A note on the Go code\n\nThe code in this suite of programs differs from typical industry standards in a few key respects. Each program is contained in one file to make it easy for a beginner to read through the whole thing. The code isn't very encapsulated, and global variables are used for convenience. `go modules` aren't used, as only dependencies are from standard library and can keep directory structure flat. No tests have been written for any of the functions ◊, however the programs themselves have been rigorously tested with user input. Telemetry from the sound engine is just shoved out without regard to whether it is properly received, sacrificing programmatic correctness for speed, which is a worthwhile tradeoff in this context (as used in telemetry library prometheus).  \nWhile there may be a few ways the code can be better structured, for now it has been thoroughly determined to perform the desired functions without runtime errors. The possibility of runtime errors in the sound engine generated by user input is handled by panic/recover to gracefully shutdown and restart without the preceding listing. That is not to say any errors won't be uncovered in future, this is software after all :)  \nPlease add a github issue for bug reports or feature requests.\n\n---\n\n\u003cbr\u003e\n\n### A note on licensing\nThe work in this file and all others in this repository is now licensed. See the licence.md file for details.  \n\n**TL;DR**  \n\n+ Running the software in person (not via a network) for the purposes of performance or education won't lead to any negative consequences.  \n\n+ Using, modifying, or distributing the software in binary or source code form for commercial purposes is not permitted.  \n\nThis semi-permissive licence has been chosen to reflect the fact that this implementation is a prototype only and has no commercial value.  \nSuggestions, including improvements to the code are welcome.  \nIf you would like to fork the code for more radical changes then we wholeheartedly suggest you instead write a unique live coding platform from scratch. The file is of an order of only three thousand lines of code after all, and the learning experience will be invaluable to you.   \nPlease get in touch if you have further questions.  \n\n### Influences and other live-coding environments\nThe term live-coding is generally taken to mean on-the-fly composition of algorithmically generated audio or graphical artefacts using software.  \nWe recommend exploring TidalCycles and Pure Data in particular. If you are more visual/graphical oriented there are live coding languages/environments for that space too.  \nMany influences and inspirations have been drawn upon either deliberately or subconsciously in the creation of Syntə. They include assembly language, Forth, RPN calculators, VIM, the live-coding languages mentioned above, modular synthesis, Musique Concrète, Go itself (the language Syntə is implemented in) and unix-like systems in general - primarily FreeBSD which was the first OS to host Syntə, both for development and execution.  \n\n### Future possibilities for Syntə  \nThe main focus of development is building up a library of functions which provide useful and intuitive abstractions to speed up and simplify performing.  \nIt would be great if translations of this document and the language itself become available in future, get in touch if you can help with this. A live distro with Syntə included could be useful for users of other operating systems to boot from. Another possibility for the code is integration with a terminal library such as tcell or bubbletea for a slicker UI. Future additions include providing for audio and MIDI input and use of other sound drivers than OSS/ALSA. A browser-based interface is another option, which would make the program extremely portable. This could be as simple as redirecting stdout to a local websocket server.\nYou may consider the current implementation of Syntə to be a prototype. At present most of the basic features have been taken care of, and as the language is tried out by different people, changes and adjustments that will tidy up and make performing easier may become apparent. The core aims of fun and accessibility won't change. \n\n### General principles of live coding performance  \nThese are, as the author understands it (opinions may differ):  \n\n+ Display your code to the audience  \n\n+ Prefer fresh code over copy-pasta  \n\n+ Improvisation and exploration are key  \n\n+ An accessible and welcoming space is essential  \n\n+ Share and mentor where possible  \n\n+ Mistakes and errors are embraced and honoured  \n \n\n**To do: (for this document)** ◊  \n\n\u003ehow to modulate pitch and volume, including ratios and exponents  \nfeedback and what it means  \nfiltering  \ndelay and reverb   \nmouse control  \ntempo and pitch  \neuclidian rhythms using `grid`  \nfractal synthesis (not implemented yet)  \nmute and solo  \n\n---\n\n[Back to top](#top)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyntelang%2Fsyntelang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsyntelang%2Fsyntelang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyntelang%2Fsyntelang/lists"}