Compare commits

...

3 Commits

Author SHA1 Message Date
veclav talica
ef17694125 oscillators article 2023-05-22 14:43:09 +05:00
veclav talica
a4bfe111cf fix time formatting 2023-05-22 14:11:24 +05:00
veclav talica
8249280b03 shell script based compilation 2023-05-22 14:11:10 +05:00
4 changed files with 101 additions and 15 deletions

View File

@ -0,0 +1,89 @@
Title: Programmatic Oscillators
Brief: Sine, cosine, saw and square oscillators with minimal binary footprint.
Date: 1684748529
Tags: Programming, Music, C
CSS: /style.css
Wanted to have some beep bops for my [4mb-jam](https://itch.io/jam/4mb-jam-2023) entry, so
I ended up with implementations of three oscillators that would require minimal amount of calculations.
Idea is to precalculate initial state offline and only have short frame generation procedure in final binary.
Thinking about using it in tracker format of sorts that would have runtime generated samples.
Inspirations are taken from [musicdsp](https://www.musicdsp.org/).
### Sine/Cosine ###
```c
/* 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
*/
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 / AUDIO_FRAME_RATE);
r.s = amplitude * sinf(phase);
r.c = amplitude * cosf(phase);
return r;
}
/* Use `s` for sine value and `c` for cosine on caller side */
void pump_sinewave(struct sinewave *wave) {
wave->s -= wave->f * wave->c;
wave->c += wave->f * wave->s;
}
```
### Square ###
```c
/* Implemented over sinewave */
struct sqrtwave {
struct sinewave w;
union {
float f;
uint32_t u;
} v;
} init_sqrtwave(float frequency, float phase, float amplitude) {
struct sqrtwave r;
r.w = init_sinewave(frequency, phase, 1.f);
r.v.f = amplitude;
return r;
}
/* Use floating point bit representation to infer sign, all other bits are set to amplitude */
void 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);
}
```
### Saw ###
```c
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 = frequency / AUDIO_FRAME_RATE * amplitude;
return r;
}
/* Simple amplitude overflow check with truncation */
void pump_sawtwave(struct sawtwave *wave) {
wave->v += wave->i;
if (wave->v > wave->a)
wave->v -= wave->a;
}
```

View File

@ -1,14 +0,0 @@
#!/usr/bin/python3
from os import walk
import subprocess
subprocess.run("./tools/main_page_generator.py ./articles | ./tools/mmd/build/multimarkdown > ./html/index.html", shell=True)
subprocess.run("mkdir -p ./html/articles", shell=True)
for root, dirs, _ in walk("./articles"):
for d in dirs:
subprocess.run(
f"""./tools/article_wrapper.py ./articles/{d}/page.mmd | ./tools/mmd/build/multimarkdown > ./html/articles/{d}.html""",
shell=True
)

11
compile.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
mkdir -p ./html/articles
./tools/main_page_generator.py ./articles | ./tools/mmd/build/multimarkdown > ./html/index.html
for d in ./articles/*; do
if [ -d "$d" ]; then
./tools/article_wrapper.py "$d/page.mmd" | ./tools/mmd/build/multimarkdown > "./html/articles/$(basename -- $d).html"
fi
done

View File

@ -40,6 +40,6 @@ for root, dirs, _ in walk(argv[1]):
page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
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:2}*\n\n"
page += f"Last compiled: *{MONTHS[curtime.tm_mon]} {curtime.tm_mday}, {curtime.tm_year} {curtime.tm_hour}:{curtime.tm_min:02d}*\n\n"
print(page_metadata + wrap_page(page))