ref: 10d8d4ff5dad3dc3a62eefba9d6abfa8243fb348
parent: 623f5427f2e5d9cbc7540e8e2a72981c973e4cac
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Thu Mar 18 10:13:45 EDT 2021
sdl2: more enhancements * set SDL version definitions * SDL_RenderSetIntegerScale nop stub * support SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 hint, bring back Alt+F4 = SDL_QUIT by default * audio format changes * audio input
--- a/README.md
+++ b/README.md
@@ -27,8 +27,6 @@
Stack size is set to 256k.
-With SDL applications Alt+Delete is used to send `SDL_QUIT` event.
-
[General porting guide](http://docs.9front.org/porting).
## Helping out
--- a/include/npe/SDL2/SDL.h
+++ b/include/npe/SDL2/SDL.h
@@ -6,6 +6,10 @@
#pragma lib "libnpe_sdl2.a"
+#define SDL_MAJOR_VERSION 2
+#define SDL_MINOR_VERSION 0
+#define SDL_PATCHLEVEL 14
+
typedef int SDL_AudioDeviceID;
typedef struct SDL_AudioSpec SDL_AudioSpec;
typedef struct SDL_Window SDL_Window;
@@ -132,11 +136,34 @@
int SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode *mode);
void SDL_WaitThread(SDL_Thread *thread, int *status);
void SDL_ShowWindow(SDL_Window *w);
+int SDL_RenderSetIntegerScale(SDL_Renderer *r, SDL_bool enable);
enum {
- AUDIO_S16,
- AUDIO_F32,
+ AUDIO_U8 = 1,
+ AUDIO_S8,
+ AUDIO_U16LSB,
+ AUDIO_S16LSB,
+ AUDIO_U16MSB,
+ AUDIO_S16MSB,
+ AUDIO_S32LSB,
+ AUDIO_S32MSB,
+ AUDIO_F32LSB,
+ AUDIO_F32MSB,
+ AUDIO_NUM_FORMATS,
+ /* show me that BIG endian device of yours */
+ AUDIO_U16 = AUDIO_U16LSB,
+ AUDIO_S16 = AUDIO_S16LSB,
+ AUDIO_S32 = AUDIO_S32LSB,
+ AUDIO_F32 = AUDIO_F32LSB,
+ AUDIO_U16SYS = AUDIO_U16,
+ AUDIO_S16SYS = AUDIO_S16,
+ AUDIO_S32SYS = AUDIO_S32,
+ AUDIO_F32SYS = AUDIO_F32,
+ SDL_AUDIO_ALLOW_FREQUENCY_CHANGE = 1<<0,
+ SDL_AUDIO_ALLOW_FORMAT_CHANGE = 1<<1,
+ SDL_AUDIO_ALLOW_CHANNELS_CHANGE = 1<<2,
+ SDL_AUDIO_ALLOW_SAMPLES_CHANGE = 1<<3,
SDL_AUDIO_ALLOW_ANY_CHANGE = ~0,
SDL_THREAD_PRIORITY_HIGH = 1,
@@ -428,6 +455,8 @@
};
#define SDL_HINT_RENDER_SCALE_QUALITY "SDL_HINT_RENDER_SCALE_QUALITY"
+#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
+#define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH "SDL_MOUSE_FOCUS_CLICKTHROUGH"
struct SDL_AudioSpec {
void (*callback)(void *, Uint8 *, int);
--- a/libnpe_sdl2/audio.c
+++ b/libnpe_sdl2/audio.c
@@ -4,22 +4,24 @@
Aout = 2,
Arec,
- Audiobufsz = 8192,
+ Audiosamples = 8192,
};
typedef struct Audiodev Audiodev;
struct Audiodev {
- QLock;
+ Lock;
void (*cb)(void *, Uint8 *, int);
void *userdata;
char *name;
Channel *wait;
+ Uint8 *buf;
+ int bufsz;
int paused;
int fd;
int pid;
+ int pidconv;
int mode;
- Uint8 buf[Audiobufsz];
};
/* FIXME extra USB audio devices? */
@@ -30,6 +32,22 @@
[Arec] = {.name = "/dev/audio", .fd = -1, .pid = -1, .mode = OREAD},
};
+static struct {
+ char *spec;
+ int ssz; /* samples size */
+}fmts[AUDIO_NUM_FORMATS] = {
+ [AUDIO_U8] = {"u8", 1},
+ [AUDIO_S8] = {"s8", 1},
+ [AUDIO_U16LSB] = {"u16", 2},
+ [AUDIO_S16LSB] = {"s16", 2},
+ [AUDIO_U16MSB] = {"U16", 2},
+ [AUDIO_S16MSB] = {"S16", 2},
+ [AUDIO_S32LSB] = {"s32", 4},
+ [AUDIO_S32MSB] = {"S32", 4},
+ [AUDIO_F32LSB] = {"f32", 4},
+ [AUDIO_F32MSB] = {"F32", -1}, /* FIXME big endian f32 not supported by pcmconv */
+};
+
int
SDL_GetNumAudioDevices(int iscapture)
{
@@ -49,13 +67,13 @@
void
SDL_LockAudioDevice(SDL_AudioDeviceID id)
{
- qlock(&au[id]);
+ lock(&au[id]);
}
void
SDL_UnlockAudioDevice(SDL_AudioDeviceID id)
{
- qunlock(&au[id]);
+ unlock(&au[id]);
}
static void
@@ -67,18 +85,22 @@
threadsetname("%s (%s)", a->name, a->mode == OREAD ? "out" : "in");
for(;;){
- qlock(a);
- if(a->paused)
- memset(a->buf, 0, sizeof(a->buf));
+ if(a->mode == OREAD && readn(a->fd, a->buf, a->bufsz) != a->bufsz)
+ break;
+
+ lock(a);
+ if(a->mode == OWRITE && a->paused)
+ memset(a->buf, 0, a->bufsz);
else
- a->cb(a->userdata, a->buf, sizeof(a->buf));
- qunlock(a);
+ a->cb(a->userdata, a->buf, a->bufsz);
+ unlock(a);
- if(write(a->fd, a->buf, sizeof(a->buf)) != sizeof(a->buf))
+ if(a->mode == OWRITE && write(a->fd, a->buf, a->bufsz) != a->bufsz)
break;
}
- sendul(a->wait, 0);
+ (a->mode == OWRITE ? write : read)(a->fd, a->buf, 0);
+ chanclose(a->wait);
threadexits(nil);
}
@@ -91,7 +113,7 @@
a = &au[id];
if(a->paused && !pause){
if(a->pid < 0)
- a->pid = proccreate(audiothread, a, mainstacksize);
+ a->pid = proccreate(audiothread, a, 4096);
a->paused = 0;
}else if(!a->paused && pause){
a->paused = 1;
@@ -98,39 +120,107 @@
}
}
+static int
+convspec(SDL_AudioSpec *s, char *spec, int n)
+{
+ int ssz;
+
+ ssz = -1;
+ if(s->format < 0 || s->format >= nelem(fmts))
+ werrstr("invalid audio format: #%d", s->format);
+ else if(fmts[s->format].ssz < 1)
+ werrstr("unsupported audio format: #%d", s->format);
+ else if(s->channels < 1)
+ werrstr("invalid number of channels: %d", s->channels);
+ else if(s->freq < 1)
+ werrstr("invalid sampling rate: %d", s->freq);
+ else if(snprint(spec, n, "%sc%dr%d", fmts[s->format].spec, s->channels, s->freq) >= n)
+ werrstr("audio spec does not fit");
+ else
+ ssz = fmts[s->format].ssz;
+
+ return ssz;
+}
+
SDL_AudioDeviceID
SDL_OpenAudioDevice(char *dev, int rec, SDL_AudioSpec *want, SDL_AudioSpec *have, u32int change)
{
- Audiodev *a;
SDL_AudioDeviceID id;
+ int p[2], ssz, fd;
+ char spec[16];
+ Audiodev *a;
/* FIXME look for extra USB devices? */
USED(dev);
- if(change != SDL_AUDIO_ALLOW_ANY_CHANGE){ /* FIXME sampling in mono */
- werrstr("SDL_OpenAudioDevice: changes not implemented");
- return 0;
- }
-
- have->freq = 44100;
- have->format = AUDIO_S16;
- have->channels = 2;
- have->samples = want->samples;
-
id = rec ? Arec : Aout;
a = &au[id];
- if(a->fd < 0 && (a->fd = open("/dev/audio", a->mode|OCEXEC)) < 0){
- werrstr("SDL_OpenAudioDevice: %r");
- return 0;
+ if(have == nil)
+ have = want;
+ *have = *want;
+ if(have->freq < 44100 && (change & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) != 0)
+ have->freq = 44100;
+ if(have->format <= 0 || have->format >= nelem(fmts) || fmts[have->format].ssz < 1 && (change & SDL_AUDIO_ALLOW_FORMAT_CHANGE) != 0)
+ have->format = AUDIO_S16;
+ if(have->channels < 1 && (change & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) != 0)
+ have->channels = 2;
+ if(have->samples < 2 || (have->samples & (have->samples-1)) != 0){
+ if(change & SDL_AUDIO_ALLOW_SAMPLES_CHANGE)
+ have->samples = Audiosamples;
+ else{
+ werrstr("invalid number of samples: %d", have->samples);
+ goto err;
+ }
}
- a->userdata = want->userdata;
- a->cb = want->callback;
- a->paused = 1;
+ if((ssz = convspec(have, spec, sizeof(spec))) < 1)
+ goto err;
+
+ a->userdata = have->userdata;
+ a->cb = have->callback;
a->wait = chancreate(sizeof(ulong), 0);
+ a->bufsz = have->samples * ssz * have->channels;
+ a->buf = malloc(a->bufsz);
+ if(a->wait == nil || a->buf == nil){
+ werrstr("memory");
+ goto err;
+ }
+ a->paused = 1;
+ a->pidconv = -1;
+ if(have->freq != 44100 || have->format != AUDIO_S16 || have->channels != 2){
+ pipe(p);
+ if((a->pidconv = rfork(RFPROC|RFFDG|RFNOTEG|RFCENVG)) == 0){
+ if((fd = open("/dev/audio", a->mode)) < 0)
+ exits("%r");
+ dup(fd, rec ? 0 : 1); close(fd);
+ dup(p[0], rec ? 1 : 0); close(p[0]);
+ close(p[1]);
+ //close(2);
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL);
+ if(execl("/bin/audio/pcmconv", "pcmconv", rec ? "-o" : "-i", spec, nil) != 0)
+ exits("%r");
+ }else if(a->pidconv < 0){
+ werrstr("pcmconv: %r");
+ goto err;
+ }
+ a->fd = p[1];
+ close(p[0]);
+ }else if(a->fd < 0 && (a->fd = open("/dev/audio", a->mode|OCEXEC)) < 0)
+ goto err;
+
return id;
+err:
+ werrstr("SDL_OpenAudioDevice: %r");
+ close(a->fd);
+ a->fd = -1;
+ free(a->buf);
+ a->buf = nil;
+ chanfree(a->wait);
+ a->wait = nil;
+
+ return 0;
}
void
@@ -137,17 +227,32 @@
SDL_CloseAudioDevice(SDL_AudioDeviceID id)
{
Audiodev *a;
+ Waitmsg *w;
+ int pid;
a = &au[id];
- qlock(a);
- close(a->fd);
- a->fd = -1;
- a->pid = -1;
- a->userdata = nil;
- a->cb = nil;
- qunlock(a);
+ if(a->fd < 0)
+ return;
- recvul(a->wait);
+ lock(a);
+ close(a->fd);
+ unlock(a);
+
+ if(a->pid >= 0)
+ recvul(a->wait);
chanfree(a->wait);
+
+ free(a->buf);
+ a->fd = -1;
+ a->pid = -1;
+again:
+ if(a->pidconv >= 0 && (w = wait()) != nil){
+ if(w->msg[0])
+ fprint(2, "SDL_CloseAudioDevice: %s: %s\n", a->name, w->msg);
+ pid = w->pid;
+ free(w);
+ if(pid != a->pidconv)
+ goto again;
+ }
}
--- a/libnpe_sdl2/sdl2.c
+++ b/libnpe_sdl2/sdl2.c
@@ -12,7 +12,7 @@
enum {
/* FIXME missing plumber→dropfile */
- Ckey = 0,
+ Ckey,
Ckeytype,
Cmouse,
Cresize,
@@ -21,6 +21,8 @@
Rdown = 0,
Rup,
Rrepeat,
+
+ Altf4noclose = 1<<0,
};
struct SDL_Window {
@@ -75,6 +77,7 @@
static int textinput;
static char basepath[PATH_MAX];
static u32int renddrawcol = DBlack;
+static int hints;
static Cursor nocursor = {
{0, 0},
@@ -733,7 +736,7 @@
break;
e->type = SDL_TEXTINPUT;
e->text.text[runetochar(e->text.text, &rune)] = 0;
- }else if((kmod & KMOD_LALT) != 0 && rune == Kdel){ /* alt+del = quit */
+ }else if((hints & Altf4noclose) == 0 && (kmod & KMOD_LALT) != 0 && rune == (KF|4)){
e->type = SDL_QUIT;
return 1;
}else if(textinput && t == Rdown){
@@ -856,6 +859,14 @@
*scaleY = 1.0;
}
+int
+SDL_RenderSetIntegerScale(SDL_Renderer *, SDL_bool enable)
+{
+ /* FIXME */
+ USED(enable);
+ return 0;
+}
+
void
SDL_GetWindowSize(SDL_Window *, int *w, int *h)
{
@@ -1155,8 +1166,10 @@
SDL_SetHint(char *name, char *value)
{
/* FIXME anyone cares about name="SDL_RENDER_SCALE_QUALITY" value="(best|nearest)"? */
- USED(name);
- USED(value);
+ if(strcmp(name, SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4) == 0){
+ hints = (hints & ~Altf4noclose) | (atoi(value) ? Altf4noclose : 0);
+ return SDL_TRUE;
+ }
return SDL_FALSE;
}