uxn

Varvara Ordinator, written in ANSI C(SDL2)
git clone https://git.eamoncaddigan.net/uxn.git
Log | Files | Refs | README | LICENSE

commit 6be1ab909d986fc695348856d40fd7e0657d7511
parent d0db60ae393489d58d9f98ea386fcb43832b5d07
Author: neauoire <aliceffekt@gmail.com>
Date:   Fri,  2 Apr 2021 11:52:29 -0700

Implemented ADSR envelopes.

Diffstat:
Mprojects/examples/dev.time.usm | 14+++++---------
Msrc/emulator.c | 72+++++++++++++++++++++++++++++++++++++++++++-----------------------------
2 files changed, 48 insertions(+), 38 deletions(-)

diff --git a/projects/examples/dev.time.usm b/projects/examples/dev.time.usm @@ -11,14 +11,13 @@ ;needles { hx 2 hy 2 mx 2 my 2 sx 2 sy 2 } ;line { x0 2 y0 2 x 2 y 2 sx 2 sy 2 dx 2 dy 2 e1 2 e2 2 } ;color { byte 1 } -;ding { volume 1 } ( devices ) |0100 ;Console { pad 8 char 1 byte 1 short 2 } |0110 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 } |0120 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 } -|0170 ;Audio { ch1asdr 2 ch2asdr 2 ch3asdr 2 ch4asdr 2 ch1pitch 1 ch1vol 1 ch2pitch 1 ch2vol 1 ch3pitch 1 ch3vol 1 ch4pitch 1 ch4vol 1 } +|0170 ;Audio { ch1adsr 2 ch2adsr 2 ch3adsr 2 ch4adsr 2 ch1pitch 1 ch1vol 1 ch2pitch 1 ch2vol 1 ch3pitch 1 ch3vol 1 ch4pitch 1 ch4vol 1 } |0190 ;Time { year 2 month 1 day 1 hour 1 minute 1 second 1 dow 1 doy 2 isdst 1 get 1 } |01F0 ;System { pad 8 r 2 g 2 b 2 } @@ -38,20 +37,17 @@ BRK @FRAME - ~ding.volume - DUP #00 EQU ^$keep JNZ - DUP #04 SUB =ding.volume - $keep - =Audio.ch1vol - #00 =Time.get ( only draw once per second ) ~Time.second ~current.second NEQ #01 JNZ BRK ~Time.second =current.second + ~Time.second #03 AND ^$no-sound JNZ + #ffff =Audio.ch1adsr ~Time.second #1d ADD =Audio.ch1pitch - #fc =ding.volume + #ff =Audio.ch1vol + $no-sound ( clear ) #0080 SCALEX #0080 SCALEY ~needles.sx ~needles.sy #00 ,draw-line JSR2 diff --git a/src/emulator.c b/src/emulator.c @@ -51,26 +51,25 @@ Uint8 font[][8] = { #define SAMPLE_FREQUENCY 48000 -static Uint32 note_periods[12] = { - /* middle C (C4) is note 60 */ - (Uint32)0xfa7e * SAMPLE_FREQUENCY, /* C-1 */ - (Uint32)0xec6f * SAMPLE_FREQUENCY, - (Uint32)0xdf2a * SAMPLE_FREQUENCY, /* D-1 */ - (Uint32)0xd2a4 * SAMPLE_FREQUENCY, - (Uint32)0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */ - (Uint32)0xbba8 * SAMPLE_FREQUENCY, /* F-1 */ - (Uint32)0xb120 * SAMPLE_FREQUENCY, - (Uint32)0xa72f * SAMPLE_FREQUENCY, /* G-1 */ - (Uint32)0x9dcd * SAMPLE_FREQUENCY, - (Uint32)0x94f2 * SAMPLE_FREQUENCY, /* A-1 */ - (Uint32)0x8c95 * SAMPLE_FREQUENCY, - (Uint32)0x84b2 * SAMPLE_FREQUENCY /* B-1 */ +static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */ + (Uint32) 0xfa7e * SAMPLE_FREQUENCY, /* C-1 */ + (Uint32) 0xec6f * SAMPLE_FREQUENCY, + (Uint32) 0xdf2a * SAMPLE_FREQUENCY, /* D-1 */ + (Uint32) 0xd2a4 * SAMPLE_FREQUENCY, + (Uint32) 0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */ + (Uint32) 0xbba8 * SAMPLE_FREQUENCY, /* F-1 */ + (Uint32) 0xb120 * SAMPLE_FREQUENCY, + (Uint32) 0xa72f * SAMPLE_FREQUENCY, /* G-1 */ + (Uint32) 0x9dcd * SAMPLE_FREQUENCY, + (Uint32) 0x94f2 * SAMPLE_FREQUENCY, /* A-1 */ + (Uint32) 0x8c95 * SAMPLE_FREQUENCY, + (Uint32) 0x84b2 * SAMPLE_FREQUENCY /* B-1 */ }; static struct audio_channel { Uint32 period, count; - int value; - Sint16 volume; + Sint32 age, a, d, s, r; + Sint16 volume, value; } channels[4]; static SDL_Window *gWindow; @@ -238,26 +237,36 @@ togglezoom(Uxn *u) } void -audio_callback(void *userdata, Uint8 *stream, int len) -{ - Sint16 *samples = (Sint16 *)stream; +audio_callback(void* userdata, Uint8* stream, int len) { + Sint16 *samples = (Sint16 *) stream; int i, j; len >>= 1; /* use len for number of samples, not bytes */ - for(j = 0; j < len; ++j) samples[j] = 0; - for(i = 0; i < 4; ++i) { + for (j = 0; j < len; ++j) samples[j] = 0; + for (i = 0; i < 4; ++i) { struct audio_channel *c = &channels[i]; - if(!c->volume) continue; - if(c->period < (1 << 20)) continue; - for(j = 0; j < len; ++j) { + if (!c->volume) continue; + if (c->period < (1 << 20)) continue; + for (j = 0; j < len; ++j) { + c->age += 1; c->count += 1 << 20; - while(c->count > c->period) { - c->value = !c->value; + while (c->count > c->period) { + int mul = c->value < 0 ? c->volume : -c->volume; c->count -= c->period; + if (c->age < c->a) + c->value = mul * c->age / c->a; + else if (c->age < c->d) + c->value = mul * (2 * c->d - c->a - c->age) / 2 / (c->d - c->a); + else if (c->age < c->s) + c->value = mul / 2; + else if (c->age < c->r) + c->value = mul * (c->r - c->age) / 2 / (c->r - c->s); + else + c->volume = c->value = 0; } - samples[j] += (c->value * 2 - 1) * c->volume; + samples[j] += c->value; } } - (void)userdata; + (void) userdata; } void @@ -464,13 +473,18 @@ Uint8 audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1) { Uint8 *m = u->ram.dat; - if(b0 & 1) { + if (b0 & 1) { Uint16 channel_addr = ptr + (b0 & 0x6); struct audio_channel *c = &channels[(b0 & 0x6) >> 1]; SDL_LockAudioDevice(audio_id); c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12); c->count %= c->period; c->volume = m[channel_addr + 9] << 5; + c->age = 0; + c->a = ((m[channel_addr] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4); + c->d = c->a + (m[channel_addr] & 0xf) * (SAMPLE_FREQUENCY >> 4); + c->s = c->d + ((m[channel_addr + 1] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4); + c->r = c->s + (m[channel_addr + 1] & 0xf) * (SAMPLE_FREQUENCY >> 4); SDL_UnlockAudioDevice(audio_id); } return b1;