]> Nishi Git Mirror - gwion.git/commitdiff
Add plugin introduction
authorJérémie Astor <fennecdjay@gmail.com>
Sun, 25 Apr 2021 19:22:43 +0000 (21:22 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Sun, 25 Apr 2021 19:22:43 +0000 (21:22 +0200)
docs/Contributing/ContributingPlugins.mdr [new file with mode: 0644]
docs/Contributing/Plugins/README.md [new file with mode: 0644]
docs/Contributing/Plugins/introduction.mdr [new file with mode: 0644]
docs/Contributing/Plugins/list [new file with mode: 0644]
docs/Contributing/list

diff --git a/docs/Contributing/ContributingPlugins.mdr b/docs/Contributing/ContributingPlugins.mdr
new file mode 100644 (file)
index 0000000..a5e8906
--- /dev/null
@@ -0,0 +1,3 @@
+# Contributing Plugins
+
+This is a step by step hands on tutorial that will quide you trought the steps of making a Gwion plugin
diff --git a/docs/Contributing/Plugins/README.md b/docs/Contributing/Plugins/README.md
new file mode 100644 (file)
index 0000000..779d515
--- /dev/null
@@ -0,0 +1 @@
+# Plugins
diff --git a/docs/Contributing/Plugins/introduction.mdr b/docs/Contributing/Plugins/introduction.mdr
new file mode 100644 (file)
index 0000000..0cf35c2
--- /dev/null
@@ -0,0 +1,155 @@
+# 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 `int`s and return their sum as an `int`.
+
+First, open up your terminal and run the following shell commands within `Gwion/plug`:
+```bash
+# 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:
+```c
+#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:
+```c
+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:
+```c
+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:
+
+```c
+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`:
+```c
+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:
+```c
+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:
+
+```c
+// 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:
+
+```c
+// 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:
+```gwion
+#! We import our newly created plugin
+#require 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:
+```bash
+gwion -p. add.gw
+```
diff --git a/docs/Contributing/Plugins/list b/docs/Contributing/Plugins/list
new file mode 100644 (file)
index 0000000..9d7dc46
--- /dev/null
@@ -0,0 +1,2 @@
+README.md
+introduction.md
index 6636e846dd0cdb2baf2676cb3ad1ce976684e460..67c0d72e4ca7805d9de12bed4c78d4185fcbd991 100644 (file)
@@ -2,4 +2,8 @@ README.md
 ContributingCode.md
 ContributingDocumentation.md
 ContributingTranslation.md
+
+ContributingPlugins.md
+Plugins
+
 Contributors.md