2015-01-06 25 views
7

ラスベリーパイプラットフォーム用のALSAデバイスドライバを最終的に作成するためにALSAオーディオレイヤーを学習しようとしました。シンプルに始めて、ALSAのプロジェクトサイトや他のオンラインソースからさまざまなサンプルをまとめて、最も簡単なことをしました.WAVファイルを読み込み、デフォルトのサウンドデバイスで再生します。私はこの単純なCサンプルを動作させることはできません。ラズベリーパイのWAVファイルを読み込んで再生するALSAアプリケーション

libsndfileを使用して、すべてのWAVファイルの読み取り/ヘッダーのデコードを行っています。バッファに読み込んだサンプルが正しいことを確認しました(サンプル値をテキストファイルにダンプするsndfile-to-textアプリケーションに対して、プログラムが何を読み込むかを最初に検証した400Kサンプル)。だから、私のバッファに正しいデータが含まれていることを知っています。問題はALSA APIに渡す方法でなければなりません。

実行すると、右側のチャンネルでのみサウンドが生成され、ゆがんだ/濁っていてほとんど認識できません。ところで、 "aplay"アプリケーションは、同じWAVファイルを完全に再生し、そのファイルが16ビットのLE、44100Hzのステレオであると報告します。これをラズベリーパイで実行する。

スペースを節約するためにここでCプログラムを最小限に抑えましたが、すべてのAPI呼び出しで正しい戻りコードが確認されました。このシンプルなALSAアプリケーションが正しいサウンドを生成しないのはなぜですか?

#include <alsa/asoundlib.h> 
#include <stdio.h> 
#include <sndfile.h> 

#define PCM_DEVICE "default" 

int main(int argc, char **argv) { 

    snd_pcm_t *pcm_handle; 
    snd_pcm_hw_params_t *params; 
    snd_pcm_uframes_t frames; 
    int dir, pcmrc; 

    char *infilename = "/home/pi/shortsample.wav"; 
    int* buf = NULL; 
    int readcount; 

    SF_INFO sfinfo; 
    SNDFILE *infile = NULL; 

    infile = sf_open(infilename, SFM_READ, &sfinfo); 
    fprintf(stderr,"Channels: %d\n", sfinfo.channels); 
    fprintf(stderr,"Sample rate: %d\n", sfinfo.samplerate); 
    fprintf(stderr,"Sections: %d\n", sfinfo.sections); 
    fprintf(stderr,"Format: %d\n", sfinfo.format); 

    /* Open the PCM device in playback mode */ 
    snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0); 

    /* Allocate parameters object and fill it with default values*/ 
    snd_pcm_hw_params_alloca(&params); 
    snd_pcm_hw_params_any(pcm_handle, params); 
    /* Set parameters */ 
    snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); 
    snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE); 
    snd_pcm_hw_params_set_channels(pcm_handle, params, sfinfo.channels); 
    snd_pcm_hw_params_set_rate(pcm_handle, params, sfinfo.samplerate, 0); 

    /* Write parameters */ 
    snd_pcm_hw_params(pcm_handle, params); 

    /* Allocate buffer to hold single period */ 
    snd_pcm_hw_params_get_period_size(params, &frames, &dir); 
    fprintf(stderr,"# frames in a period: %d\n", frames); 

    fprintf(stderr,"Starting read/write loop\n"); 
    buf = malloc(frames * sfinfo.channels * sizeof(int)); 
    while ((readcount = sf_readf_int(infile, buf, frames))>0) { 

     pcmrc = snd_pcm_writei(pcm_handle, buf, readcount); 
     if (pcmrc == -EPIPE) { 
      fprintf(stderr, "Underrun!\n"); 
      snd_pcm_prepare(pcm_handle); 
     } 
     else if (pcmrc < 0) { 
      fprintf(stderr, "Error writing to PCM device: %s\n", snd_strerror(pcmrc)); 
     } 
     else if (pcmrc != readcount) { 
      fprintf(stderr,"PCM write difffers from PCM read.\n"); 
     } 

    } 
    fprintf(stderr,"End read/write loop\n"); 

    snd_pcm_drain(pcm_handle); 
    snd_pcm_close(pcm_handle); 
    free(buf); 

    return 0; 
} 

答えて

4

あなた失敗する可能性があり、すべてのsnd_関数の戻り値をチェックする必要があります。

S16_LEのフォーマットは1サンプルあたり2バイトですが、intには4つあります。 代わりにshortを使用し、sf_readf_shortを使用してください。

+0

私の実際のコードはすべての戻り値をチェックしていますが、私はちょうど転記のためにそれを短縮しました。 intからshortに変更すると、WAVが正しく再生されます...ありがとう! –

関連する問題