1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "AudioSpeed"
17 #endif
18
19 #include "audio_speed.h"
20 #include "audio_common_log.h"
21 #include "audio_utils.h"
22 #include "audio_errors.h"
23
24 namespace OHOS {
25 namespace AudioStandard {
26
27 static constexpr float SLOW_PLAY_1_8_SPEED = 0.125f;
28
AudioSpeed(size_t rate,size_t format,size_t channels)29 AudioSpeed::AudioSpeed(size_t rate, size_t format, size_t channels):rate_(rate), format_(format), channels_(channels)
30 {
31 AUDIO_INFO_LOG("AudioSpeed construct");
32 Init();
33 streamParam_ = {};
34 }
35
~AudioSpeed()36 AudioSpeed::~AudioSpeed()
37 {
38 AUDIO_INFO_LOG("~AudioSpeed destroy");
39 if (sonicStream_ != nullptr) {
40 sonicDestroyStream(sonicStream_);
41 sonicStream_ = nullptr;
42 AUDIO_INFO_LOG("Sonic stream destroy");
43 }
44 }
45
Init()46 int32_t AudioSpeed::Init()
47 {
48 sonicStream_ = sonicCreateStream(rate_, channels_);
49 CHECK_AND_RETURN_RET_LOG(sonicStream_ != nullptr, ERROR, "sonicCreateStream failed.");
50 LoadChangeSpeedFunc();
51
52 return SUCCESS;
53 }
54
LoadChangeSpeedFunc()55 int32_t AudioSpeed::LoadChangeSpeedFunc()
56 {
57 switch (format_) {
58 case SAMPLE_U8:
59 formatSize_ = 1; // size is 1
60 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
61 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
62 return this->ChangeSpeedFor8Bit(buffer, bufferSize, outBuffer, outBufferSize);
63 };
64 break;
65 case SAMPLE_S16LE:
66 formatSize_ = 2; // size is 2
67 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
68 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
69 return this->ChangeSpeedFor16Bit(buffer, bufferSize, outBuffer, outBufferSize);
70 };
71 break;
72 case SAMPLE_S24LE:
73 formatSize_ = 3; // size is 3
74 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
75 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
76 return this->ChangeSpeedFor24Bit(buffer, bufferSize, outBuffer, outBufferSize);
77 };
78 break;
79 case SAMPLE_S32LE:
80 formatSize_ = 4; // size is 4
81 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
82 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
83 return this->ChangeSpeedFor32Bit(buffer, bufferSize, outBuffer, outBufferSize);
84 };
85 break;
86 case SAMPLE_F32LE:
87 formatSize_ = 4; // size is 4
88 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
89 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
90 return this->ChangeSpeedForFloat(reinterpret_cast<float*>(buffer), bufferSize,
91 reinterpret_cast<float*>(outBuffer.get()), outBufferSize);
92 };
93 break;
94 default:
95 formatSize_ = 2; // size is 2
96 ChangeSpeedFunc = [this] (uint8_t *buffer, int32_t bufferSize,
97 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)-> int32_t {
98 return this->ChangeSpeedFor16Bit(buffer, bufferSize, outBuffer, outBufferSize);
99 };
100 }
101 AUDIO_INFO_LOG("load change speed func for format %{public}zu", format_);
102 return SUCCESS;
103 }
104
SetSpeed(float speed)105 int32_t AudioSpeed::SetSpeed(float speed)
106 {
107 AUDIO_INFO_LOG("SetSpeed %{public}f", speed);
108 speed_ = speed;
109 sonicSetSpeed(sonicStream_, speed_);
110 return SUCCESS;
111 }
112
SetPitch(float pitch)113 int32_t AudioSpeed::SetPitch(float pitch)
114 {
115 AUDIO_INFO_LOG("SetPitch %{public}f", pitch);
116 sonicSetPitch(sonicStream_, pitch);
117 sonicSetRate(sonicStream_, 1.0f);
118 return SUCCESS;
119 }
120
GetPitchForSpeed(float speed)121 float AudioSpeed::GetPitchForSpeed(float speed)
122 {
123 float noPitchPoint = 0.5f;
124 float pitch = SPEED_NORMAL;
125 if (speed > noPitchPoint) {
126 pitch = SPEED_NORMAL;
127 } else {
128 pitch = (speed - SLOW_PLAY_1_8_SPEED) * (SPEED_NORMAL - SLOW_PLAY_1_8_SPEED) /
129 (noPitchPoint - SLOW_PLAY_1_8_SPEED) + SLOW_PLAY_1_8_SPEED;
130 }
131 AUDIO_INFO_LOG("final pitch is %{public}f for speed %{public}f", pitch, speed);
132 return pitch;
133 }
134
GetSpeed()135 float AudioSpeed::GetSpeed()
136 {
137 return speed_;
138 }
139
ChangeSpeedFor8Bit(uint8_t * buffer,int32_t bufferSize,std::unique_ptr<uint8_t[]> & outBuffer,int32_t & outBufferSize)140 int32_t AudioSpeed::ChangeSpeedFor8Bit(uint8_t *buffer, int32_t bufferSize,
141 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)
142 {
143 Trace trace("AudioSpeed::ChangeSpeedFor8Bit");
144 int32_t numSamples = bufferSize / static_cast<int32_t>(formatSize_ * channels_);
145 int32_t res = sonicWriteUnsignedCharToStream(sonicStream_, static_cast<unsigned char*>(buffer), numSamples);
146 CHECK_AND_RETURN_RET_LOG(res == 1, 0, "sonic write unsigned char to stream failed.");
147
148 int32_t outSamples = sonicReadUnsignedCharFromStream(sonicStream_,
149 static_cast<unsigned char*>(outBuffer.get()), MAX_SPEED_BUFFER_SIZE);
150 CHECK_AND_RETURN_RET_LOG(outSamples != 0, bufferSize, "sonic stream is not full continue to write.");
151
152 outBufferSize = outSamples * static_cast<int32_t>(formatSize_ * channels_);
153 return bufferSize;
154 }
155
ChangeSpeedFor16Bit(uint8_t * buffer,int32_t bufferSize,std::unique_ptr<uint8_t[]> & outBuffer,int32_t & outBufferSize)156 int32_t AudioSpeed::ChangeSpeedFor16Bit(uint8_t *buffer, int32_t bufferSize,
157 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)
158 {
159 Trace trace("AudioSpeed::ChangeSpeedFor16Bit");
160 int32_t numSamples = bufferSize / static_cast<int32_t>(formatSize_ * channels_);
161 int32_t res = sonicWriteShortToStream(sonicStream_, reinterpret_cast<short*>(buffer), numSamples);
162 CHECK_AND_RETURN_RET_LOG(res == 1, 0, "sonic write short to stream failed.");
163
164 int32_t outSamples = sonicReadShortFromStream(sonicStream_, reinterpret_cast<short*>(outBuffer.get()),
165 MAX_SPEED_BUFFER_SIZE);
166 CHECK_AND_RETURN_RET_LOG(outSamples != 0, bufferSize, "sonic stream is not full continue to write.");
167
168 outBufferSize = outSamples * static_cast<int32_t>(formatSize_ * channels_);
169 return bufferSize;
170 }
171
ChangeSpeedFor24Bit(uint8_t * buffer,int32_t bufferSize,std::unique_ptr<uint8_t[]> & outBuffer,int32_t & outBufferSize)172 int32_t AudioSpeed::ChangeSpeedFor24Bit(uint8_t *buffer, int32_t bufferSize,
173 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)
174 {
175 Trace trace("AudioSpeed::ChangeSpeedFor24Bit");
176 if (bufferSize <= 0 || bufferSize > MAX_SPEED_BUFFER_SIZE) {
177 AUDIO_ERR_LOG("BufferSize is illegal:%{public}d", bufferSize);
178 return ERR_MEMORY_ALLOC_FAILED;
179 }
180 float *bitTofloat = new (std::nothrow) float[bufferSize];
181 if (bitTofloat == nullptr) {
182 AUDIO_ERR_LOG("bitTofloat nullptr, No memory");
183 return ERR_MEMORY_ALLOC_FAILED;
184 }
185 ConvertFrom24BitToFloat(bufferSize / formatSize_, buffer, bitTofloat);
186
187 float *speedBuf = new (std::nothrow) float[MAX_SPEED_BUFFER_SIZE];
188 if (speedBuf == nullptr) {
189 AUDIO_ERR_LOG("speedBuf nullptr, No memory");
190 delete [] bitTofloat;
191 return ERR_MEMORY_ALLOC_FAILED;
192 }
193 int32_t ret = ChangeSpeedForFloat(bitTofloat, bufferSize, speedBuf, outBufferSize);
194
195 ConvertFromFloatTo24Bit(outBufferSize / formatSize_, speedBuf, outBuffer.get());
196
197 delete [] bitTofloat;
198 delete [] speedBuf;
199 return ret;
200 }
201
ChangeSpeedFor32Bit(uint8_t * buffer,int32_t bufferSize,std::unique_ptr<uint8_t[]> & outBuffer,int32_t & outBufferSize)202 int32_t AudioSpeed::ChangeSpeedFor32Bit(uint8_t *buffer, int32_t bufferSize,
203 std::unique_ptr<uint8_t []> &outBuffer, int32_t &outBufferSize)
204 {
205 Trace trace("AudioSpeed::ChangeSpeedFor32Bit");
206 if (bufferSize <= 0 || bufferSize > MAX_SPEED_BUFFER_SIZE) {
207 AUDIO_ERR_LOG("BufferSize is illegal:%{public}d", bufferSize);
208 return ERR_MEMORY_ALLOC_FAILED;
209 }
210 float *bitTofloat = new (std::nothrow) float[bufferSize];
211 if (bitTofloat == nullptr) {
212 AUDIO_ERR_LOG("bitTofloat nullptr, No memory");
213 return ERR_MEMORY_ALLOC_FAILED;
214 }
215 ConvertFrom32BitToFloat(bufferSize / formatSize_, reinterpret_cast<int32_t *>(buffer), bitTofloat);
216
217 float *speedBuf = new (std::nothrow) float[MAX_SPEED_BUFFER_SIZE];
218 if (speedBuf == nullptr) {
219 AUDIO_ERR_LOG("speedBuf nullptr, No memory");
220 delete [] bitTofloat;
221 return ERR_MEMORY_ALLOC_FAILED;
222 }
223 int32_t ret = ChangeSpeedForFloat(bitTofloat, bufferSize, speedBuf, outBufferSize);
224
225 ConvertFromFloatTo32Bit(outBufferSize / formatSize_, speedBuf, reinterpret_cast<int32_t *>(outBuffer.get()));
226
227 delete [] bitTofloat;
228 delete [] speedBuf;
229 return ret;
230 }
231
ChangeSpeedForFloat(float * buffer,int32_t bufferSize,float * outBuffer,int32_t & outBufferSize)232 int32_t AudioSpeed::ChangeSpeedForFloat(float *buffer, int32_t bufferSize,
233 float* outBuffer, int32_t &outBufferSize)
234 {
235 Trace trace("AudioSpeed::ChangeSpeedForFloat");
236 int32_t numSamples = bufferSize / static_cast<int32_t>(formatSize_ * channels_);
237 int32_t res = static_cast<int32_t>(sonicWriteFloatToStream(sonicStream_, buffer, numSamples));
238 CHECK_AND_RETURN_RET_LOG(res == 1, 0, "sonic write float to stream failed.");
239 int32_t outSamples = sonicReadFloatFromStream(sonicStream_, outBuffer, MAX_SPEED_BUFFER_SIZE);
240 outBufferSize = outSamples * static_cast<int32_t>(formatSize_ * channels_);
241 return bufferSize;
242 }
243
Flush()244 int32_t AudioSpeed::Flush()
245 {
246 Trace trace("AudioSpeed::Flush");
247 sonicFlushStream(sonicStream_);
248 std::unique_ptr<uint8_t[]> tmpBuffer = std::make_unique<uint8_t[]>(MAX_SPEED_BUFFER_SIZE);
249
250 int samplesWritten = 0;
251 const size_t channelMultiplier = static_cast<size_t>(channels_);
252 do {
253 switch (format_) {
254 case SAMPLE_U8:
255 samplesWritten = sonicReadUnsignedCharFromStream(sonicStream_,
256 reinterpret_cast<uint8_t*>(tmpBuffer.get()),
257 MAX_SPEED_BUFFER_SIZE / channelMultiplier);
258 break;
259 case SAMPLE_S24LE:
260 case SAMPLE_S32LE:
261 case SAMPLE_F32LE:
262 samplesWritten = sonicReadFloatFromStream(sonicStream_,
263 reinterpret_cast<float*>(tmpBuffer.get()),
264 MAX_SPEED_BUFFER_SIZE / (channelMultiplier * sizeof(float)));
265 break;
266 case SAMPLE_S16LE:
267 samplesWritten = sonicReadShortFromStream(sonicStream_,
268 reinterpret_cast<short*>(tmpBuffer.get()),
269 MAX_SPEED_BUFFER_SIZE / (channelMultiplier * sizeof(short)));
270 break;
271 default:
272 AUDIO_ERR_LOG("invalid format_");
273 samplesWritten = 0;
274 break;
275 }
276 } while (samplesWritten > 0);
277 return SUCCESS;
278 }
279 } // namespace AudioStandard
280 } // namespace OHOS
281