Welcome to Gwion

gwion is a strongly timed programming language for making music.

It is strongly influenced by chuck, but adds a bunch of high-level features: templating, first-class functions and more.

It aims to be simple, small, fast, extendable and embeddable.

gwion was originally designed and created by Jérémie Astor. He is a musician, who made it to assist in his shows/compositions.

We are currently looking for contributions, you can learn how to make some here.

And now for the hello world

Here is the piece of code you're waiting for:

<<< "Hello, World!" >>>;

(Bag of) Features

Try me

There's a gwion repl in the wild. You can try the language there

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Overview

This is a basic tutorial that will lead you through the basics of Gwion.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

First Steps

This guide will help you install Gwion.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Installing gwion

Get the sources

The source is accessible on github.

Provided you have git installed, you can get it with:

git clone --recursive https://github.com/Gwion/Gwion

then change to the source directory

cd Gwion

At this point, you may want to configure the build. In this case, have a look at the configuration page.

Build the libraries and program

make

Install the package

make install

You may need root privilege to do this.

This is not strictly necessary, as you can run the program by typing ./gwion in the gwion directory. It is a good idea to install it, however, so that it can be run in any folder on the system.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Configuring Gwion

Gwion can be configured to better suit the user's needs. This is mainly done in two files: config.mk and util/config.mk.

config.mk

  • DEBUG_STACK ?= 0
    • Enables the debug stack, which prints some stack info, thus verifying whether a function is balanced.

util/config.mk

  • USE_DOUBLE ?= 0
    • Sets the size of float to double
  • USE_GETTEXT ?= 0
    • Enable internationalization (almost complete)
  • USE_DEBUG ?= 1
    • Enables debug features
  • USE_LTO ?= 0
    • Enables Link-Time Optimization
  • USE_COVERAGE ?= 0
    • Enables code coverage
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Gwion On Windows

Get the sources

The source is accessible on github.

Provided you have git installed, you can get it with:

git clone --recursive https://github.com/Gwion/Gwion

then change to the source directory

cd Gwion

Setting up

Make sure that you have the following programs installed, and that they are in your path :

  • touch
  • a C compiler, in this example we will use gcc

First, we need to define some enviromment variables

set CC=gcc
set BUILD_ON_WINDOWS=1

Next we need to create some directories

mkdir .d
cd util
mkdir .d
cd ../ast
mkdir .d
cd ..

now, look for something like ast/libprettyerr/libprettyerr.a:, and replace the relevant command with:

@+set CFLAGS_=${CFLAGS} && set CFLAGS=-I<your current dir>/util/libtermcolor/include && ${MAKE} -s -C ast/libprettyerr static && set CFLAGS=CFLAGS_

where <your current dir> is the absolute path to the current working directory

and finally run

make
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Declarations

Basics

Declaring a primitive or an object is quite straight forward:

var int i;
var Object o;
<<< i, " ", o >>>;

Declaring a reference

sometimes you just want an object to be instantiated later. This is done using the late keyword

late Object object_ref;

if(object_ref)
  <<< "We have an object: ", object_ref >>>;
else
  <<< "We have no object" >>>;

trying to access, print or pass an non instantiated object will perform NullPtrException

late Object object_ref;
<<< object_ref >>>;

Arrays

array as refs

var int array_ref[];
new int[2] :=> array_ref;
<<< array_ref >>>;
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Global Values

  • adc
  • blackhole
  • dac
  • pi
  • null
  • samp
  • ms
  • second
  • hour
  • me
  • this
  • _func_
  • _file_
  • _line_
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Keywords

  • fun

  • operator

  • return

  • goto

  • switch/case/default

  • if/else

  • break/continue

  • until/do/while/for/repeat

  • global/static

  • private/protect

  • const

  • new

  • spork

  • fork

  • typeof

  • typedef

  • funptr

  • class

    • dtor
    • extends
  • enum

  • union

  • auto

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Special Values

  • me
  • this
  • vararg
  • maybe
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Tests

test.sh requires valgrind there are two kinds of tests:

Gwion tests

those tests are just gwion (.gw) files, handling special comments:

  • #! [skip] (optionally followed by reason to skip)
  • #! [todo] (optionally followed by reason to delay testing)
  • #! [contains] followed by string to match
  • #! [excludes] followed by string not to match

Shell test

those tests are just bash (.sh) files.
they should start with this snippet

#!/bin/bash
# [test] #5
n=0
[ "$1" ] && n="$1"
[ "$n" -eq 0 ] && n=1
source tests/sh/common.sh
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Core Reference

compiler generated documentation

#!+ [builtin]

#!- one type to rule them all.
primitive Class;

#!- this type is infered.
primitive auto;

#!- a void type.
primitive void;

#!- integer type.
primitive int;

#!- character type.
primitive char extends int;

#!- float type.
primitive float;

#!- represent duration.
primitive dur;

#!- represent time.
primitive time;

#!- internal time for `now`.
primitive @now extends time;
specialid const now;

#!- internal predicate representation.
specialid const @predicate;
#!- internal base of all objects and structures.
primitive enum extends int;
primitive @Compound;
primitive Object extends @Compound;
specialid const this;
specialid const super;
primitive bool extends int;
const bool true;
const bool false;
operator bool ! (int);
operator @implicit (bool, float);
specialid const maybe;
operator bool @conditional (int);
operator bool @unconditional (int);
operator int + (int, int);
operator int - (int, int);
operator int * (int, int);
operator int / (int, int);
operator int  (int, int);
operator int > (int, int);
operator int >= (int, int);
operator int < (int, int);
operator int <= (int, int);
operator int >> (int, int);
operator int << (int, int);
operator int & (int, int);
operator int | (int, int);
operator int ^ (int, int);
operator bool && (int, int);
operator bool || (int, int);
operator bool == (int, int);
operator bool != (int, int);
operator int :=> (int, int);
operator int +=> (int, int);
operator int -=> (int, int);
operator int *=> (int, int);
operator int /=> (int, int);
operator int %=> (int, int);
operator int <<=> (int, int);
operator int >>=> (int, int);
operator int &=> (int, int);
operator int |=> (int, int);
operator int ^=> (int, int);
operator int - (int);
operator int ++ (int);
operator int -- (int);
operator int ~ (int);
operator int [:] ();
operator int int ++ ();
operator int int -- ();
primitive u8 1;
primitive u16 2;
primitive u32 4;
primitive u64 8;
operator bool @conditional (float);
operator bool @unconditional (float);
operator float + (float, float);
operator float - (float, float);
operator float * (float, float);
operator float / (float, float);
operator float @implicit (float, float);
operator float :=> (float, float);
operator float +=> (float, float);
operator float -=> (float, float);
operator float *=> (float, float);
operator float /=> (float, float);
operator bool && (float, float);
operator bool || (float, float);
operator bool == (float, float);
operator bool != (float, float);
operator bool > (float, float);
operator bool >= (float, float);
operator bool < (float, float);
operator bool <= (float, float);
operator float - (float);
operator dur :: (int, dur);
operator dur :: (float, dur);
operator bool ! (float);
operator int > (int, float);
operator int >= (int, float);
operator int < (int, float);
operator int <= (int, float);
operator float + (int, float);
operator float * (int, float);
operator float - (int, float);
operator float / (int, float);
operator float :=> (int, float);
operator float +=> (int, float);
operator float -=> (int, float);
operator float *=> (int, float);
operator float /=> (int, float);
operator float $ (int, float);
operator float @implicit (int, float);
operator bool && (int, float);
operator bool || (int, float);
operator bool == (int, float);
operator bool != (int, float);
operator float + (float, int);
operator float - (float, int);
operator float * (float, int);
operator float / (float, int);
operator float :=> (float, int);
operator float +=> (float, int);
operator float -=> (float, int);
operator float *=> (float, int);
operator float /=> (float, int);
operator float $ (float, int);
operator bool && (float, int);
operator bool || (float, int);
operator bool == (float, int);
operator bool != (float, int);
operator bool > (float, int);
operator bool >= (float, int);
operator bool < (float, int);
operator bool <= (float, int);
operator bool @conditional (dur);
operator bool @unconditional (dur);
operator dur :=> (dur, dur);
operator dur +=> (dur, dur);
operator dur -=> (dur, dur);
operator dur *=> (dur, dur);
operator dur /=> (dur, dur);
operator dur + (dur, dur);
operator dur - (dur, dur);
operator dur * (dur, dur);
operator float / (dur, dur);
operator dur / (dur, float);
operator dur *=> (float, dur);
operator dur /=> (float, dur);
operator bool == (dur, dur);
operator bool != (dur, dur);
operator bool > (dur, dur);
operator bool >= (dur, dur);
operator bool < (dur, dur);
operator bool <= (dur, dur);
operator bool @conditional (time);
operator bool @unconditional (time);
operator time :=> (time, time);
operator time + (time, dur);
operator time * (time, dur);
operator time / (time, dur);
operator dur - (time, time);
operator time *=> (float, time);
operator time /=> (float, time);
operator time :=> (dur, time);
operator time + (dur, time);
operator time => (dur, @now);
operator bool => (time, time);
operator bool > (time, time);
operator bool >= (time, time);
operator bool < (time, time);
operator bool <= (time, time);

#!- the base of all functions.
primitive function;

#!- the base of decayed operators.
primitive operator extends function;

#!- the base of function pointers.
class funptr extends Object {
    fun void @ctor();
    fun void default();
}
operator funptr class ();
operator => (@Any, function);
operator => (@Any, funptr);
operator :=> (function, funptr);
operator @implicit (function, funptr);
operator $ (function, funptr);
operator @implicit (operator, funptr);
operator $ (operator, funptr);
operator :=> (function, function);
operator function @partial ();
operator Class @partial ();
primitive @error;
operator :=> (Object, Object);
operator => (@Any, @Compound);
operator bool == (Object, Object);
operator bool != (Object, Object);
operator bool $ (Object, Object);
operator bool @unconditional (Object);
operator bool @conditional (Object);
operator bool ! (Object);
operator @Compound class ();
const float samplerate;
const float pi;
const dur d_zero;
const dur samp;
const dur ms;
const dur second;
const dur minute;
const dur hour;
const time t_zero;
primitive None;
specialid const None;
operator None :=> (None, None);
const int index;
fun bool is(int member);
operator auto new:[ T ](int size, int id, T value);
operator . (union, @Any);
union Option :[ A ] {
    None none;
    A val;
};
class Array:[ T ] extends Object {
    funptr static A map_t:[ A ](T elem);
    funptr static Option:[ A ] compactmap_t:[ A ](T elem);
    funptr static A fold_t:[ A ](T elem, A acc);
    funptr static bool filter_t(T elem);
    funptr static T new_t(int idx);
    fun bool remove(int index);
    fun bool insert(int index, T data);
    fun int size();
    fun int depth();
    fun int cap();
    fun T random();
    fun A[] map:[ A ](map_t:[ A ] data);
    fun A[] compactMap:[ A ](compactmap_t:[ A ] data);
    fun T[] filter(filter_t data);
    fun int count(filter_t data);
    fun A foldl:[ A ](fold_t:[ A ] data, A initial);
    fun A foldr:[ A ](fold_t:[ A ] data, A initial);
    operator auto new(new_t init);
}
operator :=> (Array, Array);
operator @implicit (Array, Array);
operator << (Array, @Any);
operator >> (@Any, Array);
operator $ (Array, Array);
operator int [:] (int, Array);
operator [] (int, Array);
operator Array void @each_init ();
operator Array int @each ();
operator Array @each_val ();
operator Array int @each_idx ();
operator Array class ();
operator @Any bool @array_init ();
class Event extends Object {
    fun void @ctor();
    fun void signal();
    fun void broadcast();
}
operator int => (Event, @now);
class UGen extends Object {
    fun void @ctor();
    fun UGen chan(int arg0);
    fun int op();
    fun int op(int arg0);
    fun float last();
}
operator UGen ~> (UGen, UGen);
operator UGen ~< (UGen, UGen);
operator UGen :~> (UGen, UGen);
operator UGen :~< (UGen, UGen);
operator UGen[] ~> (UGen[], UGen[]);
operator UGen[] ~< (UGen[], UGen[]);
operator UGen[] :~> (UGen[], UGen[]);
operator UGen[] :~< (UGen[], UGen[]);
operator UGen[] ~> (UGen, UGen[]);
operator UGen[] ~< (UGen, UGen[]);
operator UGen[] :~> (UGen, UGen[]);
operator UGen[] :~< (UGen, UGen[]);
operator UGen ~> (UGen[], UGen);
operator UGen ~< (UGen[], UGen);
operator UGen :~> (UGen[], UGen);
operator UGen :~< (UGen[], UGen);
const UGen blackhole;
const UGen dac;
const UGen adc;
operator spork (@Any);
operator fork (@Any);
operator new (@Any);

#!- Ref: take a reference from a variable.
#!- used just as the variable it reference.
#!- can only be used as argument.
#!- and cannot be returned.
struct Ref:[ A ] {
    #!- a pointer to the referenced variable.
}

#!- internal `Ref` type creation.
operator Ref class ();
class string extends Object {
    fun void @ctor();
    fun int size();
    fun string upper();
    fun string lower();
    fun string ltrim();
    fun string rtrim();
    fun string trim();
    fun string insert(int pos, string str);
    fun string replace(int pos, string str);
    fun string replace(int pos, int n, string str);
    fun int find(char c);
    fun int find(char c, int pos);
    fun int find(string str);
    fun int find(string str, int pos);
    fun int rfind(char c);
    fun int rfind(char c, int pos);
    fun int rfind(string str);
    fun int rfind(string str, int pos);
    fun void erase(int start, int length);
    fun void save(string path);
    fun static string load(string path);
    fun int atoi();
    fun int atoi2(&int offset);
    fun float atof();
}
operator [] (int, string);
operator bool == (string, string);
operator bool != (string, string);
operator string [:] (int, string);
specialid const __file__;
specialid const __func__;
specialid const __line__;
class Shred extends Object {
    const int cancel;
    fun void exit();
    fun bool running();
    fun bool done();
    fun int id();
    fun static Shred fromId(int xid);
    fun void yield();
    fun int args();
    fun string arg(int n);
    fun string name();
    fun string path();
    fun string dir();
    fun string code_name();
    fun string code_path();
    fun string code_dir();
    fun void set_cancel(bool n);
    fun void test_cancel();
    fun void lock();
    fun void unlock();
    fun float get_now();
    fun UGen get_blackhole();
}
specialid const me;
class Fork extends Shred {
    const int is_done;
    const Event ev;
    fun void join();
    fun void test_cancel();
}
class TypedFork:[ A ] extends Fork {
    const A retval;
}
class Gain extends UGen {
    fun void @ctor();
    fun float gain();
    fun float gain(float arg0);
}
class Impulse extends UGen {
    fun void @ctor();
    fun float next();
    fun float next(float arg0);
}
class FullRect extends UGen {
    fun void @ctor();
}
class HalfRect extends UGen {
    fun void @ctor();
}
class Step extends UGen {
    fun void @ctor();
    fun float next();
    fun float next(float arg0);
}
class ZeroX extends UGen {
    fun void @ctor();
}
class UsrUGen extends UGen {
    fun void @ctor();
    fun int default_tick();
}
operator UsrUGen ~=> (function, UsrUGen);

#!- allow member access.
operator . (@Compound, @Any);
operator . (function, @Any);

#!- Operators class types.
operator bool == (Class, Class);
operator bool != (Class, Class);
operator bool >= (Class, Class);
operator bool > (Class, Class);
operator bool <= (Class, Class);
operator bool < (Class, Class);

#!- Allow binary call to constructors.
operator => (@Any, Class);

#!- internal constructor operator.
operator call_type (@Any);

#!- allow static access.
operator . (Class, @Any);

#!- Deep Equality fallback
operator bool ?= (@Any, @Any);

#!- Deep Inequality fallback
operator bool <> (@Any, @Any);

#!- Deep Equality
operator bool ?= (@Compound, @Compound);

#!- Deep Inequality
operator bool <> (@Compound, @Compound);
class Dict:[ Key, Val ] extends Object {
    fun void @ctor();
    fun void remove(Key key);
}
operator Dict class ();
operator Dict int @each ();
operator Dict void @each_init ();
operator Dict @each_val ();
operator Dict @each_idx ();
fun int hash(int key);
fun int hash(Object key);
fun int hash(float key);
fun int hash(time key);
fun int hash(dur key);
fun int hash(string key);

#!- a type for *pretty print*.
primitive @Gack;

#!- @Gack implicit cast
operator @implicit (@Gack, @Any);
class Sift extends Shred {
}

#!- This operator expands too
#!- spork {
#!-   while(true) {
#!-     lhs.last() => rhs;
#!-     samp => now;
#!-   }
#!- }
operator Sift |> (UGen, function);
operator Sift |> (Sift, function);
operator Sift |> (UGen, funptr);
operator Sift |> (Sift, funptr);

#!- Definition of the basic locale
fun float BasicLocale(string str);
enum @hidden_enum {
    0 :=> @hidden_enum,
}
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Control Flow

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

For Loops

For loops in Gwion is pretty similar to classic C syntax

basic loops

for(var int i; i < 3; ++i)
   <<< i >>>;

It also works with a block of code.

for(var int i; i < 3; ++i) {
   i/2 :=> var float f1;
   i/2. :=> var float f2;
   <<< i, " " , f1, " ", f2 >>>;
}

Nested Loops

var int array[3][4];

for(var int i; i < 3; ++i) {
  for(var int j; j < 4; ++j) {
    <<< array[i][j] >>>;
  }
}

Auto Loops

Simple auto loop

var int array[2][3];
foreach(a: array) {
  <<< a >>>;
  foreach(b: a)
    <<< b >>>;
}

Auto Pointer loop

If you want to change it the value in the array, you need a pointer

var int array[2][3];
var int i;
foreach(a: array) {
  foreach(b: a)
    <<< ++i :=> b >>>;
}
foreach(a: array) {
  foreach(b: a)
    <<< b >>>;
}
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

the Repeat keyword

let start simple ;-)
The easiest way to do an action repeatidly in Gwion is, ... the repeat keyword!

Basic example

repeat(3)
   <<< "Hello, world!" >>>;

Block example

of course this also works with a block code.

repeat(3) {
   maybe ? "You" : "Me" :=> var string s;
   <<< "Hello, ", s, "!" >>>;
}
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

While Loops

while(true) {
  if(maybe)
    break;
  <<< "running..." >>>;
}

well this may output nothing... lets try

<<< maybe >>>;
do{
  if(maybe)
    break;
  <<< "running..." >>>;
} while(true);
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Extending

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Giving gwion a new driver

basics

in order to use GWION_CTL ...

concept

upd driver

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Writing a Gwion plugin

THIS IS OUTDATED. please look at the source code in src/lib/ instead

  • [getting started]

Getting started

use the script

headers

#include "vm.h"
#include "instr.h"
#include "import.h

Class

Define the type:

struct Type_ t_mytype = { "MyType", SZ_INT, &t_object};

every type extending t_object should have SZ_INT

Handling Constructors and Destructors

CTOR

CTOR(mytype_ctor) {
  /* constructor code here */
}

DTOR

DTOR(mytype_dtor) {
  /* destructor code here */
}

those macros provide two variables:

  • o: the M_Object for the (con/des)tructor
  • shred: the VM_Shred for the (con/des)tructor
CHECK_BB(import_class_begin(env, &t_mytpe, env->global_nspc, mytype_ctor, mytype_dtor))

variable

declare a m_int. coding convention require

  • a leading _o
  • a following type
m_int o_mytype_myvaroffset;

function

/* declare a member function */
MFUN(mytype_memberfunction) {
  /* code here */
}

SFUN(mtype_staticfunction) {
  /* code here */
}

operator

Import function

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Functions

a simple (commented example)

#! declare function 'test_function'
#! with return type int
#! taking an int as argument
fun int test_function(int arg) {
  #! return the argument + 2
  return arg + 2;
}

#! now call the function (and debug print the result)
<<< test_function(0) >>>;
#! or use alternate syntax
<<< 1 => test_function >>>;

Partial Application

According to wikipeda: In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.

In gwion, you can use a hole _ to achieve that

fun int test(int i, int j) {
  return i + j;
}

test(_, 2) :=> const auto mytest;
<<< 40 => mytest >>>;
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Lambda

Overview

lambdas are anonymous functions.

The syntax to create them is simple:

\ variable0 variable1 ... {  your code here }

You can even use it to

Call a function just once

\ i { <<< "passed '", i, "'" >>>; }(3);

Short lambdas

if the lambda consists of only one expression, the result of that expression is implicetely returned. Notice there is no semicolon in the lambda body;

<<< \ { 42 }() >>>;

Use case

Passing to a function pointer

funptr void fptr_t(int);
\ i { <<< "passed '", i, "'" >>>; } :=> var fptr_t fptr;
fptr(4);

As Argument to Functions

funptr void fptr_t(int);
fun void test(fptr_t fptr) {
   fptr(5);
}
test(\ i { <<< "passed '", i, "'" >>>; });
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Variadic functions

A function whoses arity is not fixed.

Well, a function that takes a fixed number of arguments, and additionnal ones.

a simple example

fun void variadic_test(int i, ...) {
  <<<  "first argument is ", i  >>>;
  varloop vararg {
    <<<  "\tadditionnal argument", vararg $ int  >>>;
  }
}
variadic_test(1);
variadic_test(1, 2);
variadic_test(1, 2, 3);
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Pipes

Motivation

Sometimes when writing code, you have a situation such as this:

fun int incr(int i) {
  return i + 1;
}

<<< incr(incr(incr(incr(1)))) >>>;

This code looks rather unappealing due to the nested functions. Instead, you can use pipes!

Usage

Instead of nesting functions over and over again, you can pipe the functions in a nice line.

fun int incr(int i) {
  return i + 1;
}

<<< 1 => incr => incr => incr => incr >>>;

As you can see, the 1 is piped into the incr function, and the result of that is piped into the incr function, and so on.

Multiple arguments

Piping works a little differently if your function has multiple arguments. If a function has multiple arguments, there are two ways to pipe.

First off, you can pipe all arguments directly.

fun int add(int i, int j) {
  return i + j;
}

<<< (1, 2) => add >>>;

Second off, you can pipe arguments one at a time.

fun int add(int i, int j) {
  return i + j;
}

<<< 1 => add(_, 2) >>>;
<<< 2 => add(1, _) >>>;

The underscore determines where the piped argument goes. In the first line, 1 goes into the first argument, whereas in the second line, 2 goes into the second argument.

You can also have multiple underscores.

fun int add3(int i, int j, int k) {
  return i + j + k;
}

<<< (1, 3) => add3(_, 2, _) >>>;

The arguments go into their respective underscores. In this case, 1 goes into the first argument and 3 goes into the third.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Types

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Enums

For those who don't know about enumerated types, you can read about those here and here

Enums in gwion

enums require a name and at least one member.

You use them like this:

enum MyEnum {
  zero, one, two
};
<<< "${MyEnum.zero} ${MyEnum.one} ${MyEnum.two}" >>>;

Storage and access Specifiers

When inside a class, enums accept private or protect specifiers.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Function Pointers

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Primitive types

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Type aliases

Create an alias for a previously defined type.

typedef int MyInt;
var MyInt i;
<<< i >>>;
<<< i $ int >>>;

Aliases can also point to an array type

typedef float[3] Point;
var Point p;
foreach(a : p)
  <<< a >>>;

Aliases can be used to refer to a type family

typedef Ptr:[int] IntPtr;
var IntPtr int_ptr;
<<< int_ptr >>>;
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Tagged Union

Union store their component in the same memory space, but only one element can be used at a time

union U {
  int i;
  float f;
  Object o;
};

#! create an union with field `i` set to `1`
new U(i, 1) :=> var U u;

<<< u.i >>>;

#! set field f to 2.4
2.4 :=> u.f;
<<< u.f >>>;

#! this will trigger an invalid access error
<<< u.i >>>;
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Gwion Preprocessor

Memoization

You can use the memoize pragma to enable memoization on functions:

normal version

fib_recurs.gw

fun int recursive_fib(int n) {
    if (n < 2)
        return n;
    return recursive_fib(n - 2) + recursive_fib(n - 1);
}
<<< 40 => recursive_fib >>>;

memoized version

The syntax of the memoize pragma is as follow:

#pragma memoization <number of results to store>

See the memoized version of previous function:

fib_recurs_memoize.gw

fun int recursive_fib(int n) {
#pragma memoize 2
    if (n < 2)
        return n;
    return recursive_fib(n - 2) + recursive_fib(n - 1);
}
<<< 40 => recursive_fib >>>;

Under circomstance where memoization is applicable, such as this one, you can see a huge speed-up.

normal:

memoized:

Memoization setting will be active until the end of file or until it is changed. Therefore, if you want to disable memoization for subsequent functions, use:

#pragma memoize 0
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Analys

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Emoji

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

K

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Lsys

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Math

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Modules

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Std

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

TinySF

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Tuple

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Vecx

compiler generated documentation

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributing

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributing Code

this is a stub for now, this place deserves better

You might be here because you found something you could improve in Gwion. Please open an issue describing the problem and how you might address it.

Dependencies

  • C compiler supporting C99 (ex- gcc, clang)
  • GNU Make

Fork the repository

You can do this through the github site, or command-line tools like gh or hub. See Further Reading.

Clone the source

Clone the url of your fork

git clone --recursive https://github.com/<your username>/Gwion

Set up the project

Edit some files

Edit some files with your favorite text editor

cd Gwion
vim src/path/to/file

Build the project

make

Test your changes

make test

Rebuild project (if required)

make -C util clean && make -C ast clean && make clean
make

Add your changes

git add path/to/changed/files

Let the world know

git commit -m "Something meaningful about why we are here"
git push

It is recommended that you follow our styleguide for commit messages

Submit a pull request

You can do this through the github site, or command-line tools like gh or hub. See Further Reading.

It is recommended you submit a PR to a branch other than master;

  • If a branch that directly concerns your specific PR is readily available, PR to that
  • Otherwise PR to dev

You can now sit back and wait for your pull request to be reviewed. If it's accepted, congrats! 🎉 You've made a contribution!

Further reading

For a more advanced info on contributing, check out @Chaser324's GitHub Standard Fork & Pull Request Workflow.

For a guide on making a pull request, there's github's Creating a pull request from a fork.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributing Documentation

this is a stub for now, this place deserves better

You might be here because you found something you could improve in Gwion's documentation. Please open an issue describing the problem and how you might address it.

Dependencies

Technically none of these are needed, but they are quite useful:

Editing the documentation

Fork the repository

You can do this through the github site, or command-line tools like gh or hub. See Further Reading.

Clone the source

Clone the url of your fork

git clone https://github.com/<your username>/gwion-docs

Edit some files

cd gwion-docs
make watch

Add your changes

git add docs/myfile.mdr

Let the world know

git commit -m "Something meaningful about why we are here"
git push

Submit a pull request

You can do this through the github site, or command-line tools like gh or hub. See Further Reading.

You can now sit back and wait for your pull request to be reviewed. If it's accepted, congrats! 🎉 You've made a contribution!

Further reading

For a more advanced info on contributing, check out @Chaser324's GitHub Standard Fork & Pull Request Workflow.

For a guide on making a pull request, there's github's Creating a pull request from a fork.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributing translations

First off, thank you for considering translating gwion.

Thanks to the build system, you're gonna get on tracks fast.

Make your live easier use export TRANSLATION_TARGET=xxx so you don't have to repeat it on the command line

Step 1: Init the translation language

You have to make sure there is a directory for your target language (e.g.: fr, en, es_ES ...).

make translation-init TRANSLATION_TARGET=<xxx>

Where <xxx> is your language of choice. It will fail if your language already exists, but this is not a problem.

Step 2: Edit

Next, you should adjust the translations. What about using your favorite editor?

make translation-edit TRANSLATION_TARGET=<xxx>

Step 3: Update

Maybe the sources changed, and there is more messages to translate?

make translation-update

This will update all languages.
You can now get back to step 2.

Step 4: Add to VCS

It's now time to add your changes to the package

make translation-commit TRANSLATION_TARGET=<xxx>

In Gwion's case, the vcs is the well known git,
but the make recipe makes things simple

Now please submit a pull request.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributing Plugins

This is a step by step hands on tutorial that will quide you trought the steps of making a Gwion plugin

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Introduction

Plugins are an important aspect of Gwion's flexibility and extensibility. They allow you to customize behavior as well as develop novel functionality within Gwion itself.

Much of Gwion's features come from plugins. Audio generation, file I/O, image editing and more.

What is a Plugin?

Plugins are shared object files typically created from C source code. They consist of a few core functions required for the Gwion runtime to properly initialize and use it.

Simple Plugin

Let's create a simple plugin which provides a single function: add. This will take two ints and return their sum as an int.

First, open up your terminal and run the following shell commands within Gwion/plug:

# Create a new directory for our Adder plugin
mkdir Adder

# Navigate to the newly created directory
cd Adder

# Create a makefile for compilation
printf "include ../config.mk\ninclude ../config_post.mk\n" > Makefile

# Create an adder.c file with your favorite text editor
nano adder.c

We are greeted with any empty file. However, it won't be empty for long.

Let's add the following code to the top of our file:

#include "plugin_dev.h"

This will include all the necessary functions and macros to develop a plugin without much head scratching.

Next, we need the GWION_IMPORT function. This is extremely important since it is what the Gwion runtime uses to set up your plugin. GWION_IMPORT is a macro which takes the name of your plugin: in this case that is "Adder". Underneath the include let's add:

GWION_IMPORT(Adder) {
    // Init code here
}

Within this function we register the public API of our plugin to Gwion. In our case, we want an Adder class with a single static function add that takes two numbers and returns their sum.

Our first step is to create the Adder class. This is done with:

GWION_IMPORT(Adder) {
    // Begin our adder class
    DECL_OB(const Type, t_adder, = gwi_class_ini(gwi, "Adder", "Object"));
}

Now, whenever we ini a class, we must also end it:

GWION_IMPORT(Adder) {
    // Begin our adder class
    DECL_OB(const Type, t_adder, = gwi_class_ini(gwi, "Adder", "Object"));

    // End our adder class
    GWI_BB(gwi_class_end(gwi));
}

We also want to make sure to indicate that everything has gone OK. We do this by returning GW_OK:

GWION_IMPORT(Adder) {
    // Begin our adder class
    DECL_OB(const Type, t_adder, = gwi_class_ini(gwi, "Adder", "Object"));

    // End our adder class
    GWI_BB(gwi_class_end(gwi));

    return GW_OK;
}

Right now our code doesn't really do much; it creates an empty class and then exits. Let's expand this code to add a static function inside the class:

GWION_IMPORT(Adder) {
    // Begin our adder class
    DECL_OB(const Type, t_adder, = gwi_class_ini(gwi, "Adder", "Object"));

    // Create a new function named `add` with a return type of `int`
    // gwi_func_ini(gwi, return_type, name);
    GWI_BB(gwi_func_ini(gwi, "int", "add"));

    // Register our two args `a` and `b` of type `int`
    // gwi_func_arg(gwi, arg_type, name);
    GWI_BB(gwi_func_arg(gwi, "int", "a"));
    GWI_BB(gwi_func_arg(gwi, "int", "b"));

    // Mark the function as completely declared
    GWI_BB(gwi_func_end(gwi, adder_add, ae_flag_static));

    // End our adder class
    GWI_BB(gwi_class_end(gwi));

    return GW_OK;
}

Looks like we are good to go! Let's compile...and:

adder.c: In function 'import':
adder.c:22:28: error: 'adder_add' undeclared (first use in this function)
   22 |   GWI_BB(gwi_func_end(gwi, adder_add, ae_flag_static));
      |                            ^~~~~~~~~

When we marked the function as completely declared with gwi_func_end, we gave the function implementation adder_add as an argument. This tells Gwion that our Adder.add function in Gwion corresponds to the C function adder_add. However we haven't actually defined it! Let's do that. Above our GWION_IMPORT function, add:

// The `SFUN` macro defines a static function
// The `static` here is actually a C keyword, unrelated to Gwion
static SFUN(sfun) {
    // Function body
}

Let's recall what our Adder.add function does. It takes two int parameters and returns an int. Gwion provides facilities for doing this:

// The `SFUN` macro defines a static function
// The `static` here is actually a C keyword, unrelated to Gwion
static SFUN(sfun) {
    // Retrieve the arguments
    // `a` is in memory at offset 0
    const m_int a = *(m_int*)MEM(0);
    // `b` is in memory at offset `SZ_INT`
    // This is because `a` has size `SZ_INT` and `b` is after `a`
    const m_int b = *(m_int*)MEM(SZ_INT);

    // We now set the return value, given as a void pointer with the `RETURN` macro
    // We need to cast it to the pointer type we want to return and then assign the return value
    *(m_int*)RETURN = a + b;
}

Finally, we can test our plugin. After running make (which creates Adder.so) in the directory, create a new file called add.gw and insert the following code:

#! We import our newly created plugin
#import Adder

#! Let's call our add function
<<< Adder.add(1, 2) >>>;

If all goes well, running the following shell command should result in "3" being printed:

gwion -p. add.gw
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Plugin Reference

There are some general macros essential to interfacing with Gwion in general.

The return codes of functions are of type m_bool and consist of the following values:

NameValueDescription
GW_OK1Success
GW_PASS0Ignore the result and continue
GW_ERROR-1An error occured

The following macros are sugar for handling error codes. They can exit the scope of the function. It is recommended to use these rather than writing:

if (!a) return NULL;

and co.

NameValueDescription
CHECK_BBif (f < 0) return GW_ERROR;Takes an expression that evaluates to m_bool. Potentially exits function returning GW_ERROR.
CHECK_BOif (f < 0) return NULL;Takes an expression that evaluates to m_bool. Potentially exits function returning NULL.
CHECK_OBif (!f) return GW_ERROR;Takes an expression that evaluates to a pointer. Potentially exits function returning GW_ERROR.
CHECK_OOif (!f) return NULL;Takes an expression that evaluates to a pointer. Potentially exits function returning NULL.

Likewise there are the DECL_XX macros which specialize to failing if a declaration fails. Their general syntax is as follows:

DECL_XX(type, var_name, = value);

These macros are specific to creating plugins.

MFUN(name) signature for a member function SFUN(name) signature for a static function CTOR(name) signature for a constructor DTOR(name) signature for a destructor GACK(name) signature for a pretty print function TICK(name) signature for a UGen tick function GWION_IMPORT(name) main function of a plugin/library

in said main function, one should use GWI_XX instead of CHECK_XX since it takes care of position and might optimize some checks away (in gwion's internals)

OP_CHECK(name) define a type checking function. should return correct type in success error type on failure NULL to continue type checking

OP_EMIT(name) define an emitter function. returns an m_bool

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Credits

fennecdjay was of immeasurable help when I was writing these docs. Thank you to them for sitting down and working me through Gwion plugins from the basics.

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Contributors

Thanks goes to these wonderful people:

fennecdjayfennecdjay
TotallyNotChaseTotallyNotChase
PaulBatchelorPaulBatchelor
forrcahoforrcaho
benrogmansbenrogmans
JackojcJackojc
NishiOwONishiOwO
Pranav2612000Pranav2612000
umer2001umer2001
ry-v1ry-v1
scalarwavesscalarwaves
evaydeevayde
neverRareneverRare
cjh-cloudcjh-cloud
a-mere-peasanta-mere-peasant
argvsc47argvsc47
hg0428hg0428
nithin-pankajnithin-pankaj
valkariasvalkarias
built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground

Benchmarks

Author: fennecdjay Date: 02/25/24 19:27:30 Commit: 30af8f4

Results

Please note that times are in second (lower is better)

it seems that some chuck test are broken atm. we're investigating this

built with mdr and mdBook
You'll find the source here, Luke! note: privacy guards may interfere with the playground