问题
so i'm using Apple's MixerHost sample code to do a basic audiograph setup for stereo synthesis. I have some trouble figuring out how i have to fill the buffer slice. Specifically, i get audio out only in the left channel, the right channel is silent:
AudioUnitSampleType *buffer = (AudioUnitSampleType *)ioData->mBuffers[0].mData;
SInt16 sampleValue;
for(UInt32 i = 0; i < inNumberFrames; i++)
{
sampleValue = sinf(inc) * 32767.0f; // generate sine signal
inc += .08;
buffer[i] = sampleValue;
}
if(inc > 2e10) inc -= 2e10;
This plays a sine wave on the left channel... The pitch kind of changes every 10 seconds or so, another indicator that i'm doing it wrong :]
i've tried other ways of stepping through the array. this produced interesting sounds which were far from a sine signal. At one point i had glitchy/choppy output on both channels, which was kind of like a success.
If i inspect the AudioBuffer struct, it confirms there are 2 channels, and the bytesize per frame is 4. So per frame, there are two SInt16, right? One for left, and one for the right channel.. and they are supposed to be interleaved?
Note that i am using a stream format that is different from Apple's example because i don't know fixed point math.
The stream format is setup like so:
size_t bytesPerSample = sizeof (AudioUnitSampleType);
stereoStreamFormat.mFormatID = kAudioFormatLinearPCM;
stereoStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
stereoStreamFormat.mBytesPerPacket = bytesPerSample;
stereoStreamFormat.mFramesPerPacket = 1;
stereoStreamFormat.mBytesPerFrame = bytesPerSample;
stereoStreamFormat.mChannelsPerFrame = 2;
stereoStreamFormat.mBitsPerChannel = 8 * bytesPerSample;
stereoStreamFormat.mSampleRate = graphSampleRate;
so my question is, how do i fill a stereo buffer which is setup like above with data so that it just works?
thanks!
回答1:
Take a look at Classes/MixerHostAudio.m
in the MixerHost
example, and scroll down to where they define and assign outSamplesChannelLeft
and outSamplesChannelRight
. It looks like the API expects left and right samples in different buffers, not interleaved.
As for the changing pitch, try
if (inc > M_PI) inc -= 2.0*M_PI;
(or whatever Apple defines in place of M_PI
) and do this within the loop, not after filling the whole frame. Floating point error accumulates surprisingly quickly. The correction above uses the fact that sin
is periodic over 2*pi
. Your correction arbitrarily wraps inc
back in, and will cause a glitch at the wrap point if the wrapping isn't phase continuous.
And finally, it's not clear to me if your bytesPerSample
is 2 or not, you might want to check this. If it is, then I'd guess your other assumption about bytesPerFrame
is correct.
回答2:
You are setting mBytesPerFrame = bytesPerSample. This only allows one sample per frame. For interleaved stereo (i.e. mChannelsPerFrame = 2) you need two samples per frame. Try setting mBytesPerFrame = 2 * bytesPerSample.
In your render function:
UInt32 numOfSamples = 2 * inNumberFrames;
for (i = 0; i < numOfSamples; i+=2) {
buffer[i] = //assign left channel value;
buffer[i+1] = //assign right channel value;
}
来源:https://stackoverflow.com/questions/6091500/how-to-properly-fill-a-stereo-audiobuffer