C++中的双耳节拍

Binaural beats in C++

本文关键字:C++      更新时间:2023-10-16

我正试图在复盆子PI上使用EEG输入和"接近实时"输出光脉冲和双耳节拍来构建一个大脑设备。使用WiringPi,光输出没有问题,但任何音频输出似乎都是一个主要障碍。计算缓冲区正弦波的数学方法很简单,但通过任何标准库在两个通道上播放两个频率似乎是一个非常复杂的过程,我无法想出任何相关的例子。多亏了本教程,我成功地打开和关闭了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;
}

使用一些最新的例子,比如:

#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: %sn", 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: %sn", 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: %sn", snd_strerror(err));
            break;
        }
    }
    snd_pcm_close(handle);
    return 0;
}
相关文章:
  • 没有找到相关文章