commit b2891da133caa5df40f4fe0062afbf5e07a27324
parent 25fc9ca5fdfea7d5b2270f7d9865ca2a6c062f31
Author: neauoire <aliceffekt@gmail.com>
Date: Fri, 18 Mar 2022 11:03:07 -0700
Merge branch 'main' of git.sr.ht:~rabbits/uxn
Diffstat:
6 files changed, 183 insertions(+), 116 deletions(-)
diff --git a/src/devices/audio.c b/src/devices/audio.c
@@ -16,6 +16,14 @@ WITH REGARD TO THIS SOFTWARE.
#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025)
#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf)
+typedef struct {
+ Uint8 *addr;
+ Uint32 count, advance, period, age, a, d, s, r;
+ Uint16 i, len;
+ Sint8 volume[2];
+ Uint8 pitch, repeat;
+} UxnAudio;
+
/* clang-format off */
static Uint32 advances[12] = {
@@ -23,7 +31,7 @@ static Uint32 advances[12] = {
0xb504f, 0xbfc88, 0xcb2ff, 0xd7450, 0xe411f, 0xf1a1c
};
-UxnAudio uxn_audio[POLYPHONY];
+static UxnAudio uxn_audio[POLYPHONY];
/* clang-format on */
@@ -40,8 +48,9 @@ envelope(UxnAudio *c, Uint32 age)
}
int
-audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end)
+audio_render(int instance, Sint16 *sample, Sint16 *end)
{
+ UxnAudio *c = &uxn_audio[instance];
Sint32 s;
if(!c->advance || !c->period) return 0;
while(sample < end) {
@@ -59,13 +68,26 @@ audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end)
*sample++ += s * c->volume[0] / 0x180;
*sample++ += s * c->volume[1] / 0x180;
}
- if(!c->advance) audio_finished_handler(c);
+ if(!c->advance) audio_finished_handler(instance);
return 1;
}
void
-audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch)
+audio_start(int instance, Device *d)
{
+ UxnAudio *c = &uxn_audio[instance];
+ Uint16 addr, adsr;
+ Uint8 pitch;
+ DEVPEEK16(adsr, 0x8);
+ DEVPEEK16(c->len, 0xa);
+ DEVPEEK16(addr, 0xc);
+ if(c->len > 0x10000 - addr)
+ c->len = 0x10000 - addr;
+ c->addr = &d->u->ram[addr];
+ c->volume[0] = d->dat[0xe] >> 4;
+ c->volume[1] = d->dat[0xe] & 0xf;
+ c->repeat = !(d->dat[0xf] & 0x80);
+ pitch = d->dat[0xf] & 0x7f;
if(pitch < 108 && c->len)
c->advance = advances[pitch % 12] >> (8 - pitch / 12);
else {
@@ -85,8 +107,9 @@ audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch)
}
Uint8
-audio_get_vu(UxnAudio *c)
+audio_get_vu(int instance)
{
+ UxnAudio *c = &uxn_audio[instance];
int i;
Sint32 sum[2] = {0, 0};
if(!c->advance || !c->period) return 0;
@@ -97,3 +120,10 @@ audio_get_vu(UxnAudio *c)
}
return (sum[0] << 4) | sum[1];
}
+
+Uint16
+audio_get_position(int instance)
+{
+ UxnAudio *c = &uxn_audio[instance];
+ return c->i;
+}
diff --git a/src/devices/audio.h b/src/devices/audio.h
@@ -15,17 +15,8 @@ typedef signed int Sint32;
#define SAMPLE_FREQUENCY 44100
#define POLYPHONY 4
-typedef struct {
- Uint8 *addr;
- Uint32 count, advance, period, age, a, d, s, r;
- Uint16 i, len;
- Sint8 volume[2];
- Uint8 pitch, repeat;
-} UxnAudio;
-
-extern UxnAudio uxn_audio[POLYPHONY];
-
-Uint8 audio_get_vu(UxnAudio *c);
-int audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end);
-void audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch);
-void audio_finished_handler(UxnAudio *c);
+Uint8 audio_get_vu(int instance);
+Uint16 audio_get_position(int instance);
+int audio_render(int instance, Sint16 *sample, Sint16 *end);
+void audio_start(int instance, Device *d);
+void audio_finished_handler(int instance);
diff --git a/src/devices/file.c b/src/devices/file.c
@@ -19,29 +19,32 @@ WITH REGARD TO THIS SOFTWARE.
#include <sys/stat.h>
#include <unistd.h>
-static FILE *f;
-static DIR *dir;
-static char *current_filename = "";
-static struct dirent *de;
-
-static enum { IDLE,
- FILE_READ,
- FILE_WRITE,
- DIR_READ } state;
+typedef struct {
+ FILE *f;
+ DIR *dir;
+ char current_filename[4096];
+ struct dirent *de;
+ enum { IDLE,
+ FILE_READ,
+ FILE_WRITE,
+ DIR_READ } state;
+} UxnFile;
+
+static UxnFile uxn_file[POLYFILEY];
static void
-reset(void)
+reset(UxnFile *c)
{
- if(f != NULL) {
- fclose(f);
- f = NULL;
+ if(c->f != NULL) {
+ fclose(c->f);
+ c->f = NULL;
}
- if(dir != NULL) {
- closedir(dir);
- dir = NULL;
+ if(c->dir != NULL) {
+ closedir(c->dir);
+ c->dir = NULL;
}
- de = NULL;
- state = IDLE;
+ c->de = NULL;
+ c->state = IDLE;
}
static Uint16
@@ -61,20 +64,20 @@ get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int f
}
static Uint16
-file_read_dir(char *dest, Uint16 len)
+file_read_dir(UxnFile *c, char *dest, Uint16 len)
{
- static char pathname[4096];
+ static char pathname[4352];
char *p = dest;
- if(de == NULL) de = readdir(dir);
- for(; de != NULL; de = readdir(dir)) {
+ if(c->de == NULL) c->de = readdir(c->dir);
+ for(; c->de != NULL; c->de = readdir(c->dir)) {
Uint16 n;
- if(de->d_name[0] == '.' && de->d_name[1] == '\0')
+ if(c->de->d_name[0] == '.' && c->de->d_name[1] == '\0')
continue;
- if(strlen(current_filename) + 1 + strlen(de->d_name) < sizeof(pathname))
- sprintf(pathname, "%s/%s", current_filename, de->d_name);
+ if(strlen(c->current_filename) + 1 + strlen(c->de->d_name) < sizeof(pathname))
+ sprintf(pathname, "%s/%s", c->current_filename, c->de->d_name);
else
pathname[0] = '\0';
- n = get_entry(p, len, pathname, de->d_name, 1);
+ n = get_entry(p, len, pathname, c->de->d_name, 1);
if(!n) break;
p += n;
len -= n;
@@ -83,102 +86,126 @@ file_read_dir(char *dest, Uint16 len)
}
static Uint16
-file_init(void *filename)
+file_init(UxnFile *c, char *filename, size_t max_len)
{
- reset();
- current_filename = filename;
+ char *p = c->current_filename;
+ size_t len = sizeof(c->current_filename);
+ reset(c);
+ if(len > max_len) len = max_len;
+ while(len) {
+ if((*p++ = *filename++) == '\0')
+ return 0;
+ len--;
+ }
+ c->current_filename[0] = '\0';
return 0;
}
static Uint16
-file_read(void *dest, Uint16 len)
+file_read(UxnFile *c, void *dest, Uint16 len)
{
- if(state != FILE_READ && state != DIR_READ) {
- reset();
- if((dir = opendir(current_filename)) != NULL)
- state = DIR_READ;
- else if((f = fopen(current_filename, "rb")) != NULL)
- state = FILE_READ;
+ if(c->state != FILE_READ && c->state != DIR_READ) {
+ reset(c);
+ if((c->dir = opendir(c->current_filename)) != NULL)
+ c->state = DIR_READ;
+ else if((c->f = fopen(c->current_filename, "rb")) != NULL)
+ c->state = FILE_READ;
}
- if(state == FILE_READ)
- return fread(dest, 1, len, f);
- if(state == DIR_READ)
- return file_read_dir(dest, len);
+ if(c->state == FILE_READ)
+ return fread(dest, 1, len, c->f);
+ if(c->state == DIR_READ)
+ return file_read_dir(c, dest, len);
return 0;
}
static Uint16
-file_write(void *src, Uint16 len, Uint8 flags)
+file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
{
Uint16 ret = 0;
- if(state != FILE_WRITE) {
- reset();
- if((f = fopen(current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
- state = FILE_WRITE;
+ if(c->state != FILE_WRITE) {
+ reset(c);
+ if((c->f = fopen(c->current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
+ c->state = FILE_WRITE;
}
- if(state == FILE_WRITE) {
- if((ret = fwrite(src, 1, len, f)) > 0 && fflush(f) != 0)
+ if(c->state == FILE_WRITE) {
+ if((ret = fwrite(src, 1, len, c->f)) > 0 && fflush(c->f) != 0)
ret = 0;
}
return ret;
}
static Uint16
-file_stat(void *dest, Uint16 len)
+file_stat(UxnFile *c, void *dest, Uint16 len)
{
- char *basename = strrchr(current_filename, '/');
+ char *basename = strrchr(c->current_filename, '/');
if(basename != NULL)
basename++;
else
- basename = current_filename;
- return get_entry(dest, len, current_filename, basename, 0);
+ basename = c->current_filename;
+ return get_entry(dest, len, c->current_filename, basename, 0);
}
static Uint16
-file_delete(void)
+file_delete(UxnFile *c)
{
- return unlink(current_filename);
+ return unlink(c->current_filename);
}
/* IO */
void
-file_deo(Device *d, Uint8 port)
+file_i_deo(int instance, Device *d, Uint8 port)
{
- Uint16 a, b, res;
+ UxnFile *c = &uxn_file[instance];
+ Uint16 addr, len, res;
switch(port) {
case 0x5:
- DEVPEEK16(a, 0x4);
- DEVPEEK16(b, 0xa);
- if(b > 0x10000 - a)
- b = 0x10000 - a;
- res = file_stat(&d->u->ram[a], b);
+ DEVPEEK16(addr, 0x4);
+ DEVPEEK16(len, 0xa);
+ if(len > 0x10000 - addr)
+ len = 0x10000 - addr;
+ res = file_stat(c, &d->u->ram[addr], len);
DEVPOKE16(0x2, res);
break;
case 0x6:
- res = file_delete();
+ res = file_delete(c);
DEVPOKE16(0x2, res);
break;
case 0x9:
- DEVPEEK16(a, 0x8);
- res = file_init(&d->u->ram[a]);
+ DEVPEEK16(addr, 0x8);
+ res = file_init(c, (char *)&d->u->ram[addr], 0x10000 - addr);
DEVPOKE16(0x2, res);
break;
case 0xd:
- DEVPEEK16(a, 0xc);
- DEVPEEK16(b, 0xa);
- if(b > 0x10000 - a)
- b = 0x10000 - a;
- res = file_read(&d->u->ram[a], b);
+ DEVPEEK16(addr, 0xc);
+ DEVPEEK16(len, 0xa);
+ if(len > 0x10000 - addr)
+ len = 0x10000 - addr;
+ res = file_read(c, &d->u->ram[addr], len);
DEVPOKE16(0x2, res);
break;
case 0xf:
- DEVPEEK16(a, 0xe);
- DEVPEEK16(b, 0xa);
- if(b > 0x10000 - a)
- b = 0x10000 - a;
- res = file_write(&d->u->ram[a], b, d->dat[0x7]);
+ DEVPEEK16(addr, 0xe);
+ DEVPEEK16(len, 0xa);
+ if(len > 0x10000 - addr)
+ len = 0x10000 - addr;
+ res = file_write(c, &d->u->ram[addr], len, d->dat[0x7]);
+ DEVPOKE16(0x2, res);
+ break;
+ }
+}
+
+Uint8
+file_i_dei(int instance, Device *d, Uint8 port)
+{
+ UxnFile *c = &uxn_file[instance];
+ Uint16 res;
+ switch(port) {
+ case 0xc:
+ case 0xd:
+ res = file_read(c, &d->dat[port], 1);
DEVPOKE16(0x2, res);
break;
}
+ return d->dat[port];
}
diff --git a/src/devices/file.h b/src/devices/file.h
@@ -10,4 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
-void file_deo(Device *d, Uint8 port);
+#define POLYFILEY 1
+
+void file_i_deo(int instance, Device *d, Uint8 port);
+Uint8 file_i_dei(int instance, Device *d, Uint8 port);
diff --git a/src/uxncli.c b/src/uxncli.c
@@ -17,6 +17,8 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
+static Device *devfile0;
+
static int
error(char *msg, const char *err)
{
@@ -42,6 +44,18 @@ console_deo(Device *d, Uint8 port)
}
}
+static void
+file_deo(Device *d, Uint8 port)
+{
+ file_i_deo(d - devfile0, d, port);
+}
+
+static Uint8
+file_dei(Device *d, Uint8 port)
+{
+ return file_i_dei(d - devfile0, d, port);
+}
+
static Uint8
nil_dei(Device *d, Uint8 port)
{
@@ -102,7 +116,7 @@ start(Uxn *u)
/* empty */ uxn_port(u, 0x7, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x8, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0x9, nil_dei, nil_deo);
- /* file */ uxn_port(u, 0xa, nil_dei, file_deo);
+ /* file */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo);
/* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo);
/* empty */ uxn_port(u, 0xc, nil_dei, nil_deo);
/* empty */ uxn_port(u, 0xd, nil_dei, nil_deo);
diff --git a/src/uxnemu.c b/src/uxnemu.c
@@ -42,7 +42,7 @@ static SDL_Rect gRect;
/* devices */
-static Device *devscreen, *devmouse, *devctrl, *devaudio0;
+static Device *devscreen, *devmouse, *devctrl, *devaudio0, *devfile0;
static Uint8 zoom = 1;
static Uint32 stdin_event, audio0_event;
@@ -58,21 +58,21 @@ error(char *msg, const char *err)
static void
audio_callback(void *u, Uint8 *stream, int len)
{
- int i, running = 0;
+ int instance, running = 0;
Sint16 *samples = (Sint16 *)stream;
SDL_memset(stream, 0, len);
- for(i = 0; i < POLYPHONY; i++)
- running += audio_render(&uxn_audio[i], samples, samples + len / 2);
+ for(instance = 0; instance < POLYPHONY; instance++)
+ running += audio_render(instance, samples, samples + len / 2);
if(!running)
SDL_PauseAudioDevice(audio_id, 1);
(void)u;
}
void
-audio_finished_handler(UxnAudio *c)
+audio_finished_handler(int instance)
{
SDL_Event event;
- event.type = audio0_event + (c - uxn_audio);
+ event.type = audio0_event + instance;
SDL_PushEvent(&event);
}
@@ -185,11 +185,11 @@ console_deo(Device *d, Uint8 port)
static Uint8
audio_dei(Device *d, Uint8 port)
{
- UxnAudio *c = &uxn_audio[d - devaudio0];
+ int instance = d - devaudio0;
if(!audio_id) return d->dat[port];
switch(port) {
- case 0x4: return audio_get_vu(c);
- case 0x2: DEVPOKE16(0x2, c->i); /* fall through */
+ case 0x4: return audio_get_vu(instance);
+ case 0x2: DEVPOKE16(0x2, audio_get_position(instance)); /* fall through */
default: return d->dat[port];
}
}
@@ -197,26 +197,28 @@ audio_dei(Device *d, Uint8 port)
static void
audio_deo(Device *d, Uint8 port)
{
- UxnAudio *c = &uxn_audio[d - devaudio0];
+ int instance = d - devaudio0;
if(!audio_id) return;
if(port == 0xf) {
- Uint16 addr, adsr;
SDL_LockAudioDevice(audio_id);
- DEVPEEK16(adsr, 0x8);
- DEVPEEK16(c->len, 0xa);
- DEVPEEK16(addr, 0xc);
- if(c->len > 0x10000 - addr)
- c->len = 0x10000 - addr;
- c->addr = &d->u->ram[addr];
- c->volume[0] = d->dat[0xe] >> 4;
- c->volume[1] = d->dat[0xe] & 0xf;
- c->repeat = !(d->dat[0xf] & 0x80);
- audio_start(c, adsr, d->dat[0xf] & 0x7f);
+ audio_start(instance, d);
SDL_UnlockAudioDevice(audio_id);
SDL_PauseAudioDevice(audio_id, 0);
}
}
+static void
+file_deo(Device *d, Uint8 port)
+{
+ file_i_deo(d - devfile0, d, port);
+}
+
+static Uint8
+file_dei(Device *d, Uint8 port)
+{
+ return file_i_dei(d - devfile0, d, port);
+}
+
static Uint8
nil_dei(Device *d, Uint8 port)
{
@@ -263,7 +265,7 @@ start(Uxn *u, char *rom)
/* unused */ uxn_port(u, 0x7, nil_dei, nil_deo);
/* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo);
/* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo);
- /* file */ uxn_port(u, 0xa, nil_dei, file_deo);
+ /* file */ devfile0 = uxn_port(u, 0xa, file_dei, file_deo);
/* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo);
/* unused */ uxn_port(u, 0xc, nil_dei, nil_deo);
/* unused */ uxn_port(u, 0xd, nil_dei, nil_deo);