Compare commits

..

3 Commits

Author SHA1 Message Date
veclav talica
4163177071 waveform generation, fixes of walk 2023-05-25 19:06:05 +05:00
veclav talica
1a18af8baf fixes to oscillators article 2023-05-25 19:05:34 +05:00
veclav talica
3dc8c60a99 ignore hidden directories 2023-05-25 19:04:54 +05:00
10 changed files with 176 additions and 5 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
**/__pycache__/* **/__pycache__/*
html/ html/
**/.*/

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "tools/mmd"] [submodule "tools/mmd"]
path = tools/mmd path = tools/mmd
url = https://github.com/fletcher/MultiMarkdown-6 url = https://github.com/fletcher/MultiMarkdown-6
[submodule "tools/gifenc"]
path = tools/gifenc
url = https://github.com/lecram/gifenc

7
articles/oscillators/make Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
cd $(dirname "$0")
mkdir ./.dynamic
mkdir ./.temp
gcc waveforms.c -I../../tools ../../tools/gifenc/gifenc.c -O2 -o ./.temp/waveforms
./.temp/waveforms

View File

@ -14,6 +14,8 @@ Inspirations are taken from [musicdsp](https://www.musicdsp.org/).
### Sine/Cosine ### ### Sine/Cosine ###
![](/articles/oscillators/sine.gif)
```c ```c
/* Intended to be executed offline with values then embedded in the binary. /* Intended to be executed offline with values then embedded in the binary.
* By having usage of glibc sin and cos functions strictly offline it's easier to have it freestanding * By having usage of glibc sin and cos functions strictly offline it's easier to have it freestanding
@ -38,6 +40,8 @@ void pump_sinewave(struct sinewave *wave) {
### Square ### ### Square ###
![](/articles/oscillators/sqrt.gif)
```c ```c
/* Implemented over sinewave */ /* Implemented over sinewave */
struct sqrtwave { struct sqrtwave {
@ -49,7 +53,9 @@ struct sqrtwave {
} init_sqrtwave(float frequency, float phase, float amplitude) { } init_sqrtwave(float frequency, float phase, float amplitude) {
struct sqrtwave r; struct sqrtwave r;
r.w = init_sinewave(frequency, phase, 1.f); r.w = init_sinewave(frequency, phase, 1.f);
r.v.f = amplitude; v.f = r.w.s;
a.f = amplitude;
r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
return r; return r;
} }
@ -68,6 +74,8 @@ void pump_sqrtwave(struct sqrtwave *wave) {
### Saw ### ### Saw ###
![](/articles/oscillators/sawt.gif)
```c ```c
struct sawtwave { struct sawtwave {
float v, a, i; float v, a, i;
@ -75,7 +83,7 @@ struct sawtwave {
struct sawtwave r; struct sawtwave r;
r.v = sinf(phase) * amplitude; r.v = sinf(phase) * amplitude;
r.a = amplitude; r.a = amplitude;
r.i = frequency / AUDIO_FRAME_RATE * amplitude; r.i = 2.f * frequency / AUDIO_FRAME_RATE * amplitude;
return r; return r;
} }
@ -83,7 +91,11 @@ struct sawtwave {
void pump_sawtwave(struct sawtwave *wave) { void pump_sawtwave(struct sawtwave *wave) {
wave->v += wave->i; wave->v += wave->i;
if (wave->v > wave->a) if (wave->v > wave->a)
wave->v -= wave->a; wave->v -= wave->a * 2.f;
} }
``` ```
### Edits ###
- Fixed initial value based on phase in sqrtwave, proper range for sawtwave.
- Added waveform gifs.

View File

@ -0,0 +1,138 @@
#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;
}

View File

@ -6,8 +6,15 @@ mkdir -p ./html/articles
./tools/main_page_generator.py ./articles | ./tools/mmd/build/multimarkdown > ./html/index.html ./tools/main_page_generator.py ./articles | ./tools/mmd/build/multimarkdown > ./html/index.html
for d in ./articles/*; do for d in ./articles/*/; do
if [ -d "$d" ]; then if [ -d "$d" ]; then
if test -f "$d/make"; then
"$d/make"
fi
if test -d "$d/.dynamic"; then
mkdir -p "./html/articles/$(basename -- $d)"
cp -r "$d/.dynamic/." "./html/articles/$(basename -- $d)/"
fi
./tools/article_wrapper.py "$d/page.mmd" | ./tools/mmd/build/multimarkdown > "./html/articles/$(basename -- $d).html" ./tools/article_wrapper.py "$d/page.mmd" | ./tools/mmd/build/multimarkdown > "./html/articles/$(basename -- $d).html"
fi fi
done done

View File

@ -57,6 +57,7 @@ for root, dirs, _ in walk(argv[1]):
f""" <link>{address}/articles/{urllib.parse.quote(d)}</link>\n""" f""" <link>{address}/articles/{urllib.parse.quote(d)}</link>\n"""
" </item>\n" " </item>\n"
) )
break
feed += """ </channel> feed += """ </channel>
</rss>""" </rss>"""

1
tools/gifenc Submodule

@ -0,0 +1 @@
Subproject commit 87acd487dfa2f2a638eec751a1d6c2fff60822da

View File

@ -38,6 +38,7 @@ for root, dirs, _ in walk(argv[1]):
) )
if "Tags" in metadata: if "Tags" in metadata:
page += f""">*{','.join(metadata["Tags"])}*\n---\n""" page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
break
curtime = time.gmtime(int(time.time())) curtime = time.gmtime(int(time.time()))
page += f"Last compiled: *{MONTHS[curtime.tm_mon]} {curtime.tm_mday}, {curtime.tm_year} {curtime.tm_hour}:{curtime.tm_min:02d} UTC*\n\n" page += f"Last compiled: *{MONTHS[curtime.tm_mon]} {curtime.tm_mday}, {curtime.tm_year} {curtime.tm_hour}:{curtime.tm_min:02d} UTC*\n\n"

View File

@ -88,6 +88,7 @@ for _, _, files in walk(argv[1]):
f""" <div><p style="display: inline;">{f[:-4]}</p><button style="float: right;" onclick="window.loadAndPlayTrack('/tracks/{f}')">play</button></div>\n""" f""" <div><p style="display: inline;">{f[:-4]}</p><button style="float: right;" onclick="window.loadAndPlayTrack('/tracks/{f}')">play</button></div>\n"""
" <hr/>\n" " <hr/>\n"
) )
break
page += """ </div> page += """ </div>
</div> </div>