2016-05-02 19 views
2

我正嘗試構建一個使用EEG輸入並在Ras接近實時的Raspberry PI上輸出光脈衝和雙耳節拍的大腦設備。使用WiringPi光輸出不成問題,但任何音頻輸出似乎都是一個主要障礙。計算緩衝區正弦波的數學計算很簡單,但通過任何標準庫在兩個頻道上播放兩個頻率似乎是一個非常複雜的過程,我不能拿出任何相關示例。感謝this tutorial,我成功地打開和關閉了一個ALSA設備,這使得我的代碼非常簡單,但對於ALSA來說似乎是必需的。如果有人能夠向我展示在左右聲道上播放兩種不同計算音調的最簡單方法,我會非常感激。下面的代碼是我能找到的最簡單的ALSA回放示例。C++中的雙耳節拍

#include <alsa/asoundlib.h> 

#include <iostream> 

using namespace std; 

// Globals are generally a bad idea in code. We're using one here to keep it simple. 

snd_pcm_t * _soundDevice; 

bool Init(const char *name) 

{ 

    int i; 

    int err; 

    snd_pcm_hw_params_t *hw_params; 

    if(name == NULL) 

    { 

     // Try to open the default device 

     err = snd_pcm_open(&_soundDevice, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0); 

    } 

    else 

    { 

     // Open the device we were told to open. 

     err = snd_pcm_open (&_soundDevice, name, SND_PCM_STREAM_PLAYBACK, 0); 

    } 

    // Check for error on open. 

    if(err < 0) 

    { 

     cout << "Init: cannot open audio device " << name << " (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    else 

    { 

     cout << "Audio device opened successfully." << endl; 

    } 

    // Allocate the hardware parameter structure. 

    if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) 

    { 

     cout << "Init: cannot allocate hardware parameter structure (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    if ((err = snd_pcm_hw_params_any (_soundDevice, hw_params)) < 0) 

    { 

     cout << "Init: cannot initialize hardware parameter structure (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    // Enable resampling. 

    unsigned int resample = 1; 

    err = snd_pcm_hw_params_set_rate_resample(_soundDevice, hw_params, resample); 

    if (err < 0) 

    { 

     cout << "Init: Resampling setup failed for playback: " << snd_strerror(err) << endl; 

     return err; 

    } 

    // Set access to RW interleaved. 

    if ((err = snd_pcm_hw_params_set_access (_soundDevice, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 

    { 

     cout << "Init: cannot set access type (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    if ((err = snd_pcm_hw_params_set_format (_soundDevice, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) 

    { 

     cout << "Init: cannot set sample format (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    // Set channels to stereo (2). 

    if ((err = snd_pcm_hw_params_set_channels (_soundDevice, hw_params, 2)) < 0) 

    { 

     cout << "Init: cannot set channel count (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    // Set sample rate. 

    unsigned int actualRate = 44100; 

    if ((err = snd_pcm_hw_params_set_rate_near (_soundDevice, hw_params, &actualRate, 0)) < 0) 

    { 

     cout << "Init: cannot set sample rate to 44100. (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    if(actualRate < 44100) 

    { 

     cout << "Init: sample rate does not match requested rate. (" << "44100 requested, " << actualRate << " acquired)" << endl; 

    } 

    // Apply the hardware parameters that we've set. 

    if ((err = snd_pcm_hw_params (_soundDevice, hw_params)) < 0) 

    { 

     cout << "Init: cannot set parameters (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    else 

    { 

    cout << "Audio device parameters have been set successfully." << endl; 

    } 

    // Get the buffer size. 

    snd_pcm_uframes_t bufferSize; 

    snd_pcm_hw_params_get_buffer_size(hw_params, &bufferSize); 

    // If we were going to do more with our sound device we would want to store 

    // the buffer size so we know how much data we will need to fill it with. 

    cout << "Init: Buffer size = " << bufferSize << " frames." << endl; 

    // Display the bit size of samples. 

    cout << "Init: Significant bits for linear samples = " << snd_pcm_hw_params_get_sbits(hw_params) << endl; 

    // Free the hardware parameters now that we're done with them. 

    snd_pcm_hw_params_free (hw_params); 

    // Prepare interface for use. 

    if ((err = snd_pcm_prepare (_soundDevice)) < 0) 

    { 

     cout << "Init: cannot prepare audio interface for use (" << snd_strerror (err) << ")" << endl; 

     return false; 

    } 

    else 

    { 

     cout << "Audio device has been prepared for use." << endl; 

    } 

    return true; 

} 

bool UnInit() 

{ 

    snd_pcm_close (_soundDevice); 

    cout << "Audio device has been uninitialized." << endl; 

    return true; 

} 

int main(char *argc, int argv) 

{ 

     Init(NULL); 

     UnInit(); 

     return 0; 

} 
+0

這不是一個問題...? – immibis

+0

一個簡單的方法是從代碼中調用shell命令「aplay」。 –

回答

3

使用一些先進的最新例子,像這樣:

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

static const char *device = "default"; 

unsigned short buffer[2 * 24000]; 

int main(void) 
{ 
    int err; 
    snd_pcm_t *handle; 

    if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { 
     printf("open error: %s\n", snd_strerror(err)); 
     exit(EXIT_FAILURE); 
    } 
    if ((err = snd_pcm_set_params(handle, 
            SND_PCM_FORMAT_S16, 
            SND_PCM_ACCESS_RW_INTERLEAVED, 
            2,    /* channels */ 
            48000,   /* rate */ 
            1, 
            500000)) < 0) { /* buffer: 0.5 sec */ 
     printf("open error: %s\n", snd_strerror(err)); 
     exit(EXIT_FAILURE); 
    } 

    for (;;) { 
     for (int i = 0; i < 24000; i++) { 
      buffer[2 * i + 0] = 32767 * sin(...); /* left channel */ 
      buffer[2 * i + 1] = 32767 * sin(...); /* right channel */ 
     } 

     snd_pcm_sframes_t frames = snd_pcm_writei(handle, buffer, 24000); 
     if (frames < 0) 
      frames = snd_pcm_recover(handle, frames, 0); 
     if (frames < 0) { 
      printf("snd_pcm_writei failed: %s\n", snd_strerror(err)); 
      break; 
     } 
    } 

    snd_pcm_close(handle); 
    return 0; 
} 
+0

謝謝,這看起來像我的解決方案。 –