summaryrefslogtreecommitdiff
path: root/arm7/lib/src/SND_util.c
blob: 5c0b220bbc3cd20d68227bab9ed9add2b3875a08 (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
#include "SND_util.h"

#include "syscall.h"

// TODO remove this extern once the static const definition of it is here
extern s8 sLfoSinTable[0x21];

u16 SND_CalcTimer(int timer, int pitch)
{
    int octave = 0;
    int pitch_normalized = -pitch;

    while (pitch_normalized < 0)
    {
        octave--;
        pitch_normalized += 768;
    }

    while (pitch_normalized >= 768)
    {
        octave++;
        pitch_normalized -= 768;
    }

    u64 result = SVC_GetPitchTable(pitch_normalized);

    result += 0x10000;
    result *= timer;

    int shift = octave - 16;

    if (shift <= 0)
    {
        shift = -shift;
        result >>= shift;
    }
    else if (shift < 32)
    {
        // clamp in case timer value overflows
        u64 tmp = result & ~0uLL << (32 - shift);
        if (tmp != 0)
            return 0xFFFF;
        result <<= shift;
    }
    else
    {
        return 0xFFFF;
    }

    if (result < 0x10)
        result = 0x10;
    else if (result > 0xFFFF)
        result = 0xFFFF;

    return (u16)result;
}

u16 SND_CalcChannelVolume(int value)
{
    if (value < SND_VOL_DB_MIN)
        value = SND_VOL_DB_MIN;
    else if (value > 0)
        value = 0;

    int result = SVC_GetVolumeTable(value + (-SND_VOL_DB_MIN));
    int div;

    if (value < -240)
        div = 3;
    else if (value < -120)
        div = 2;
    else if (value < -60)
        div = 1;
    else
        div = 0;

    return (u16)(result | (div << 8));
}

s8 SND_SinIdx(int x)
{
    // BUG: UB for out of range values

    if (x < 0x20)
    {
        return sLfoSinTable[x];
    }
    else if (x < 0x40)
    {
        return sLfoSinTable[0x40 - x];
    }
    else if (x < 0x60)
    {
        return (s8)(-sLfoSinTable[x - 0x40]);
    }
    else
    {
        return (s8)(-sLfoSinTable[0x20 - (x - 0x60)]);
    }
}

u16 SND_CalcRandom(void)
{
    static u32 state = 0x12345678;

    // values from "Numerical Recipes"
    state = state * 1664525u + 1013904223u;
    return (u16)(state >> 16u);
}