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. circle_pointer は遅延量に初期化する必要があります (基本的に、書き込みヘッドは 0 から開始されるため、遅延はありません!)
  2. playhead と circle_buffer は、process_data への呼び出し間で更新されません (circular_buffer は値で渡されます...)
  3. playhead は負のインデックスから読み取っています。正しい再生ヘッドの計算は

    #define MAX_DELAY     44100
    playhead++;
    playhead = playhead%MAX_DELAY;
    
  4. process_data の最後にある circle_buffer への 2 回目の書き込みは不要であり、正しくありません。

デバッガーでコードを実行し、再生ヘッドとcircular_pointerが何をしているかを注意深く観察する時間を費やすことを強くお勧めします。

マイク

于 2013-05-13T11:10:06.890 に答える
0

少なくとも 1 つの問題は、circular_pointer を参照ではなく値で渡すことです。関数内で更新すると、次に関数を呼び出したときに同じ値に戻ります。

ここでは正しい軌道に乗っていると思いますが、もう少し構造化されたものが必要な場合は、この回答もチェックアウトすることをお勧めします。

Objective-Cを使用してオーディオファイルにエコー効果を追加する方法

于 2013-05-10T16:30:24.903 に答える