Formatting

This commit is contained in:
neauoire 2023-10-20 11:54:25 -04:00
parent c4ec4a6340
commit 87d6798593
3 changed files with 242 additions and 229 deletions

View File

@ -19,42 +19,44 @@ WITH REGARD TO THIS SOFTWARE.
#define INTERPOL_METHOD 1 #define INTERPOL_METHOD 1
typedef enum EnvStage { typedef enum EnvStage {
ENV_ATTACK = (1 << 0), ENV_ATTACK = (1 << 0),
ENV_DECAY = (1 << 1), ENV_DECAY = (1 << 1),
ENV_SUSTAIN = (1 << 2), ENV_SUSTAIN = (1 << 2),
ENV_RELEASE = (1 << 3), ENV_RELEASE = (1 << 3),
} EnvStage; } EnvStage;
typedef struct Envelope { typedef struct Envelope {
float a; float a;
float d; float d;
float s; float s;
float r; float r;
float vol; float vol;
EnvStage stage; EnvStage stage;
} Envelope; } Envelope;
typedef struct Sample { typedef struct Sample {
Uint8 *data; Uint8 *data;
float len; float len;
float pos; float pos;
float inc; float inc;
float loop; float loop;
Uint8 pitch; Uint8 pitch;
Envelope env; Envelope env;
} Sample; } Sample;
typedef struct AudioChannel { typedef struct AudioChannel {
Sample sample; Sample sample;
Sample next_sample; Sample next_sample;
bool xfade; bool xfade;
float duration; float duration;
float vol_l; float vol_l;
float vol_r; float vol_r;
} AudioChannel; } AudioChannel;
AudioChannel channel[POLYPHONY]; AudioChannel channel[POLYPHONY];
/* clang-format off */
const float tuning[109] = { const float tuning[109] = {
0.00058853f, 0.00062352f, 0.00066060f, 0.00069988f, 0.00074150f, 0.00058853f, 0.00062352f, 0.00066060f, 0.00069988f, 0.00074150f,
0.00078559f, 0.00083230f, 0.00088179f, 0.00093423f, 0.00098978f, 0.00078559f, 0.00083230f, 0.00088179f, 0.00093423f, 0.00098978f,
@ -80,236 +82,247 @@ const float tuning[109] = {
0.25338348f, 0.26845044f, 0.28441334f, 0.30132544f, 0.25338348f, 0.26845044f, 0.28441334f, 0.30132544f,
}; };
/* clang-format on */
void void
env_on(Envelope *env) { env_on(Envelope *env)
env->stage = ENV_ATTACK; {
env->vol = 0.0f; env->stage = ENV_ATTACK;
if (env->a > 0) { env->vol = 0.0f;
env->a = (SOUND_TIMER / AUDIO_BUFSIZE) / env->a; if(env->a > 0) {
} else if (env->stage == ENV_ATTACK) { env->a = (SOUND_TIMER / AUDIO_BUFSIZE) / env->a;
env->stage = ENV_DECAY; } else if(env->stage == ENV_ATTACK) {
env->vol = 1.0f; env->stage = ENV_DECAY;
} env->vol = 1.0f;
if (env->d < 10.0f) { }
env->d = 10.0f; if(env->d < 10.0f) {
} env->d = 10.0f;
env->d = (SOUND_TIMER / AUDIO_BUFSIZE) / env->d; }
if (env->r < 10.0f) { env->d = (SOUND_TIMER / AUDIO_BUFSIZE) / env->d;
env->r = 10.0f; if(env->r < 10.0f) {
} env->r = 10.0f;
env->r = (SOUND_TIMER / AUDIO_BUFSIZE) / env->r; }
env->r = (SOUND_TIMER / AUDIO_BUFSIZE) / env->r;
} }
void void
env_off(Envelope *env) { env_off(Envelope *env)
env->stage = ENV_RELEASE; {
env->stage = ENV_RELEASE;
} }
void void
note_on(AudioChannel *channel, Uint16 duration, Uint8 *data, Uint16 len, Uint8 vol, note_on(AudioChannel *channel, Uint16 duration, Uint8 *data, Uint16 len, Uint8 vol, Uint8 attack, Uint8 decay, Uint8 sustain, Uint8 release, Uint8 pitch, bool loop)
Uint8 attack, Uint8 decay, Uint8 sustain, Uint8 release, Uint8 pitch, bool loop) { {
channel->duration = duration > 0 ? duration : len / 44.1f; channel->duration = duration > 0 ? duration : len / 44.1f;
channel->vol_l = (vol >> 4) / 15.0f; channel->vol_l = (vol >> 4) / 15.0f;
channel->vol_r = (vol & 0xf) / 15.0f; channel->vol_r = (vol & 0xf) / 15.0f;
Sample sample = {0}; Sample sample = {0};
sample.data = data; sample.data = data;
sample.len = len; sample.len = len;
sample.pos = 0; sample.pos = 0;
sample.env.a = attack * 64.0f; sample.env.a = attack * 64.0f;
sample.env.d = decay * 64.0f; sample.env.d = decay * 64.0f;
sample.env.s = sustain / 16.0f; sample.env.s = sustain / 16.0f;
sample.env.r = release * 64.0f; sample.env.r = release * 64.0f;
if (loop) { if(loop) {
sample.loop = len; sample.loop = len;
} else { } else {
sample.loop = 0; sample.loop = 0;
} }
env_on(&sample.env); env_on(&sample.env);
if (pitch < 20) { if(pitch < 20) {
pitch = 20; pitch = 20;
} }
float sample_rate = 44100 / 261.60; float sample_rate = 44100 / 261.60;
if (len <= 256) { if(len <= 256) {
sample_rate = len; sample_rate = len;
} }
const float *inc = &tuning[pitch - 20]; const float *inc = &tuning[pitch - 20];
sample.inc = *(inc) * sample_rate; sample.inc = *(inc)*sample_rate;
channel->next_sample = sample; channel->next_sample = sample;
channel->xfade = true; channel->xfade = true;
} }
void void
note_off(AudioChannel *channel, Uint16 duration) { note_off(AudioChannel *channel, Uint16 duration)
channel->duration = duration; {
env_off(&channel->sample.env); channel->duration = duration;
env_off(&channel->sample.env);
} }
void void
env_advance(Envelope *env) { env_advance(Envelope *env)
switch (env->stage) { {
case ENV_ATTACK: { switch(env->stage) {
env->vol += env->a; case ENV_ATTACK: {
if (env->vol >= 1.0f) { env->vol += env->a;
env->stage = ENV_DECAY; if(env->vol >= 1.0f) {
env->vol = 1.0f; env->stage = ENV_DECAY;
} env->vol = 1.0f;
} break; }
case ENV_DECAY: { } break;
env->vol -= env->d; case ENV_DECAY: {
if (env->vol <= env->s || env->d <= 0) { env->vol -= env->d;
env->stage = ENV_SUSTAIN; if(env->vol <= env->s || env->d <= 0) {
env->vol = env->s; env->stage = ENV_SUSTAIN;
} env->vol = env->s;
} break; }
case ENV_SUSTAIN: { } break;
env->vol = env->s; case ENV_SUSTAIN: {
} break; env->vol = env->s;
case ENV_RELEASE: { } break;
if (env->vol <= 0 || env->r <= 0) { case ENV_RELEASE: {
env->vol = 0; if(env->vol <= 0 || env->r <= 0) {
} else { env->vol = 0;
env->vol -= env->r; } else {
} env->vol -= env->r;
} break; }
} } break;
}
} }
float float
interpolate_sample(Uint8 *data, Uint16 len, float pos) { interpolate_sample(Uint8 *data, Uint16 len, float pos)
{
#if INTERPOL_METHOD == 0 #if INTERPOL_METHOD == 0
return data[(int)pos]; return data[(int)pos];
#elif INTERPOL_METHOD == 1 #elif INTERPOL_METHOD == 1
float x = pos; float x = pos;
int x0 = (int)x; int x0 = (int)x;
int x1 = (x0 + 1); int x1 = (x0 + 1);
float y0 = data[x0]; float y0 = data[x0];
float y1 = data[x1 % len]; float y1 = data[x1 % len];
x = x - x0; x = x - x0;
float y = y0 + x * (y1 - y0); float y = y0 + x * (y1 - y0);
return y; return y;
#elif INTERPOL_METHOD == 2 #elif INTERPOL_METHOD == 2
float x = pos; float x = pos;
int x0 = x - 1; int x0 = x - 1;
int x1 = x; int x1 = x;
int x2 = x + 1; int x2 = x + 1;
int x3 = x + 2; int x3 = x + 2;
float y0 = data[x0 % len]; float y0 = data[x0 % len];
float y1 = data[x1]; float y1 = data[x1];
float y2 = data[x2 % len]; float y2 = data[x2 % len];
float y3 = data[x3 % len]; float y3 = data[x3 % len];
x = x - x1; x = x - x1;
float c0 = y1; float c0 = y1;
float c1 = 0.5f * (y2 - y0); float c1 = 0.5f * (y2 - y0);
float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3; float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;
float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0); float c3 = 1.5f * (y1 - y2) + 0.5f * (y3 - y0);
return ((c3 * x + c2) * x + c1) * x + c0; return ((c3 * x + c2) * x + c1) * x + c0;
#endif #endif
} }
Sint16 Sint16
next_sample(Sample *sample) { next_sample(Sample *sample)
if (sample->pos >= sample->len) { {
if (sample->loop == 0) { if(sample->pos >= sample->len) {
sample->data = 0; if(sample->loop == 0) {
return 0; sample->data = 0;
} return 0;
while (sample->pos >= sample->len) { }
sample->pos -= sample->loop; while(sample->pos >= sample->len) {
} sample->pos -= sample->loop;
} }
}
float val = interpolate_sample(sample->data, sample->len, sample->pos); float val = interpolate_sample(sample->data, sample->len, sample->pos);
val *= sample->env.vol; val *= sample->env.vol;
Sint8 next = (Sint8)0x80 ^ (Uint8)val; Sint8 next = (Sint8)0x80 ^ (Uint8)val;
sample->pos += sample->inc; sample->pos += sample->inc;
env_advance(&sample->env); env_advance(&sample->env);
return next; return next;
} }
void void
audio_handler(void *ctx, Uint8 *out_stream, int len) { audio_handler(void *ctx, Uint8 *out_stream, int len)
Sint16 *stream = (Sint16 *)out_stream; {
memset(stream, 0x00, len); Sint16 *stream = (Sint16 *)out_stream;
memset(stream, 0x00, len);
int n; int n;
for (n = 0; n < POLYPHONY; n++) { for(n = 0; n < POLYPHONY; n++) {
Uint8 device = (3 + n) << 4; Uint8 device = (3 + n) << 4;
Uxn *u = (Uxn *)ctx; Uxn *u = (Uxn *)ctx;
Uint8 *addr = &u->dev[device]; Uint8 *addr = &u->dev[device];
if (channel[n].duration <= 0 && PEEK2(addr)) { if(channel[n].duration <= 0 && PEEK2(addr)) {
uxn_eval(u, PEEK2(addr)); uxn_eval(u, PEEK2(addr));
} }
channel[n].duration -= SOUND_TIMER; channel[n].duration -= SOUND_TIMER;
int x = 0; int x = 0;
if (channel[n].xfade) { if(channel[n].xfade) {
float delta = 1.0f / (XFADE_SAMPLES * 2); float delta = 1.0f / (XFADE_SAMPLES * 2);
while (x < XFADE_SAMPLES * 2) { while(x < XFADE_SAMPLES * 2) {
float alpha = x * delta; float alpha = x * delta;
float beta = 1.0f - alpha; float beta = 1.0f - alpha;
Sint16 next_a = next_sample(&channel[n].next_sample); Sint16 next_a = next_sample(&channel[n].next_sample);
Sint16 next_b = 0; Sint16 next_b = 0;
if (channel[n].sample.data != 0) { if(channel[n].sample.data != 0) {
next_b = next_sample(&channel[n].sample); next_b = next_sample(&channel[n].sample);
} }
Sint16 next = alpha * next_a + beta * next_b; Sint16 next = alpha * next_a + beta * next_b;
stream[x++] += next * channel[n].vol_l; stream[x++] += next * channel[n].vol_l;
stream[x++] += next * channel[n].vol_r; stream[x++] += next * channel[n].vol_r;
} }
channel[n].sample = channel[n].next_sample; channel[n].sample = channel[n].next_sample;
channel[n].xfade = false; channel[n].xfade = false;
} }
Sample *sample = &channel[n].sample; Sample *sample = &channel[n].sample;
while (x < len / 2) { while(x < len / 2) {
if (sample->data == 0) { if(sample->data == 0) {
break; break;
} }
Sint16 next = next_sample(sample); Sint16 next = next_sample(sample);
stream[x++] += next * channel[n].vol_l; stream[x++] += next * channel[n].vol_l;
stream[x++] += next * channel[n].vol_r; stream[x++] += next * channel[n].vol_r;
} }
} }
int i; int i;
for (i = 0; i < len / 2; i++) { for(i = 0; i < len / 2; i++) {
stream[i] <<= 6; stream[i] <<= 6;
} }
} }
void void
audio_start(int idx, Uint8 *d, Uxn *u) audio_start(int idx, Uint8 *d, Uxn *u)
{ {
Uint16 duration = PEEK2(d + 0x5); Uint16 duration = PEEK2(d + 0x5);
Uint8 off = d[0xf] == 0x00; Uint8 off = d[0xf] == 0x00;
if (!off) { if(!off) {
Uint16 addr = PEEK2(d + 0xc); Uint16 addr = PEEK2(d + 0xc);
Uint8 *data = &u->ram[addr]; Uint8 *data = &u->ram[addr];
Uint16 len = PEEK2(d + 0xa); Uint16 len = PEEK2(d + 0xa);
Uint8 volume = d[0xe]; Uint8 volume = d[0xe];
bool loop = !(d[0xf] & 0x80); bool loop = !(d[0xf] & 0x80);
Uint8 pitch = d[0xf] & 0x7f; Uint8 pitch = d[0xf] & 0x7f;
Uint16 adsr = PEEK2(d + 0x8); Uint16 adsr = PEEK2(d + 0x8);
Uint8 attack = (adsr >> 12) & 0xF; Uint8 attack = (adsr >> 12) & 0xF;
Uint8 decay = (adsr >> 8) & 0xF; Uint8 decay = (adsr >> 8) & 0xF;
Uint8 sustain = (adsr >> 4) & 0xF; Uint8 sustain = (adsr >> 4) & 0xF;
Uint8 release = (adsr >> 0) & 0xF; Uint8 release = (adsr >> 0) & 0xF;
note_on(&channel[idx], duration, data, len, volume, attack, decay, sustain, release, pitch, loop); note_on(&channel[idx], duration, data, len, volume, attack, decay, sustain, release, pitch, loop);
} else { } else {
note_off(&channel[idx], duration); note_off(&channel[idx], duration);
} }
} }
Uint8 Uint8
audio_get_vu(int instance) { audio_get_vu(int instance)
return channel[instance].sample.env.vol * 255.0f; {
return channel[instance].sample.env.vol * 255.0f;
} }
Uint16 Uint16
audio_get_position(int instance) { audio_get_position(int instance)
return channel[instance].sample.pos; {
return channel[instance].sample.pos;
} }

View File

@ -64,7 +64,7 @@ emu_end(Uxn *u)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
Uint8 dev[0x100] = {0}; Uint8 dev[0x100] = {0};
Uxn u; Uxn u;
u.dev = (Uint8 *)&dev; u.dev = (Uint8 *)&dev;
int i = 1; int i = 1;

View File

@ -70,20 +70,20 @@ clamp(int v, int min, int max)
static Uint8 static Uint8
audio_dei(int instance, Uint8 *d, Uint8 port) audio_dei(int instance, Uint8 *d, Uint8 port)
{ {
switch(port) { switch(port) {
case 0x2: case 0x2:
return audio_get_position(instance) >> 8; return audio_get_position(instance) >> 8;
case 0x3: case 0x3:
return audio_get_position(instance); return audio_get_position(instance);
case 0x4: case 0x4:
return audio_get_vu(instance); return audio_get_vu(instance);
case 0x0: case 0x0:
case 0x8: case 0x8:
case 0xa: case 0xa:
case 0xc: return PEEK2(d + port); case 0xc: return PEEK2(d + port);
default: return d[port]; default: return d[port];
} }
return d[port]; return d[port];
} }
static void static void
@ -94,7 +94,7 @@ audio_deo(int instance, Uint8 *d, Uint8 port, Uxn *u)
SDL_LockAudioDevice(audio_id); SDL_LockAudioDevice(audio_id);
audio_start(instance, d, u); audio_start(instance, d, u);
SDL_UnlockAudioDevice(audio_id); SDL_UnlockAudioDevice(audio_id);
SDL_PauseAudioDevice(audio_id, 0); SDL_PauseAudioDevice(audio_id, 0);
} }
} }
@ -271,7 +271,7 @@ emu_init(Uxn *u)
deadline_interval = ms_interval * TIMEOUT_MS; deadline_interval = ms_interval * TIMEOUT_MS;
exec_deadline = SDL_GetPerformanceCounter() + deadline_interval; exec_deadline = SDL_GetPerformanceCounter() + deadline_interval;
screen_resize(WIDTH, HEIGHT); screen_resize(WIDTH, HEIGHT);
SDL_PauseAudioDevice(audio_id, 1); SDL_PauseAudioDevice(audio_id, 1);
return 1; return 1;
} }
@ -514,7 +514,7 @@ emu_run(Uxn *u, char *rom)
static int static int
emu_end(Uxn *u) emu_end(Uxn *u)
{ {
SDL_CloseAudioDevice(audio_id); SDL_CloseAudioDevice(audio_id);
#ifdef _WIN32 #ifdef _WIN32
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
TerminateThread((HANDLE)SDL_GetThreadID(stdin_thread), 0); TerminateThread((HANDLE)SDL_GetThreadID(stdin_thread), 0);
@ -529,7 +529,7 @@ emu_end(Uxn *u)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
Uint8 dev[0x100] = {0}; Uint8 dev[0x100] = {0};
Uxn u = {0}; Uxn u = {0};
Uxn u_audio = {0}; Uxn u_audio = {0};
u.dev = (Uint8 *)&dev; u.dev = (Uint8 *)&dev;
@ -555,10 +555,10 @@ main(int argc, char **argv)
char *rom = argv[i++]; char *rom = argv[i++];
if(!system_init(&u, ram, rom)) { if(!system_init(&u, ram, rom)) {
return system_error("Init", "Failed to initialize uxn."); return system_error("Init", "Failed to initialize uxn.");
} }
if(!system_init(&u_audio, ram, rom)) { if(!system_init(&u_audio, ram, rom)) {
return system_error("Init", "Failed to initialize uxn."); return system_error("Init", "Failed to initialize uxn.");
} }
if(!emu_init(&u_audio)) if(!emu_init(&u_audio))
return system_error("Init", "Failed to initialize varvara."); return system_error("Init", "Failed to initialize varvara.");
/* Game Loop */ /* Game Loop */