xref: /aosp_15_r20/cts/apps/CtsVerifier/jni/audio_loopback/WaveFileWriter.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker  * Copyright 2024 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker  *
4*b7c941bbSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker  *
8*b7c941bbSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker  *
10*b7c941bbSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker  * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker  */
16*b7c941bbSAndroid Build Coastguard Worker 
17*b7c941bbSAndroid Build Coastguard Worker #include "WaveFileWriter.h"
18*b7c941bbSAndroid Build Coastguard Worker 
19*b7c941bbSAndroid Build Coastguard Worker #include <android/log.h>
20*b7c941bbSAndroid Build Coastguard Worker 
write(float value)21*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::write(float value) {
22*b7c941bbSAndroid Build Coastguard Worker     if (!headerWritten) {
23*b7c941bbSAndroid Build Coastguard Worker         writeHeader();
24*b7c941bbSAndroid Build Coastguard Worker     }
25*b7c941bbSAndroid Build Coastguard Worker     if (bitsPerSample == 24) {
26*b7c941bbSAndroid Build Coastguard Worker         writePCM24(value);
27*b7c941bbSAndroid Build Coastguard Worker     } else {
28*b7c941bbSAndroid Build Coastguard Worker         writePCM16(value);
29*b7c941bbSAndroid Build Coastguard Worker     }
30*b7c941bbSAndroid Build Coastguard Worker }
31*b7c941bbSAndroid Build Coastguard Worker 
write(float * buffer,int32_t startSample,int32_t numSamples)32*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::write(float *buffer, int32_t startSample, int32_t numSamples) {
33*b7c941bbSAndroid Build Coastguard Worker     for (int32_t i = 0; i < numSamples; i++) {
34*b7c941bbSAndroid Build Coastguard Worker         write(buffer[startSample + i]);
35*b7c941bbSAndroid Build Coastguard Worker     }
36*b7c941bbSAndroid Build Coastguard Worker }
37*b7c941bbSAndroid Build Coastguard Worker 
writeIntLittle(int32_t n)38*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeIntLittle(int32_t n) {
39*b7c941bbSAndroid Build Coastguard Worker     writeByte(n);
40*b7c941bbSAndroid Build Coastguard Worker     writeByte(n >> 8);
41*b7c941bbSAndroid Build Coastguard Worker     writeByte(n >> 16);
42*b7c941bbSAndroid Build Coastguard Worker     writeByte(n >> 24);
43*b7c941bbSAndroid Build Coastguard Worker }
44*b7c941bbSAndroid Build Coastguard Worker 
writeShortLittle(int16_t n)45*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeShortLittle(int16_t n) {
46*b7c941bbSAndroid Build Coastguard Worker     writeByte(n);
47*b7c941bbSAndroid Build Coastguard Worker     writeByte(n >> 8);
48*b7c941bbSAndroid Build Coastguard Worker }
49*b7c941bbSAndroid Build Coastguard Worker 
writeFormatChunk()50*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeFormatChunk() {
51*b7c941bbSAndroid Build Coastguard Worker     int32_t bytesPerSample = (bitsPerSample + 7) / 8;
52*b7c941bbSAndroid Build Coastguard Worker 
53*b7c941bbSAndroid Build Coastguard Worker     writeByte('f');
54*b7c941bbSAndroid Build Coastguard Worker     writeByte('m');
55*b7c941bbSAndroid Build Coastguard Worker     writeByte('t');
56*b7c941bbSAndroid Build Coastguard Worker     writeByte(' ');
57*b7c941bbSAndroid Build Coastguard Worker     writeIntLittle(16); // chunk size
58*b7c941bbSAndroid Build Coastguard Worker     writeShortLittle(WAVE_FORMAT_PCM);
59*b7c941bbSAndroid Build Coastguard Worker     writeShortLittle((int16_t) mSamplesPerFrame);
60*b7c941bbSAndroid Build Coastguard Worker     writeIntLittle(mFrameRate);
61*b7c941bbSAndroid Build Coastguard Worker     // bytes/second
62*b7c941bbSAndroid Build Coastguard Worker     writeIntLittle(mFrameRate * mSamplesPerFrame * bytesPerSample);
63*b7c941bbSAndroid Build Coastguard Worker     // block align
64*b7c941bbSAndroid Build Coastguard Worker     writeShortLittle((int16_t) (mSamplesPerFrame * bytesPerSample));
65*b7c941bbSAndroid Build Coastguard Worker     writeShortLittle((int16_t) bitsPerSample);
66*b7c941bbSAndroid Build Coastguard Worker }
67*b7c941bbSAndroid Build Coastguard Worker 
writeDataChunkHeader()68*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeDataChunkHeader() {
69*b7c941bbSAndroid Build Coastguard Worker     writeByte('d');
70*b7c941bbSAndroid Build Coastguard Worker     writeByte('a');
71*b7c941bbSAndroid Build Coastguard Worker     writeByte('t');
72*b7c941bbSAndroid Build Coastguard Worker     writeByte('a');
73*b7c941bbSAndroid Build Coastguard Worker     // Maximum size is not strictly correct but is commonly used
74*b7c941bbSAndroid Build Coastguard Worker     // when we do not know the final size.
75*b7c941bbSAndroid Build Coastguard Worker     writeIntLittle(INT32_MAX);
76*b7c941bbSAndroid Build Coastguard Worker }
77*b7c941bbSAndroid Build Coastguard Worker 
writeHeader()78*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeHeader() {
79*b7c941bbSAndroid Build Coastguard Worker     writeRiffHeader();
80*b7c941bbSAndroid Build Coastguard Worker     writeFormatChunk();
81*b7c941bbSAndroid Build Coastguard Worker     writeDataChunkHeader();
82*b7c941bbSAndroid Build Coastguard Worker     headerWritten = true;
83*b7c941bbSAndroid Build Coastguard Worker }
84*b7c941bbSAndroid Build Coastguard Worker 
85*b7c941bbSAndroid Build Coastguard Worker // Write lower 8 bits. Upper bits ignored.
writeByte(uint8_t b)86*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeByte(uint8_t b) {
87*b7c941bbSAndroid Build Coastguard Worker     mOutputStream->write(b);
88*b7c941bbSAndroid Build Coastguard Worker     bytesWritten += 1;
89*b7c941bbSAndroid Build Coastguard Worker }
90*b7c941bbSAndroid Build Coastguard Worker 
writePCM24(float value)91*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writePCM24(float value) {
92*b7c941bbSAndroid Build Coastguard Worker     // Offset before casting so that we can avoid using floor().
93*b7c941bbSAndroid Build Coastguard Worker     // Also round by adding 0.5 so that very small signals go to zero.
94*b7c941bbSAndroid Build Coastguard Worker     float temp = (PCM24_MAX * value) + 0.5 - PCM24_MIN;
95*b7c941bbSAndroid Build Coastguard Worker     int32_t sample = ((int) temp) + PCM24_MIN;
96*b7c941bbSAndroid Build Coastguard Worker     // clip to 24-bit range
97*b7c941bbSAndroid Build Coastguard Worker     if (sample > PCM24_MAX) {
98*b7c941bbSAndroid Build Coastguard Worker         sample = PCM24_MAX;
99*b7c941bbSAndroid Build Coastguard Worker     } else if (sample < PCM24_MIN) {
100*b7c941bbSAndroid Build Coastguard Worker         sample = PCM24_MIN;
101*b7c941bbSAndroid Build Coastguard Worker     }
102*b7c941bbSAndroid Build Coastguard Worker     // encode as little-endian
103*b7c941bbSAndroid Build Coastguard Worker     writeByte(sample); // little end
104*b7c941bbSAndroid Build Coastguard Worker     writeByte(sample >> 8); // middle
105*b7c941bbSAndroid Build Coastguard Worker     writeByte(sample >> 16); // big end
106*b7c941bbSAndroid Build Coastguard Worker }
107*b7c941bbSAndroid Build Coastguard Worker 
writePCM16(float value)108*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writePCM16(float value) {
109*b7c941bbSAndroid Build Coastguard Worker     // Offset before casting so that we can avoid using floor().
110*b7c941bbSAndroid Build Coastguard Worker     // Also round by adding 0.5 so that very small signals go to zero.
111*b7c941bbSAndroid Build Coastguard Worker     float temp = (INT16_MAX * value) + 0.5 - INT16_MIN;
112*b7c941bbSAndroid Build Coastguard Worker     int32_t sample = ((int) temp) + INT16_MIN;
113*b7c941bbSAndroid Build Coastguard Worker     if (sample > INT16_MAX) {
114*b7c941bbSAndroid Build Coastguard Worker         sample = INT16_MAX;
115*b7c941bbSAndroid Build Coastguard Worker     } else if (sample < INT16_MIN) {
116*b7c941bbSAndroid Build Coastguard Worker         sample = INT16_MIN;
117*b7c941bbSAndroid Build Coastguard Worker     }
118*b7c941bbSAndroid Build Coastguard Worker     writeByte(sample); // little end
119*b7c941bbSAndroid Build Coastguard Worker     writeByte(sample >> 8); // big end
120*b7c941bbSAndroid Build Coastguard Worker }
121*b7c941bbSAndroid Build Coastguard Worker 
writeRiffHeader()122*b7c941bbSAndroid Build Coastguard Worker void WaveFileWriter::writeRiffHeader() {
123*b7c941bbSAndroid Build Coastguard Worker     writeByte('R');
124*b7c941bbSAndroid Build Coastguard Worker     writeByte('I');
125*b7c941bbSAndroid Build Coastguard Worker     writeByte('F');
126*b7c941bbSAndroid Build Coastguard Worker     writeByte('F');
127*b7c941bbSAndroid Build Coastguard Worker     // Maximum size is not strictly correct but is commonly used
128*b7c941bbSAndroid Build Coastguard Worker     // when we do not know the final size.
129*b7c941bbSAndroid Build Coastguard Worker     writeIntLittle(INT32_MAX);
130*b7c941bbSAndroid Build Coastguard Worker     writeByte('W');
131*b7c941bbSAndroid Build Coastguard Worker     writeByte('A');
132*b7c941bbSAndroid Build Coastguard Worker     writeByte('V');
133*b7c941bbSAndroid Build Coastguard Worker     writeByte('E');
134*b7c941bbSAndroid Build Coastguard Worker }
135