• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Playing multiple sounds
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Playing multiple sounds


  • Subject: Re: Playing multiple sounds
  • From: "Andreas Falkenhahn" <email@hidden>
  • Date: Fri, 24 Aug 2007 15:01:08 +0200

Thanks for your help. I'm getting there.... but very slowly. The sound plays now
but it is choppy, and I don't know what I'm doing wrong.

I've set up a very basic test environment. It's really nothing complicated. I'm trying
to play a 8 bit sampled, mono, 13964hz sound through the default audio device
using bus 0 of 8 busses in total. The code currently plays the sound and then
crashes. I know that. It's just that I want to keep it brief. I will make all this code
beautiful as soon as I hear my sound correctly.

It's really not much code:

UInt8 *g_sound = <pointer to PCM sound data here>;

OSStatus ACComplexInputProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* userData)
{
 ioData->mBuffers[0].mData = g_sound;
 ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets;

 g_sound = g_sound + *ioNumberDataPackets;	// Yes I know this will crash at sound end
 return noErr;
}

OSStatus myMixerInputCallback(void *inRefCon, AudioUnitRenderActionFlags inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
{
 AudioBufferList myList;
 UInt32 inNumFrames = ioData->mDataByteSize;   // for my 8 bit mono sound a frame is just a byte

 // keep all other busses quiet for now
 if(inBusNumber != 0) {
  memset(ioData->mData, 0, ioData->mDataByteSize);
  return noErr;
 }

 myList.mNumberBuffers = 1;
 myList.mBuffers[0] = *ioData;

 AudioConverterFillComplexBuffer(converter, ACComplexInputProc, NULL, &inNumFrames, &myList, NULL);

 *ioData = myList.mBuffers[0];

 return noErr;
}

That's all. The mixer is connected to the default audio unit. I have 8 busses on the
mixer but only bus 0 is currently filled with data as you can see above. All other
busses get their data cleared out using memset() so they should be silent.

As I said, the sound is played and clearly audible, but it is choppy and a bit too slow.
If I remove the 7 other busses completely from the mixer so that I have only one input
proc left, the sound is still choppy, but not as bad as when the 7 other busses are active,
but it is still choppy.

I'm really clueless about this. Is it really such an exotic task that I'm trying to do
here? Just to put a bunch of sounds with different sample rates and PCM encodings
through the default audio device? Why is all this so difficult? I've already spent many
hours on this and still feel like being far far away from a nice, smooth audio playback
with Core Audio :-(

It's really all very low-level, and I have no idea why the sound is choppy now. I'm
clueless where this problem comes from.

Please help someone! Thanks!

Andreas

On 23.08.2007 at 15:53 Mark Pauley wrote:

>>
>> 1. Install a render callback on my audio unit using SetRenderCallback
>> in AudioUnitSetProperty(). (Question: But my audio unit is already
>> configured
>> to use the mixer unit as the input source. Can I still set a render
>> callback
>> on it now? Doesn't this somewhat conflict with each other? This
>> confuses me
>> a little.)
>>
>Hm, good point.  For some reason I was assuming that the mixers used
>buffer lists, not buffers.
>If they use buffers and there's no v2.0 mixers, then you'll have to
>stick with stuffing AudioBuffer pointers into AudioBufferList structs,
>you can do this easily by:
>
>/*
>typedef struct AudioBufferList {
>UInt32 mNumberBuffers;
>AudioBuffer mBuffers[1];
>} AudioBufferList;
>*/
>...
>// AudioBuffer myBuffer is a param
>AudioBufferList myList = {1, &myBuffer};
>
>then pass myList on as necessary.
>
>
>> 2. Install eight input callbacks on my mixer unit using
>> SetInputCallback
>> in AudioUnitSetProperty() using busses 0 to 7.
>Yes, it's in these callbacks that you'll be dispatching the converters.
>As you're setting up the mixer bus callbacks, you'll want to create a
>new converter for each bus with the input format being the format
>you'll be supplying and the output format being the format you want to
>give to the mixer and register the AudioConverterFillBufferCallback
>for each of those converters.
>You can just store the converter as part of the refcon you stuff into
>the callback struct, when you get the callback on any bus, you pull
>bytes from the respective converter which you will unpack from the
>refcon we give you in the mixer callback, which in turn pulls from the
>converter callback, which is where you put the sound in the buffer.
>
>It's in the converter callback that you will actually supply the
>signals of differing format, the converter slurps them up and they
>come out the other side all the same format.  The mixer just muxes the
>8 separate signals into one signal.
>
>> I still don't think I have understood this correctly :(
>
>You're getting there, don't give up!
>:)
>
>Here's a (crappy) diagram:
>
>source 1 -> converter 1 \
>source 2 -> converter 2 \ \
>source 3 -> converter 3 \ \ \
>source 4 -> converter 4-(mixer)->output->speakers
>
>Imagine that your converters are like physical cable converters, and
>then see electrons getting pulled, with the speakers doing the
>pulling.  It's like that but with samples.
>:D
>
>So it's like your mixer only has rca inputs, but your synths / mics /
>amps all have like 1/8'' or 1/4'' or XLR or whatever, so for each of
>those you've got to change them to rca.
>
>
>so to recap:
>
>1) get an output unit
>2) get a mixer
>3) connect the mixer to the output unit
>4) for each of the busses on the mixer
>   a) create a converter for that bus
>   b) make an input callback function that pulls from a converter
>stored in the refcon (could probably share this function among all
>busses, the converters will end up calling different callbacks)
>   c) make a converter fill bytes function for the bus and set it as
>the callback of the converter, this is where the source signal is
>piped in
>
>
>_Mark
>
>>
>>
>> Andreas
>>
>> _______________________________________________
>> Do not post admin requests to the list. They will be ignored.
>> Coreaudio-api mailing list      (email@hidden)
>> Help/Unsubscribe/Update your Subscription:
>>
>> This email sent to email@hidden



--
"Remember: It's nice to be important but it's more important to be nice!"


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Playing multiple sounds
      • From: "Andreas Falkenhahn" <email@hidden>
References: 
 >Playing multiple sounds (From: "Andreas Falkenhahn" <email@hidden>)
 >Re: Playing multiple sounds (From: Mark Pauley <email@hidden>)
 >Re: Playing multiple sounds (From: Mark Pauley <email@hidden>)
 >Re: Playing multiple sounds (From: "Andreas Falkenhahn" <email@hidden>)
 >Re: Playing multiple sounds (From: Mark Pauley <email@hidden>)

  • Prev by Date: Re: RawAudioFileComponent example crash
  • Next by Date: Re: CallHostTransportState doesn't return to stopped state
  • Previous by thread: Re: Playing multiple sounds
  • Next by thread: Re: Playing multiple sounds
  • Index(es):
    • Date
    • Thread