Запутался в передаче пользовательских данных в Обратные вызовы PortAudio - PullRequest
1 голос
/ 28 февраля 2020

Это мой первый пост здесь, и я довольно плохо знаком с программированием, особенно с C. Пару недель спустя go я начал работать с Книгой аудиопрограммирования (пресса MIT) и расширил некоторые примеры, чтобы попытаться понять вещи дальше.

Я думаю, что мой вопрос заключается в том, как я пытаюсь передать данные (полученные от пользователя в функции инициализации) в обратный вызов 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;
}

Uncommenting data->frequency = 400; по крайней мере воспроизводит синусоидальный сигнал 400 Гц, но это игнорирует любой пользовательский ввод, сделанный в init_stuff()

Если я поместил printf("%f\n",data->frequency); внутри обратного вызова, он напечатает 0,000000 или что-то вроде -146730090609497866240.000000. Это довольно непредсказуемо, и это действительно заставляет меня думать, что это связано с указателем.

Моя цель этого кода - в конечном итоге включить генераторы огибающей для изменения высоты тона и, возможно, включить осцилляторы с волновой графикой, чтобы я не вычислял sin (x) за каждую итерацию. Я могу заставить работать конверты и волновые таблицы, используя блокирующий API, такой как portsf, который используется в книге, но попытка адаптировать любой из этого кода из предыдущих глав для использования обратных вызовов PortAudio превращает мой мозг в mu sh.

Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 29 февраля 2020

Мне не удалось заставить исходный код работать с использованием malloc, но на основе обоих предложений я нашел другое работоспособное решение. Поскольку запуск init_stuff() привел к тому, что мои данные были освобождены, сейчас я просто выполняю все свои назначения и звонки на Pa_OpenStream() с main.

Работает прекрасно, и теперь я могу отправлять любые данные, которые я хочу на обратный звонок. Спасибо за помощь!

0 голосов
/ 28 февраля 2020

Проблема с вашими данными обратного вызова заключается в том, что они выходят за пределы области действия, и память освобождается, как только init_stuff заканчивает выполнение.

Вы должны выделить память для данных обратного вызова, используя malloc или new и передав ему указатель для обратного вызова.

Например:

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

  ... 
...