Compare commits
No commits in common. "ef176941257ca7ebe33d8fb78cdfbc54463c7547" and "a3f3b3410f62afe1ec360072b9be983baf13e9d5" have entirely different histories.
ef17694125
...
a3f3b3410f
@ -1,89 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
14
compile.py
Executable file
14
compile.py
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/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
11
compile.sh
@ -1,11 +0,0 @@
|
|||||||
#!/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
|
|
@ -40,6 +40,6 @@ for root, dirs, _ in walk(argv[1]):
|
|||||||
page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
|
page += f""">*{','.join(metadata["Tags"])}*\n---\n"""
|
||||||
|
|
||||||
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}*\n\n"
|
page += f"Last compiled: *{MONTHS[curtime.tm_mon]} {curtime.tm_mday}, {curtime.tm_year} {curtime.tm_hour}:{curtime.tm_min:2}*\n\n"
|
||||||
|
|
||||||
print(page_metadata + wrap_page(page))
|
print(page_metadata + wrap_page(page))
|
||||||
|
Loading…
Reference in New Issue
Block a user