#include #include #include xas_bank *xas_bank_new(size_t sample_size, size_t sample_rate, size_t entry_size, size_t entry_count) { xas_bank *bank; size_t entry_size_total = sizeof(xas_bank_entry) + sample_size * entry_size; size_t total = sizeof(xas_bank) + entry_count * entry_size_total; if ((bank = malloc(total)) == NULL) { goto error_malloc_bank; } memset(bank, '\0', total); bank->sample_size = sample_size; bank->sample_rate = sample_rate; bank->entry_size = entry_size; bank->entry_count = entry_count; return bank; error_malloc_bank: return NULL; } void xas_bank_destroy(xas_bank *bank) { free(bank); } int xas_bank_play(xas_bank *bank, size_t entry, float force) { bank->flags |= XAS_BANK_ACTIVE; bank->force = force; bank->entry = entry; bank->index = 0; return 0; } void xas_bank_stop(xas_bank *bank) { bank->flags &= ~XAS_BANK_ACTIVE; bank->force = 0.0; bank->entry = 0; bank->index = 0; } int xas_bank_active(xas_bank *bank) { return bank->flags & XAS_BANK_ACTIVE; } static inline void *ptr(xas_audio_stream *stream, void *buf, size_t index) { return ((uint8_t *)buf) + stream->channels * stream->sample_size * index; } ssize_t xas_bank_record(xas_bank *bank, xas_audio_stream *input, size_t entry_index, size_t count) { xas_bank_entry *entry = &((xas_bank_entry *)(bank + 1))[entry_index]; size_t left = count, index_o = 0; if (count > bank->entry_size) { count = bank->entry_size; } while (left) { ssize_t readlen, amount = left > count? count: left; void *buf; if ((readlen = xas_audio_stream_read(input, &buf, amount)) < 0) { goto error_audio_stream_read; } memcpy(ptr(input, entry + 1, index_o), ptr(input, buf, 0), readlen * bank->sample_size); left -= readlen; index_o += readlen; } return entry->duration = index_o; error_audio_stream_read: return -1; } static ssize_t stream_fill(xas_bank *bank, int16_t *samples, size_t count, xas_audio_stream *stream) { size_t index_o = 0, left = count; while (left) { if (bank->flags & XAS_BANK_ACTIVE) { xas_bank_entry *entry = &((xas_bank_entry *)(bank + 1))[bank->entry]; size_t remaining = entry->duration - bank->index, amount = remaining < left? remaining: left; memcpy(ptr(stream, samples, index_o), ptr(stream, entry + 1, bank->index), amount * stream->channels * stream->sample_size); left -= amount; bank->index += amount; index_o += amount; if (bank->index == entry->duration) { xas_bank_stop(bank); } } else { memset(ptr(stream, samples, index_o), '\0', left); index_o += left; left = 0; } } return count; } void stream_cleanup(xas_bank *bank, xas_audio_stream *stream) { return; } xas_audio_stream *xas_bank_stream_new(xas_bank *bank) { return xas_audio_stream_new_source((xas_audio_fill)stream_fill, (xas_audio_cleanup)stream_cleanup, bank, XAS_AUDIO_MONO, bank->sample_size, bank->sample_rate, bank->entry_size); }