audio_sample_types.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef MEDIA_BASE_AUDIO_SAMPLE_TYPES_H_
  5. #define MEDIA_BASE_AUDIO_SAMPLE_TYPES_H_
  6. #include <cmath>
  7. #include <cstdint>
  8. #include <limits>
  9. #include <type_traits>
  10. // To specify different sample formats, we provide a class for each sample
  11. // format that knows certain things about it, such as the C++ data type used
  12. // to store sample values, min and max values, as well as how to convert to
  13. // and from floating point formats. Each class must satisfy a concept we call
  14. // "SampleTypeTraits", which requires that the following publics are provided:
  15. // * A type |ValueType| specifying the C++ type for storing sample values
  16. // * A static constant kMinValue which specifies the minimum sample value
  17. // * A static constant kMaxValue which specifies the maximum sample value
  18. // * A static constant kZeroPointValue which specifies the sample value
  19. // representing an amplitude of zero
  20. // * A static method ConvertFromFloat() that takes a float sample value and
  21. // converts it to the corresponding ValueType
  22. // * A static method ConvertFromDouble() that takes a double sample value and
  23. // converts it to the corresponding ValueType
  24. // * A static method ConvertToFloat() that takes a ValueType sample value and
  25. // converts it to the corresponding float value
  26. // * A static method ConvertToDouble() that takes a ValueType sample value and
  27. // converts it to the corresponding double value
  28. namespace media {
  29. // For float or double.
  30. // See also the aliases for commonly used types at the bottom of this file.
  31. template <typename SampleType>
  32. class FloatSampleTypeTraits {
  33. static_assert(std::is_floating_point<SampleType>::value,
  34. "Template is only valid for float types.");
  35. public:
  36. using ValueType = SampleType;
  37. static constexpr SampleType kMinValue = -1.0f;
  38. static constexpr SampleType kMaxValue = +1.0f;
  39. static constexpr SampleType kZeroPointValue = 0.0f;
  40. static SampleType FromFloat(float source_value) {
  41. return From<float>(source_value);
  42. }
  43. static float ToFloat(SampleType source_value) {
  44. return To<float>(source_value);
  45. }
  46. static SampleType FromDouble(double source_value) {
  47. return From<double>(source_value);
  48. }
  49. static double ToDouble(SampleType source_value) {
  50. return To<double>(source_value);
  51. }
  52. private:
  53. template <typename FloatType>
  54. static SampleType From(FloatType source_value) {
  55. // Apply clipping (aka. clamping). These values are frequently sent to OS
  56. // level drivers that may not properly handle these values.
  57. if (UNLIKELY(!(source_value >= kMinValue)))
  58. return kMinValue;
  59. if (UNLIKELY(source_value >= kMaxValue))
  60. return kMaxValue;
  61. return static_cast<SampleType>(source_value);
  62. }
  63. template <typename FloatType>
  64. static FloatType To(SampleType source_value) {
  65. return static_cast<FloatType>(source_value);
  66. }
  67. };
  68. // Similar to above, but does not apply clipping.
  69. template <typename SampleType>
  70. class FloatSampleTypeTraitsNoClip {
  71. static_assert(std::is_floating_point<SampleType>::value,
  72. "Template is only valid for float types.");
  73. public:
  74. using ValueType = SampleType;
  75. static constexpr SampleType kMinValue = -1.0f;
  76. static constexpr SampleType kMaxValue = +1.0f;
  77. static constexpr SampleType kZeroPointValue = 0.0f;
  78. static SampleType FromFloat(float source_value) {
  79. return From<float>(source_value);
  80. }
  81. static float ToFloat(SampleType source_value) {
  82. return To<float>(source_value);
  83. }
  84. static SampleType FromDouble(double source_value) {
  85. return From<double>(source_value);
  86. }
  87. static double ToDouble(SampleType source_value) {
  88. return To<double>(source_value);
  89. }
  90. private:
  91. template <typename FloatType>
  92. static SampleType From(FloatType source_value) {
  93. return static_cast<SampleType>(source_value);
  94. }
  95. template <typename FloatType>
  96. static FloatType To(SampleType source_value) {
  97. return static_cast<FloatType>(source_value);
  98. }
  99. };
  100. // For uint8_t, int16_t, int32_t...
  101. // See also the aliases for commonly used types at the bottom of this file.
  102. template <typename SampleType>
  103. class FixedSampleTypeTraits {
  104. static_assert(std::numeric_limits<SampleType>::is_integer,
  105. "Template is only valid for integer types.");
  106. public:
  107. using ValueType = SampleType;
  108. static constexpr SampleType kMinValue =
  109. std::numeric_limits<SampleType>::min();
  110. static constexpr SampleType kMaxValue =
  111. std::numeric_limits<SampleType>::max();
  112. static constexpr SampleType kZeroPointValue =
  113. (kMinValue == 0) ? (kMaxValue / 2 + 1) : 0;
  114. static SampleType FromFloat(float source_value) {
  115. return From<float>(source_value);
  116. }
  117. static float ToFloat(SampleType source_value) {
  118. return To<float>(source_value);
  119. }
  120. static SampleType FromDouble(double source_value) {
  121. return From<double>(source_value);
  122. }
  123. static double ToDouble(SampleType source_value) {
  124. return To<double>(source_value);
  125. }
  126. private:
  127. // We pre-compute the scaling factors for conversion at compile-time in order
  128. // to save computation time during runtime.
  129. template <typename FloatType>
  130. struct ScalingFactors {
  131. // Since zero_point_value() is not the exact center between
  132. // min_value() and max_value(), we apply a different scaling for positive
  133. // and negative values.
  134. // Note that due to the limited precision, the FloatType values may not
  135. // always be able to represent the max and min values of the integer
  136. // SampleType exactly. This is a concern when using these scale factors for
  137. // scaling input sample values for conversion. However, since the min value
  138. // of SampleType is usually of the form -2^N and the max value is usually of
  139. // the form (+2^N)-1, and due to the fact that the float types store a
  140. // significand value plus a binary exponent it just so happens that
  141. // FloatType can usually represent the min value exactly and its
  142. // representation of the max value is only off by 1, i.e. it quantizes to
  143. // (+2^N) instead of (+2^N-1).
  144. static constexpr FloatType kForPositiveInput =
  145. static_cast<FloatType>(kMaxValue) -
  146. static_cast<FloatType>(kZeroPointValue);
  147. // Note: In the below expression, it is important that we cast kMinValue to
  148. // FloatType _before_ taking the negative of it. For example, for SampleType
  149. // int32_t, the expression (- kMinValue) would evaluate to
  150. // -numeric_limits<int32_t>::min(), which falls outside the numeric
  151. // range, wraps around, and ends up being the same as
  152. // +numeric_limits<int32_t>::min().
  153. static constexpr FloatType kForNegativeInput =
  154. static_cast<FloatType>(kZeroPointValue) -
  155. static_cast<FloatType>(kMinValue);
  156. static constexpr FloatType kInverseForPositiveInput =
  157. 1.0f / kForPositiveInput;
  158. static constexpr FloatType kInverseForNegativeInput =
  159. 1.0f / kForNegativeInput;
  160. };
  161. template <typename FloatType>
  162. static SampleType From(FloatType source_value) {
  163. // Note, that the for the case of |source_value| == 1.0, the imprecision of
  164. // |kScalingFactorForPositive| can lead to a product that is larger than the
  165. // maximum possible value of SampleType. To ensure this does not happen, we
  166. // handle the case of |source_value| == 1.0 as part of the clipping check.
  167. // For all FloatType values smaller than 1.0, the imprecision of
  168. // |kScalingFactorForPositive| is small enough to not push the scaled
  169. // |source_value| outside the numeric range of SampleType.
  170. // The nested if/else structure appears to compile to a
  171. // better-performing release binary compared to handling the clipping for
  172. // both positive and negative values first.
  173. //
  174. // Inlining the computation formula for multiplication with the scaling
  175. // factor and addition of |kZeroPointValue| results in better performance
  176. // for the int16_t case on Arm when compared to storing the scaling factor
  177. // in a temporary variable and applying it outside of the if-else block.
  178. //
  179. // It is important to have the cast to SampleType take place _after_
  180. // adding |kZeroPointValue|, because the scaled source value may be negative
  181. // and SampleType may be an unsigned integer type. The result of casting a
  182. // negative float to an unsigned integer is undefined.
  183. if (source_value < 0) {
  184. // Apply clipping (aka. clamping).
  185. if (source_value <= FloatSampleTypeTraits<float>::kMinValue)
  186. return kMinValue;
  187. return static_cast<SampleType>(
  188. (source_value * ScalingFactors<FloatType>::kForNegativeInput) +
  189. static_cast<FloatType>(kZeroPointValue));
  190. } else {
  191. // Apply clipping (aka. clamping).
  192. // As mentioned above, here we must include the case |source_value| == 1.
  193. if (source_value >= FloatSampleTypeTraits<float>::kMaxValue)
  194. return kMaxValue;
  195. return static_cast<SampleType>(
  196. (source_value * ScalingFactors<FloatType>::kForPositiveInput) +
  197. static_cast<FloatType>(kZeroPointValue));
  198. }
  199. }
  200. template <typename FloatType>
  201. static FloatType To(SampleType source_value) {
  202. FloatType offset_value =
  203. static_cast<FloatType>(source_value - kZeroPointValue);
  204. // We multiply with the inverse scaling factor instead of dividing by the
  205. // scaling factor, because multiplication performs faster than division
  206. // on many platforms.
  207. return (offset_value < 0.0f)
  208. ? (offset_value *
  209. ScalingFactors<FloatType>::kInverseForNegativeInput)
  210. : (offset_value *
  211. ScalingFactors<FloatType>::kInverseForPositiveInput);
  212. }
  213. };
  214. // Aliases for commonly used sample formats.
  215. using Float32SampleTypeTraits = FloatSampleTypeTraits<float>;
  216. using Float32SampleTypeTraitsNoClip = FloatSampleTypeTraitsNoClip<float>;
  217. using Float64SampleTypeTraits = FloatSampleTypeTraits<double>;
  218. using UnsignedInt8SampleTypeTraits = FixedSampleTypeTraits<uint8_t>;
  219. using SignedInt16SampleTypeTraits = FixedSampleTypeTraits<int16_t>;
  220. using SignedInt32SampleTypeTraits = FixedSampleTypeTraits<int32_t>;
  221. } // namespace media
  222. #endif // MEDIA_BASE_AUDIO_SAMPLE_TYPES_H_