|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
#include "common.h"
|
|
|
|
|
#include "miniaudio.h"
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fnmatch.h>
|
|
|
|
|
#include <getopt.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
@ -13,6 +14,7 @@
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <wordexp.h>
|
|
|
|
|
|
|
|
|
|
#define KEY_LENGTH 256
|
|
|
|
|
#define MAX_SOUNDS_PER_KEY 32
|
|
|
|
@ -44,14 +46,20 @@ struct sfx_pool {
|
|
|
|
|
|
|
|
|
|
float volume;
|
|
|
|
|
float pitch_min, pitch_max;
|
|
|
|
|
|
|
|
|
|
int bst_parent, bst_left, bst_right;
|
|
|
|
|
bool inside_bst;
|
|
|
|
|
} *sounds;
|
|
|
|
|
int cap, use;
|
|
|
|
|
|
|
|
|
|
int bst_root;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ssize_t send_data(struct msg_target tgt, const void *data, ssize_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 execute_file(struct msg_target tgt, const char *path, int depth);
|
|
|
|
|
void send_help(struct msg_target tgt);
|
|
|
|
|
|
|
|
|
|
bool ipc_init(const char *sock_path);
|
|
|
|
|
void ipc_loop(void);
|
|
|
|
@ -66,17 +74,95 @@ 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 };
|
|
|
|
|
struct sfx_pool sounds_pool = { 0, 0, 0, .bst_root = -1 };
|
|
|
|
|
|
|
|
|
|
#ifndef NO_COUNTERS
|
|
|
|
|
struct global_counters {
|
|
|
|
|
uint64_t pool_read;
|
|
|
|
|
uint64_t pool_write;
|
|
|
|
|
uint64_t hash_misses_write;
|
|
|
|
|
uint64_t hash_misses_read;
|
|
|
|
|
uint64_t hash_misses_write;
|
|
|
|
|
uint64_t hash_misses_read_acc;
|
|
|
|
|
uint64_t hash_misses_write_acc;
|
|
|
|
|
} global_counters = { 0 };
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void sfx_pool_bst_insert(struct sfx_pool_item* lst, int *root_idx_ptr, int new_idx) {
|
|
|
|
|
// TODO balanced
|
|
|
|
|
struct sfx_pool_item *new_item = lst + new_idx;
|
|
|
|
|
int *new_idx_ptr = root_idx_ptr;
|
|
|
|
|
int parent_idx = -1;
|
|
|
|
|
int depth = 0;
|
|
|
|
|
|
|
|
|
|
int next_parent_idx;
|
|
|
|
|
while ((next_parent_idx = *new_idx_ptr) >= 0) {
|
|
|
|
|
depth++;
|
|
|
|
|
parent_idx = next_parent_idx;
|
|
|
|
|
struct sfx_pool_item *parent_item = lst + parent_idx;
|
|
|
|
|
if (strcmp(new_item->key, parent_item->key) < 0) {
|
|
|
|
|
new_idx_ptr = &parent_item->bst_left;
|
|
|
|
|
} else {
|
|
|
|
|
new_idx_ptr = &parent_item->bst_right;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*new_idx_ptr = new_idx;
|
|
|
|
|
new_item->bst_parent = parent_idx;
|
|
|
|
|
new_item->bst_left = -1;
|
|
|
|
|
new_item->bst_right = -1;
|
|
|
|
|
new_item->inside_bst = true;
|
|
|
|
|
send_txt((struct msg_target){ stdout, 0, 0, 0 }, "INF: Sorting element at index %d with key '%s' under the element at index %d with depth of %d\n", new_idx, lst[new_idx].key, parent_idx, depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't need deletion support
|
|
|
|
|
|
|
|
|
|
void sfx_pool_bst_insert_all(struct sfx_pool_item *lst, int *root_idx_ptr, int size) {
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
if (!lst[i].inside_bst && lst[i].key[0] != '\0') {
|
|
|
|
|
sfx_pool_bst_insert(lst, root_idx_ptr, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sfx_pool_bst_leftmost(const struct sfx_pool_item *lst, int parent_idx) {
|
|
|
|
|
if (parent_idx < 0) {
|
|
|
|
|
return parent_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int next_idx;
|
|
|
|
|
while ((next_idx = lst[parent_idx].bst_left) >= 0) {
|
|
|
|
|
parent_idx = next_idx;
|
|
|
|
|
}
|
|
|
|
|
return parent_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sfx_pool_bst_go_right(const struct sfx_pool_item *lst, int cur_idx) {
|
|
|
|
|
if (cur_idx < 0) {
|
|
|
|
|
return cur_idx;
|
|
|
|
|
}
|
|
|
|
|
const struct sfx_pool_item *cur_item = lst + cur_idx;
|
|
|
|
|
if (cur_item->bst_right >= 0) {
|
|
|
|
|
return sfx_pool_bst_leftmost(lst, cur_item->bst_right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
int parent_idx = cur_item->bst_parent;
|
|
|
|
|
if (parent_idx < 0) {
|
|
|
|
|
// We are a root => end iterator
|
|
|
|
|
return parent_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lst[parent_idx].bst_left == cur_idx) {
|
|
|
|
|
// We are a left child
|
|
|
|
|
return parent_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We are a right child
|
|
|
|
|
cur_idx = parent_idx;
|
|
|
|
|
cur_item = lst + cur_idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void usage(int argc, char **argv) {
|
|
|
|
|
// TODO
|
|
|
|
|
(void)argc;
|
|
|
|
@ -148,9 +234,10 @@ void ipc_loop(void) {
|
|
|
|
|
if (params != NULL) {
|
|
|
|
|
*params = '\0';
|
|
|
|
|
params++;
|
|
|
|
|
} else {
|
|
|
|
|
params = "";
|
|
|
|
|
}
|
|
|
|
|
execute_command((struct msg_target) { 0, ipc.sock_fd, sa_client, sl_client }, command, params);
|
|
|
|
|
SOFT_EXPECT(sendto(ipc.sock_fd, "OK\n", 4, 0, sa_client, sl_client), == 4,);
|
|
|
|
|
SOFT_EXPECT(sendto(ipc.sock_fd, "", 0, 0, sa_client, sl_client), == 0,);
|
|
|
|
|
sl_client = sizeof(ipc.sa_client);
|
|
|
|
|
}
|
|
|
|
@ -193,8 +280,16 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
send_txt((struct msg_target){ stdout, 0, 0, 0 }, "INF: Received '%s' with '%s'\n", command, params);
|
|
|
|
|
|
|
|
|
|
if (0 == strcmp(command, "load")) {
|
|
|
|
|
if (strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: KEY\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const char *key = params;
|
|
|
|
|
char *path = strchr(params, ' ');
|
|
|
|
|
if (path == NULL) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: PATH\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*path = '\0';
|
|
|
|
|
path++;
|
|
|
|
|
|
|
|
|
@ -214,9 +309,13 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
send_txt(tgt, "OK: Loaded as %08x\n", adler32(key, strlen(key)));
|
|
|
|
|
}
|
|
|
|
|
} else if (0 == strcmp(command, "play")) {
|
|
|
|
|
if (strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: KEY\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
|
|
|
|
if (!sound) {
|
|
|
|
|
send_txt(tgt, "No such sound: '%s'\n", params);
|
|
|
|
|
send_txt(tgt, "ERR: No such sound: '%s'\n", params);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -227,6 +326,10 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
ma_sound_set_volume(sfx, sound->volume);
|
|
|
|
|
ma_sound_start(sfx);
|
|
|
|
|
} else if (0 == strcmp(command, "play:rs")) {
|
|
|
|
|
if (strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: KEY\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
struct sfx_pool_item *sound = sfx_pool_lookup(params);
|
|
|
|
|
if (!sound) {
|
|
|
|
|
send_txt(tgt, "ERR: No such sound: '%s'\n", params);
|
|
|
|
@ -243,7 +346,11 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
} else if (0 == strcmp(command, "set:pitch")) {
|
|
|
|
|
float min, max;
|
|
|
|
|
char *key;
|
|
|
|
|
sscanf(params, "%ms %f %f", &key, &min, &max);
|
|
|
|
|
int retval = sscanf(params, "%ms %f %f", &key, &min, &max);
|
|
|
|
|
if (retval != 3) {
|
|
|
|
|
send_txt(tgt, "ERR: not enough arguments: KEY MIN MAX needed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sfx_pool_item *sound = sfx_pool_lookup(key);
|
|
|
|
|
if (!sound) {
|
|
|
|
@ -269,7 +376,11 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
} else if (0 == strcmp(command, "set:volume")) {
|
|
|
|
|
float vol;
|
|
|
|
|
char *key;
|
|
|
|
|
sscanf(params, "%ms %f", &key, &vol);
|
|
|
|
|
int retval = sscanf(params, "%ms %f", &key, &vol);
|
|
|
|
|
if (retval != 2) {
|
|
|
|
|
send_txt(tgt, "ERR: not enough arguments: KEY VOLUME\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sfx_pool_item *sound = sfx_pool_lookup(key);
|
|
|
|
|
if (!sound) {
|
|
|
|
@ -282,8 +393,53 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sound->volume = vol;
|
|
|
|
|
} else if (0 == strcmp(command, "find")) {
|
|
|
|
|
if (strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: QUERY\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
|
|
|
|
struct sfx_pool_item item = sounds_pool.sounds[i];
|
|
|
|
|
if (item.key[0] != '\0' && strcasestr(item.key, params)) {
|
|
|
|
|
send_txt(tgt, "%s\n", item.key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (0 == strcmp(command, "list") || 0 == strcmp(command, "ls")) {
|
|
|
|
|
sfx_pool_bst_insert_all(sounds_pool.sounds, &sounds_pool.bst_root, sounds_pool.cap);
|
|
|
|
|
for (int i = sfx_pool_bst_leftmost(sounds_pool.sounds, sounds_pool.bst_root); i >= 0; i = sfx_pool_bst_go_right(sounds_pool.sounds, i)) {
|
|
|
|
|
struct sfx_pool_item *item = &sounds_pool.sounds[i];
|
|
|
|
|
if (item->key[0] == '\0') continue;
|
|
|
|
|
if (0 == fnmatch(params, item->key, 0) || strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "%s\n", item->key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (0 == strcmp(command, "source")) {
|
|
|
|
|
execute_file(tgt, params, 0);
|
|
|
|
|
if (strlen(params) == 0) {
|
|
|
|
|
send_txt(tgt, "ERR: argument required: PATH\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
wordexp_t p;
|
|
|
|
|
int retval = wordexp(params, &p, 0);
|
|
|
|
|
#define _WORDEXP_ERROR(ERR_CODE) case ERR_CODE: send_txt(tgt, "ERR: wordexp: " #ERR_CODE); return;
|
|
|
|
|
switch (retval) {
|
|
|
|
|
case 0: break;
|
|
|
|
|
_WORDEXP_ERROR(WRDE_BADCHAR);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_BADVAL);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_CMDSUB);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_NOSPACE);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_SYNTAX);
|
|
|
|
|
default: send_txt(tgt, "ERR: wordexp: Unknown error: %d\n", retval); return;
|
|
|
|
|
}
|
|
|
|
|
#undef _WORDEXP_ERROR
|
|
|
|
|
for (size_t i = 0; i < p.we_wordc; i++) {
|
|
|
|
|
execute_file(tgt, p.we_wordv[i], 0);
|
|
|
|
|
}
|
|
|
|
|
wordfree(&p);
|
|
|
|
|
} else if (0 == strcmp(command, "help")) {
|
|
|
|
|
send_help(tgt);
|
|
|
|
|
} else if (0 == strcmp(command, "meow")) {
|
|
|
|
|
send_txt(tgt, "mrr~\n");
|
|
|
|
|
} else if (0 == strcmp(command, "dbg:dump")) {
|
|
|
|
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
|
|
|
|
struct sfx_pool_item item = sounds_pool.sounds[i];
|
|
|
|
@ -302,15 +458,48 @@ void execute_command(struct msg_target tgt, const char *command, const char *par
|
|
|
|
|
send_txt(tgt, ".pool_write = %ld\n", global_counters.pool_write);
|
|
|
|
|
send_txt(tgt, ".hash_misses_read = %ld\n", global_counters.hash_misses_read);
|
|
|
|
|
send_txt(tgt, ".hash_misses_write = %ld\n", global_counters.hash_misses_write);
|
|
|
|
|
send_txt(tgt, ".hash_misses_read_acc = %ld\n", global_counters.hash_misses_read_acc);
|
|
|
|
|
send_txt(tgt, ".hash_misses_write_acc = %ld\n", global_counters.hash_misses_write_acc);
|
|
|
|
|
send_txt(tgt, ".pool.use = %d\n", sounds_pool.use);
|
|
|
|
|
send_txt(tgt, ".pool.cap = %d\n", sounds_pool.cap);
|
|
|
|
|
#endif
|
|
|
|
|
} else if (0 == strcmp(command, "dbg:map")) {
|
|
|
|
|
int n_hits = 0, n_misses = 0;
|
|
|
|
|
for (int i = 0; i < sounds_pool.cap; i++) {
|
|
|
|
|
struct sfx_pool_item *item = &sounds_pool.sounds[i];
|
|
|
|
|
if ((i % 16) == 0) {
|
|
|
|
|
send_txt(tgt, "# ");
|
|
|
|
|
}
|
|
|
|
|
if (item->key[0] == '\0') {
|
|
|
|
|
send_txt(tgt, "-- ");
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t hash = adler32(item->key, strlen(item->key));
|
|
|
|
|
int index = hash % sounds_pool.cap;
|
|
|
|
|
send_txt(tgt, "%02d ", i - index);
|
|
|
|
|
}
|
|
|
|
|
if ((i % 16) == 15) {
|
|
|
|
|
send_txt(tgt, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
send_txt(tgt, ".used = %ld\n.size = %ld\n", sounds_pool.use, sounds_pool.cap);
|
|
|
|
|
send_txt(tgt, ".hits = %d\n.misses = %d\n", n_hits, n_misses);
|
|
|
|
|
} else if (0 == strcmp(command, "")) {
|
|
|
|
|
} else {
|
|
|
|
|
send_txt(tgt, "ERR: unknown command: %s\n", command);
|
|
|
|
|
} // commands
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void send_help(struct msg_target tgt) {
|
|
|
|
|
send_txt(tgt, "load NAME PATH load PATH sound as NAME\n");
|
|
|
|
|
send_txt(tgt, "play NAME play previously loaded NAME\n");
|
|
|
|
|
send_txt(tgt, "play:rs NAME play _ _ _ with random pitch\n");
|
|
|
|
|
send_txt(tgt, "set:pitch NAME MIN MAX set pitch range for NAME\n");
|
|
|
|
|
send_txt(tgt, "set:volume NAME VOLUME set loudness for NAME\n");
|
|
|
|
|
send_txt(tgt, "source PATH load instructions from PATH\n");
|
|
|
|
|
send_txt(tgt, "find QUERY search for keys by QUERY\n");
|
|
|
|
|
send_txt(tgt, "list [QUERY] basically ls\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
@ -345,7 +534,24 @@ bool execute_file(struct msg_target tgt, const char *path, int depth) {
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
execute_file(tgt, args, depth + 1);
|
|
|
|
|
wordexp_t p;
|
|
|
|
|
int retval = wordexp(args, &p, 0);
|
|
|
|
|
#define _WORDEXP_ERROR(ERR_CODE) case ERR_CODE: send_txt(tgt, "ERR: wordexp: " #ERR_CODE); return false;
|
|
|
|
|
switch (retval) {
|
|
|
|
|
case 0: break;
|
|
|
|
|
_WORDEXP_ERROR(WRDE_BADCHAR);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_BADVAL);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_CMDSUB);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_NOSPACE);
|
|
|
|
|
_WORDEXP_ERROR(WRDE_SYNTAX);
|
|
|
|
|
default: send_txt(tgt, "ERR: wordexp: Unknown error: %d\n", retval); return false;
|
|
|
|
|
}
|
|
|
|
|
#undef _WORDEXP_ERROR
|
|
|
|
|
for (size_t i = 0; i < p.we_wordc; i++) {
|
|
|
|
|
send_txt(tgt, "DBG: executing file %s\n", p.we_wordv[i]);
|
|
|
|
|
execute_file(tgt, p.we_wordv[i], depth + 1);
|
|
|
|
|
}
|
|
|
|
|
wordfree(&p);
|
|
|
|
|
} else {
|
|
|
|
|
execute_command(tgt, cmd, args);
|
|
|
|
|
}
|
|
|
|
@ -377,14 +583,15 @@ void sfx_pool_grow(int size) {
|
|
|
|
|
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));
|
|
|
|
|
global_counters.pool_write++;
|
|
|
|
|
for (int offset = 0; offset < size; offset++) {
|
|
|
|
|
int index = (new_hash + offset) % size;
|
|
|
|
|
if (new_items[index].key[0] == '\0') {
|
|
|
|
|
#ifndef NO_COUNTERS
|
|
|
|
|
global_counters.hash_misses_write_acc++;
|
|
|
|
|
if (offset != 0) {
|
|
|
|
|
global_counters.hash_misses_write++;
|
|
|
|
|
}
|
|
|
|
|
global_counters.pool_write++;
|
|
|
|
|
#endif
|
|
|
|
|
memcpy(&new_items[index], &sounds_pool.sounds[i], sizeof(struct sfx_pool_item));
|
|
|
|
|
used++;
|
|
|
|
@ -401,12 +608,14 @@ void sfx_pool_grow(int size) {
|
|
|
|
|
|
|
|
|
|
struct sfx_pool_item *sfx_pool_lookup(const char *key) {
|
|
|
|
|
if (key == NULL) return NULL;
|
|
|
|
|
if (strlen(key) == 0) return NULL;
|
|
|
|
|
uint32_t hash = adler32(key, strlen(key));
|
|
|
|
|
global_counters.pool_read++;
|
|
|
|
|
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)) {
|
|
|
|
|
#ifndef NO_COUNTERS
|
|
|
|
|
global_counters.pool_read++;
|
|
|
|
|
global_counters.hash_misses_read_acc++;
|
|
|
|
|
if (offset != 0) {
|
|
|
|
|
global_counters.hash_misses_read++;
|
|
|
|
|
}
|
|
|
|
@ -418,12 +627,15 @@ struct sfx_pool_item *sfx_pool_lookup(const char *key) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct sfx_pool_item *sfx_pool_find_place_for(const char *key) {
|
|
|
|
|
if (key == NULL) return NULL;
|
|
|
|
|
if (strlen(key) == 0) return NULL;
|
|
|
|
|
uint32_t hash = adler32(key, strlen(key));
|
|
|
|
|
global_counters.pool_write++;
|
|
|
|
|
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)) {
|
|
|
|
|
#ifndef NO_COUNTERS
|
|
|
|
|
global_counters.pool_write++;
|
|
|
|
|
global_counters.hash_misses_write_acc++;
|
|
|
|
|
if (offset != 0) {
|
|
|
|
|
global_counters.hash_misses_write++;
|
|
|
|
|
}
|
|
|
|
@ -436,6 +648,7 @@ 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) {
|
|
|
|
|
if (key == NULL || path == NULL) return NULL;
|
|
|
|
|
if (strlen(key) == 0 || strlen(path) == 0) return NULL;
|
|
|
|
|
|
|
|
|
|
struct sfx_pool_item *sound = sfx_pool_find_place_for(key);
|
|
|
|
|
SOFT_EXPECT(sound == NULL, == false, NULL);
|
|
|
|
|