139 lines
3.3 KiB
C
139 lines
3.3 KiB
C
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include "gifenc/gifenc.h"
|
|
|
|
#define NOTE 440
|
|
#define AUDIO_FRAME_RATE 44100
|
|
#define LENGTH (AUDIO_FRAME_RATE / NOTE)
|
|
|
|
#define WIDTH LENGTH * 4
|
|
#define HEIGHT 128
|
|
|
|
#define RED 0
|
|
#define GREEN 0
|
|
#define BLUE 0
|
|
|
|
static struct sinewave {
|
|
float f, s, c;
|
|
} init_sinewave(float frequency, float phase, float amplitude) {
|
|
struct sinewave r;
|
|
r.f = 2.f * sinf((float)M_PI * frequency / (float)AUDIO_FRAME_RATE);
|
|
r.s = amplitude * sinf(phase);
|
|
r.c = amplitude * cosf(phase);
|
|
return r;
|
|
}
|
|
|
|
static float pump_sinewave(struct sinewave *wave) {
|
|
wave->s -= wave->f * wave->c;
|
|
wave->c += wave->f * wave->s;
|
|
return wave->s;
|
|
}
|
|
|
|
static struct sqrtwave {
|
|
struct sinewave w;
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} v;
|
|
} init_sqrtwave(float frequency, float phase, float amplitude) {
|
|
struct sqrtwave r;
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} v, a;
|
|
r.w = init_sinewave(frequency, phase, 1.f);
|
|
v.f = r.w.s;
|
|
a.f = amplitude;
|
|
r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
|
|
return r;
|
|
}
|
|
|
|
static float pump_sqrtwave(struct sqrtwave *wave) {
|
|
union {
|
|
float f;
|
|
uint32_t u;
|
|
} v;
|
|
pump_sinewave(&wave->w);
|
|
v.f = wave->w.s;
|
|
wave->v.u = (wave->v.u & 0x7fffffff) | (v.u & 0x80000000);
|
|
return wave->v.f;
|
|
}
|
|
|
|
static struct sawtwave {
|
|
float v, a, i;
|
|
} init_sawtwave(float frequency, float phase, float amplitude) {
|
|
struct sawtwave r;
|
|
r.v = sinf(phase) * amplitude;
|
|
r.a = amplitude;
|
|
r.i = 2.f * frequency / AUDIO_FRAME_RATE * amplitude;
|
|
return r;
|
|
}
|
|
|
|
static float pump_sawtwave(struct sawtwave *wave) {
|
|
wave->v += wave->i;
|
|
if (wave->v > wave->a)
|
|
wave->v -= wave->a * 2.f;
|
|
return wave->v;
|
|
}
|
|
|
|
static int absi(int v) {
|
|
return v > 0 ? v : -v;
|
|
}
|
|
|
|
static void plot_line(uint8_t *frame, int x, int xt, int y, int yt) {
|
|
int dx = xt - x;
|
|
int dy = yt - y;
|
|
int step = absi(dx) >= absi(dy) ? absi(dx) : absi(dy);
|
|
dx /= step;
|
|
dy /= step;
|
|
int xc = x;
|
|
int yc = y;
|
|
int i = 1;
|
|
while (i <= step) {
|
|
frame[xc + yc * WIDTH] = 1;
|
|
xc += dx;
|
|
yc += dy;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static void generate_wave(char const *filepath, void *generator, float (*pumper)(void *)) {
|
|
float wave[LENGTH];
|
|
for (int i = 0; i < LENGTH; ++i) {
|
|
wave[i] = pumper(generator);
|
|
}
|
|
uint8_t palette[6] = { [3] = RED, [4] = GREEN, [5] = BLUE };
|
|
ge_GIF *g = ge_new_gif(filepath, WIDTH, HEIGHT, palette, 1, 0, 0);
|
|
assert(g);
|
|
for (int f = 0; f < LENGTH; ++f) {
|
|
memset(g->frame, 0, WIDTH * HEIGHT);
|
|
for (int i = 0; i < WIDTH; ++i) {
|
|
int l0 = (int)((wave[(f + i) % LENGTH] + 1.0f) * 127.5f) / 2;
|
|
int l1 = (int)((wave[(f + i + 1) % LENGTH] + 1.0f) * 127.5f) / 2;
|
|
if (i == WIDTH - 1)
|
|
g->frame[i + l0 * WIDTH] = 1;
|
|
else
|
|
plot_line(g->frame, i, i + 1, l0, l1);
|
|
}
|
|
ge_add_frame(g, 1);
|
|
}
|
|
ge_close_gif(g);
|
|
}
|
|
|
|
int main(void) {
|
|
struct sinewave sine = init_sinewave((float)NOTE, 0.0f, 1.0f);
|
|
generate_wave(".dynamic/sine.gif", &sine, pump_sinewave);
|
|
|
|
struct sqrtwave sqrt = init_sqrtwave((float)NOTE, 0.0f, 1.0f);
|
|
generate_wave(".dynamic/sqrt.gif", &sqrt, pump_sqrtwave);
|
|
|
|
struct sawtwave sawt = init_sawtwave((float)NOTE, 0.0f, 1.0f);
|
|
generate_wave(".dynamic/sawt.gif", &sawt, pump_sawtwave);
|
|
|
|
return 0;
|
|
}
|