2

我正在尝试在 C 中实现一个简单的音频延迟。我之前制作了一个测试延迟程序,该程序在打印的正弦波上运行并有效地工作。我尝试将我的延迟合并为 SFProcess - libsndfile 中的过程 - 用我的音频“数据”输入替换正弦波输入。

我几乎拥有它,但我得到的不是干净的采样延迟,而是各种故障和失真。

关于如何纠正这个问题的任何想法?

#include <stdio.h>
#include </usr/local/include/sndfile.h>//libsamplerate libsamplerate
//#include </usr/local/include/samplerate.h>

#define BUFFER_LEN 1024 //defines buffer length
#define MAX_CHANNELS 2 //defines max channels 

static void process_data (double *data, double*circular,int count, int numchannels, int circular_pointer );

enum {DT_PROGNAME,ARG_INFILE,ARG_OUTFILE,ARG_NARGS, DT_VOL};

int main (int argc, const char * argv[])//Main
{
    static double data [BUFFER_LEN]; // the buffer that carries the samples

    double circular [44100] = {0}; // the circular buffer for the delay
    for (int i = 0; i < 44100; i++) { circular[i] = 0; }  // zero the circular buffer

    int circular_pointer = 0;          // where we currently are in the circular buffer

    //float myvolume; // the volume entered by the user as optional 3rd argument

    SNDFILE *infile, *outfile;
    SF_INFO sfinfo;

    int readcount;
    const char *infilename = NULL;
    const char  *outfilename = NULL;

    if(argc < ARG_NARGS) {
        printf("usage: %s infile outfile\n",argv[DT_PROGNAME]);
        return 1;
    }

    //if(argc > ARG_NARGS) {
    //  
    //  myvolume = argv[DT_VOL];
    //};
    infilename = argv[ARG_INFILE];
    outfilename = argv[ARG_OUTFILE];

    if (! (infile = sf_open (infilename, SFM_READ, &sfinfo)))

    {printf ("Not able to open input file %s.\n", infilename) ;
        puts (sf_strerror (NULL)) ;
        return  1 ;
    };

    if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo)))
    {   printf ("Not able to open output file %s.\n", outfilename) ;
        puts (sf_strerror (NULL)) ;
        return  1 ;
    } ;

    while ((readcount = sf_read_double (infile, data, BUFFER_LEN)))
    {   process_data (data, circular, readcount, sfinfo.channels,  circular_pointer) ;
        sf_write_double (outfile, data, readcount) ;
    };

    sf_close (infile) ;
    sf_close (outfile) ;

    printf("the sample rate is %d\n", sfinfo.samplerate);

    return 0;
}


static void process_data (double *data, double *circular, int count, int numchannels, int circular_pointer) {

    //int j,k;
    //float vol = 1;
    int playhead;
    int wraparound = 10000;

    float delay = 1000;  // delay time in samples

    for (int ind = 0; ind < BUFFER_LEN; ind++){

        circular_pointer = fmod(ind,wraparound);     // wrap around pointer
        circular[circular_pointer] = data[ind];


        playhead = fmod(ind-delay, wraparound);     // read the delayed signal

        data[ind] = circular[playhead];            // output delayed signal

        circular[ind] = data[ind];   // write the incoming signal
    };


    //volume
    /*for (j=0; j<numchannels; j++) {
        for (k=0; k<count; k++){ 
            data[k] = data[k]*-vol;*/

        //}printf ("the volume is %f", vol);

    return;
}
4

3 回答 3

1

您的代码存在一些问题,导致您访问数组边界之外并且未按预期方式读取\写入循环缓冲区。

我建议阅读http://en.wikipedia.org/wiki/Circular_buffer以更好地了解循环缓冲区。

您的代码遇到的主要问题:

  1. 循环指针应该初始化为延迟量(基本上写头从0开始,所以永远不会有任何延迟!)
  2. 在对 process_data 的调用之间不更新播放头和循环缓冲区(循环缓冲区按值传递......)
  3. 播放头正在从负索引中读取。正确的播放头计算是

    #define MAX_DELAY     44100
    playhead++;
    playhead = playhead%MAX_DELAY;
    
  4. 在 process_data 结束时对 circular_buffer 的第二次写入是不必要且不正确的。

我强烈建议花一些时间在调试器中运行您的代码,并密切关注您的播放头和循环指针正在做什么。

麦克风

于 2013-05-13T11:10:06.890 回答
0

至少一个问题是您通过值而不是引用传递 circular_pointer。当您在函数中更新它时,它会在您下次调用该函数时恢复到相同的值。

我认为你在正确的轨道上,在这里,但如果你想要一些结构更好的东西,你可能还想查看这个答案:

如何使用objective-c在音频文件上添加回声效果

于 2013-05-10T16:30:24.903 回答
-3

样本延迟可以设置为 100 毫秒就足够了

于 2013-05-10T12:45:48.413 回答