summaryrefslogtreecommitdiffstats
path: root/src/bank.c
blob: 957d6c073679e525be8bfc5483727934c1d8de9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdlib.h>
#include <string.h>

#include <xas/bank.h>

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) + entry_size;

    size_t total = sizeof(xas_bank) + sample_size
                                      * entry_size_total
                                      * entry_count;

    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;
}

static inline void *ptr(xas_audio_stream *stream, void *buf, size_t index) {
    return ((uint8_t *)buf) + stream->channels * stream->sample_size * index;
}

static ssize_t bank_fill(xas_bank *bank,
                         int16_t *samples,
                         size_t count,
                         xas_audio_stream *stream) {
    size_t index_o = 0,
           left    = count;

    if (!(bank->flags & XAS_BANK_ACTIVE)) {
        memset(samples, '\0', count * bank->sample_size);

        return count;
    }

    while (left) {
        xas_bank_entry *entry =
            &((xas_bank_entry *)(bank + 1))[bank->entry];

        size_t remaining = bank->entry_size - 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;
        index_o += amount;

        bank->index += amount;

        if (bank->index == entry->duration) {
            bank->index = 0;
        }
    }

    return count;
}

void bank_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)bank_fill,
                                         (xas_audio_cleanup)bank_cleanup,
                                         bank,
                                         XAS_AUDIO_MONO,
                                         bank->sample_size,
                                         bank->sample_rate,
                                         bank->entry_size);
}