Как я могу безопасно сделать float * x в const float * const * y? - PullRequest
3 голосов
/ 17 мая 2011

У меня есть функция audioReceived (float * input, int bufferSize, int nChannels), внутри которой я хочу вызвать функцию из библиотеки, которой требуется const float *const *inputBuffers.

Очевидно, что приведение const float *const *inputBuffers = (const float* const*)input; компилируется, но это ужасная идея, вылетает программа, убивает котят и т. Д. Никому никогда не нужно изменять исходный float* input, это входящие аудиоданные, которые обрабатываются.

Как мне сделать это правильно?

РЕДАКТИРОВАТЬ: Вот еще немного кода. audioReceived это:

void testApp::audioReceived (float * input, int bufferSize, int nChannels){ 

     Vamp::RealTime rt = Vamp::RealTime::fromMilliseconds(ofGetSystemTime());
     float const *const tmp[] = { input, 0 };    
     Vamp::Plugin::FeatureSet fs = myPlugin->process(tmp, rt);
 }

Библиотечная функция process фактически определена в базовом классе:

 /**
 * Process a single block of input data.
 * 
 * If the plugin's inputDomain is TimeDomain, inputBuffers will
 * point to one array of floats per input channel, and each of
 * these arrays will contain blockSize consecutive audio samples
 * (the host will zero-pad as necessary).  The timestamp in this
 * case will be the real time in seconds of the start of the
 * supplied block of samples.
 *
 * If the plugin's inputDomain is FrequencyDomain, inputBuffers
 * will point to one array of floats per input channel, and each
 * of these arrays will contain blockSize/2+1 consecutive pairs of
 * real and imaginary component floats corresponding to bins
 * 0..(blockSize/2) of the FFT output.  That is, bin 0 (the first
 * pair of floats) contains the DC output, up to bin blockSize/2
 * which contains the Nyquist-frequency output.  There will
 * therefore be blockSize+2 floats per channel in total.  The
 * timestamp will be the real time in seconds of the centre of the
 * FFT input window (i.e. the very first block passed to process
 * might contain the FFT of half a block of zero samples and the
 * first half-block of the actual data, with a timestamp of zero).
 *
 * Return any features that have become available after this
 * process call.  (These do not necessarily have to fall within
 * the process block, except for OneSamplePerStep outputs.)
 */
virtual FeatureSet process(const float *const *inputBuffers,
               RealTime timestamp) = 0;

и вот в фактическом заголовке:

FeatureSet process(const float *const *inputBuffers, Vamp::RealTime timestamp);

Я думаю, что EXC_BAD_ACCESS может быть следствием библиотечной функции, которая хочет массив с нулевым заполнением, а я не даю его. (a) Это звучит разумно, и (b) Если да, то пришло ли время задать другой вопрос SO?

Спасибо всем за вашу помощь, это очень поучительно / разъясняюще / познавательно / интересно.

Ответы [ 4 ]

2 голосов
/ 17 мая 2011

Семантика здесь важна. Из названий параметров я могу догадаться, что функция, которую вы хотите вызвать, принимает несколько буферов, поэтому она хочет, чтобы массив указателей плавал (то есть массив массивов). Поскольку у вас есть только массив, вам нужно создать массив, содержащий исходный указатель, и передать его функции.

Если функция имеет отдельный аргумент для длины передаваемого массива (т. Е. Количества буферов), тогда достаточно взять адрес с помощью унарного оператора & и передать длину 1, в противном случае вам нужно создать временный массив с нулевым символом в конце:

float const *const tmp[] = { input, 0 };

и передайте это функции.

2 голосов
/ 17 мая 2011

Выполнения &input должно быть достаточно для самого актера.Обратите внимание, что аргумент внутренней функции является указателем на указатель.

Редактировать:

Чтобы получить нулевой завершенный список входных буферов, как требуется в ваших комментарияхОригинальный вопрос, вы можете использовать:

float const * const buffers[] = {input, 0};
1 голос
/ 17 мая 2011
float *

- это не то же самое, что

float **

, поэтому приведение input к inputBuffers не будет работать.const неявный, вам не нужно делать ничего особенного.Вы не можете так просто разыграть константность в неконстантность.Что логично, когда вы об этом думаете.

0 голосов
/ 20 марта 2013

Вам нужно передать ему float **, т.е. указатель на указатель на число с плавающей точкой.const s просто говорит вам, что функция не будет изменять ни одно из значений, на которые указывают.

Если у вас есть потенциально переменное количество каналов nChannels, из bufferSize с плавающей точкой наканал, тогда вы можете установить необходимое хранилище, например,

float **data = new float *[nChannels];
for (int c = 0; c < nChannels; ++c) {
    data[c] = new float[bufferSize];
}

, после чего data будет в правильном формате для перехода к этой функции.(Функция знает, насколько велики эти вещи, потому что вы ранее указали количество каналов и размер блока для конструктора плагина.)

Ваш пример кода показывает, что у вас есть один указатель float *, который предлагаетможет начинаться с данных в чередующемся формате (то есть значения чередующихся каналов в одном массиве).Если это так, вам нужно будет перемежить отдельные каналы, чтобы перейти к функции process:

for (int i = 0; i < bufferSize; ++i) {
    for (int c = 0; c < nChannels; ++c) {
        data[c][i] = input[i * nChannels + c];
    }
}
myPlugin->process(data, rt);

Наконец, не забудьте также delete[] указатели на элементывпоследствии как двойной указатель.

for (int c = 0; c < nChannels; ++c) {
    delete[] data[c];
}
delete[] data;

Если, с другой стороны, вы знаете, что у вас когда-либо будет только один канал данных - и вы указали 1 в качестве числа каналов в конструкторе плагина- тогда вы можете просто сделать дополнительное перенаправление, как предлагали другие:

myPlugin->process(&input, rt);

(раскрытие: я написал код, который сбивал с толку спрашивающего)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...