Missing commands, bugfixes, CLI arguments
+ Pool resizing works properly now + Added command for sourcing a file + Added the rest of commands from the old sfxd + Just in case, buffers for text-processing functions are static and global
This commit is contained in:
parent
bcaceb0428
commit
bf7c04fc8b
175
src/sfxd.c
175
src/sfxd.c
|
@ -1,5 +1,6 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "miniaudio.h"
|
#include "miniaudio.h"
|
||||||
|
#include <getopt.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
|
|
||||||
#define KEY_LENGTH 256
|
#define KEY_LENGTH 256
|
||||||
#define MAX_SOUNDS_PER_KEY 32
|
#define MAX_SOUNDS_PER_KEY 32
|
||||||
|
#define MAX_SOURCE_DEPTH 32
|
||||||
|
|
||||||
struct msg_target {
|
struct msg_target {
|
||||||
FILE *file_handle;
|
FILE *file_handle;
|
||||||
|
@ -31,7 +33,7 @@ struct audio_data {
|
||||||
struct sfx_pool {
|
struct sfx_pool {
|
||||||
struct sfx_pool_item {
|
struct sfx_pool_item {
|
||||||
char key[KEY_LENGTH];
|
char key[KEY_LENGTH];
|
||||||
ma_sound sounds[MAX_SOUNDS_PER_KEY];
|
ma_sound *sounds;
|
||||||
int last_index;
|
int last_index;
|
||||||
|
|
||||||
float volume;
|
float volume;
|
||||||
|
@ -43,6 +45,7 @@ struct sfx_pool {
|
||||||
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 send_txt(struct msg_target tgt, const char *fmt, ...);
|
ssize_t send_txt(struct msg_target tgt, const char *fmt, ...);
|
||||||
void execute_command(struct msg_target tgt, const char *command, const char *params);
|
void execute_command(struct msg_target tgt, const char *command, const char *params);
|
||||||
|
bool execute_file(struct msg_target tgt, const char *path, int depth);
|
||||||
|
|
||||||
bool ipc_init(const char *sock_path);
|
bool ipc_init(const char *sock_path);
|
||||||
void ipc_loop();
|
void ipc_loop();
|
||||||
|
@ -59,14 +62,35 @@ struct ipc_data ipc = { 0 };
|
||||||
struct audio_data audio = { 0 };
|
struct audio_data audio = { 0 };
|
||||||
struct sfx_pool sounds_pool = { 0, 0, 0 };
|
struct sfx_pool sounds_pool = { 0, 0, 0 };
|
||||||
|
|
||||||
|
void usage(int argc, char **argv) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
char *sock_path = DAEMON_SOCKET_PATH;
|
||||||
|
|
||||||
sfx_pool_grow(32);
|
sfx_pool_grow(32);
|
||||||
printf("audio_init()\n");
|
|
||||||
if (!audio_init()) {
|
if (!audio_init()) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sock_path = DAEMON_SOCKET_PATH;
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "hC:S:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
usage(argc, argv);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
sock_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
EXPECT(execute_file((struct msg_target) { stdout, 0, 0, 0 }, optarg, 0), == true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!ipc_init(sock_path)) {
|
if (!ipc_init(sock_path)) {
|
||||||
unlink(sock_path);
|
unlink(sock_path);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -88,14 +112,14 @@ bool ipc_init(const char *sock_path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char buffer_ipc_loop[BUFFER_SIZE];
|
||||||
void ipc_loop() {
|
void ipc_loop() {
|
||||||
static char buffer[BUFFER_SIZE];
|
|
||||||
ssize_t data_len;
|
ssize_t data_len;
|
||||||
socklen_t sl_client = sizeof(ipc.sa_client);
|
socklen_t sl_client = sizeof(ipc.sa_client);
|
||||||
while ((data_len = recvfrom(ipc.sock_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&ipc.sa_client, &sl_client)) != -1) {
|
while ((data_len = recvfrom(ipc.sock_fd, buffer_ipc_loop, sizeof(buffer_ipc_loop) - 1, 0, (struct sockaddr *)&ipc.sa_client, &sl_client)) != -1) {
|
||||||
buffer[data_len] = '\0';
|
buffer_ipc_loop[data_len] = '\0';
|
||||||
struct sockaddr_un *sau_client = &ipc.sa_client;
|
struct sockaddr_un *sau_client = &ipc.sa_client;
|
||||||
char *command = buffer;
|
char *command = buffer_ipc_loop;
|
||||||
char *params = strchr(command, ' ');
|
char *params = strchr(command, ' ');
|
||||||
if (params != NULL) {
|
if (params != NULL) {
|
||||||
*params = '\0';
|
*params = '\0';
|
||||||
|
@ -131,8 +155,8 @@ ssize_t send_data(struct msg_target tgt, const void *data, size_t len) {
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char txtbuf[BUFFER_SIZE];
|
||||||
ssize_t send_txt(struct msg_target tgt, const char *fmt, ...) {
|
ssize_t send_txt(struct msg_target tgt, const char *fmt, ...) {
|
||||||
static char txtbuf[BUFFER_SIZE];
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(txtbuf, BUFFER_SIZE - 1, fmt, args);
|
vsnprintf(txtbuf, BUFFER_SIZE - 1, fmt, args);
|
||||||
|
@ -141,18 +165,28 @@ ssize_t send_txt(struct msg_target tgt, const char *fmt, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_command(struct msg_target tgt, const char *command, const char *params) {
|
void execute_command(struct msg_target tgt, const char *command, const char *params) {
|
||||||
send_txt(tgt, "Received '%s' with '%s'\n", command, params);
|
send_txt(tgt, "INF: Received '%s' with '%s'\n", command, params);
|
||||||
|
|
||||||
if (0 == strcmp(command, "load")) {
|
if (0 == strcmp(command, "load")) {
|
||||||
const char *key = params;
|
const char *key = params;
|
||||||
char *path = strchr(params, ' ');
|
char *path = strchr(params, ' ');
|
||||||
*path = '\0';
|
*path = '\0';
|
||||||
path++;
|
path++;
|
||||||
|
|
||||||
|
if (sounds_pool.use / (float)sounds_pool.cap >= 0.75) {
|
||||||
|
send_txt(tgt, "DBG: pool overflow: %d/%d (%.3f%%)\n",
|
||||||
|
sounds_pool.use, sounds_pool.cap,
|
||||||
|
100.0 * sounds_pool.use / (float)sounds_pool.cap);
|
||||||
|
sfx_pool_grow(sounds_pool.cap + 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_txt(tgt, "Loading audio key=%s from %s\n", key, path);
|
||||||
|
|
||||||
struct sfx_pool_item *sound = sfx_pool_load(key, path);
|
struct sfx_pool_item *sound = sfx_pool_load(key, path);
|
||||||
if (sound == NULL) {
|
if (sound == NULL) {
|
||||||
send_txt(tgt, "Load failed\n");
|
send_txt(tgt, "ERR: Load failed\n");
|
||||||
} else {
|
} else {
|
||||||
send_txt(tgt, "Loaded as %08x\n", adler32(key, strlen(key)));
|
send_txt(tgt, "OK: Loaded as %08x\n", adler32(key, strlen(key)));
|
||||||
}
|
}
|
||||||
} else if (0 == strcmp(command, "play")) {
|
} else if (0 == strcmp(command, "play")) {
|
||||||
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
||||||
|
@ -165,9 +199,117 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
||||||
ma_sound_set_pitch(sfx, sound->pitch_min);
|
ma_sound_set_pitch(sfx, sound->pitch_min);
|
||||||
ma_sound_set_volume(sfx, sound->volume);
|
ma_sound_set_volume(sfx, sound->volume);
|
||||||
ma_sound_start(sfx);
|
ma_sound_start(sfx);
|
||||||
}
|
} else if (0 == strcmp(command, "play:rs") || 0 == strcmp(command, "play_rs")) {
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
||||||
|
if (!sound) {
|
||||||
|
send_txt(tgt, "ERR: No such sound: '%s'\n", params);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_sound *sfx = &sound->sounds[(sound->last_index++) % MAX_SOUNDS_PER_KEY];
|
||||||
|
float pitch = sound->pitch_min + (rand() / (float)RAND_MAX) * (sound->pitch_max - sound->pitch_min);
|
||||||
|
ma_sound_set_pitch(sfx, pitch);
|
||||||
|
ma_sound_set_volume(sfx, sound->volume);
|
||||||
|
ma_sound_start(sfx);
|
||||||
|
} else if (0 == strcmp(command, "set:pitch") || 0 == strcmp(command, "setpitchrange")) {
|
||||||
|
float min, max;
|
||||||
|
char *key;
|
||||||
|
sscanf(params, "%ms %f %f", &key, &min, &max);
|
||||||
|
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_lookup(key);
|
||||||
|
if (!sound) {
|
||||||
|
send_txt(tgt, "ERR: No such sound: '%s'\n", key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min < 0) send_txt(tgt, "WARN: min pitch is too small: %f < 0\n", min);
|
||||||
|
if (max < 0) send_txt(tgt, "WARN: max pitch is too small: %f < 0\n", max);
|
||||||
|
if (max < min) {
|
||||||
|
send_txt(tgt, "WARN: max < min: %f < %f\n", max, min);
|
||||||
|
float tmp = max;
|
||||||
|
max = min;
|
||||||
|
min = tmp;
|
||||||
|
}
|
||||||
|
if (min < 0 || max < 0) {
|
||||||
|
send_txt(tgt, "ERR: either min or max are too small\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sound->pitch_min = min;
|
||||||
|
sound->pitch_max = max;
|
||||||
|
} else if (0 == strcmp(command, "set:volume") || 0 == strcmp(command, "volume")) {
|
||||||
|
float vol;
|
||||||
|
char *key;
|
||||||
|
sscanf(params, "%ms %f", &key, &vol);
|
||||||
|
|
||||||
|
struct sfx_pool_item *sound = sfx_pool_lookup(key);
|
||||||
|
if (!sound) {
|
||||||
|
send_txt(tgt, "ERR: No such sound: '%s'\n", key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vol < 0 || vol > 1) {
|
||||||
|
send_txt(tgt, "ERR: Volume out of range: 0 <= %f < 1\n", vol);
|
||||||
|
}
|
||||||
|
|
||||||
|
sound->volume = vol;
|
||||||
|
} else if (0 == strcmp(command, "dump")) {
|
||||||
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
||||||
|
struct sfx_pool_item item = sounds_pool.sounds[i];
|
||||||
|
if (item.key[0] != '\0') {
|
||||||
|
send_txt(tgt, "%3d vol=%7.5f pitch=%7.5f..%7.5f @%2d (0x%08x) \"%s\"\n",
|
||||||
|
i, item.volume, item.pitch_min, item.pitch_max, item.last_index, adler32(item.key, strlen(item.key)), item.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (0 == strcmp(command, "source")) {
|
||||||
|
execute_file(tgt, params, 0);
|
||||||
|
} else if (0 == strcmp(command, "")) {
|
||||||
|
|
||||||
|
} // commands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char buffer_exec_file[BUFFER_SIZE];
|
||||||
|
bool execute_file(struct msg_target tgt, const char *path, int depth) {
|
||||||
|
send_txt(tgt, "DBG: soucing file %s at depth %d\n", path, depth);
|
||||||
|
char *newline;
|
||||||
|
FILE *fp = fopen(path, "rt");
|
||||||
|
if (!fp) {
|
||||||
|
send_txt(tgt, "ERR: failed to open file: %d %s\n", errno, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int lineno = 1; fgets(buffer_exec_file, BUFFER_SIZE, fp); lineno++) {
|
||||||
|
if ((newline = strchr(buffer_exec_file, '\n')) != NULL) {
|
||||||
|
*newline = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_exec_file[0] == '#') {
|
||||||
|
send_txt(tgt, "DBG: comment: %s\n", buffer_exec_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *cmd = buffer_exec_file;
|
||||||
|
char *args = strchr(buffer_exec_file, ' ');
|
||||||
|
if (args != NULL) {
|
||||||
|
*args = '\0';
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_txt(tgt, "DBG: running: %s %s\n", cmd, args);
|
||||||
|
if (0 == strcmp(cmd, "source")) {
|
||||||
|
if (depth >= MAX_SOURCE_DEPTH) {
|
||||||
|
send_txt(tgt, "ERR: recursion error: %d deep in %s:%d\n", depth, path, lineno);
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
execute_file(tgt, args, depth + 1);
|
||||||
|
} else {
|
||||||
|
execute_command(tgt, cmd, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void sfx_pool_clear() {
|
void sfx_pool_clear() {
|
||||||
for (int i = 0; i < sounds_pool.cap; i++) {
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
||||||
|
@ -176,7 +318,9 @@ void sfx_pool_clear() {
|
||||||
ma_sound_uninit(&sounds_pool.sounds[i].sounds[j]);
|
ma_sound_uninit(&sounds_pool.sounds[i].sounds[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(sounds_pool.sounds[i].sounds);
|
||||||
}
|
}
|
||||||
|
sounds_pool.use = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfx_pool_grow(int size) {
|
void sfx_pool_grow(int size) {
|
||||||
|
@ -232,14 +376,12 @@ 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 sfx_pool_item *sfx_pool_load(const char *key, const char *path) {
|
||||||
if (key == NULL || path == NULL) return NULL;
|
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);
|
struct sfx_pool_item *sound = sfx_pool_find_place_for(key);
|
||||||
SOFT_EXPECT(sound == NULL, == false, NULL);
|
SOFT_EXPECT(sound == NULL, == false, NULL);
|
||||||
|
|
||||||
ma_result res;
|
ma_result res;
|
||||||
|
ma_sound *sounds = calloc(MAX_SOUNDS_PER_KEY, sizeof(ma_sound));
|
||||||
|
sound->sounds = sounds;
|
||||||
SOFT_EXPECT(res = ma_sound_init_from_file(&audio.engine, path, 0, 0, 0, &sound->sounds[0]), == MA_SUCCESS, NULL);
|
SOFT_EXPECT(res = ma_sound_init_from_file(&audio.engine, path, 0, 0, 0, &sound->sounds[0]), == MA_SUCCESS, NULL);
|
||||||
|
|
||||||
bool keep_parameters = false;
|
bool keep_parameters = false;
|
||||||
|
@ -261,6 +403,7 @@ struct sfx_pool_item *sfx_pool_load(const char *key, const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(sound->key, key, KEY_LENGTH);
|
strncpy(sound->key, key, KEY_LENGTH);
|
||||||
|
sounds_pool.use++;
|
||||||
|
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue