Я пытаюсь использовать 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( ¶meters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&instrument_FM);
}
catch ( RtError &error ) {
error.printMessage();
Sleep(1000);
goto cleanup;
}
Размер nFrames, похоже, не влияет. Мне просто показалось, что ошибки такого типа обычно происходят из-за ссылки на void.
Проблема в том, что вы берете адрес указателя и передаете его в openStream
,
// pointer to instrument
Instrmnt * instrument_FM;
// snip ...
// &instrument_FM is a pointer to a pointer! i.e. Instrmnt **
dac.openStream( ¶meters, /* other params */, (void *)&instrument_FM)
Самое быстрое решение — просто избавиться от &
в этой строке.
Теперь несколько комментариев о C ++ и еще несколько исправлений в вашем коде. Код выглядит как смесь C и Java и открывает множество подводных камней, одна из которых привела к вашей проблеме.
FMVoices
, Используйте стек так же, как для RtAudio dac
,
delete
память, которую вы выделилиFMVoices instrument_FM;
try
/catch
в большинстве случаев для очистки, поскольку C ++ имеет деструкторы, которые срабатывают в конце области и распространяют ошибку.
delete
и имея операции по очисткеgoto
в C ++ это действительно не нужно. (в отличие от 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( ¶meters, NULL, format, static_cast<unsigned int>(Stk::sampleRate()), &bufferFrames, &tick, reinterpret_cast<void*>(&instrument_FM));
}
catch ( RtError& error ) {
error.printMessage();
}
}
Других решений пока нет …