commit e39ed74796041eb6167dec30ebb9135c31531f88
parent 8a8960debe777381cb931b8062d62bc232c80bd1
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date: Fri, 2 Apr 2021 19:26:50 +0100
Implemented ADSR envelopes.
Diffstat:
2 files changed, 25 insertions(+), 13 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
@@ -68,8 +68,8 @@ static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */
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;
@@ -247,12 +247,23 @@ audio_callback(void* userdata, Uint8* stream, int len) {
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;
+ 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;
@@ -469,6 +480,11 @@ audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
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;