【问题标题】:Confused about Passing user data to PortAudio Callbacks对将用户数据传递给 PortAudio 回调感到困惑
【发布时间】:2020-06-12 23:23:31
【问题描述】:

这是我在这里的第一篇文章,我对编程,尤其是 C 语言还很陌生。几周前,我开始阅读 Audio Programming Book(麻省理工学院出版社),并扩展了一些示例以尝试理解事物进一步。

我认为我的问题在于我如何尝试将数据(在初始化函数中从用户检索)传递给 PortAudio 回调。我觉得我所做的与示例没有什么不同(来自本书和 PortAudio 的示例,如 paex_sine.c),但由于某种原因,我的代码无法工作,我一直在敲我的头靠墙试图理解原因。我已经尝试过广泛搜索解决方案或示例代码来研究,但我有点不知道我不知道什么,所以没有太多回报。

如何将用户数据放入回调中?

我只是不了解指针和结构的工作原理,并试图强迫它们做他们不想做的事情吗?

或者,我只是忽略了一些非常明显的事情吗?

下面的代码要么给出一个非常高音调的输出、短的高音调信号,要么没有(听得见的)输出:

#include <stdio.h>
#include <math.h>
#include "portaudio.h"

#define FRAME_BLOCK_LEN 64
#define SAMPLING_RATE 44100
#define TWO_PI (3.14159265f * 2.0f)

PaStream *audioStream;
double si = 0;

typedef struct
{
  float frequency;
  float phase;
}
paTestData;

int audio_callback (const void *inputBuffer, void *outputBuffer,
                    unsigned long framesPerBuffer,
                    const PaStreamCallbackTimeInfo* timeinfo,
                    PaStreamCallbackFlags statusFlags,
                    void *userData )
{
  paTestData *data = (paTestData*)userData;
  float *out = (float*)outputBuffer;
  unsigned long i;
  // data->frequency = 400;

  for(i = 0; i < framesPerBuffer; i++){
    si = TWO_PI * data->frequency / SAMPLING_RATE;  // calculate sampling-incr

    *out++ = sin(data->phase);
    *out++ = sin(data->phase);

    data->phase += si; // add sampling-incr to phase
  }

  return paContinue;
}

void init_stuff()
{
  float frequency;
  int i;
  PaStreamParameters outputParameters;
  paTestData data;

  printf("type the modulator frequency in Hz: ");
  scanf("%f", &data.frequency);  // get modulator frequency
  printf("you chose data.frequency %.2f\n",data.frequency);

  data.phase = 0.0;

  printf("initializing Portaudio. Please wait...\n");
  Pa_Initialize();  // initialize Portaudio

  outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
  outputParameters.channelCount = 2;       /* stereo output */
  outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
  outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
  outputParameters.hostApiSpecificStreamInfo = NULL;

  Pa_OpenStream(              // open paStream object
          &audioStream,       // portaudio stream object
          NULL,               // input params
          &outputParameters,  // output params
          SAMPLING_RATE,      // SampleRate
          FRAME_BLOCK_LEN,    // frames per buffer
          paNoFlag,           // set no Flag
          audio_callback,     // callbak function address
          &data );            // user data

  Pa_StartStream(audioStream);  // start the callback mechanism
  printf("running... press space bar and enter to exit\n");
}

void terminate_stuff()
{
  Pa_StopStream(audioStream);   // stop callback mechanism
  Pa_CloseStream(audioStream);  // destroy audio stream object
  Pa_Terminate();               // terminate portaudio
}

int main(void)
{
  init_stuff();
  while(getchar() != ' ') Pa_Sleep(100);
  terminate_stuff();
  return 0;
}

取消注释 data-&gt;frequency = 400; 至少会播放 400hz 正弦波,但这会忽略在 init_stuff() 中完成的任何用户输入

如果我在回调中添加printf("%f\n",data-&gt;frequency);,它会打印 0.000000 或类似 -146730090609497866240.000000 的内容。 这是非常不可预测的,这真的让我觉得它与指针有关。

我对这段代码的目标是最终结合包络发生器来改变音高,并可能结合波表振荡器,所以我不会为每次迭代计算 sin(x)。 我可以在使用本书中使用的诸如 portsf 之类的阻塞 API 的同时使信封和波表工作,但是尝试调整前面章节中的任何代码以使用 PortAudio 回调使我的大脑变得糊涂。

非常感谢!

【问题讨论】:

  • 您说“我所做的与示例没有什么不同”,但您是否逐字尝试过?
  • 是的。他们按原样工作。只是当我尝试组合概念以扩展其功能时,我遇到了问题。接下来将尝试@spartygw 的建议,看看它是否能让我更接近。

标签: c audio callback portaudio


【解决方案1】:

您的回调数据遇到的问题是它超出范围,并且在 init_stuff 完成执行后立即释放内存。

您应该使用mallocnew 为您的回调数据分配内存,并将指针传递给它以进行回调。

例如:

void init_stuff()
{
  float frequency;
  int i;
  PaStreamParameters outputParameters;
  paTestData *data = (paTestData *) malloc(sizeof(paTestData));


  printf("type the modulator frequency in Hz: ");
  scanf("%f", &(data->frequency));  // get modulator frequency
  printf("you chose data.frequency %.2f\n",data->frequency);

  data->phase = 0.0;

  ...

   Pa_OpenStream(              // open paStream object
      &audioStream,       // portaudio stream object
      NULL,               // input params
      &outputParameters,  // output params
      SAMPLING_RATE,      // SampleRate
      FRAME_BLOCK_LEN,    // frames per buffer
      paNoFlag,           // set no Flag
      audio_callback,     // callbak function address
      data );   

  ... 

【讨论】:

  • 好的。这是有道理且有帮助的。打算试一试。如果我在init_stuff()malloc,那么我将在哪里free 那个内存?
【解决方案2】:

我无法使用malloc 使原始代码工作,但基于这两个建议,我实现了另一个可行的解决方案。因为运行 init_stuff() 导致我的数据被释放,所以我现在只是完成我的所有任务并从 main 调用 Pa_OpenStream()

效果很好,我现在可以将任何我想要的数据发送到回调。感谢您的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    相关资源
    最近更新 更多