Re: A driver question - hiding channels in a DMA buffer
Re: A driver question - hiding channels in a DMA buffer
- Subject: Re: A driver question - hiding channels in a DMA buffer
- From: Mark Cookson <email@hidden>
- Date: Tue, 10 Sep 2002 08:25:20 -0700
Sorry, I didn't realize that this was for input, I thought you were
asking about output.
The only solution I have for input in that situation is double
buffering, or possibly having two streams, one stereo stream and one 4
channel stream, if your hardware can write the samples contiguously to
two separate buffers (how sophisticated is your DMA chip?).
CoreAudio requires that the samples be contiguous in memory, if the
hardware doesn't do that, then you'll need to copy the data around to
make it contiguous.
If your DMA doesn't let you break up the data, then you will have to
use double buffering. Have your hardware put samples into a buffer
that is large enough for all 12 channels. At some interrupt that's
convenient, or when your convertInputSamples() routine is called, copy
the samples from that buffer into the second buffer that is only 6
channels wide.
Make sure that you take the time stamp when you get the byte that will
be copied to byte 0 of the 6 channel buffer as that's the one that
CoreAudio cares about.
If you double buffer, there is a direct one to one relationship between
the two buffers, so it's easy to compute exactly where a sample from
the hardware buffer has to go in the buffer that you register with
CoreAudio. When your convertInputSamples() function is called, you get
a pointer to the start of your hardware buffer (the 6 channel one), a
pointer to where it wants the data to be placed, a number that tells
you it's asking for sample X, how many samples it's asking for, the
stream format, and the stream. You can calculate where you need to get
the sample from your 12 channel buffer by just taking the pointer to
the beginning of your 12 channel buffer, multiplying by the byte size
of the samples, channels, and X and that tells you where to begin
copying from your hardware buffer. You will have to do multiple copies
since you don't want to copy the empty space, but calculating the start
and stop pointers for those copies won't be difficult. You copy those
samples into the destination buffer (no offset is needed to be
calculated for the first copy, after that you just have to continue
where you left off), and you're done.
That AppleUSBAudio driver has to do this when recording because the USB
hardware doesn't return the same number of samples in every USB frame,
so the driver has to coalesce the data to get rid of the empty spots
that didn't contain any data. I don't see your hardware as being much
different, you just have larger empty spots and they are more regular
(since the USB empties move around in the frame list), which,
thankfully, makes things easier for you. The USB driver does the
coalescing in the USB completion routine, but it can also be done in
the convertInputSamples() function which might make things easier for
you, if you don't already have a secondary interrupt to do the work in.
However, you want to take the time stamp in a primary (a.k.a. filter)
interrupt as you want that to happen as close to when the first sample
in the buffer is recorded, though you don't want to spend a lot of time
in that interrupt, so either use a secondary interrupt to coalesce the
data, or do it in convertInputSamples() (and doing it in
convertInputSamples() seems to be best since secondary interrupts can
be delayed by the real-time thread that CoreAudio uses).
I hope this helps,
Mark
On Monday, September 9, 2002, at 04:36 PM, Devendra Parakh wrote:
Mark,
Thank you for the quick response!
The problem is that CoreAudio wants to know a lot about the DMA buffer
(which in this case is a shared memory buffer - the data stays in main
memory, the hardware fetches the samples directly from the buffer via
PCI
transactions). It wants to know the sample size and the number of
channels and the total buffer size (in samples).
Based on this information, and the location reported by
"takeTimeStamp",
ConvertInputSamples(since this is Input we're talking about) is called
with a pointer into my DMA buffer. The only problem is that since I'm
not
telling CoreAudio the whole truth (the DMA buffer really always has 12
channels), it will send me a pointer based on a 6ch. x 32bit buffer.
What's more, I don't think CoreAudio has any responsibility to provide
me
with a pointer into "my" physical buffer. It might as well copy the DMA
buffer into a private buffer, and then provide me a pointer to this
private buffer.
Or am I being unnecessarily paranoid here!
Thanks.
Devendra.
At 10:51 AM 9/9/2002, Mark Cookson wrote:
I can't think of any other way of doing this than to just report your
device as 6 channels (because that's what it is), and then do the
math to get your data to the right place.
It shouldn't be too bad as the buffer given to you by CoreAudio will
be sequential audio, though your clip routine will need to convert
from float to 32 bit and calculate where to put that sample in your
PCI card's memory. It's too bad that the hardware is using channels
1,2,3,4,5,6 because that gap from channel 2 to channel 7 is going to
give the PCI bus a real workout.
There are two ways to do the copy, and you should experiment to find
out which one works best. One way is to copy linearly from the
CoreAudio buffer to your hardware, jumping around in PCI memory as
required by your card. The other option is to jump around in
CoreAudio's buffer to go linearly through your PCI card's memory.
Normally this is a better way to go because the PCI bus is so much
slower than the main memory bus, you want the performance improvement
of having all the writes gathered together. However, with your
writes being slightly scattered, there might not be much of a
performance boost. Still, it's worth experimenting with.
Good luck,
Mark
On Monday, September 9, 2002, at 09:56 AM, Devendra Parakh wrote:
Hi,
We have a driver for a PCI audio device with 12 input channels
(32bit
samples). This driver is working fine.
We have to now modify this driver for another flavor of the
device which
only only provides connectors for 6 of the 12 channels. In other
words,
we want to expose only 6 channels (channel number 1,2,7,8,9,10,11
and 12)
to CoreAudio HAL.
However, the DMA buffers will always contain data for all 12
channels.
Is there a good solution?
If I report 6 channels, then ConvertInputSamples() will probably
come
back with inappropriate buffer pointers!
Any help would be greatly appreciated!
Thanks.
Devendra.
Devendra ParakhSinging Electrons,
Inc.http://www.singingelectrons.com425-889-2478
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.
--
Mark Cookson
Engineering Droid
Apple Computer, Inc.
Core Audio CPU Software
6 Infinite Loop MS 306-2CW
Cupertino, CA 95014
Devendra ParakhSinging Electrons,
Inc.http://www.singingelectrons.com425-889-2478
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.
--
Mark Cookson
Engineering Droid
Apple Computer, Inc.
Core Audio CPU Software
6 Infinite Loop MS 306-2CW
Cupertino, CA 95014
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.