summaryrefslogtreecommitdiff
path: root/src/libultra/audio/resample.c
blob: 8001eb151b220dd037de69bf8c07388e1460b9db (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
#include "libaudio.h"
#include "synthInternals.h"
#include "stdbool.h"
#include "stddef.h"
#include "ultra64/convert.h"

Acmd* alResamplePull(void* filter, s16* outp, s32 outCnt, s32 sampleOffset, Acmd* p) {
    ALResampler* f = (ALResampler*)filter;
    Acmd* ptr = p;
    s16 inp;
    s32 inCount;
    ALFilter* source = f->filter.source;
    s32 incr;
    f32 finCount;

    inp = AL_DECODER_OUT;

    if (outCnt == 0) {
        return ptr;
    }

    // check if resampler is required
    if (f->upitch != 0) {
        ptr = (*source->handler)(source, &inp, outCnt, sampleOffset, p);
        aDMEMMove(ptr++, inp, *outp, outCnt << 1);
    } else {
        // clip to maximum allowable pitch
        // FIXME: should we check for some minimum as well?
        if (f->ratio > MAX_RATIO) {
            f->ratio = MAX_RATIO;
        }

        // quantize the pitch
        f->ratio = (s32)(f->ratio * UNITY_PITCH);
        f->ratio = f->ratio / UNITY_PITCH;

        // determine how many samples to generate
        finCount = f->delta + f->ratio * (f32)outCnt;
        inCount = (s32)finCount;
        f->delta = finCount - (f32)inCount;

        // ask all filters upstream from us to build their command lists.
        ptr = (*source->handler)(source, &inp, inCount, sampleOffset, p);

        // construct our portion of the command list
        incr = (s32)(f->ratio * UNITY_PITCH);
        aSetBuffer(ptr++, 0, inp, *outp, outCnt << 1);
        aResample(ptr++, f->first, incr, osVirtualToPhysical(f->state));
        f->first = false;
    }
    return ptr;
}

s32 alResampleParam(void* filter, s32 paramID, void* param) {
    ALFilter* f = (ALFilter*)filter;
    ALResampler* r = (ALResampler*)filter;
    union {
        f32 f;
        s32 i;
    } data;

    switch (paramID) {
        case AL_FILTER_SET_SOURCE:
            f->source = (ALFilter*)param;
            break;

        case AL_FILTER_RESET:
            r->delta = 0.0f;
            r->first = true;
            r->motion = AL_STOPPED;
            r->upitch = 0;
            if (f->source != NULL) {
                (*f->source->setParam)(f->source, AL_FILTER_RESET, 0);
            }
            break;

        case AL_FILTER_START:
            r->motion = AL_PLAYING;
            if (f->source != NULL) {
                (*f->source->setParam)(f->source, AL_FILTER_START, 0);
            }
            break;

        case AL_FILTER_SET_PITCH:
            data.i = (s32)param;
            r->ratio = data.f;
            break;

        case AL_FILTER_SET_UNITY_PITCH:
            r->upitch = 1;
            break;

        default:
            if (f->source != NULL) {
                (*f->source->setParam)(f->source, paramID, param);
            }
            break;
    }
    return 0;
}