8

Come si disimpegna lo float *newAudio in float *channel1 e float* channel2 e lo si ritrasforma in newAudio?Buffer con interleave e interleave con vDSP_ctoz() e vDSP_ztoz()?

Novocaine *audioManager = [Novocaine audioManager]; 

__block float *channel1; 
__block float *channel2; 
[audioManager setInputBlock:^(float *newAudio, UInt32 numSamples, UInt32 numChannels) { 
    // Audio comes in interleaved, so, 
    // if numChannels = 2, newAudio[0] is channel 1, newAudio[1] is channel 2, newAudio[2] is channel 1, etc. 

     // Deinterleave with vDSP_ctoz()/vDSP_ztoz(); and fill channel1 and channel2 
     // ... processing on channel1 & channel2 
     // Interleave channel1 and channel2 with vDSP_ctoz()/vDSP_ztoz(); to newAudio 
}]; 

Come sarebbero queste due righe di codice? Non capisco la sintassi di ctoz/ztoz.

risposta

11

Quello che faccio nelle classi accessorie di Novocaine, come il ringbuffer, per de-interlacciamento:

float zero = 0.0; 
vDSP_vsadd(data, numChannels, &zero, leftSampleData, 1, numFrames); 
vDSP_vsadd(data+1, numChannels, &zero, rightSampleData, 1, numFrames); 

per interleaving:

float zero = 0.0; 
vDSP_vsadd(leftSampleData, 1, &zero, data, numChannels, numFrames); 
vDSP_vsadd(rightSampleData, 1, &zero, data+1, numChannels, numFrames); 

Il modo più generale di fare le cose è avere una matrice di matrici, come

int maxNumChannels = 2; 
int maxNumFrames = 1024; 
float **arrays = (float **)calloc(maxNumChannels, sizeof(float *)); 
for (int i=0; i < maxNumChannels; ++i) { 
    arrays[i] = (float *)calloc(maxNumFrames, sizeof(float)); 
} 

[[Novocaine audioManager] setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) { 
    float zero = 0.0; 
    for (int iChannel = 0; iChannel < numChannels; ++iChannel) { 
     vDSP_vsadd(data, numChannels, &zero, arrays[iChannel], 1, numFrames); 
    } 
}]; 

che è quello che uso internamente molto nelle classi di accessori RingBuffer per Novocaine. Ho calcolato la velocità di vDSP_vsadd rispetto a memcpy e (molto, molto sorprendentemente), non c'è differenza di velocità.

Naturalmente, si può sempre e solo usare un buffer circolare, e risparmiare il fastidio

#import "RingBuffer.h" 

int maxNumFrames = 4096 
int maxNumChannels = 2 
RingBuffer *ringBuffer = new RingBuffer(maxNumFrames, maxNumChannels) 

[[Novocaine audioManager] setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) { 
    ringBuffer->AddNewInterleavedFloatData(data, numFrames, numChannels); 
}]; 

[[Novocaine audioManager] setOuputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) { 
    ringBuffer->FetchInterleavedData(data, numFrames, numChannels); 
}]; 

Speranza che aiuta.

+0

Grazie, sembra un modo pulito per farlo! – bartolsthoorn

+0

Alex, per favore dai un'occhiata a [questo] (http://stackoverflow.com/questions/13228618/how-to-read-vbr-audio-in-novacaine-as-opposed-to-pcm) question, i ' Sto cercando di aggiungere al tuo esempio di novacaine permettendo di leggere i dati VBR (in SInt16 anziché in virgola mobile) – abbood

8

Ecco un esempio:

#include <Accelerate/Accelerate.h> 

int main(int argc, const char * argv[]) 
{ 
    // Bogus interleaved stereo data 
    float stereoInput [1024]; 
    for(int i = 0; i < 1024; ++i) 
     stereoInput[i] = (float)i; 

    // Buffers to hold the deinterleaved data 
    float leftSampleData [1024/2]; 
    float rightSampleData [1024/2]; 

    DSPSplitComplex output = { 
     .realp = leftSampleData, 
     .imagp = rightSampleData 
    }; 

    // Split the data. The left (even) samples will end up in leftSampleData, and the right (odd) will end up in rightSampleData 
    vDSP_ctoz((const DSPComplex *)stereoInput, 2, &output, 1, 1024/2); 

    // Print the result for verification 
    for(int i = 0; i < 512; ++i) 
     printf("%d: %f + %f\n", i, leftSampleData[i], rightSampleData[i]); 

    return 0; 
} 
3

sbooth risponde come de-interleave utilizzando vDSP_ctoz. Ecco l'operazione complementare, ovvero l'interleaving usando vDSP_ztoc.

#include <stdio.h> 
#include <Accelerate/Accelerate.h> 

int main(int argc, const char * argv[]) 
{ 
    const int NUM_FRAMES = 16; 
    const int NUM_CHANNELS = 2; 

    // Buffers for left/right channels 
    float xL[NUM_FRAMES]; 
    float xR[NUM_FRAMES]; 

    // Initialize with some identifiable data 
    for (int i = 0; i < NUM_FRAMES; i++) 
    { 
     xL[i] = 2*i; // Even 
     xR[i] = 2*i+1; // Odd 
    } 

    // Buffer for interleaved data 
    float stereo[NUM_CHANNELS*NUM_FRAMES]; 
    vDSP_vclr(stereo, 1, NUM_CHANNELS*NUM_FRAMES); 

    // Interleave - take separate left & right buffers, and combine into 
    // single buffer alternating left/right/left/right, etc. 
    DSPSplitComplex x = {xL, xR}; 
    vDSP_ztoc(&x, 1, (DSPComplex*)stereo, 2, NUM_FRAMES); 

    // Print the result for verification. Should give output like 
    // i:  L,  R 
    // 0: 0.00, 1.00 
    // 1: 2.00, 3.00 
    // etc... 
    printf(" i:  L,  R\n"); 
    for (int i = 0; i < NUM_FRAMES; i++) 
    { 
     printf("%2d: %5.2f, %5.2f\n", i, stereo[2*i], stereo[2*i+1]); 
    } 
    return 0; 
}