diff options
author | Bad Diode <bd@badd10de.dev> | 2022-10-20 21:59:09 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2022-10-20 21:59:09 +0200 |
commit | 98b84781ebe0ceafe434dbeb90dc790c00ce6cb0 (patch) | |
tree | 6318fc521e7c38e9fb7d8507a3c51b4f25569273 | |
parent | bc14ac83a5ad898aafd312e4d5f8fe8f43c60b0f (diff) | |
download | uxn64-98b84781ebe0ceafe434dbeb90dc790c00ce6cb0.tar.gz uxn64-98b84781ebe0ceafe434dbeb90dc790c00ce6cb0.zip |
Add initial audio implementation
-rw-r--r-- | src/main.c | 135 |
1 files changed, 99 insertions, 36 deletions
@@ -33,11 +33,24 @@ OSPiHandle *rom_handle; | |||
33 | // UXN. | 33 | // UXN. |
34 | // | 34 | // |
35 | 35 | ||
36 | #include "ppu.c" | ||
37 | #include "uxn/src/uxn.c" | 36 | #include "uxn/src/uxn.c" |
37 | #include "uxn/src/devices/audio.c" | ||
38 | #include "ppu.c" | ||
38 | 39 | ||
39 | #include "rom.c" | 40 | #include "rom.c" |
40 | 41 | ||
42 | #define N_AUDIO_BUF 3 | ||
43 | #define AUDIO_RATE 44100 | ||
44 | #define MAX_AUDIO_LENGTH KB(4) | ||
45 | #define AUDIO_BUF_SIZE (MAX_AUDIO_LENGTH * sizeof(s32)) | ||
46 | static s16 audio_samples[N_AUDIO_BUF] = {0, 0, 0}; | ||
47 | static s16 audio_buffers[N_AUDIO_BUF][AUDIO_BUF_SIZE] __attribute__((aligned(64))); | ||
48 | static s32 active_audio = 0; | ||
49 | static s32 frame_size = 0; | ||
50 | static s32 min_frame_size = 0; | ||
51 | static s32 samples_left = 0; | ||
52 | static int pause_audio = 0; | ||
53 | |||
41 | #define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) | 54 | #define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) |
42 | 55 | ||
43 | static u8 uxn_ram[0x10000]; | 56 | static u8 uxn_ram[0x10000]; |
@@ -45,6 +58,7 @@ static Uxn u; | |||
45 | static Device *devscreen; | 58 | static Device *devscreen; |
46 | static Device *devctrl; | 59 | static Device *devctrl; |
47 | static Device *devmouse; | 60 | static Device *devmouse; |
61 | static Device *devaudio; | ||
48 | 62 | ||
49 | #define MOUSE_DELTA 1 | 63 | #define MOUSE_DELTA 1 |
50 | typedef struct Mouse { | 64 | typedef struct Mouse { |
@@ -57,7 +71,7 @@ typedef struct Mouse { | |||
57 | static Mouse mouse = {0}; | 71 | static Mouse mouse = {0}; |
58 | 72 | ||
59 | int | 73 | int |
60 | uxn_halt(Uxn *u, Uint8 error, Uint16 addr) { | 74 | uxn_halt(Uxn *u, u8 error, u16 addr) { |
61 | (void)u; | 75 | (void)u; |
62 | (void)error; | 76 | (void)error; |
63 | (void)addr; | 77 | (void)addr; |
@@ -100,25 +114,25 @@ screen_palette(Device *d) { | |||
100 | 114 | ||
101 | u8 | 115 | u8 |
102 | system_dei(Device *d, u8 port) { | 116 | system_dei(Device *d, u8 port) { |
103 | switch(port) { | 117 | switch(port) { |
104 | case 0x2: return d->u->wst.ptr; | 118 | case 0x2: return d->u->wst.ptr; |
105 | case 0x3: return d->u->rst.ptr; | 119 | case 0x3: return d->u->rst.ptr; |
106 | default: return d->dat[port]; | 120 | default: return d->dat[port]; |
107 | } | 121 | } |
108 | } | 122 | } |
109 | 123 | ||
110 | void | 124 | void |
111 | system_deo(Device *d, u8 port) { | 125 | system_deo(Device *d, u8 port) { |
112 | switch(port) { | 126 | switch(port) { |
113 | case 0x2: d->u->wst.ptr = d->dat[port]; break; | 127 | case 0x2: d->u->wst.ptr = d->dat[port]; break; |
114 | case 0x3: d->u->rst.ptr = d->dat[port]; break; | 128 | case 0x3: d->u->rst.ptr = d->dat[port]; break; |
115 | case 0xe: break; | 129 | case 0xe: break; |
116 | default: { | 130 | default: { |
117 | if(port > 0x7 && port < 0xe) { | 131 | if(port > 0x7 && port < 0xe) { |
118 | screen_palette(d); | 132 | screen_palette(d); |
119 | } | 133 | } |
120 | } break; | 134 | } break; |
121 | } | 135 | } |
122 | } | 136 | } |
123 | 137 | ||
124 | static void | 138 | static void |
@@ -141,20 +155,6 @@ screen_dei(Device *d, u8 port) { | |||
141 | void | 155 | void |
142 | screen_deo(Device *d, u8 port) { | 156 | screen_deo(Device *d, u8 port) { |
143 | switch(port) { | 157 | switch(port) { |
144 | // case 0x3: | ||
145 | // if(!FIXED_SIZE) { | ||
146 | // Uint16 w; | ||
147 | // DEVPEEK16(w, 0x2); | ||
148 | // screen_resize(&uxn_screen, clamp(w, 1, 1024), uxn_screen.height); | ||
149 | // } | ||
150 | // break; | ||
151 | // case 0x5: | ||
152 | // if(!FIXED_SIZE) { | ||
153 | // Uint16 h; | ||
154 | // DEVPEEK16(h, 0x4); | ||
155 | // screen_resize(&uxn_screen, uxn_screen.width, clamp(h, 1, 1024)); | ||
156 | // } | ||
157 | // break; | ||
158 | case 0xe: { | 158 | case 0xe: { |
159 | u16 x, y; | 159 | u16 x, y; |
160 | u8 layer = d->dat[0xe] & 0x40; | 160 | u8 layer = d->dat[0xe] & 0x40; |
@@ -193,10 +193,30 @@ screen_deo(Device *d, u8 port) { | |||
193 | DEVPOKE16(0x8, x + dx); /* auto x+8 */ | 193 | DEVPOKE16(0x8, x + dx); /* auto x+8 */ |
194 | DEVPOKE16(0xa, y + dy); /* auto y+8 */ | 194 | DEVPOKE16(0xa, y + dy); /* auto y+8 */ |
195 | } break; | 195 | } break; |
196 | } | 196 | } |
197 | reqdraw = 1; | 197 | reqdraw = 1; |
198 | } | 198 | } |
199 | 199 | ||
200 | static u8 | ||
201 | audio_dei(Device *d, u8 port) { | ||
202 | int instance = d - devaudio; | ||
203 | switch(port) { | ||
204 | case 0x4: return audio_get_vu(instance); | ||
205 | case 0x2: DEVPOKE16(0x2, audio_get_position(instance)); /* fall through */ | ||
206 | default: return d->dat[port]; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static void | ||
211 | audio_deo(Device *d, u8 port) { | ||
212 | int instance = d - devaudio; | ||
213 | if(port == 0xf) { | ||
214 | // TODO: stop the audio before audio_start | ||
215 | audio_start(instance, d); | ||
216 | pause_audio = 0; | ||
217 | } | ||
218 | } | ||
219 | |||
200 | void | 220 | void |
201 | init_ctrl(void) { | 221 | init_ctrl(void) { |
202 | osCreateMesgQueue(&ctrl_msg_queue, ctrl_msg, 1); | 222 | osCreateMesgQueue(&ctrl_msg_queue, ctrl_msg, 1); |
@@ -352,10 +372,10 @@ poll_input() { | |||
352 | void | 372 | void |
353 | init_uxn(Uxn *u) { | 373 | init_uxn(Uxn *u) { |
354 | // Setup UXN memory. | 374 | // Setup UXN memory. |
355 | for (size_t i = 0; i < sizeof(uxn_ram); i++) { | 375 | for (size_t i = 0; i < sizeof(uxn_ram); i++) { |
356 | uxn_ram[i] = 0; | 376 | uxn_ram[i] = 0; |
357 | } | 377 | } |
358 | uxn_boot(u, uxn_ram); | 378 | uxn_boot(u, uxn_ram); |
359 | 379 | ||
360 | // Copy rom to VM. | 380 | // Copy rom to VM. |
361 | // memcpy(u->ram + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); | 381 | // memcpy(u->ram + PAGE_PROGRAM, uxn_rom, sizeof(uxn_rom)); |
@@ -369,10 +389,10 @@ init_uxn(Uxn *u) { | |||
369 | /* system */ uxn_port(u, 0x0, system_dei, system_deo); | 389 | /* system */ uxn_port(u, 0x0, system_dei, system_deo); |
370 | /* console */ uxn_port(u, 0x1, nil_dei, console_deo); | 390 | /* console */ uxn_port(u, 0x1, nil_dei, console_deo); |
371 | /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo); | 391 | /* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo); |
372 | /* audio0 */ uxn_port(u, 0x3, nil_dei, nil_deo); | 392 | /* audio0 */ devaudio = uxn_port(u, 0x3, audio_dei, audio_deo); |
373 | /* audio1 */ uxn_port(u, 0x4, nil_dei, nil_deo); | 393 | /* audio1 */ uxn_port(u, 0x4, audio_dei, audio_deo); |
374 | /* audio2 */ uxn_port(u, 0x5, nil_dei, nil_deo); | 394 | /* audio2 */ uxn_port(u, 0x5, audio_dei, audio_deo); |
375 | /* audio3 */ uxn_port(u, 0x6, nil_dei, nil_deo); | 395 | /* audio3 */ uxn_port(u, 0x6, audio_dei, audio_deo); |
376 | /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo); | 396 | /* unused */ uxn_port(u, 0x7, nil_dei, nil_deo); |
377 | /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo); | 397 | /* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo); |
378 | /* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo); | 398 | /* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo); |
@@ -385,22 +405,65 @@ init_uxn(Uxn *u) { | |||
385 | uxn_eval(u, PAGE_PROGRAM); | 405 | uxn_eval(u, PAGE_PROGRAM); |
386 | } | 406 | } |
387 | 407 | ||
408 | void | ||
409 | init_audio(void) { | ||
410 | s32 audio_rate = osAiSetFrequency(AUDIO_RATE); | ||
411 | osWritebackDCache(audio_buffers, sizeof(audio_buffers)); | ||
412 | } | ||
413 | |||
414 | void | ||
415 | handle_audio(void) { | ||
416 | if (pause_audio) { | ||
417 | return; | ||
418 | } | ||
419 | |||
420 | u32 status = osAiGetStatus(); | ||
421 | if (status & AI_STATUS_FIFO_FULL > 0) { | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | int running = 0; | ||
426 | s16 *samples = &audio_buffers[active_audio]; | ||
427 | for (size_t i = 0; i < AUDIO_BUF_SIZE; i++) { | ||
428 | samples[i] = 0; | ||
429 | } | ||
430 | for(int channel = 0; channel < POLYPHONY; channel++) { | ||
431 | running += audio_render(channel, samples, samples + AUDIO_BUF_SIZE / 2); | ||
432 | } | ||
433 | if(!running) { | ||
434 | pause_audio = 1; | ||
435 | } | ||
436 | |||
437 | osAiSetNextBuffer(audio_buffers[active_audio], AUDIO_BUF_SIZE); | ||
438 | active_audio++; | ||
439 | if (active_audio == N_AUDIO_BUF) { | ||
440 | active_audio = 0; | ||
441 | } | ||
442 | } | ||
443 | |||
388 | static void | 444 | static void |
389 | main_proc(void *arg) { | 445 | main_proc(void *arg) { |
390 | (void)arg; | 446 | (void)arg; |
391 | init_ppu(); | 447 | init_ppu(); |
448 | init_audio(); | ||
392 | init_ctrl(); | 449 | init_ctrl(); |
393 | init_uxn(&u); | 450 | init_uxn(&u); |
394 | 451 | ||
395 | // Main loop. | 452 | // Main loop. |
396 | while (true) { | 453 | while (true) { |
397 | poll_input(); | 454 | poll_input(); |
455 | handle_audio(); | ||
398 | uxn_eval(&u, GETVECTOR(devscreen)); | 456 | uxn_eval(&u, GETVECTOR(devscreen)); |
399 | blit_framebuffer(); | 457 | blit_framebuffer(); |
400 | swap_buffers(); | 458 | swap_buffers(); |
401 | } | 459 | } |
402 | } | 460 | } |
403 | 461 | ||
462 | void | ||
463 | audio_finished_handler(int instance) { | ||
464 | (void)instance; | ||
465 | } | ||
466 | |||
404 | static void | 467 | static void |
405 | idle_proc(void *arg) { | 468 | idle_proc(void *arg) { |
406 | (void)arg; | 469 | (void)arg; |