Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
150 lines (133 loc) · 5.51 KB

File metadata and controls

150 lines (133 loc) · 5.51 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// ============================================================
// CardputerGroovebox - wavetable.cpp
// ============================================================
#include "wavetable.h"
#include "sampler.h" // reuse WAV parsing helpers
#include <SD.h>
#include <math.h>
#include <string.h>
int16_t g_wavetables[NUM_WT_TOTAL][WT_SIZE];
char g_wtNames[NUM_WT_TOTAL][WT_NAME_LEN];
uint8_t g_numWavetables = 0;
static void normalizeTable(float* buf) {
float peak = 0.0001f;
for (int i = 0; i < WT_SIZE; i++) {
float a = fabsf(buf[i]);
if (a > peak) peak = a;
}
float g = 0.98f / peak;
for (int i = 0; i < WT_SIZE; i++) buf[i] *= g;
}
static void commitTable(int slot, const float* buf, const char* name) {
for (int i = 0; i < WT_SIZE; i++)
g_wavetables[slot][i] = (int16_t)(buf[i] * 32767.0f);
strncpy(g_wtNames[slot], name, WT_NAME_LEN - 1);
g_wtNames[slot][WT_NAME_LEN - 1] = 0;
}
void wavetableInitBuiltins() {
float buf[WT_SIZE];
float ph;
// 0: ORGAN - harmonics 1,2,4,8
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
buf[i] = sinf(ph) + 0.5f * sinf(2*ph) + 0.35f * sinf(4*ph) + 0.2f * sinf(8*ph);
}
normalizeTable(buf); commitTable(0, buf, "ORGAN");
// 1: SOFTSAW - band-limited saw (8 harmonics)
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
float s = 0;
for (int h = 1; h <= 8; h++) s += sinf(h * ph) / (float)h;
buf[i] = s;
}
normalizeTable(buf); commitTable(1, buf, "SOFTSAW");
// 2: PWM25 - band-limited 25% pulse (odd/even mix via harmonic series)
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
float s = 0;
for (int h = 1; h <= 10; h++)
s += (2.0f / (h * 3.14159f)) * sinf(h * 3.14159f * 0.25f) * cosf(h * ph);
buf[i] = s;
}
normalizeTable(buf); commitTable(2, buf, "PWM25");
// 3: BELL - inharmonic partials
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
buf[i] = sinf(ph) + 0.6f * sinf(2.76f * ph) + 0.4f * sinf(5.4f * ph) + 0.25f * sinf(8.93f * ph);
}
normalizeTable(buf); commitTable(3, buf, "BELL");
// 4: FORMANT - vowel-ish resonant bumps
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
buf[i] = sinf(ph) + 0.7f * sinf(3*ph) * (0.5f + 0.5f * sinf(ph))
+ 0.5f * sinf(5*ph) * (0.5f + 0.5f * cosf(2*ph));
}
normalizeTable(buf); commitTable(4, buf, "FORMANT");
// 5: METAL - high odd partials, gritty
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
buf[i] = sinf(ph) + 0.8f * sinf(7*ph) + 0.6f * sinf(11*ph) + 0.4f * sinf(13*ph);
}
normalizeTable(buf); commitTable(5, buf, "METAL");
// 6: FOLDSIN - waveshaped (folded) sine, rich and warm
for (int i = 0; i < WT_SIZE; i++) {
ph = TWO_PI_F * (float)i / WT_SIZE;
buf[i] = sinf(1.8f * sinf(ph) * 3.14159f * 0.5f);
}
normalizeTable(buf); commitTable(6, buf, "FOLDSIN");
// 7: GRIT - fixed pseudo-random cycle (deterministic seed), lo-fi digital
{
uint32_t seed = 0xC0FFEE42;
float last = 0;
for (int i = 0; i < WT_SIZE; i++) {
seed = seed * 1664525u + 1013904223u;
float n = ((float)(seed >> 16) / 32768.0f) - 1.0f;
last = last * 0.7f + n * 0.3f; // slight smoothing
buf[i] = last + 0.5f * sinf(TWO_PI_F * (float)i / WT_SIZE);
}
// remove DC
float dc = 0; for (int i = 0; i < WT_SIZE; i++) dc += buf[i];
dc /= WT_SIZE; for (int i = 0; i < WT_SIZE; i++) buf[i] -= dc;
normalizeTable(buf); commitTable(7, buf, "GRIT");
}
g_numWavetables = NUM_BUILTIN_WT;
}
void wavetableLoadUserFromSD() {
File dir = SD.open(DIR_WAVETABLES);
if (!dir || !dir.isDirectory()) return;
// temp buffer for decoded wav (single cycle files are small; cap 4096 frames)
const int MAXF = 4096;
static int16_t tmp[MAXF];
File f = dir.openNextFile();
while (f && g_numWavetables < NUM_WT_TOTAL) {
String nm = f.name();
int slash = nm.lastIndexOf('/');
if (slash >= 0) nm = nm.substring(slash + 1);
if (!f.isDirectory() && (nm.endsWith(".wav") || nm.endsWith(".WAV"))) {
uint32_t frames = 0, rate = 0;
if (wavDecodeToMono16(f, tmp, MAXF, frames, rate) && frames >= 8) {
// resample whole file (assumed single cycle) to WT_SIZE
float buf[WT_SIZE];
for (int i = 0; i < WT_SIZE; i++) {
float pos = (float)i * (float)frames / (float)WT_SIZE;
uint32_t a = (uint32_t)pos;
float fr = pos - a;
uint32_t b = (a + 1 < frames) ? a + 1 : 0;
buf[i] = ((float)tmp[a] * (1.0f - fr) + (float)tmp[b] * fr) / 32768.0f;
}
// remove DC + normalize
float dc = 0; for (int i = 0; i < WT_SIZE; i++) dc += buf[i];
dc /= WT_SIZE; for (int i = 0; i < WT_SIZE; i++) buf[i] -= dc;
normalizeTable(buf);
// strip extension for name
int dot = nm.lastIndexOf('.');
String base = (dot > 0) ? nm.substring(0, dot) : nm;
commitTable(g_numWavetables, buf, base.c_str());
g_numWavetables++;
}
}
f.close();
f = dir.openNextFile();
}
dir.close();
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.