C ++中的双耳节拍

时间:2016-05-02 00:37:01

标签: c++ linux audio raspberry-pi alsa

我正在尝试使用EEG输入构建大脑设备,并在接近实时的情况下输出光脉冲和双耳节拍"在Raspberry PI上。使用WiringPi,光输出没有问题,但任何音频输出似乎都是一个主要障碍。为缓冲区计算正弦波的算法很简单,但是通过任何标准库在两个通道上播放两个频率似乎是一个非常复杂的过程,我无法提出任何相关的例子。由于this tutorial,我已经成功打开并关闭了一个ALSA设备,这使我非常简单的代码非常复杂,但对于ALSA来说似乎是必要的。如果有人能告诉我在左右声道播放两种不同的计算音调的最简单方法,我将非常感激。下面的代码是我能找到的最简单的ALSA回放示例。

#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;

}

1 个答案:

答案 0 :(得分: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;
}