michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #ifndef MOZILLA_AUDIOSAMPLEFORMAT_H_ michael@0: #define MOZILLA_AUDIOSAMPLEFORMAT_H_ michael@0: michael@0: #include "nsAlgorithm.h" michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * Audio formats supported in MediaStreams and media elements. michael@0: * michael@0: * Only one of these is supported by AudioStream, and that is determined michael@0: * at compile time (roughly, FLOAT32 on desktops, S16 on mobile). Media decoders michael@0: * produce that format only; queued AudioData always uses that format. michael@0: */ michael@0: enum AudioSampleFormat michael@0: { michael@0: // Native-endian signed 16-bit audio samples michael@0: AUDIO_FORMAT_S16, michael@0: // Signed 32-bit float samples michael@0: AUDIO_FORMAT_FLOAT32, michael@0: // Silence: format will be chosen later michael@0: AUDIO_FORMAT_SILENCE, michael@0: // The format used for output by AudioStream. michael@0: #ifdef MOZ_SAMPLE_TYPE_S16 michael@0: AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_S16 michael@0: #else michael@0: AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_FLOAT32 michael@0: #endif michael@0: }; michael@0: michael@0: enum { michael@0: MAX_AUDIO_SAMPLE_SIZE = sizeof(float) michael@0: }; michael@0: michael@0: template class AudioSampleTraits; michael@0: michael@0: template <> class AudioSampleTraits { michael@0: public: michael@0: typedef float Type; michael@0: }; michael@0: template <> class AudioSampleTraits { michael@0: public: michael@0: typedef int16_t Type; michael@0: }; michael@0: michael@0: typedef AudioSampleTraits::Type AudioDataValue; michael@0: michael@0: template class AudioSampleTypeToFormat; michael@0: michael@0: template <> class AudioSampleTypeToFormat { michael@0: public: michael@0: static const AudioSampleFormat Format = AUDIO_FORMAT_FLOAT32; michael@0: }; michael@0: michael@0: template <> class AudioSampleTypeToFormat { michael@0: public: michael@0: static const AudioSampleFormat Format = AUDIO_FORMAT_S16; michael@0: }; michael@0: michael@0: // Single-sample conversion michael@0: /* michael@0: * Use "2^N" conversion since it's simple, fast, "bit transparent", used by michael@0: * many other libraries and apparently behaves reasonably. michael@0: * http://blog.bjornroche.com/2009/12/int-float-int-its-jungle-out-there.html michael@0: * http://blog.bjornroche.com/2009/12/linearity-and-dynamic-range-in-int.html michael@0: */ michael@0: inline float michael@0: AudioSampleToFloat(float aValue) michael@0: { michael@0: return aValue; michael@0: } michael@0: inline float michael@0: AudioSampleToFloat(int16_t aValue) michael@0: { michael@0: return aValue/32768.0f; michael@0: } michael@0: michael@0: template T FloatToAudioSample(float aValue); michael@0: michael@0: template <> inline float michael@0: FloatToAudioSample(float aValue) michael@0: { michael@0: return aValue; michael@0: } michael@0: template <> inline int16_t michael@0: FloatToAudioSample(float aValue) michael@0: { michael@0: float v = aValue*32768.0f; michael@0: float clamped = std::max(-32768.0f, std::min(32767.0f, v)); michael@0: return int16_t(clamped); michael@0: } michael@0: michael@0: // Sample buffer conversion michael@0: michael@0: template inline void michael@0: ConvertAudioSamples(const From* aFrom, To* aTo, int aCount) michael@0: { michael@0: for (int i = 0; i < aCount; ++i) { michael@0: aTo[i] = FloatToAudioSample(AudioSampleToFloat(aFrom[i])); michael@0: } michael@0: } michael@0: inline void michael@0: ConvertAudioSamples(const int16_t* aFrom, int16_t* aTo, int aCount) michael@0: { michael@0: memcpy(aTo, aFrom, sizeof(*aTo)*aCount); michael@0: } michael@0: inline void michael@0: ConvertAudioSamples(const float* aFrom, float* aTo, int aCount) michael@0: { michael@0: memcpy(aTo, aFrom, sizeof(*aTo)*aCount); michael@0: } michael@0: michael@0: // Sample buffer conversion with scale michael@0: michael@0: template inline void michael@0: ConvertAudioSamplesWithScale(const From* aFrom, To* aTo, int aCount, float aScale) michael@0: { michael@0: if (aScale == 1.0f) { michael@0: ConvertAudioSamples(aFrom, aTo, aCount); michael@0: return; michael@0: } michael@0: for (int i = 0; i < aCount; ++i) { michael@0: aTo[i] = FloatToAudioSample(AudioSampleToFloat(aFrom[i])*aScale); michael@0: } michael@0: } michael@0: inline void michael@0: ConvertAudioSamplesWithScale(const int16_t* aFrom, int16_t* aTo, int aCount, float aScale) michael@0: { michael@0: if (aScale == 1.0f) { michael@0: ConvertAudioSamples(aFrom, aTo, aCount); michael@0: return; michael@0: } michael@0: if (0.0f <= aScale && aScale < 1.0f) { michael@0: int32_t scale = int32_t((1 << 16) * aScale); michael@0: for (int i = 0; i < aCount; ++i) { michael@0: aTo[i] = int16_t((int32_t(aFrom[i]) * scale) >> 16); michael@0: } michael@0: return; michael@0: } michael@0: for (int i = 0; i < aCount; ++i) { michael@0: aTo[i] = FloatToAudioSample(AudioSampleToFloat(aFrom[i])*aScale); michael@0: } michael@0: } michael@0: michael@0: // In place audio sample scaling. michael@0: inline void michael@0: ScaleAudioSamples(float* aBuffer, int aCount, float aScale) michael@0: { michael@0: for (int32_t i = 0; i < aCount; ++i) { michael@0: aBuffer[i] *= aScale; michael@0: } michael@0: } michael@0: michael@0: inline void michael@0: ScaleAudioSamples(short* aBuffer, int aCount, float aScale) michael@0: { michael@0: int32_t volume = int32_t((1 << 16) * aScale); michael@0: for (int32_t i = 0; i < aCount; ++i) { michael@0: aBuffer[i] = short((int32_t(aBuffer[i]) * volume) >> 16); michael@0: } michael@0: } michael@0: michael@0: inline const void* michael@0: AddAudioSampleOffset(const void* aBase, AudioSampleFormat aFormat, michael@0: int32_t aOffset) michael@0: { michael@0: static_assert(AUDIO_FORMAT_S16 == 0, "Bad constant"); michael@0: static_assert(AUDIO_FORMAT_FLOAT32 == 1, "Bad constant"); michael@0: NS_ASSERTION(aFormat == AUDIO_FORMAT_S16 || aFormat == AUDIO_FORMAT_FLOAT32, michael@0: "Unknown format"); michael@0: michael@0: return static_cast(aBase) + (aFormat + 1)*2*aOffset; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif /* MOZILLA_AUDIOSAMPLEFORMAT_H_ */