xref: /aosp_15_r20/external/oboe/src/flowgraph/resampler/README.md (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu# Sample Rate Converter
2*05767d91SRobert Wu
3*05767d91SRobert WuThis folder contains a sample rate converter, or "resampler".
4*05767d91SRobert Wu
5*05767d91SRobert WuThe converter is based on a sinc function that has been windowed by a hyperbolic cosine.
6*05767d91SRobert WuWe found this had fewer artifacts than the more traditional Kaiser window.
7*05767d91SRobert Wu
8*05767d91SRobert Wu## Building the Resampler
9*05767d91SRobert Wu
10*05767d91SRobert WuIt is part of [Oboe](https://github.com/google/oboe) but has no dependencies on Oboe.
11*05767d91SRobert WuSo the contents of this folder can be used outside of Oboe.
12*05767d91SRobert Wu
13*05767d91SRobert WuTo build it for use outside of Oboe:
14*05767d91SRobert Wu
15*05767d91SRobert Wu1. Copy the "resampler" folder to a folder in your project that is in the include path.
16*05767d91SRobert Wu2. Add all of the \*.cpp files in the resampler folder to your project IDE or Makefile.
17*05767d91SRobert Wu3. In ResamplerDefinitions.h, define RESAMPLER_OUTER_NAMESPACE with your own project name. Alternatively, use -DRESAMPLER_OUTER_NAMESPACE=mynamespace when compiling to avoid modifying the resampler code.
18*05767d91SRobert Wu
19*05767d91SRobert Wu## Creating a Resampler
20*05767d91SRobert Wu
21*05767d91SRobert WuInclude the [main header](MultiChannelResampler.h) for the resampler.
22*05767d91SRobert Wu
23*05767d91SRobert Wu    #include "resampler/MultiChannelResampler.h"
24*05767d91SRobert Wu
25*05767d91SRobert WuHere is an example of creating a stereo resampler that will convert from 44100 to 48000 Hz.
26*05767d91SRobert WuOnly do this once, when you open your stream. Then use the sample resampler to process multiple buffers.
27*05767d91SRobert Wu
28*05767d91SRobert Wu    MultiChannelResampler *resampler = MultiChannelResampler::make(
29*05767d91SRobert Wu            2, // channel count
30*05767d91SRobert Wu            44100, // input sampleRate
31*05767d91SRobert Wu            48000, // output sampleRate
32*05767d91SRobert Wu            MultiChannelResampler::Quality::Medium); // conversion quality
33*05767d91SRobert Wu
34*05767d91SRobert WuPossible values for quality include { Fastest, Low, Medium, High, Best }.
35*05767d91SRobert WuHigher quality levels will sound better but consume more CPU because they have more taps in the filter.
36*05767d91SRobert Wu
37*05767d91SRobert Wu## Fractional Frame Counts
38*05767d91SRobert Wu
39*05767d91SRobert WuNote that the number of output frames generated for a given number of input frames can vary.
40*05767d91SRobert Wu
41*05767d91SRobert WuFor example, suppose you are converting from 44100 Hz to 48000 Hz and using an input buffer with 960 frames. If you calculate the number of output frames you get:
42*05767d91SRobert Wu
43*05767d91SRobert Wu    960.0 * 48000 / 44100 = 1044.897959...
44*05767d91SRobert Wu
45*05767d91SRobert WuYou cannot generate a fractional number of frames. So the resampler will sometimes generate 1044 frames and sometimes 1045 frames. On average it will generate 1044.897959 frames. The resampler stores the fraction internally and keeps track of when to consume or generate a frame.
46*05767d91SRobert Wu
47*05767d91SRobert WuYou can either use a fixed number of input frames or a fixed number of output frames. The other frame count will vary.
48*05767d91SRobert Wu
49*05767d91SRobert Wu## Calling the Resampler with a fixed number of OUTPUT frames
50*05767d91SRobert Wu
51*05767d91SRobert WuIn this example, suppose we have a fixed number of output frames and a variable number of input frames.
52*05767d91SRobert Wu
53*05767d91SRobert WuAssume you start with these variables and a method that returns the next input frame:
54*05767d91SRobert Wu
55*05767d91SRobert Wu    float *outputBuffer;     // multi-channel buffer to be filled
56*05767d91SRobert Wu    int    numOutputFrames;  // number of frames of output
57*05767d91SRobert Wu
58*05767d91SRobert WuThe resampler has a method isWriteNeeded() that tells you whether to write to or read from the resampler.
59*05767d91SRobert Wu
60*05767d91SRobert Wu    int outputFramesLeft = numOutputFrames;
61*05767d91SRobert Wu    while (outputFramesLeft > 0) {
62*05767d91SRobert Wu        if(resampler->isWriteNeeded()) {
63*05767d91SRobert Wu            const float *frame = getNextInputFrame(); // you provide this
64*05767d91SRobert Wu            resampler->writeNextFrame(frame);
65*05767d91SRobert Wu        } else {
66*05767d91SRobert Wu            resampler->readNextFrame(outputBuffer);
67*05767d91SRobert Wu            outputBuffer += channelCount;
68*05767d91SRobert Wu            outputFramesLeft--;
69*05767d91SRobert Wu        }
70*05767d91SRobert Wu    }
71*05767d91SRobert Wu
72*05767d91SRobert Wu## Calling the Resampler with a fixed number of INPUT frames
73*05767d91SRobert Wu
74*05767d91SRobert WuIn this example, suppose we have a fixed number of input frames and a variable number of output frames.
75*05767d91SRobert Wu
76*05767d91SRobert WuAssume you start with these variables:
77*05767d91SRobert Wu
78*05767d91SRobert Wu    float *inputBuffer;     // multi-channel buffer to be consumed
79*05767d91SRobert Wu    float *outputBuffer;    // multi-channel buffer to be filled
80*05767d91SRobert Wu    int    numInputFrames;  // number of frames of input
81*05767d91SRobert Wu    int    numOutputFrames = 0;
82*05767d91SRobert Wu    int    channelCount;    // 1 for mono, 2 for stereo
83*05767d91SRobert Wu
84*05767d91SRobert Wu    int inputFramesLeft = numInputFrames;
85*05767d91SRobert Wu    while (inputFramesLeft > 0) {
86*05767d91SRobert Wu        if(resampler->isWriteNeeded()) {
87*05767d91SRobert Wu            resampler->writeNextFrame(inputBuffer);
88*05767d91SRobert Wu            inputBuffer += channelCount;
89*05767d91SRobert Wu            inputFramesLeft--;
90*05767d91SRobert Wu        } else {
91*05767d91SRobert Wu            resampler->readNextFrame(outputBuffer);
92*05767d91SRobert Wu            outputBuffer += channelCount;
93*05767d91SRobert Wu            numOutputFrames++;
94*05767d91SRobert Wu        }
95*05767d91SRobert Wu    }
96*05767d91SRobert Wu
97*05767d91SRobert Wu## Deleting the Resampler
98*05767d91SRobert Wu
99*05767d91SRobert WuWhen you are done, you should delete the Resampler to avoid a memory leak.
100*05767d91SRobert Wu
101*05767d91SRobert Wu    delete resampler;
102