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