#+TITLE: Core* OverviewThis document describes and outlines a small API forsndkit. It is primarily designed to be a small layer on topof Patchwerk, a library used to build up directed audiographs. A large portion of the functionality is based onwhat is found in runt-patchwerk. Just simpler. In addition to maintaining an instance of patchwerk, thesndkit API provides a stack and a register system. Thestack is the primary means of sharing data between nodes.Registers are for more persitently used values.* Tangled files=core.h= and =core.c=. #+NAME: core.h#+BEGIN_SRC c :tangle core.h#ifndef SKPW_H#define SKPW_H #ifndef SKFLT#define SKFLT float#endif <<typedefs>>#ifdef SK_CORE_PRIV<<structs>><<core>>#endif<<macros>><<funcdefs>>#endif#+END_SRC #+NAME: core.c#+BEGIN_SRC c :tangle core.c#include <stdlib.h>#include <math.h>#include <string.h>#include "patchwerk.h"#define SK_CORE_PRIV#include "core.h"<<enums>><<funcs>>#+END_SRC* Engine ManagementAll this behavior is defined in a struct called =sk_core=. Creating/freeing is done with =sk_core_new= and=sk_core_del=. #+NAME: funcdefs#+BEGIN_SRC csk_core * sk_core_new(int sr);void sk_core_del(sk_core *core);#+END_SRC #+NAME: funcs#+BEGIN_SRC csk_core * sk_core_new(int sr){ sk_core *core; pw_patch *patch; core = malloc(sizeof(sk_core)); core->patch = malloc(pw_patch_size()); patch = core->patch; pw_patch_init(patch, 64); pw_patch_alloc(patch, 8, 10); pw_patch_srate_set(patch, sr); sk_stack_init(&core->stack); sk_regtbl_init(&core->regtbl); sk_core_srand(core, 0); return core;}#+END_SRC #+NAME: funcs#+BEGIN_SRC cvoid sk_core_del(sk_core *core){ if (core == NULL) return; pw_patch_destroy(core->patch); pw_patch_free_nodes(core->patch); free(core->patch); free(core); core = NULL;}#+END_SRC #+NAME: typedefs#+BEGIN_SRC ctypedef struct sk_core sk_core;#+END_SRC #+NAME: core#+BEGIN_SRC cstruct sk_core { pw_patch *patch; sk_stack stack; sk_regtbl regtbl; unsigned long rng;};#+END_SRC A internal block of audio can be computed with=sk_core_compute=. Usually this size is 64 samples. #+NAME: funcdefs#+BEGIN_SRC cvoid sk_core_compute(sk_core *core);#+END_SRC #+NAME: funcs#+BEGIN_SRC cvoid sk_core_compute(sk_core *core){ pw_patch_compute(core->patch);}#+END_SRC =sk_core_computes= is like =sk_core_compute=, but computesan approximuate number of seconds of audio. This valuegets rounded to the nearest block. The number of blocksrendered gets rendered. #+NAME: funcdefs#+BEGIN_SRC csize_t sk_core_computes(sk_core *core, SKFLT secs);#+END_SRC #+NAME: funcs#+BEGIN_SRC csize_t sk_core_computes(sk_core *core, SKFLT secs){ size_t nblocks, n; nblocks = sk_core_seconds_to_blocks(core, secs); for (n = 0; n < nblocks; n++) { sk_core_compute(core); } return nblocks;}#+END_SRC Building up nodes involves interacting with the patchwerkAPI. To get the top level struct of that opaquely, use=sk_core_patch=. #+NAME: funcdefs#+BEGIN_SRC cpw_patch * sk_core_patch(sk_core *core);#+END_SRC #+NAME: funcs#+BEGIN_SRC cpw_patch * sk_core_patch(sk_core *core){ return core->patch;}#+END_SRC The function =sk_core_seconds_to_blocks= convertsseconds to a number of render blocks. #+NAME: funcdefs#+BEGIN_SRC csize_t sk_core_seconds_to_blocks(sk_core *core, SKFLT secs);#+END_SRC #+NAME: funcs#+BEGIN_SRC csize_t sk_core_seconds_to_blocks(sk_core *core, SKFLT secs){ size_t nblocks; int sr; sr = pw_patch_srate_get(core->patch); nblocks = floor((sr * secs) / 64) + 1; return nblocks;}#+END_SRC* Stack** Core Data TypesAn item on a stack is contained in a thing known as a=stacklet=. A stacklet has integer for a type flag, afloating point number for numerical values, and a genericpointer for C structures. #+NAME: typedefs#+BEGIN_SRC ctypedef struct sk_stacklet sk_stacklet;#+END_SRC #+NAME: structs#+BEGIN_SRC cstruct sk_stacklet { int type; SKFLT f; void *ptr;};<<stack_struct>>#+END_SRC A stacklet is initialized with the function=sk_stacklet_init=. #+NAME: funcdefs#+BEGIN_SRC cvoid sk_stacklet_init(sk_stacklet *s);#+END_SRC #+NAME: funcs#+BEGIN_SRC cvoid sk_stacklet_init(sk_stacklet *s){ s->type = SK_TYPE_NONE; s->f = 0; s->ptr = NULL;}#+END_SRC An array of stacklets forms the foundation of a =sk_stack=. #+NAME: typedefs#+BEGIN_SRC ctypedef struct sk_stack sk_stack;#+END_SRC The stack will be hard coded to be 16. An integer =pos= is used to keep track of position. #+NAME: stack_struct#+BEGIN_SRC c#define SK_STACKSIZE 16struct sk_stack { sk_stacklet stack[SK_STACKSIZE]; int pos;};#+END_SRC A stack is initialized with =sk_stack_init=. #+NAME: funcdefs#+BEGIN_SRC cvoid sk_stack_init(sk_stack *s);#+END_SRC The position is set to be negative, indicating an emptystack. #+NAME: funcs#+BEGIN_SRC cvoid sk_stack_init(sk_stack *s){ int i; for (i = 0; i < SK_STACKSIZE; i++) { sk_stacklet_init(&s->stack[i]); } s->pos = -1;}#+END_SRC** TypesThe typeflag currently supports the following types: #+NAME: enums#+BEGIN_SRC cenum { SK_TYPE_NONE, SK_TYPE_CONSTANT, SK_TYPE_CABLE, SK_TYPE_TABLE, SK_TYPE_GENERIC};#+END_SRC** Push/PopPush and pop are the core operations for the stack. Bothreturn non-zero values on error. =sk_stack_pop= will pop a value off the stack and save itto the stacklet variable =s=. =sk_stack_push= will push an initialized stacklet to thestack, and save that value to stacklet variable =s= tobe filled with some item. #+NAME: funcdefs#+BEGIN_SRC cint sk_stack_pop(sk_stack *stack, sk_stacklet **out);int sk_stack_push(sk_stack *stack, sk_stacklet **out);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_pop(sk_stack *stack, sk_stacklet **out){ sk_stacklet *s; /* no items on stack */ if (stack->pos < 0) return 1; /* stack overflow */ if (stack->pos >= SK_STACKSIZE) return 2; s = &stack->stack[stack->pos]; stack->pos--; *out = s; return 0;}#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_push(sk_stack *stack, sk_stacklet **out){ sk_stacklet *s; if (stack->pos >= (SK_STACKSIZE - 1)) return 1; stack->pos++; s = &stack->stack[stack->pos]; sk_stacklet_init(s); *out = s; return 0;}#+END_SRC** PeakThe function =sk_stack_peak= will look at the last item onthe stack, but not pop it off the stack. #+NAME: funcdefs#+BEGIN_SRC cint sk_stack_peak(sk_stack *stack, sk_stacklet **out);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_peak(sk_stack *stack, sk_stacklet **out){ sk_stacklet *s; if (stack->pos < 0) return 1; if (stack->pos >= SK_STACKSIZE) return 2; s = &stack->stack[stack->pos]; *out = s; return 0;}#+END_SRC** Dup=dup= is an operation that duplicates an item on the stack. The basic operation can be done with =sk_stack_dup=. Theoperation will store the duplicated stack item to =out= ifthe argument is not =NULL=. #+NAME: funcdefs#+BEGIN_SRC cint sk_stack_dup(sk_stack *stack, sk_stacklet **out);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_dup(sk_stack *stack, sk_stacklet **out){ int rc; sk_stacklet *a, *b; rc = sk_stack_peak(stack, &a); SK_ERROR_CHECK(rc); rc = sk_stack_push(stack, &b); SK_ERROR_CHECK(rc); *b = *a; if (out != NULL) *out = b; return 0;}#+END_SRC =sk_core_dup= will call =sk_stack_dup= on the internalstack, but also will call a dup operation on the patchwerkstack if the item is a patchwerk cable. #+NAME: funcdefs#+BEGIN_SRC cint sk_core_dup(sk_core *core);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_core_dup(sk_core *core){ sk_stacklet *s; int rc; rc = sk_stack_dup(&core->stack, &s); SK_ERROR_CHECK(rc); if (s->type == SK_TYPE_CABLE) { pw_stack *stack; stack = pw_patch_stack(core->patch); pw_stack_dup(stack); } return 0;}#+END_SRC** Drop=drop= is an operation that drops an item on the stack. The basic operation is done with =sk_stack_drop=. The dropped value will be saved to =out= if =out= isnot =NULL=. #+NAME: funcdefs#+BEGIN_SRC cint sk_stack_drop(sk_stack *stack, sk_stacklet **out);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_drop(sk_stack *stack, sk_stacklet **out){ int rc; sk_stacklet *s; rc = sk_stack_pop(stack, &s); SK_ERROR_CHECK(rc); if (out != NULL) *out = s; return 0;}#+END_SRC The function =sk_core_drop= performs a drop on the stackin the core struct. If the item is a patchwerk cable, itwill also perform a drop on the patchwerk buffer stack. #+NAME: funcdefs#+BEGIN_SRC cint sk_core_drop(sk_core *core);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_core_drop(sk_core *core){ int rc; sk_stacklet *s; rc = sk_stack_drop(&core->stack, &s); SK_ERROR_CHECK(rc); if (s->type == SK_TYPE_CABLE) { pw_stack *stack; stack = pw_patch_stack(core->patch); pw_stack_pop(stack, NULL); } return 0;}#+END_SRC** Swap=swap= will swap the positions of the last two items onthe stack. The basic operation is done with =sk_stack_swap=. #+NAME: funcdefs#+BEGIN_SRC cint sk_stack_swap(sk_stack *stack, sk_stacklet **s1, sk_stacklet **s2);#+END_SRC #+NAME: funcs#+BEGIN_SRC cint sk_stack_swap(sk_stack *stack, sk_stacklet **out1, sk_stacklet **out2){ sk_stacklet tmp; int pos; pos = stack->pos;Lines 1–500 of 1342. Load more
#+TITLE: Core * Overview This document describes and outlines a small API for sndkit. It is primarily designed to be a small layer on top of Patchwerk, a library used to build up directed audio graphs. A large portion of the functionality is based on what is found in runt-patchwerk. Just simpler. In addition to maintaining an instance of patchwerk, the sndkit API provides a stack and a register system. The stack is the primary means of sharing data between nodes. Registers are for more persitently used values. * Tangled files =core.h= and =core.c=. #+NAME: core.h #+BEGIN_SRC c :tangle core.h #ifndef SKPW_H #define SKPW_H #ifndef SKFLT #define SKFLT float #endif <<typedefs>> #ifdef SK_CORE_PRIV <<structs>> <<core>> #endif <<macros>> <<funcdefs>> #endif #+END_SRC #+NAME: core.c #+BEGIN_SRC c :tangle core.c #include <stdlib.h> #include <math.h> #include <string.h> #include "patchwerk.h" #define SK_CORE_PRIV #include "core.h" <<enums>> <<funcs>> #+END_SRC * Engine Management All this behavior is defined in a struct called =sk_core=. Creating/freeing is done with =sk_core_new= and =sk_core_del=. #+NAME: funcdefs #+BEGIN_SRC c sk_core * sk_core_new(int sr); void sk_core_del(sk_core *core); #+END_SRC #+NAME: funcs #+BEGIN_SRC c sk_core * sk_core_new(int sr) { sk_core *core; pw_patch *patch; core = malloc(sizeof(sk_core)); core->patch = malloc(pw_patch_size()); patch = core->patch; pw_patch_init(patch, 64); pw_patch_alloc(patch, 8, 10); pw_patch_srate_set(patch, sr); sk_stack_init(&core->stack); sk_regtbl_init(&core->regtbl); sk_core_srand(core, 0); return core; } #+END_SRC #+NAME: funcs #+BEGIN_SRC c void sk_core_del(sk_core *core) { if (core == NULL) return; pw_patch_destroy(core->patch); pw_patch_free_nodes(core->patch); free(core->patch); free(core); core = NULL; } #+END_SRC #+NAME: typedefs #+BEGIN_SRC c typedef struct sk_core sk_core; #+END_SRC #+NAME: core #+BEGIN_SRC c struct sk_core { pw_patch *patch; sk_stack stack; sk_regtbl regtbl; unsigned long rng; }; #+END_SRC A internal block of audio can be computed with =sk_core_compute=. Usually this size is 64 samples. #+NAME: funcdefs #+BEGIN_SRC c void sk_core_compute(sk_core *core); #+END_SRC #+NAME: funcs #+BEGIN_SRC c void sk_core_compute(sk_core *core) { pw_patch_compute(core->patch); } #+END_SRC =sk_core_computes= is like =sk_core_compute=, but computes an approximuate number of seconds of audio. This value gets rounded to the nearest block. The number of blocks rendered gets rendered. #+NAME: funcdefs #+BEGIN_SRC c size_t sk_core_computes(sk_core *core, SKFLT secs); #+END_SRC #+NAME: funcs #+BEGIN_SRC c size_t sk_core_computes(sk_core *core, SKFLT secs) { size_t nblocks, n; nblocks = sk_core_seconds_to_blocks(core, secs); for (n = 0; n < nblocks; n++) { sk_core_compute(core); } return nblocks; } #+END_SRC Building up nodes involves interacting with the patchwerk API. To get the top level struct of that opaquely, use =sk_core_patch=. #+NAME: funcdefs #+BEGIN_SRC c pw_patch * sk_core_patch(sk_core *core); #+END_SRC #+NAME: funcs #+BEGIN_SRC c pw_patch * sk_core_patch(sk_core *core) { return core->patch; } #+END_SRC The function =sk_core_seconds_to_blocks= converts seconds to a number of render blocks. #+NAME: funcdefs #+BEGIN_SRC c size_t sk_core_seconds_to_blocks(sk_core *core, SKFLT secs); #+END_SRC #+NAME: funcs #+BEGIN_SRC c size_t sk_core_seconds_to_blocks(sk_core *core, SKFLT secs) { size_t nblocks; int sr; sr = pw_patch_srate_get(core->patch); nblocks = floor((sr * secs) / 64) + 1; return nblocks; } #+END_SRC * Stack ** Core Data Types An item on a stack is contained in a thing known as a =stacklet=. A stacklet has integer for a type flag, a floating point number for numerical values, and a generic pointer for C structures. #+NAME: typedefs #+BEGIN_SRC c typedef struct sk_stacklet sk_stacklet; #+END_SRC #+NAME: structs #+BEGIN_SRC c struct sk_stacklet { int type; SKFLT f; void *ptr; }; <<stack_struct>> #+END_SRC A stacklet is initialized with the function =sk_stacklet_init=. #+NAME: funcdefs #+BEGIN_SRC c void sk_stacklet_init(sk_stacklet *s); #+END_SRC #+NAME: funcs #+BEGIN_SRC c void sk_stacklet_init(sk_stacklet *s) { s->type = SK_TYPE_NONE; s->f = 0; s->ptr = NULL; } #+END_SRC An array of stacklets forms the foundation of a =sk_stack=. #+NAME: typedefs #+BEGIN_SRC c typedef struct sk_stack sk_stack; #+END_SRC The stack will be hard coded to be 16. An integer =pos= is used to keep track of position. #+NAME: stack_struct #+BEGIN_SRC c #define SK_STACKSIZE 16 struct sk_stack { sk_stacklet stack[SK_STACKSIZE]; int pos; }; #+END_SRC A stack is initialized with =sk_stack_init=. #+NAME: funcdefs #+BEGIN_SRC c void sk_stack_init(sk_stack *s); #+END_SRC The position is set to be negative, indicating an empty stack. #+NAME: funcs #+BEGIN_SRC c void sk_stack_init(sk_stack *s) { int i; for (i = 0; i < SK_STACKSIZE; i++) { sk_stacklet_init(&s->stack[i]); } s->pos = -1; } #+END_SRC ** Types The typeflag currently supports the following types: #+NAME: enums #+BEGIN_SRC c enum { SK_TYPE_NONE, SK_TYPE_CONSTANT, SK_TYPE_CABLE, SK_TYPE_TABLE, SK_TYPE_GENERIC }; #+END_SRC ** Push/Pop Push and pop are the core operations for the stack. Both return non-zero values on error. =sk_stack_pop= will pop a value off the stack and save it to the stacklet variable =s=. =sk_stack_push= will push an initialized stacklet to the stack, and save that value to stacklet variable =s= to be filled with some item. #+NAME: funcdefs #+BEGIN_SRC c int sk_stack_pop(sk_stack *stack, sk_stacklet **out); int sk_stack_push(sk_stack *stack, sk_stacklet **out); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_pop(sk_stack *stack, sk_stacklet **out) { sk_stacklet *s; /* no items on stack */ if (stack->pos < 0) return 1; /* stack overflow */ if (stack->pos >= SK_STACKSIZE) return 2; s = &stack->stack[stack->pos]; stack->pos--; *out = s; return 0; } #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_push(sk_stack *stack, sk_stacklet **out) { sk_stacklet *s; if (stack->pos >= (SK_STACKSIZE - 1)) return 1; stack->pos++; s = &stack->stack[stack->pos]; sk_stacklet_init(s); *out = s; return 0; } #+END_SRC ** Peak The function =sk_stack_peak= will look at the last item on the stack, but not pop it off the stack. #+NAME: funcdefs #+BEGIN_SRC c int sk_stack_peak(sk_stack *stack, sk_stacklet **out); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_peak(sk_stack *stack, sk_stacklet **out) { sk_stacklet *s; if (stack->pos < 0) return 1; if (stack->pos >= SK_STACKSIZE) return 2; s = &stack->stack[stack->pos]; *out = s; return 0; } #+END_SRC ** Dup =dup= is an operation that duplicates an item on the stack. The basic operation can be done with =sk_stack_dup=. The operation will store the duplicated stack item to =out= if the argument is not =NULL=. #+NAME: funcdefs #+BEGIN_SRC c int sk_stack_dup(sk_stack *stack, sk_stacklet **out); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_dup(sk_stack *stack, sk_stacklet **out) { int rc; sk_stacklet *a, *b; rc = sk_stack_peak(stack, &a); SK_ERROR_CHECK(rc); rc = sk_stack_push(stack, &b); SK_ERROR_CHECK(rc); *b = *a; if (out != NULL) *out = b; return 0; } #+END_SRC =sk_core_dup= will call =sk_stack_dup= on the internal stack, but also will call a dup operation on the patchwerk stack if the item is a patchwerk cable. #+NAME: funcdefs #+BEGIN_SRC c int sk_core_dup(sk_core *core); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_core_dup(sk_core *core) { sk_stacklet *s; int rc; rc = sk_stack_dup(&core->stack, &s); SK_ERROR_CHECK(rc); if (s->type == SK_TYPE_CABLE) { pw_stack *stack; stack = pw_patch_stack(core->patch); pw_stack_dup(stack); } return 0; } #+END_SRC ** Drop =drop= is an operation that drops an item on the stack. The basic operation is done with =sk_stack_drop=. The dropped value will be saved to =out= if =out= is not =NULL=. #+NAME: funcdefs #+BEGIN_SRC c int sk_stack_drop(sk_stack *stack, sk_stacklet **out); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_drop(sk_stack *stack, sk_stacklet **out) { int rc; sk_stacklet *s; rc = sk_stack_pop(stack, &s); SK_ERROR_CHECK(rc); if (out != NULL) *out = s; return 0; } #+END_SRC The function =sk_core_drop= performs a drop on the stack in the core struct. If the item is a patchwerk cable, it will also perform a drop on the patchwerk buffer stack. #+NAME: funcdefs #+BEGIN_SRC c int sk_core_drop(sk_core *core); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_core_drop(sk_core *core) { int rc; sk_stacklet *s; rc = sk_stack_drop(&core->stack, &s); SK_ERROR_CHECK(rc); if (s->type == SK_TYPE_CABLE) { pw_stack *stack; stack = pw_patch_stack(core->patch); pw_stack_pop(stack, NULL); } return 0; } #+END_SRC ** Swap =swap= will swap the positions of the last two items on the stack. The basic operation is done with =sk_stack_swap=. #+NAME: funcdefs #+BEGIN_SRC c int sk_stack_swap(sk_stack *stack, sk_stacklet **s1, sk_stacklet **s2); #+END_SRC #+NAME: funcs #+BEGIN_SRC c int sk_stack_swap(sk_stack *stack, sk_stacklet **out1, sk_stacklet **out2) { sk_stacklet tmp; int pos; pos = stack->pos;