Browse code

Implemented ADSR envelopes.

neauoire authored on 02/04/2021 18:52:29
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
... ...
@@ -51,26 +51,25 @@ Uint8 font[][8] = {
51 51
 
52 52
 #define SAMPLE_FREQUENCY 48000
53 53
 
54
-static Uint32 note_periods[12] = {
55
-	/* middle C (C4) is note 60 */
56
-	(Uint32)0xfa7e * SAMPLE_FREQUENCY, /* C-1 */
57
-	(Uint32)0xec6f * SAMPLE_FREQUENCY,
58
-	(Uint32)0xdf2a * SAMPLE_FREQUENCY, /* D-1 */
59
-	(Uint32)0xd2a4 * SAMPLE_FREQUENCY,
60
-	(Uint32)0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */
61
-	(Uint32)0xbba8 * SAMPLE_FREQUENCY, /* F-1 */
62
-	(Uint32)0xb120 * SAMPLE_FREQUENCY,
63
-	(Uint32)0xa72f * SAMPLE_FREQUENCY, /* G-1 */
64
-	(Uint32)0x9dcd * SAMPLE_FREQUENCY,
65
-	(Uint32)0x94f2 * SAMPLE_FREQUENCY, /* A-1 */
66
-	(Uint32)0x8c95 * SAMPLE_FREQUENCY,
67
-	(Uint32)0x84b2 * SAMPLE_FREQUENCY /* B-1 */
54
+static Uint32 note_periods[12] = { /* middle C (C4) is note 60 */
55
+	(Uint32) 0xfa7e * SAMPLE_FREQUENCY, /* C-1 */
56
+	(Uint32) 0xec6f * SAMPLE_FREQUENCY,
57
+	(Uint32) 0xdf2a * SAMPLE_FREQUENCY, /* D-1 */
58
+	(Uint32) 0xd2a4 * SAMPLE_FREQUENCY,
59
+	(Uint32) 0xc6d1 * SAMPLE_FREQUENCY, /* E-1 */
60
+	(Uint32) 0xbba8 * SAMPLE_FREQUENCY, /* F-1 */
61
+	(Uint32) 0xb120 * SAMPLE_FREQUENCY,
62
+	(Uint32) 0xa72f * SAMPLE_FREQUENCY, /* G-1 */
63
+	(Uint32) 0x9dcd * SAMPLE_FREQUENCY,
64
+	(Uint32) 0x94f2 * SAMPLE_FREQUENCY, /* A-1 */
65
+	(Uint32) 0x8c95 * SAMPLE_FREQUENCY,
66
+	(Uint32) 0x84b2 * SAMPLE_FREQUENCY  /* B-1 */
68 67
 };
69 68
 
70 69
 static struct audio_channel {
71 70
 	Uint32 period, count;
72
-	int value;
73
-	Sint16 volume;
71
+	Sint32 age, a, d, s, r;
72
+	Sint16 volume, value;
74 73
 } channels[4];
75 74
 
76 75
 static SDL_Window *gWindow;
... ...
@@ -238,26 +237,36 @@ togglezoom(Uxn *u)
238 237
 }
239 238
 
240 239
 void
241
-audio_callback(void *userdata, Uint8 *stream, int len)
242
-{
243
-	Sint16 *samples = (Sint16 *)stream;
240
+audio_callback(void* userdata, Uint8* stream, int len) {
241
+	Sint16 *samples = (Sint16 *) stream;
244 242
 	int i, j;
245 243
 	len >>= 1; /* use len for number of samples, not bytes */
246
-	for(j = 0; j < len; ++j) samples[j] = 0;
247
-	for(i = 0; i < 4; ++i) {
244
+	for (j = 0; j < len; ++j) samples[j] = 0;
245
+	for (i = 0; i < 4; ++i) {
248 246
 		struct audio_channel *c = &channels[i];
249
-		if(!c->volume) continue;
250
-		if(c->period < (1 << 20)) continue;
251
-		for(j = 0; j < len; ++j) {
247
+		if (!c->volume) continue;
248
+		if (c->period < (1 << 20)) continue;
249
+		for (j = 0; j < len; ++j) {
250
+			c->age += 1;
252 251
 			c->count += 1 << 20;
253
-			while(c->count > c->period) {
254
-				c->value = !c->value;
252
+			while (c->count > c->period) {
253
+				int mul = c->value < 0 ? c->volume : -c->volume;
255 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;
256 265
 			}
257
-			samples[j] += (c->value * 2 - 1) * c->volume;
266
+			samples[j] += c->value;
258 267
 		}
259 268
 	}
260
-	(void)userdata;
269
+	(void) userdata;
261 270
 }
262 271
 
263 272
 void
... ...
@@ -464,13 +473,18 @@ Uint8
464 473
 audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
465 474
 {
466 475
 	Uint8 *m = u->ram.dat;
467
-	if(b0 & 1) {
476
+	if (b0 & 1) {
468 477
 		Uint16 channel_addr = ptr + (b0 & 0x6);
469 478
 		struct audio_channel *c = &channels[(b0 & 0x6) >> 1];
470 479
 		SDL_LockAudioDevice(audio_id);
471 480
 		c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12);
472 481
 		c->count %= c->period;
473 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);
474 488
 		SDL_UnlockAudioDevice(audio_id);
475 489
 	}
476 490
 	return b1;