Draw the rest of the fucking owl
This commit is contained in:
parent
3671e34d4e
commit
bcaceb0428
|
@ -1,2 +1,3 @@
|
||||||
sfxd
|
sfxd
|
||||||
sfxc
|
sfxc
|
||||||
|
miniaudio.o
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -4,9 +4,12 @@ LDFLAGS := -lm
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: sfxd sfxc
|
all: sfxd sfxc
|
||||||
|
|
||||||
sfxd:
|
miniaudio.o: src/miniaudio.c
|
||||||
$(CC) $(CFLAGS) src/sfxd.c $(LDFLAGS) -o sfxd
|
$(CC) $(CFLAGS) -c src/miniaudio.c -o miniaudio.o
|
||||||
sfxc:
|
|
||||||
|
sfxd: src/sfxd.c miniaudio.o
|
||||||
|
$(CC) $(CFLAGS) src/sfxd.c miniaudio.o $(LDFLAGS) -o sfxd
|
||||||
|
sfxc: src/sfxc.c
|
||||||
$(CC) $(CFLAGS) src/sfxc.c $(LDFLAGS) -o sfxc
|
$(CC) $(CFLAGS) src/sfxc.c $(LDFLAGS) -o sfxc
|
||||||
|
|
||||||
|
|
||||||
|
|
20
src/common.h
20
src/common.h
|
@ -19,6 +19,25 @@
|
||||||
if (!(__res CONDITION)) \
|
if (!(__res CONDITION)) \
|
||||||
PANIC_FMT("%s failed condition: %zd %s", #CODE, __res, #CONDITION); \
|
PANIC_FMT("%s failed condition: %zd %s", #CODE, __res, #CONDITION); \
|
||||||
}
|
}
|
||||||
|
#define SOFT_PANIC_FMT(FMT, ...) _soft_panic(__LINE__, __FILE__, errno, FMT, __VA_ARGS__)
|
||||||
|
#define SOFT_PANIC(TXT) _soft_panic(__LINE__, __FILE__, errno, TXT)
|
||||||
|
#define SOFT_EXPECT(CODE, CONDITION, FAILSAFE) { \
|
||||||
|
ssize_t __res = (CODE); \
|
||||||
|
if (!(__res CONDITION)) { \
|
||||||
|
SOFT_PANIC_FMT("%s failed condition: %zd %s", #CODE, __res, #CONDITION); \
|
||||||
|
return FAILSAFE; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _soft_panic(int line, const char *filename, int _errno, const char *fmt, ...) {
|
||||||
|
fprintf(stderr, "Soft panic at %s:%d\nMessage: ", filename, line);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
fprintf(stderr, "\nerrno: %d (%s)\n", _errno, strerror(_errno));
|
||||||
|
}
|
||||||
|
|
||||||
static inline void _panic(int line, const char *filename, int _errno, const char *fmt, ...) {
|
static inline void _panic(int line, const char *filename, int _errno, const char *fmt, ...) {
|
||||||
fprintf(stderr, "Panic at %s:%d\nMessage: ", filename, line);
|
fprintf(stderr, "Panic at %s:%d\nMessage: ", filename, line);
|
||||||
|
@ -28,7 +47,6 @@ static inline void _panic(int line, const char *filename, int _errno, const char
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
fprintf(stderr, "\nerrno: %d (%s)\n", _errno, strerror(_errno));
|
fprintf(stderr, "\nerrno: %d (%s)\n", _errno, strerror(_errno));
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
|
#include "miniaudio.h"
|
|
@ -23,12 +23,14 @@ int main(int argc, char **argv) {
|
||||||
EXPECT(bind(sock_fd, (struct sockaddr *)&sa_client, sizeof(struct sockaddr_un)), == 0);
|
EXPECT(bind(sock_fd, (struct sockaddr *)&sa_client, sizeof(struct sockaddr_un)), == 0);
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
strncat(buffer, argv[1], BUFFER_SIZE - strlen(buffer) - 1);
|
strncat(buffer, argv[i], BUFFER_SIZE - strlen(buffer) - 1);
|
||||||
if (i != argc - 1) {
|
if (i != argc - 1) {
|
||||||
strncat(buffer, " ", BUFFER_SIZE - strlen(buffer) - 1);
|
strncat(buffer, " ", BUFFER_SIZE - strlen(buffer) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("send: '%s'\n", buffer);
|
||||||
|
|
||||||
EXPECT(sendto(sock_fd, buffer, strlen(buffer), 0, (struct sockaddr *)&sa_server, sizeof(sa_server)), == strlen(buffer));
|
EXPECT(sendto(sock_fd, buffer, strlen(buffer), 0, (struct sockaddr *)&sa_server, sizeof(sa_server)), == strlen(buffer));
|
||||||
int data_len;
|
int data_len;
|
||||||
while ((data_len = recv(sock_fd, buffer, BUFFER_SIZE, 0)) > 0) {
|
while ((data_len = recv(sock_fd, buffer, BUFFER_SIZE, 0)) > 0) {
|
||||||
|
|
243
src/sfxd.c
243
src/sfxd.c
|
@ -1,11 +1,17 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "miniaudio.h"
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define KEY_LENGTH 256
|
||||||
|
#define MAX_SOUNDS_PER_KEY 32
|
||||||
|
|
||||||
struct msg_target {
|
struct msg_target {
|
||||||
FILE *file_handle;
|
FILE *file_handle;
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
|
@ -13,58 +19,111 @@ struct msg_target {
|
||||||
ssize_t sock_addr_size;
|
ssize_t sock_addr_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
ssize_t send_data(struct msg_target tgt, const void *data, size_t len);
|
struct ipc_data {
|
||||||
void execute_command(struct msg_target tgt, const char *command, const char *params);
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
|
|
||||||
struct sockaddr_un sa_server, sa_client;
|
struct sockaddr_un sa_server, sa_client;
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
static char buffer[BUFFER_SIZE];
|
};
|
||||||
|
|
||||||
|
struct audio_data {
|
||||||
|
ma_engine engine;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfx_pool {
|
||||||
|
struct sfx_pool_item {
|
||||||
|
char key[KEY_LENGTH];
|
||||||
|
ma_sound sounds[MAX_SOUNDS_PER_KEY];
|
||||||
|
int last_index;
|
||||||
|
|
||||||
|
float volume;
|
||||||
|
float pitch_min, pitch_max;
|
||||||
|
} *sounds;
|
||||||
|
int cap, use;
|
||||||
|
};
|
||||||
|
|
||||||
|
ssize_t send_data(struct msg_target tgt, const void *data, size_t len);
|
||||||
|
ssize_t send_txt(struct msg_target tgt, const char *fmt, ...);
|
||||||
|
void execute_command(struct msg_target tgt, const char *command, const char *params);
|
||||||
|
|
||||||
|
bool ipc_init(const char *sock_path);
|
||||||
|
void ipc_loop();
|
||||||
|
|
||||||
|
bool audio_init();
|
||||||
|
|
||||||
|
void sfx_pool_clear(void);
|
||||||
|
void sfx_pool_grow(int size);
|
||||||
|
struct sfx_pool_item *sfx_pool_lookup(const char *key);
|
||||||
|
struct sfx_pool_item *sfx_pool_find_place_for(const char *key);
|
||||||
|
struct sfx_pool_item *sfx_pool_load(const char *key, const char *path);
|
||||||
|
|
||||||
|
struct ipc_data ipc = { 0 };
|
||||||
|
struct audio_data audio = { 0 };
|
||||||
|
struct sfx_pool sounds_pool = { 0, 0, 0 };
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
sfx_pool_grow(32);
|
||||||
|
printf("audio_init()\n");
|
||||||
|
if (!audio_init()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
char *sock_path = DAEMON_SOCKET_PATH;
|
char *sock_path = DAEMON_SOCKET_PATH;
|
||||||
|
if (!ipc_init(sock_path)) {
|
||||||
|
unlink(sock_path);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT(sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0), > 0);
|
ipc_loop();
|
||||||
|
unlink(sock_path);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&sa_server, 0, sizeof(sa_server));
|
bool ipc_init(const char *sock_path) {
|
||||||
memset(&sa_client, 0, sizeof(sa_client));
|
SOFT_EXPECT(ipc.sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0), > 0, false);
|
||||||
|
|
||||||
sa_server.sun_family = AF_UNIX;
|
memset(&ipc.sa_server, 0, sizeof(ipc.sa_server));
|
||||||
strncpy(sa_server.sun_path, sock_path, sizeof(sa_server.sun_path) - 1);
|
memset(&ipc.sa_client, 0, sizeof(ipc.sa_client));
|
||||||
|
ipc.sa_server.sun_family = AF_UNIX;
|
||||||
unlink(sa_server.sun_path);
|
strncpy(ipc.sa_server.sun_path, sock_path, sizeof(ipc.sa_server.sun_path) - 1);
|
||||||
EXPECT(bind(sock_fd, (struct sockaddr *)&sa_server, sizeof(struct sockaddr_un)), >= 0);
|
unlink(ipc.sa_server.sun_path);
|
||||||
|
SOFT_EXPECT(bind(ipc.sock_fd, (struct sockaddr *)&ipc.sa_server, sizeof(struct sockaddr_un)), >= 0, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ipc_loop() {
|
||||||
|
static char buffer[BUFFER_SIZE];
|
||||||
ssize_t data_len;
|
ssize_t data_len;
|
||||||
socklen_t sl_client = sizeof(sa_client);
|
socklen_t sl_client = sizeof(ipc.sa_client);
|
||||||
while ((data_len = recvfrom(sock_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&sa_client, &sl_client)) != -1) {
|
while ((data_len = recvfrom(ipc.sock_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&ipc.sa_client, &sl_client)) != -1) {
|
||||||
buffer[data_len] = '\0';
|
buffer[data_len] = '\0';
|
||||||
struct sockaddr_un *sau_client = &sa_client;
|
struct sockaddr_un *sau_client = &ipc.sa_client;
|
||||||
char *command = buffer;
|
char *command = buffer;
|
||||||
char *params = strchr(buffer, ' ');
|
char *params = strchr(command, ' ');
|
||||||
if (params != NULL) {
|
if (params != NULL) {
|
||||||
*params = '\0';
|
*params = '\0';
|
||||||
params++;
|
params++;
|
||||||
}
|
}
|
||||||
execute_command((struct msg_target) { 0, sock_fd, (struct sockaddr *)&sa_client, sl_client }, command, params);
|
execute_command((struct msg_target) { 0, ipc.sock_fd, (struct sockaddr *)&ipc.sa_client, sl_client }, command, params);
|
||||||
EXPECT(sendto(sock_fd, "OK\n", 4, 0, (struct sockaddr *)&sa_client, sl_client), == 4);
|
SOFT_EXPECT(sendto(ipc.sock_fd, "OK\n", 4, 0, (struct sockaddr *)&ipc.sa_client, sl_client), == 4,);
|
||||||
EXPECT(sendto(sock_fd, "", 0, 0, (struct sockaddr *)&sa_client, sl_client), == 0);
|
SOFT_EXPECT(sendto(ipc.sock_fd, "", 0, 0, (struct sockaddr *)&ipc.sa_client, sl_client), == 0,);
|
||||||
sl_client = sizeof(sa_client);
|
sl_client = sizeof(ipc.sa_client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(sa_server.sun_path);
|
bool audio_init() {
|
||||||
|
ma_result result;
|
||||||
|
SOFT_EXPECT((result = ma_engine_init(NULL, &audio.engine)), == MA_SUCCESS, false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t send_data(struct msg_target tgt, const void *data, size_t len) {
|
ssize_t send_data(struct msg_target tgt, const void *data, size_t len) {
|
||||||
ssize_t written;
|
ssize_t written;
|
||||||
if (tgt.file_handle) {
|
if (tgt.file_handle) {
|
||||||
if ((written = fwrite(data, 1, len, tgt.file_handle)) != len) {
|
if ((written = fwrite(data, 1, len, tgt.file_handle)) != len) {
|
||||||
PANIC_FMT("fwrite(ptr=%p, size=%zd, nmemb=%zd, stream=%p) -> %zd",
|
SOFT_PANIC_FMT("fwrite(ptr=%p, size=%zd, nmemb=%zd, stream=%p) -> %zd",
|
||||||
data, 1, len, tgt.file_handle, written);
|
data, 1, len, tgt.file_handle, written);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((written = sendto(tgt.sock_fd, data, len, 0, tgt.sock_addr, tgt.sock_addr_size)) != len) {
|
if ((written = sendto(tgt.sock_fd, data, len, 0, tgt.sock_addr, tgt.sock_addr_size)) != len) {
|
||||||
PANIC_FMT("sendto(socket=%d, message=%p, length=%zd, flags=%d, dest_addr=%p, dest_len=%zd) -> %zd",
|
SOFT_PANIC_FMT("sendto(socket=%d, message=%p, length=%zd, flags=%d, dest_addr=%p, dest_len=%zd) -> %zd",
|
||||||
tgt.sock_fd, data, len, 0, tgt.sock_addr, tgt.sock_addr_size, written);
|
tgt.sock_fd, data, len, 0, tgt.sock_addr, tgt.sock_addr_size, written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +131,136 @@ ssize_t send_data(struct msg_target tgt, const void *data, size_t len) {
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_command(struct msg_target tgt, const char *command, const char *params) {
|
ssize_t send_txt(struct msg_target tgt, const char *fmt, ...) {
|
||||||
send_data(tgt, "WAAAAAAAAAAAAAA\n", 16);
|
static char txtbuf[BUFFER_SIZE];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(txtbuf, BUFFER_SIZE - 1, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return send_data(tgt, txtbuf, strlen(txtbuf) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_command(struct msg_target tgt, const char *command, const char *params) {
|
||||||
|
send_txt(tgt, "Received '%s' with '%s'\n", command, params);
|
||||||
|
|
||||||
|
if (0 == strcmp(command, "load")) {
|
||||||
|
const char *key = params;
|
||||||
|
char *path = strchr(params, ' ');
|
||||||
|
*path = '\0';
|
||||||
|
path++;
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_load(key, path);
|
||||||
|
if (sound == NULL) {
|
||||||
|
send_txt(tgt, "Load failed\n");
|
||||||
|
} else {
|
||||||
|
send_txt(tgt, "Loaded as %08x\n", adler32(key, strlen(key)));
|
||||||
|
}
|
||||||
|
} else if (0 == strcmp(command, "play")) {
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
||||||
|
if (!sound) {
|
||||||
|
send_txt(tgt, "No such sound: '%s'\n", params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_sound *sfx = &sound->sounds[(sound->last_index++) % MAX_SOUNDS_PER_KEY];
|
||||||
|
ma_sound_set_pitch(sfx, sound->pitch_min);
|
||||||
|
ma_sound_set_volume(sfx, sound->volume);
|
||||||
|
ma_sound_start(sfx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sfx_pool_clear() {
|
||||||
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
||||||
|
if (sounds_pool.sounds[i].key[0]) {
|
||||||
|
for (int j = 0; j < MAX_SOUNDS_PER_KEY; j++) {
|
||||||
|
ma_sound_uninit(&sounds_pool.sounds[i].sounds[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sfx_pool_grow(int size) {
|
||||||
|
if (size <= sounds_pool.cap) return;
|
||||||
|
|
||||||
|
// TODO: move to realloc?
|
||||||
|
struct sfx_pool_item *new_items = calloc(size, sizeof(struct sfx_pool_item));
|
||||||
|
EXPECT(new_items == NULL, == false);
|
||||||
|
|
||||||
|
int used = 0;
|
||||||
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
||||||
|
if (sounds_pool.sounds[i].key[0] == '\0') continue;
|
||||||
|
uint32_t new_hash = adler32(sounds_pool.sounds[i].key, strlen(sounds_pool.sounds[i].key));
|
||||||
|
for (int offset = 0; offset < size; offset++) {
|
||||||
|
int index = (new_hash + offset) % size;
|
||||||
|
if (new_items[index].key[0] == '\0') {
|
||||||
|
memcpy(&new_items[index], &sounds_pool.sounds[i], sizeof(struct sfx_pool_item));
|
||||||
|
used++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sounds_pool.sounds);
|
||||||
|
sounds_pool.use = used;
|
||||||
|
sounds_pool.cap = size;
|
||||||
|
sounds_pool.sounds = new_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sfx_pool_item *sfx_pool_lookup(const char *key) {
|
||||||
|
if (key == NULL) return NULL;
|
||||||
|
uint32_t hash = adler32(key, strlen(key));
|
||||||
|
for (int offset = 0; offset < sounds_pool.cap; offset++) {
|
||||||
|
int index = (hash + offset) % sounds_pool.cap;
|
||||||
|
if (0 == strncmp(key, sounds_pool.sounds[index].key, KEY_LENGTH)) {
|
||||||
|
return &sounds_pool.sounds[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sfx_pool_item *sfx_pool_find_place_for(const char *key) {
|
||||||
|
uint32_t hash = adler32(key, strlen(key));
|
||||||
|
for (int offset = 0; offset < sounds_pool.cap; offset++) {
|
||||||
|
int index = (hash + offset) % sounds_pool.cap;
|
||||||
|
if (sounds_pool.sounds[index].key[0] == '\0' || 0 == strncmp(sounds_pool.sounds[index].key, key, KEY_LENGTH)) {
|
||||||
|
return &sounds_pool.sounds[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sfx_pool_item *sfx_pool_load(const char *key, const char *path) {
|
||||||
|
if (key == NULL || path == NULL) return NULL;
|
||||||
|
|
||||||
|
if (sounds_pool.use / (float)sounds_pool.cap >= 0.75) {
|
||||||
|
sfx_pool_grow(sounds_pool.cap + 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_find_place_for(key);
|
||||||
|
SOFT_EXPECT(sound == NULL, == false, NULL);
|
||||||
|
|
||||||
|
ma_result res;
|
||||||
|
SOFT_EXPECT(res = ma_sound_init_from_file(&audio.engine, path, 0, 0, 0, &sound->sounds[0]), == MA_SUCCESS, NULL);
|
||||||
|
|
||||||
|
bool keep_parameters = false;
|
||||||
|
if ((keep_parameters = (0 == strncmp(sound->key, key, KEY_LENGTH)))) {
|
||||||
|
for (int i = 0; i < MAX_SOUNDS_PER_KEY; i++) {
|
||||||
|
ma_sound_uninit(&sound->sounds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < MAX_SOUNDS_PER_KEY; i++) {
|
||||||
|
SOFT_EXPECT(res = ma_sound_init_copy(&audio.engine, &sound->sounds[0], 0, 0, &sound->sounds[i]), == MA_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keep_parameters) {
|
||||||
|
sound->last_index = 0;
|
||||||
|
sound->pitch_max = 1.0;
|
||||||
|
sound->pitch_min = 1.0;
|
||||||
|
sound->volume = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(sound->key, key, KEY_LENGTH);
|
||||||
|
|
||||||
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue