aboutsummaryrefslogtreecommitdiff
path: root/src/sound.c
blob: 3f9989593c2837f1751af2256215ae9e10eeb318 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <stdint.h>

#include "data.h"

#include "mikmod.h"

typedef struct
{
    SAMPLE *s;
    const char *data;
    size_t len;
} Efx;

#define EFX_CNT 7

static Efx efx[EFX_CNT] =
{
    { NULL, (const char *)binary_gold_efx_start, (size_t)&binary_gold_efx_size},
    { NULL, (const char *)binary_jump_efx_start, (size_t)&binary_jump_efx_size},
    { NULL, (const char *)binary_warp_efx_start, (size_t)&binary_warp_efx_size},
    { NULL, (const char *)binary_pickup_efx_start, (size_t)&binary_pickup_efx_size},
    { NULL, (const char *)binary_time_efx_start, (size_t)&binary_time_efx_size},
    { NULL, (const char *)binary_hit_efx_start, (size_t)&binary_hit_efx_size},
    { NULL, (const char *)binary_death_efx_start, (size_t)&binary_death_efx_size},
};

static uint8_t cur = 0;
static uint32_t voice = 0;

static MODULE *music = NULL;

#define MAX_QUEUE 4

static uint8_t queue[MAX_QUEUE];
static uint8_t queue_top;

uint8_t sound_init()
{
    MikMod_RegisterAllDrivers();
    MikMod_RegisterLoader(&load_it);

    md_mode |= DMODE_SOFT_SNDFX | DMODE_SOFT_MUSIC;
    md_volume = 128;
    md_sndfxvolume = 128;
    md_pansep = 0;
    md_mixfreq = 22050;

    if (MikMod_Init(NULL))
        return 0;

    for (uint8_t i = 0; i < EFX_CNT; i++)
    {
        efx[i].s = Sample_LoadMem(efx[i].data, efx[i].len);
        if (!efx[i].s)
            return 0;
    }

    /* 1 voice for effects */
    MikMod_SetNumVoices(-1, 1);

    /* needs a song playing to get effects; have a "silence" pattern on 0 */
    music = Player_LoadMem((const char *)binary_music_start, (size_t)&binary_music_size, 8, 0);
    if (!music)
        return 0;

    Player_Start(music);
    MikMod_EnableOutput();

    queue_top = 0;

    return 1;
}

volatile static uint8_t divider = 0;

/* To be called from the timer int, so we update every 540ms approx by using a
 * counter and updating 1 in 10 interrupts */
void sound_update()
{
    if (++divider == 10)
    {
        divider = 0;
        MikMod_Update();
    }
}

void sound_mute()
{
    MikMod_DisableOutput();
}

void sound_unmute()
{
    MikMod_EnableOutput();
}

void sound_free()
{
    MikMod_DisableOutput();

    if (music)
        Player_Free(music);

    for (uint8_t i = 0; i < EFX_CNT; i++)
        if (!efx[i].s)
            Sample_Free(efx[i].s);

    MikMod_Exit();
}

void sound_music_pattern(uint16_t pat)
{
    Player_SetPosition(pat);
}

void sound_play_efx(uint8_t efxno)
{
    if (cur > efxno && !Voice_Stopped(voice))
        return;

    cur = efxno;
    voice = Sample_Play(efx[cur].s, 0, 0);
}

void sound_queue_efx(uint8_t efxno)
{
    if (queue_top >= MAX_QUEUE)
        return;

    queue[queue_top++] = efxno;
}

void sound_play_queue()
{
    while (queue_top > 0)
        sound_play_efx(queue[--queue_top]);

    MikMod_Update();
}