Browse code

Added square wave audio, no ASDR support yet.

Andrew Alderwick authored on 02/04/2021 15:05:08
Showing 1 changed files
... ...
@@ -49,11 +49,35 @@ Uint8 font[][8] = {
49 49
 	{0x00, 0x7e, 0x40, 0x7c, 0x40, 0x40, 0x7e, 0x00},
50 50
 	{0x00, 0x7e, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x00}};
51 51
 
52
+#define SAMPLE_FREQUENCY 48000
53
+
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 */
67
+};
68
+
69
+static struct audio_channel {
70
+	Uint32 period, count;
71
+	int value;
72
+	Sint16 volume;
73
+} channels[4];
74
+
52 75
 static SDL_Window *gWindow;
53 76
 static SDL_Renderer *gRenderer;
54 77
 static SDL_Texture *gTexture;
78
+static SDL_AudioDeviceID audio_id;
55 79
 static Screen screen;
56
-static Device *devscreen, *devmouse, *devkey, *devctrl;
80
+static Device *devscreen, *devmouse, *devkey, *devctrl, *devaudio;
57 81
 
58 82
 #pragma mark - Helpers
59 83
 
... ...
@@ -212,6 +236,28 @@ togglezoom(Uxn *u)
212 236
 	redraw(pixels, u);
213 237
 }
214 238
 
239
+void
240
+audio_callback(void* userdata, Uint8* stream, int len) {
241
+	Sint16 *samples = (Sint16 *) stream;
242
+	int i, j;
243
+	len >>= 1; /* use len for number of samples, not bytes */
244
+	for (j = 0; j < len; ++j) samples[j] = 0;
245
+	for (i = 0; i < 4; ++i) {
246
+		struct audio_channel *c = &channels[i];
247
+		if (!c->volume) continue;
248
+		if (c->period < (1 << 20)) continue;
249
+		for (j = 0; j < len; ++j) {
250
+			c->count += 1 << 20;
251
+			while (c->count > c->period) {
252
+				c->value = !c->value;
253
+				c->count -= c->period;
254
+			}
255
+			samples[j] += (c->value * 2 - 1) * c->volume;
256
+		}
257
+	}
258
+	(void) userdata;
259
+}
260
+
215 261
 void
216 262
 quit(void)
217 263
 {
... ...
@@ -229,7 +275,8 @@ quit(void)
229 275
 int
230 276
 init(void)
231 277
 {
232
-	if(SDL_Init(SDL_INIT_VIDEO) < 0)
278
+	SDL_AudioSpec as;
279
+	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
233 280
 		return error("Init", SDL_GetError());
234 281
 	gWindow = SDL_CreateWindow("Uxn", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH * ZOOM, HEIGHT * ZOOM, SDL_WINDOW_SHOWN);
235 282
 	if(gWindow == NULL)
... ...
@@ -245,6 +292,15 @@ init(void)
245 292
 	clear(pixels);
246 293
 	SDL_StartTextInput();
247 294
 	SDL_ShowCursor(SDL_DISABLE);
295
+	as.freq = SAMPLE_FREQUENCY;
296
+	as.format = AUDIO_S16;
297
+	as.channels = 1;
298
+	as.callback = audio_callback;
299
+	as.samples = 2048;
300
+	audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
301
+	if(!audio_id)
302
+		return error("Audio", SDL_GetError());
303
+	SDL_PauseAudioDevice(audio_id, 0);
248 304
 	screen.x1 = PAD * 8;
249 305
 	screen.x2 = WIDTH - PAD * 8 - 1;
250 306
 	screen.y1 = PAD * 8;
... ...
@@ -405,8 +461,16 @@ file_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
405 461
 Uint8
406 462
 audio_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
407 463
 {
408
-	(void)u;
409
-	printf("%04x - %02x,%02x\n", ptr, b0, b1);
464
+	Uint8 *m = u->ram.dat;
465
+	if (b0 & 1) {
466
+		Uint16 channel_addr = ptr + (b0 & 0x6);
467
+		struct audio_channel *c = &channels[(b0 & 0x6) >> 1];
468
+		SDL_LockAudioDevice(audio_id);
469
+		c->period = note_periods[m[channel_addr + 8] % 12] >> (m[channel_addr + 8] / 12);
470
+		c->count %= c->period;
471
+		c->volume = m[channel_addr + 9] << 5;
472
+		SDL_UnlockAudioDevice(audio_id);
473
+	}
410 474
 	return b1;
411 475
 }
412 476
 
... ...
@@ -517,7 +581,7 @@ main(int argc, char **argv)
517 581
 	devkey = portuxn(&u, "key", ppnil);
518 582
 	devmouse = portuxn(&u, "mouse", ppnil);
519 583
 	portuxn(&u, "file", file_poke);
520
-	portuxn(&u, "audio", audio_poke);
584
+	devaudio = portuxn(&u, "audio", audio_poke);
521 585
 	portuxn(&u, "midi", ppnil);
522 586
 	portuxn(&u, "datetime", datetime_poke);
523 587
 	portuxn(&u, "---", ppnil);