• 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: Native Device Formats
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Native Device Formats


  • Subject: Re: Native Device Formats
  • From: Brian Willoughby <email@hidden>
  • Date: Sun, 8 Jun 2008 14:29:27 -0700

This is a very important issue to be mindful of, but it's perhaps not as horribly difficult as you might imagine. It all stems from the limitation of twos-complement integer formatting. Because we're talking about binary numbers, the inclusion of a code for zero means that you would have an odd number of values if both positive and negative versions of every other number were included. But any binary number always has an even number of codes, so twos-complement sacrifices one single maximum positive value, such that there is one single negative number which cannot be converted to the positive. This sacrifice is made to make room for the zero code. In other words, you can reach -1.0, but you can never reach +1.0, at least not so long as we are stuck with DACs that use twos-complement integers (and they all do).

The proper algorithm depends upon the type of audio material.
e.g. outside sampled versus processed versus generated.

For outside samples - e.g. from CD or from an A/D interface - you're fine using the standard conversion and pretending that the range is [-1.0, 1.0) ... the fact that +1.0 is never reached is immaterial. The final conversion from float to integer will preserve the original outside samples at whatever bit depth they originated.

For processed samples, particularly with limiters designed to avoid clipping, the algorithm must be mindful that +1.0 cannot be represented on the analog output. An advanced algorithm can specifically allow -1.0 to pass without correcting for "clipping" while smartly detecting any signal which approaches +1.0 and dynamically adjusting the gain to keep the output away from a +1.0 value. Obviously, any negative below less than -1.0 would also be gain-adjusted. The algorithm can assume 16-bit or 24-bit or allow the user some choice, and the bit-depth ultimate determines how close the signal can get to the +1.0 value.

For generated samples, you do have to be mindful not to simply call the sin() function and expect a scaling of +1.0 to be free from clipping. My approach is to use 32767.0/32768.0 as the scaling factor, such that my generated samples can be played on any 24-bit or 16-bit DAC without clipping distortion. You would use 255.0/256.0 for an 8-bit DAC, and I'll leave it to the reader to calculate the scaling factor for 24-bit. In the case of generated samples, Mikael is basically right. But the key is that the same approach is not necessarily appropriate for outside sample sources or processed audio.

All of the above is really just a lead-in to answering your final question. We do not map [-1.0, 1.0] to [0x800000, 0x7FFFFF] for several reasons. First of all, that mapping creates a negative DC bias in the output signal of one-half LSB. More importantly, that mapping would create serious digital quantization noise in even the most simple case of sending 16-bit CD audio through floating point processing. Finally, I would say that your suggested mapping is not more "intuitive" but perhaps more "convenient" in a limited number of circumstances. The standard mapping that we're using is perfect for A/D and most processing, with the only exceptions being generated samples and dynamics processing which attempts to prevent clipping. The standard mapping is actually the more intuitive one for those aware of the mathematics and binary representations.

Brian Willoughby
Sound Consulting


On Jun 8, 2008, at 08:21, Mikael Hakman wrote:

AudioConverter tells me that in order to get the lowest 24-bit value (0x800000) I have to use -1.0 Float32 value (0xbf800000). In order to get highest 24-bit value (0x7fffff) I have to use 0.99999988 Float32 value (0x3f7ffffe). This means that FS amplitude when using Float32 is 0.99999944 (0x3f7fffff), not 1.0.

This may have some significance when e.g. generating FS precision test signals as in:

s = 0.99999944 * (sin (2 * PI * f * t) + 1.0) - 1.0

Omitting the scaling as in:

s = sin (2 * PI * f * t)

would result in a slight clipping on the positive side.

Could you please give some explanation why we are using this mapping as compared to (more intuitive) mapping of [-1.0, 1.0] to [0x800000, 0x7fffff] which would allow using sin() function results directly as input to CoreAudio?

Regards/Mikael

_______________________________________________
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: Native Device Formats
      • From: "Mikael Hakman" <email@hidden>
    • Re: Native Device Formats
      • From: Dave Malham <email@hidden>
References: 
 >Native Device Formats (From: email@hidden)
 >Re: Native Device Formats (From: Jeff Moore <email@hidden>)
 >Re: Native Device Formats (From: "Mikael Hakman" <email@hidden>)
 >Re: Native Device Formats (From: Jeff Moore <email@hidden>)
 >Re: Native Device Formats (From: "Mikael Hakman" <email@hidden>)

  • Prev by Date: RE: Native Device Formats
  • Next by Date: Aggregate Device
  • Previous by thread: RE: Native Device Formats
  • Next by thread: Re: Native Device Formats
  • Index(es):
    • Date
    • Thread