From 82939a2228fb00c243423bc72ffd31ca37e81074 Mon Sep 17 00:00:00 2001 From: Dimitri Diakopoulos Date: Tue, 26 Jul 2016 10:29:59 -0700 Subject: [PATCH] hermite resampling just for fun --- examples/src/Main.cpp | 10 ++++++---- include/libnyquist/WavEncoder.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/examples/src/Main.cpp b/examples/src/Main.cpp index 2a31cad..a83a1b6 100644 --- a/examples/src/Main.cpp +++ b/examples/src/Main.cpp @@ -41,7 +41,7 @@ int main(int argc, const char **argv) try //loader.Load(fileData.get(), "test_data/1ch/44100/8/test.wav"); //loader.Load(fileData.get(), "test_data/1ch/44100/16/test.wav"); //loader.Load(fileData.get(), "test_data/1ch/44100/24/test.wav"); - //loader.Load(fileData.get(), "test_data/1ch/44100/32/test.wav"); + loader.Load(fileData.get(), "test_data/1ch/44100/32/test.wav"); //loader.Load(fileData.get(), "test_data/1ch/44100/64/test.wav"); // 2-channel wave @@ -86,14 +86,16 @@ int main(int argc, const char **argv) try //loader.Load(fileData.get(), "test_data/ad_hoc/44_16_mono.mpc"); } + /* // Test Recording Capabilities of AudioDevice - fileData->samples.reserve(44100 * 2); + fileData->samples.reserve(44100 * 5); fileData->channelCount = 1; fileData->frameSize = 32; - fileData->lengthSeconds = 2.0; + fileData->lengthSeconds = 5.0; fileData->sampleRate = 44100; - std::cout << "Starting recording for two seconds..." << std::endl; + std::cout << "Starting recording ..." << std::endl; myDevice.Record(fileData->sampleRate * fileData->lengthSeconds, fileData->samples); + */ // Libnyquist does not (currently) perform sample rate conversion - not exactly true, anymore. See below. if (fileData->sampleRate != desiredSampleRate) diff --git a/include/libnyquist/WavEncoder.h b/include/libnyquist/WavEncoder.h index 8aedfb6..f66a03b 100644 --- a/include/libnyquist/WavEncoder.h +++ b/include/libnyquist/WavEncoder.h @@ -32,7 +32,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace nqr { - // This is a naieve implementation of a resampling filter where a lerp is used as a bad low-pass. // It very far from the ideal case and should be used with caution (or not at all) on signals that matter. // It is included here to upsample 44.1k to 48k for the purposes of microphone input => Opus, where the the @@ -46,7 +45,7 @@ namespace nqr { uint32_t readIndex = static_cast(virtualReadIndex); i = virtualReadIndex - readIndex; - a = input[readIndex + 0]; + a = input[readIndex + 0]; b = input[readIndex + 1]; sample = (1.0 - i) * a + i * b; // linear interpolate output.push_back(sample); @@ -54,6 +53,32 @@ namespace nqr } } + static inline double sample_hermite_4p_3o(double x, double * y) + { + static double c0, c1, c2, c3; + c0 = y[1]; + c1 = (1.0/2.0)*(y[2]-y[0]); + c2 = (y[0] - (5.0/2.0)*y[1]) + (2.0*y[2] - (1.0/2.0)*y[3]); + c3 = (1.0/2.0)*(y[3]-y[0]) + (3.0/2.0)*(y[1]-y[2]); + return ((c3*x+c2)*x+c1)*x+c0; + } + + static inline void hermite_resample(const double rate, const std::vector & input, std::vector & output, size_t samplesToProcess) + { + double virtualReadIndex = 1; + double i, sample; + uint32_t n = samplesToProcess - 1; + while (n--) + { + uint32_t readIndex = static_cast(virtualReadIndex); + i = virtualReadIndex - readIndex; + double samps[4] = {input[readIndex - 1], input[readIndex], input[readIndex + 1], input[readIndex + 2]}; + sample = sample_hermite_4p_3o(i, samps); // cubic hermite interpolate over 4 samples + output.push_back(sample); + virtualReadIndex += rate; + } + } + enum EncoderError { NoError,