Browse code

Implemented ADSR envelopes.

Andrew Alderwick authored on 02/04/2021 18:26:50
Showing 2 changed files
... ...
@@ -11,14 +11,13 @@
11 11
 ;needles { hx 2 hy 2 mx 2 my 2 sx 2 sy 2 }
12 12
 ;line { x0 2 y0 2 x 2 y 2 sx 2 sy 2 dx 2 dy 2 e1 2 e2 2 }
13 13
 ;color { byte 1 }
14
-;ding { volume 1 }
15 14
 
16 15
 ( devices )
17 16
 
18 17
 |0100 ;Console { pad 8 char 1 byte 1 short 2 }
19 18
 |0110 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 }
20 19
 |0120 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 }
21
-|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 }
20
+|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 }
22 21
 |0190 ;Time { year 2 month 1 day 1 hour 1 minute 1 second 1 dow 1 doy 2 isdst 1 get 1 }
23 22
 |01F0 ;System { pad 8 r 2 g 2 b 2 }
24 23
 
... ...
@@ -38,20 +37,17 @@ BRK
38 37
 
39 38
 @FRAME
40 39
 	
41
-	~ding.volume
42
-	DUP #00 EQU ^$keep JNZ
43
-	DUP #04 SUB =ding.volume
44
-	$keep
45
-	=Audio.ch1vol
46
-
47 40
 	#00 =Time.get
48 41
 
49 42
 	( only draw once per second )
50 43
 	~Time.second ~current.second NEQ #01 JNZ BRK
51 44
 	~Time.second =current.second
52 45
 
46
+	~Time.second #03 AND ^$no-sound JNZ
47
+	#ffff =Audio.ch1adsr
53 48
 	~Time.second #1d ADD =Audio.ch1pitch
54
-	#fc =ding.volume
49
+	#ff =Audio.ch1vol
50
+	$no-sound
55 51
 
56 52
 	( clear )
57 53
 	#0080 SCALEX #0080 SCALEY ~needles.sx ~needles.sy #00 ,draw-line JSR2
... ...
@@ -68,8 +68,8 @@ static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */
68 68
 
69 69
 static struct audio_channel {
70 70
 	Uint32 period, count;
71
-	int value;
72
-	Sint16 volume;
71
+	Sint32 age, a, d, s, r;
72
+	Sint16 volume, value;
73 73
 } channels[4];
74 74
 
75 75
 static SDL_Window *gWindow;
... ...
@@ -247,12 +247,23 @@ audio_callback(void* userdata, Uint8* stream, int len) {
247 247
 		if (!c->volume) continue;
248 248
 		if (c->period < (1 << 20)) continue;
249 249
 		for (j = 0; j < len; ++j) {
250
+			c->age += 1;
250 251
 			c->count += 1 << 20;
251 252
 			while (c->count > c->period) {
252
-				c->value = !c->value;
253
+				int mul = c->value < 0 ? c->volume : -c->volume;
253 254
 				c->count -= c->period;
255
+				if (c->age < c->a)
256
+					c->value = mul * c->age / c->a;
257
+				else if (c->age < c->d)
258
+					c->value = mul * (2 * c->d - c->a - c->age) / 2 / (c->d - c->a);
259
+				else if (c->age < c->s)
260
+					c->value = mul / 2;
261
+				else if (c->age < c->r)
262
+					c->value = mul * (c->r - c->age) / 2 / (c->r - c->s);
263
+				else
264
+					c->volume = c->value = 0;
254 265
 			}
255
-			samples[j] += (c->value * 2 - 1) * c->volume;
266
+			samples[j] += c->value;
256 267
 		}
257 268
 	}
258 269
 	(void) userdata;
... ...
@@ -469,6 +480,11 @@ audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
469 480
 		c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12);
470 481
 		c->count %= c->period;
471 482
 		c->volume = m[channel_addr + 9] << 5;
483
+		c->age = 0;
484
+		c->a = ((m[channel_addr] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4);
485
+		c->d = c->a + (m[channel_addr] & 0xf) * (SAMPLE_FREQUENCY >> 4);
486
+		c->s = c->d + ((m[channel_addr + 1] >> 4) & 0xf) * (SAMPLE_FREQUENCY >> 4);
487
+		c->r = c->s + (m[channel_addr + 1] & 0xf) * (SAMPLE_FREQUENCY >> 4);
472 488
 		SDL_UnlockAudioDevice(audio_id);
473 489
 	}
474 490
 	return b1;