2015-02-20 1 views
2

надеюсь, что вы можете мне помочь :)Как разобрать перемежаемое буфер на отдельные несколько буферов каналов с Portaudio

Я пытаюсь получить аудиоданные из многоканального ASIO устройства с библиотекой Portaudio. Все в порядке: мне удалось установить API-интерфейс хоста по умолчанию как ASIO, и мне также удалось выбрать 4 конкретных канала в качестве входных данных. Затем я получаю чередующийся аудиопоток, который звучит правильно, но я хотел бы получить каждый канал данных отдельно.

PortAudio позволяет делать запись без чередования, но я не знаю, как писать или изменять свой RecordCallBack и указатель мультибуфера (один буфер на канал). Конечно, я пытался ... :(

Было бы массивной помощь мне, если кто-то знает, как справиться с этой проблемой.

Оригинальная функция RecordCallBack взята из хорошо известного стерео примера (немного модифицирован для управления 4 channles вместо 2), но он управляет одним перемежаемое буфер:

static int recordCallback(const void *inputBuffer, void *outputBuffer, 
         unsigned long framesPerBuffer, 
         const PaStreamCallbackTimeInfo* timeInfo, 
         PaStreamCallbackFlags statusFlags, 
         void *userData) 
{ 
paTestData *data = (paTestData*)userData; 
const short *rptr = (const short*)inputBuffer; 
short *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS_I]; 
long framesToCalc; 
long i; 
int finished; 
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; 

(void) outputBuffer; /* Prevent unused variable warnings. */ 
(void) timeInfo; 
(void) statusFlags; 
(void) userData; 

if(framesLeft < framesPerBuffer) 
{ 
    framesToCalc = framesLeft; 
    finished = paComplete; 
} 
else 
{ 
    framesToCalc = framesPerBuffer; 
    finished = paContinue; 
} 

if(inputBuffer == NULL) 
{ 
    for(i=0; i<framesToCalc; i++) 
    { 
     *wptr++ = SAMPLE_SILENCE; /* ch1*/ 
     if(NUM_CHANNELS_I == 4){ 
      *wptr++ = SAMPLE_SILENCE;/* ch2*/ 
      *wptr++ = SAMPLE_SILENCE;/* ch3*/ 
      *wptr++ = SAMPLE_SILENCE;} /* ch4*/ 
    } 
} 
else 
{ 
    for(i=0; i<framesToCalc; i++) 
    { 
     *wptr++ = *rptr++; /* ch1*/ 
     if(NUM_CHANNELS_I == 4){ 
      *wptr++ = *rptr++;/* ch2*/ 
      *wptr++ = *rptr++;/* ch3*/ 
      *wptr++ = *rptr++;} /* ch4*/ 
    } 
} 
data->frameIndex += framesToCalc; 

return finished; 
} 

Символ * указатель INPUTBUFFER объявлен как:

PaStream* stream; 

И функция Open_Stream называется:

err = Pa_OpenStream(
      &stream, 
      NULL, /* no input */ 
      &outputParameters, 
      SAMPLE_RATE, 
      FRAMES_PER_BUFFER, 
      paClipOff,  /* we won't output out of range samples so don't bother clipping them */ 
      playCallback, 
      &data); 

ответ

1

Спасибо Скотту за вашу помощь. Решение было прямо перед моими глазами, и мне, наконец, не пришлось работать со смещением образцов.Я не дал вам достаточно информации о коде, так что ваш подход был отличным, но сам код обеспечивает более простой способ сделать это:

Данные хранить эту в structrue:

typedef struct 
{ 
int   frameIndex; /* Index into sample array. */ 
int   maxFrameIndex; 
short  *recordedSamples; 
} 
paTestData; 

I модифицирована его:

typedef struct 
{ 
int   frameIndex; /* Index into sample array. */ 
int   maxFrameIndex; 
short  *recordedSamples; 
short  * recordedSamples2; //ch2 
short  * recordedSamples3; //ch3 
short  *recordedSamples4; //ch4 
} 
paTestData; 

Тогда я просто должен был выделить эти переменные в памяти и изменить функцию recordCallback следующим образом:

static int recordCallback(const void *inputBuffer, void *outputBuffer, 
         unsigned long framesPerBuffer, 
         const PaStreamCallbackTimeInfo* timeInfo, 
         PaStreamCallbackFlags statusFlags, 
         void *userData) 
{ 
paTestData *data = (paTestData*)userData; 
const short *rptr = (const short*)inputBuffer; 

short *wptr = &data->recordedSamples[data->frameIndex]; 
short *wptr2=&data->recordedSamples2[data->frameIndex]; 
short *wptr3=&data->recordedSamples3[data->frameIndex]; 
short *wptr4=&data->recordedSamples4[data->frameIndex]; 
long framesToCalc; 
long i; 
int finished; 
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; 

(void) outputBuffer; /* Prevent unused variable warnings. */ 
(void) timeInfo; 
(void) statusFlags; 
(void) userData; 

if(framesLeft < framesPerBuffer) 
{ 
    framesToCalc = framesLeft; 
    finished = paComplete; 
} 
else 
{ 
    framesToCalc = framesPerBuffer; 
    finished = paContinue; 
} 

if(inputBuffer == NULL) 
{ 
    for(i=0; i<framesToCalc; i++) 
    { 
     *wptr++ = SAMPLE_SILENCE; //ch1 
     if(NUM_CHANNELS_I == 4){ 
      *wptr2++ = SAMPLE_SILENCE;//ch2 
      *wptr3 ++= SAMPLE_SILENCE;//ch3 
      *wptr4++ = SAMPLE_SILENCE;} //ch4 
    } 
} 
else 
{ 
    for(i=0; i<framesToCalc; i++) 
    { 
     *wptr++ = *rptr++; //ch1 
     if(NUM_CHANNELS_I == 4){ 
      *wptr2++ = *rptr++;//ch2 
      *wptr3++ = *rptr++;//ch3 
      *wptr4 ++= *rptr++;} //ch4 
    } 
} 
data->frameIndex += framesToCalc; 

return finished; 
} 

Надеюсь, это поможет другим людям. И еще раз спасибо, Скотт

1

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

aabbccddeeaabbccddeeaabbccddee (each character represents one byte) 

, где этот входной буфер содержит два байта (16 бит) на каждый из 5 каналов: a, b, c, d & e, поскольку он выполняет 3 повтора по множеству каналов, которые равны 3 отсчетам на канал ... поэтому знание ввода чередуется, его можно извлечь в отдельные буферы выходных каналов по одному на канал , но в вашем коде у вас есть только один выходной буфер, который, как вы говорите, обусловлен необходимой сигнатурой обратного вызова ... one appr тренере было бы написать каждый выходной канал в один выходной буфер, разделенном различными смещениями для каждого канала так, выходной сигнал будет

aaaaaabbbbbbccccccddddddeeeeee 

затем вне обратного вызова извлечь из каждого канала, также используя тот же смещение для каждого канала

Сначала вы необходимо получить размер выходного буфера заданного, скажем, Х, количество каналов, Y и число байтов на канал в образце, Z. таким образом, глобальный канал смещения будет

size_offset = X/(Y * Z) # assure this is an integer 
          # if its a fraction then error in assumptions 

поэтому при адресации выходного буфера как внутри, так обратный вызов й снаружи мы используем это смещение и знание того, какой канал мы на, W (значения 0, 1, 2, 3, ...), и который образец К:

index_output_buffer = K + (W * size_offset)  # 1st byte of sample pair 

теперь используют index_output_buffer ... то вычислить последующие по индексу:

index_output_buffer = K + (W * size_offset) + 1 # 2nd byte of sample pair 

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

+0

Привет, Скотт, благодарю вас за ваш ответ. Если я получаю вас правильно, так как мои образцы имеют длину в 16 бит (короткий), чередование 4 каналов означает буфер: samplech1samplech2samplech3samplech4samplech1samplech2samplech3samplech4 ... ??? Мой первый подход заключался в том, чтобы обрабатывать подобный буффер, и получать каждую шанель следующим образом (в цикле): datach2 (i) = data (i + 1); datach3 (i) = data (i + 2); datach4 (i) = данные (я + 3). Где «данные» содержат весь поток бурового буфера. Но это не сработало ... Может быть, мне что-то не хватает ... – JavaRar

+0

Я вижу, что вы используете смещение всего 1 между каналами, и вы используете отдельные буферы для каждого канала - я предложил подход выше, который будет работать как внутри callback, а также за пределами ... удачи –

+0

Большое спасибо Скотту, я очень ценю вашу помощь. Я постараюсь сделать то, что вы предлагаете как можно скорее, тогда я дам вам знать, насколько я уверен в успехе или нет. Еще раз спасибо – JavaRar

 Смежные вопросы

  • Нет связанных вопросов^_^