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