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