GEN routines
Overview
This document outlines a set of useful GEN routines.
What exactly is a GEN routine?
A GEN routine is used to describe a function that works
on table (a SKFLT
array in C). These are usually used to
generate wavetables.
The term "GEN routine" (yes, all caps), is borrowed from Csound and MUSIC-N languages as GENerators for function tables, affectionately referred to as "f-tables", which are essentially just "tables" in the sndkit world.
Tangled Files
gen.c
and gen.h
.
#ifndef SK_GEN_SINE
#define SK_GEN_SINE
#ifndef SKFLT
#define SKFLT float
#endif
<<funcdefs>>
#endif
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "gen.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
<<funcs>>
Sine
The function sk_gen_sine
generates a sampled period
of a sine wave.
void sk_gen_sine(SKFLT *tab, unsigned long sz);
void sk_gen_sine(SKFLT *tab, unsigned long sz)
{
int i;
SKFLT step;
if (sz <= 0) return;
step = 2 * M_PI / sz;
for (i = 0; i < sz; i++) {
tab[i] = sin(i * step);
}
}
Saw
Samples a single period of a simple sawtooth waveform. Note that this will produce aliasing artifacts. For specialized sawtooth oscillators with alias supression, consider using blep.
void sk_gen_saw(SKFLT *tab, unsigned long sz);
void sk_gen_saw(SKFLT *tab, unsigned long sz)
{
int i;
SKFLT step;
if (sz <= 0) return;
step = 1.0 / sz;
for (i = 0; i < sz; i++) {
tab[i] = 2.0*(i*step) - 1.0;
}
}
String Values
Generates a table from a string of values separated by spaces. Extracted from the Soundpipe library.
This will actually re-allocate the table if need be, which is why the arguments are pointers.
void sk_gen_vals(SKFLT **ptab, int *psz, const char *str);
static char * tokenize(char **next, int *size)
{
char *token;
char *str;
char *peak;
if (*size <= 0) return NULL;
token = *next;
str = *next;
peak = str + 1;
while ((*size)--) {
if (*str == ' ') {
*str = 0;
if (*peak != ' ') break;
}
str = str + 1;
peak = str + 1;
}
*next = peak;
return token;
}
void sk_gen_vals(SKFLT **ptab, int *psz, const char *string)
{
int size;
char *str;
char *out;
char *ptr;
int j;
int sz;
SKFLT *tab;
size = strlen(string);
str = malloc(sizeof(char) * size + 1);
strcpy(str, string);
ptr = str;
j = 0;
tab = *ptab;
sz = *psz;
while (size > 0) {
out = tokenize(&str, &size);
if (sz < j + 1) {
tab = realloc(tab, sizeof(SKFLT) * (sz + 2));
/* zero out new tables */
tab[sz] = 0;
tab[sz + 1] = 0;
sz++;
}
tab[j] = atof(out);
j++;
}
*ptab = tab;
*psz = sz;
free(ptr);
}
Sine Sum
void sk_gen_sinesum(SKFLT *tab,
int sz,
const char *argstring,
int normalize);
void sk_gen_sinesum(SKFLT *tab,
int sz,
const char *argstring,
int normalize)
{
SKFLT *args;
int argsz;
int phs;
SKFLT amp;
int flen;
SKFLT tpdlen;
int i, n;
SKFLT ampsum;
args = malloc(sizeof(SKFLT));
args[0] = 0;
argsz = 1;
ampsum = 0;
sk_gen_vals(&args, &argsz, argstring);
flen = sz;
tpdlen = 2.0 * M_PI / (SKFLT) flen;
for (i = argsz; i > 0; i--) {
amp = args[i - 1];
if (amp > 0) {
ampsum += amp;
for (phs = 0, n = 0; n < sz; n++) {
tab[n] += sin(phs * tpdlen) * amp;
phs += i;
phs %= flen;
}
}
}
if (normalize) {
SKFLT norm;
norm = 1.0 / ampsum;
for (n = 0; n < sz; n++) {
tab[n] *= norm;
}
}
free(args);
}