• 简洁明了的插值音频重采样算法例子 (附完整C代码)


    近一段时间在图像算法以及音频算法之间来回游走。

    经常有一些需求,需要将音频进行采样转码处理。

    现有的知名开源库,诸如: webrtc , sox等,

    代码阅读起来实在闹心。

    而音频重采样其实也就是插值算法。

    与图像方面的插值算法没有太大的区别。

    基于双线性插值的思路。

    博主简单实现一个简洁的重采样算法,

    用在对采样音质要求不高的情况下,也是够用了。

    编解码库采用dr_wav

    https://github.com/mackron/dr_libs/blob/master/dr_wav.h 

    近期有点强迫症,纯c实现。

    贴上完整代码:

    #ifdef __cplusplus
    extern "C" {
    #endif
    #define  _CRT_SECURE_NO_WARNINGS
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    #define DR_WAV_IMPLEMENTATION
    
    #include "dr_wav.h"
    
    #define DR_MP3_IMPLEMENTATION
    
    
    #include "dr_mp3.h"
    
    #include "timing.h"
    
    
    void wavWrite_f32(char *filename, float *buffer, int sampleRate, uint32_t totalSampleCount, uint32_t channels) {
        drwav_data_format format;
        format.container = drwav_container_riff;
        format.format = DR_WAVE_FORMAT_IEEE_FLOAT;
        format.channels = channels;
        format.sampleRate = (drwav_uint32) sampleRate;
        format.bitsPerSample = 32;
        drwav *pWav = drwav_open_file_write(filename, &format);
        if (pWav) {
            drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer);
            drwav_uninit(pWav);
            if (samplesWritten != totalSampleCount) {
                fprintf(stderr, "write file [%s] error.
    ", filename);
                exit(1);
            }
        }
    }
    
    float *wavRead_f32(const char *filename, uint32_t *sampleRate, uint64_t *sampleCount, uint32_t *channels) {
        drwav_uint64 totalSampleCount = 0;
        float *input = drwav_open_file_and_read_pcm_frames_f32(filename, channels, sampleRate, &totalSampleCount);
        if (input == NULL) {
            drmp3_config pConfig;
            input = drmp3_open_file_and_read_f32(filename, &pConfig, &totalSampleCount);
            if (input != NULL) {
                *channels = pConfig.outputChannels;
                *sampleRate = pConfig.outputSampleRate;
            }
        }
        if (input == NULL) {
            fprintf(stderr, "read file [%s] error.
    ", filename);
            exit(1);
        }
        *sampleCount = totalSampleCount * (*channels);
        return input;
    }
    
    
    void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
        const char *end;
        const char *p;
        const char *s;
        if (path[0] && path[1] == ':') {
            if (drv) {
                *drv++ = *path++;
                *drv++ = *path++;
                *drv = '';
            }
        } else if (drv)
            *drv = '';
        for (end = path; *end && *end != ':';)
            end++;
        for (p = end; p > path && *--p != '\' && *p != '/';)
            if (*p == '.') {
                end = p;
                break;
            }
        if (ext)
            for (s = end; (*ext = *s++);)
                ext++;
        for (p = end; p > path;)
            if (*--p == '\' || *p == '/') {
                p++;
                break;
            }
        if (name) {
            for (s = p; s < end;)
                *name++ = *s++;
            *name = '';
        }
        if (dir) {
            for (s = path; s < p;)
                *dir++ = *s++;
            *dir = '';
        }
    }
    
    
    uint64_t Resample_f32(const float *input, float *output, int inSampleRate, int outSampleRate, uint64_t inputSize,
                          uint32_t channels
    ) {
        if (input == NULL)
            return 0;
        uint64_t outputSize = inputSize * outSampleRate / inSampleRate;
        if (output == NULL)
            return outputSize;
        double stepDist = ((double) inSampleRate / (double) outSampleRate);
        const uint64_t fixedFraction = (1LL << 32);
        const double normFixed = (1.0 / (1LL << 32));
        uint64_t step = ((uint64_t) (stepDist * fixedFraction + 0.5));
        uint64_t curOffset = 0;
        for (uint32_t i = 0; i < outputSize; i += 1) {
            for (uint32_t c = 0; c < channels; c += 1) {
                *output++ = (float) (input[c] + (input[c + channels] - input[c]) * (
                        (double) (curOffset >> 32) + ((curOffset & (fixedFraction - 1)) * normFixed)
                )
                );
            }
            curOffset += step;
            input += (curOffset >> 32) * channels;
            curOffset &= (fixedFraction - 1);
        }
        return outputSize;
    }
    
    
    uint64_t Resample_s16(const int16_t *input, int16_t *output, int inSampleRate, int outSampleRate, uint64_t inputSize,
                          uint32_t channels
    ) {
        if (input == NULL)
            return 0;
        uint64_t outputSize = inputSize * outSampleRate / inSampleRate;
        if (output == NULL)
            return outputSize;
        double stepDist = ((double) inSampleRate / (double) outSampleRate);
        const uint64_t fixedFraction = (1LL << 32);
        const double normFixed = (1.0 / (1LL << 32));
        uint64_t step = ((uint64_t) (stepDist * fixedFraction + 0.5));
        uint64_t curOffset = 0;
        for (uint32_t i = 0; i < outputSize; i += 1) {
            for (uint32_t c = 0; c < channels; c += 1) {
                *output++ = (int16_t) (input[c] + (input[c + channels] - input[c]) * (
                        (double) (curOffset >> 32) + ((curOffset & (fixedFraction - 1)) * normFixed)
                )
                );
            }
            curOffset += step;
            input += (curOffset >> 32) * channels;
            curOffset &= (fixedFraction - 1);
        }
        return outputSize;
    }
    
    void printUsage() {
        printf("usage:
    ");
        printf("./Resampler input.wav 48000
    ");
        printf("./Resampler input.mp3 16000
    ");
        printf("or
    ");
        printf("./Resampler input.wav output.wav 8000
    ");
        printf("./Resampler input.mp3 output.wav 44100
    ");
        printf("press any key to exit.
    ");
        getchar();
    }
    
    void resampler(char *in_file, char *out_file, uint32_t targetSampleRate) {
        if (targetSampleRate == 0) {
            printUsage();
            return;
        }
        uint32_t sampleRate = 0;
        uint64_t sampleCount = 0;
        uint32_t channels = 0;
        float *input = wavRead_f32(in_file, &sampleRate, &sampleCount, &channels);
        uint64_t targetSampleCount = Resample_f32(input, 0, sampleRate, targetSampleRate, sampleCount, channels);
        if (input) {
            float *output = (float *) malloc(targetSampleCount * sizeof(float));
            if (output) {
                double startTime = now();
                Resample_f32(input, output, sampleRate, targetSampleRate, sampleCount / channels, channels);
                double time_interval = calcElapsed(startTime, now());
                printf("time interval: %f ms
     ", (time_interval * 1000));
                wavWrite_f32(out_file, output, targetSampleRate, (uint32_t) targetSampleCount, channels);
                free(output);
            }
            free(input);
        }
    }
    
    
    int main(int argc, char *argv[]) {
        printf("Audio Processing
    ");
        printf("blog:http://cpuimage.cnblogs.com/
    ");
        printf("Audio Resampler
    ");
        if (argc < 3) {
            printUsage();
            return -1;
        }
        char *in_file = argv[1];
        if (argc > 3) {
            char *out_file = argv[2];
            uint32_t targetSampleRate = (uint32_t) atoi(argv[3]);
            resampler(in_file, out_file, targetSampleRate);
        } else {
            int32_t targetSampleRate = (uint32_t) atoi(argv[2]);
            char drive[3];
            char dir[256];
            char fname[256];
            char ext[256];
            char out_file[1024];
            splitpath(in_file, drive, dir, fname, ext);
            sprintf(out_file, "%s%s%s_out.wav", drive, dir, fname);
            resampler(in_file, out_file, targetSampleRate);
        }
    
        return 0;
    }
    
    #ifdef __cplusplus
    }
    #endif

    项目地址:

    https://github.com/cpuimage/resampler/

    不多注释,代码比较简单,一看就明了。

    示例具体流程为:

    加载wav(拖放wav文件到可执行文件上)->重采样为原采样的2倍->保存wav

    若有其他相关问题或者需求也可以邮件联系俺探讨。

    邮箱地址是: 
    gaozhihan@vip.qq.com

  • 相关阅读:
    TCP拥塞控制算法纵横谈-Illinois和YeAH
    精度解析百思不得姐流行框架之精华版
    3D物体识别的如果检验
    Android内存泄漏检測与MAT使用
    Android学习——在Android中使用OpenCV的第一个程序
    virtio-netdev 数据包的发送
    【剑指Offer学习】【面试题23:从上往下打印二叉树】
    纵谈进程枚举
    《谈学单片机有前途还是嵌入式系统有前途》一文吴坚鸿回复整理
    结构类模式(七):代理(Proxy)
  • 原文地址:https://www.cnblogs.com/cpuimage/p/8654297.html
Copyright © 2020-2023  润新知