Ошибка доступа к памяти при использовании STK и класса FMVoices

Я пытаюсь использовать STK из Стэнфорда, чтобы сделать синтез в реальном времени. Я использую класс инструментов FMVoices https://ccrma.stanford.edu/software/stk/classstk_1_1FMVoices.html
и пытается использовать его в процедуре обратного вызова, определенной ниже.

int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *dataPointer )
{

FMVoices *FM = (FMVoices *) dataPointer;
register StkFloat *samples = (StkFloat *) outputBuffer;

for ( unsigned int i=0; i<nBufferFrames; i++ )
*samples++ = FM->tick();

return 0;
}

Проблема, я думаю, связана с типом этого последнего параметра. Я получаю сообщение об ошибке во время выполнения: «0xC0000005: нарушение прав доступа, местоположение выполнения 0x000000001». Теперь это способ, которым обратный вызов должен быть написан для других инструментов STK, таких как Clarinet или даже класс FileLoop, но в FMVoices есть что-то прикольное. Объект передается openStream (который обрабатывает специфичные для платформы выходные данные в реальном времени) как указатель на void. Обратный вызов вызывается автоматически, когда звуковой буфер системы заполнен. Фрагмент кода, который реализует это и работает для других инструментов, показан ниже:

int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;Instrmnt * instrument_FM;int nFrames = 10000;
try {

instrument_FM = new FMVoices;

}
catch ( StkError & ) {
goto cleanup;
}instrument_FM->setFrequency(440.0);// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;
try {
dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&instrument_FM);
}
catch ( RtError &error ) {
error.printMessage();
Sleep(1000);
goto cleanup;

}

Размер nFrames, похоже, не влияет. Мне просто показалось, что ошибки такого типа обычно происходят из-за ссылки на void.

0

Решение

Проблема в том, что вы берете адрес указателя и передаете его в openStream,

// pointer to instrument
Instrmnt * instrument_FM;

// snip ...

// &instrument_FM is a pointer to a pointer! i.e. Instrmnt **
dac.openStream( &parameters, /* other params */, (void *)&instrument_FM)

Самое быстрое решение — просто избавиться от & в этой строке.


Теперь несколько комментариев о C ++ и еще несколько исправлений в вашем коде. Код выглядит как смесь C и Java и открывает множество подводных камней, одна из которых привела к вашей проблеме.

  • Нет необходимости динамически распределять FMVoices , Используйте стек так же, как для RtAudio dac,
    • Не нужно беспокоиться об указателях, и deleteпамять, которую вы выделили
    • Поэтому нет утечек памяти.
    • Просто пиши FMVoices instrument_FM;
  • Там нет необходимости делать try/catch в большинстве случаев для очистки, поскольку C ++ имеет деструкторы, которые срабатывают в конце области и распространяют ошибку.
    • Если вы используете только стек, вам не нужно беспокоиться о delete и имея операции по очистке
  • Никогда не используйте goto в C ++ это действительно не нужно. (в отличие от C, где он может быть использован для очистки).
    • Есть деструкторы и RAII для этого.
  • Используйте C ++ приведения, которые более мелкозернистые, такие как static_cast<> а также reinterpret_cast<>вместо бросков в стиле C

Вот пересмотренный код:

int main()
{
// Set the global sample rate before creating class instances.
Stk::setSampleRate( 44100.0 );
RtAudio dac;

FMVoices instrument_FM;
instrument_FM.setFrequency(440.0);

// Figure out how many bytes in an StkFloat and setup the RtAudio stream.
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = 1;
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
unsigned int bufferFrames = RT_BUFFER_SIZE;

// didn't get rid of this try since you want to print the error message.
try {
// note here i need the ampersand &, because instrument_FM is on the stack
dac.openStream( &parameters, NULL, format, static_cast<unsigned int>(Stk::sampleRate()), &bufferFrames, &tick, reinterpret_cast<void*>(&instrument_FM));
}
catch ( RtError& error ) {
error.printMessage();
}
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]