Bug 1708422: part 16) Rename `mozInlineSpellChecker::SpellCheckerTimeSlice` to `mozIn...
[gecko.git] / dom / media / AudioSegment.cpp
blobf00b793496646e9282b5f936d207b3ce70559054
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "AudioSegment.h"
7 #include "AudioMixer.h"
8 #include "AudioChannelFormat.h"
9 #include <speex/speex_resampler.h>
11 namespace mozilla {
13 const uint8_t
14 SilentChannel::gZeroChannel[MAX_AUDIO_SAMPLE_SIZE *
15 SilentChannel::AUDIO_PROCESSING_FRAMES] = {0};
17 template <>
18 const float* SilentChannel::ZeroChannel<float>() {
19 return reinterpret_cast<const float*>(SilentChannel::gZeroChannel);
22 template <>
23 const int16_t* SilentChannel::ZeroChannel<int16_t>() {
24 return reinterpret_cast<const int16_t*>(SilentChannel::gZeroChannel);
27 void AudioSegment::ApplyVolume(float aVolume) {
28 for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
29 ci->mVolume *= aVolume;
33 void AudioSegment::ResampleChunks(nsAutoRef<SpeexResamplerState>& aResampler,
34 uint32_t* aResamplerChannelCount,
35 uint32_t aInRate, uint32_t aOutRate) {
36 if (mChunks.IsEmpty()) {
37 return;
40 AudioSampleFormat format = AUDIO_FORMAT_SILENCE;
41 for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
42 if (ci->mBufferFormat != AUDIO_FORMAT_SILENCE) {
43 format = ci->mBufferFormat;
47 switch (format) {
48 // If the format is silence at this point, all the chunks are silent. The
49 // actual function we use does not matter, it's just a matter of changing
50 // the chunks duration.
51 case AUDIO_FORMAT_SILENCE:
52 case AUDIO_FORMAT_FLOAT32:
53 Resample<float>(aResampler, aResamplerChannelCount, aInRate, aOutRate);
54 break;
55 case AUDIO_FORMAT_S16:
56 Resample<int16_t>(aResampler, aResamplerChannelCount, aInRate, aOutRate);
57 break;
58 default:
59 MOZ_ASSERT(false);
60 break;
64 // This helps to to safely get a pointer to the position we want to start
65 // writing a planar audio buffer, depending on the channel and the offset in the
66 // buffer.
67 static AudioDataValue* PointerForOffsetInChannel(AudioDataValue* aData,
68 size_t aLengthSamples,
69 uint32_t aChannelCount,
70 uint32_t aChannel,
71 uint32_t aOffsetSamples) {
72 size_t samplesPerChannel = aLengthSamples / aChannelCount;
73 size_t beginningOfChannel = samplesPerChannel * aChannel;
74 MOZ_ASSERT(aChannel * samplesPerChannel + aOffsetSamples < aLengthSamples,
75 "Offset request out of bounds.");
76 return aData + beginningOfChannel + aOffsetSamples;
79 void AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
80 uint32_t aSampleRate) {
81 AutoTArray<AudioDataValue,
82 SilentChannel::AUDIO_PROCESSING_FRAMES * GUESS_AUDIO_CHANNELS>
83 buf;
84 AutoTArray<const AudioDataValue*, GUESS_AUDIO_CHANNELS> channelData;
85 uint32_t offsetSamples = 0;
86 uint32_t duration = GetDuration();
88 if (duration <= 0) {
89 MOZ_ASSERT(duration == 0);
90 return;
93 uint32_t outBufferLength = duration * aOutputChannels;
94 buf.SetLength(outBufferLength);
96 for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
97 AudioChunk& c = *ci;
98 uint32_t frames = c.mDuration;
100 // If the chunk is silent, simply write the right number of silence in the
101 // buffers.
102 if (c.mBufferFormat == AUDIO_FORMAT_SILENCE) {
103 for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
104 AudioDataValue* ptr =
105 PointerForOffsetInChannel(buf.Elements(), outBufferLength,
106 aOutputChannels, channel, offsetSamples);
107 PodZero(ptr, frames);
109 } else {
110 // Othewise, we need to upmix or downmix appropriately, depending on the
111 // desired input and output channels.
112 channelData.SetLength(c.mChannelData.Length());
113 for (uint32_t i = 0; i < channelData.Length(); ++i) {
114 channelData[i] = static_cast<const AudioDataValue*>(c.mChannelData[i]);
116 if (channelData.Length() < aOutputChannels) {
117 // Up-mix.
118 AudioChannelsUpMix(&channelData, aOutputChannels,
119 SilentChannel::ZeroChannel<AudioDataValue>());
120 for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
121 AudioDataValue* ptr = PointerForOffsetInChannel(
122 buf.Elements(), outBufferLength, aOutputChannels, channel,
123 offsetSamples);
124 PodCopy(ptr,
125 reinterpret_cast<const AudioDataValue*>(channelData[channel]),
126 frames);
128 MOZ_ASSERT(channelData.Length() == aOutputChannels);
129 } else if (channelData.Length() > aOutputChannels) {
130 // Down mix.
131 AutoTArray<AudioDataValue*, GUESS_AUDIO_CHANNELS> outChannelPtrs;
132 outChannelPtrs.SetLength(aOutputChannels);
133 uint32_t offsetSamples = 0;
134 for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
135 outChannelPtrs[channel] = PointerForOffsetInChannel(
136 buf.Elements(), outBufferLength, aOutputChannels, channel,
137 offsetSamples);
139 AudioChannelsDownMix(channelData, outChannelPtrs.Elements(),
140 aOutputChannels, frames);
141 } else {
142 // The channel count is already what we want, just copy it over.
143 for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
144 AudioDataValue* ptr = PointerForOffsetInChannel(
145 buf.Elements(), outBufferLength, aOutputChannels, channel,
146 offsetSamples);
147 PodCopy(ptr,
148 reinterpret_cast<const AudioDataValue*>(channelData[channel]),
149 frames);
153 offsetSamples += frames;
156 if (offsetSamples) {
157 MOZ_ASSERT(offsetSamples == outBufferLength / aOutputChannels,
158 "We forgot to write some samples?");
159 aMixer.Mix(buf.Elements(), aOutputChannels, offsetSamples, aSampleRate);
163 void AudioSegment::WriteTo(AudioMixer& aMixer, uint32_t aOutputChannels,
164 uint32_t aSampleRate) {
165 AutoTArray<AudioDataValue,
166 SilentChannel::AUDIO_PROCESSING_FRAMES * GUESS_AUDIO_CHANNELS>
167 buf;
168 // Offset in the buffer that will be written to the mixer, in samples.
169 uint32_t offset = 0;
171 if (GetDuration() <= 0) {
172 MOZ_ASSERT(GetDuration() == 0);
173 return;
176 uint32_t outBufferLength = GetDuration() * aOutputChannels;
177 buf.SetLength(outBufferLength);
179 for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
180 AudioChunk& c = *ci;
182 switch (c.mBufferFormat) {
183 case AUDIO_FORMAT_S16:
184 WriteChunk<int16_t>(c, aOutputChannels, buf.Elements() + offset);
185 break;
186 case AUDIO_FORMAT_FLOAT32:
187 WriteChunk<float>(c, aOutputChannels, buf.Elements() + offset);
188 break;
189 case AUDIO_FORMAT_SILENCE:
190 // The mixer is expecting interleaved data, so this is ok.
191 PodZero(buf.Elements() + offset, c.mDuration * aOutputChannels);
192 break;
193 default:
194 MOZ_ASSERT(false, "Not handled");
197 offset += c.mDuration * aOutputChannels;
200 if (offset) {
201 aMixer.Mix(buf.Elements(), aOutputChannels, offset / aOutputChannels,
202 aSampleRate);
206 } // namespace mozilla