xref: /aosp_15_r20/cts/apps/CtsVerifier/jni/audio_loopback/WaveFileWriter.h (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 // Based on the WaveFileWriter in Java from the open source JSyn library by Phil Burk
18 // https://github.com/philburk/jsyn/blob/master/src/main/java/com/jsyn/util/WaveFileWriter.java
19 
20 #ifndef UTIL_WAVE_FILE_WRITER
21 #define UTIL_WAVE_FILE_WRITER
22 
23 #include <cassert>
24 #include <stdio.h>
25 
26 class WaveFileOutputStream {
27 public:
28     virtual ~WaveFileOutputStream() = default;
29     virtual void write(uint8_t b) = 0;
30 };
31 
32 /**
33  * Write audio data to a WAV file.
34  *
35  * <pre>
36  * <code>
37  * WaveFileWriter writer = new WaveFileWriter(waveFileOutputStream);
38  * writer.setFrameRate(48000);
39  * writer.setBitsPerSample(24);
40  * writer.write(floatArray, 0, numSamples);
41  * writer.close();
42  * </code>
43  * </pre>
44  *
45  */
46 class WaveFileWriter {
47 public:
48 
49     /**
50      * Create an object that will write a WAV file image to the specified stream.
51      *
52      * @param outputStream stream to receive the bytes
53      * @throws FileNotFoundException
54      */
WaveFileWriter(WaveFileOutputStream * outputStream)55     WaveFileWriter(WaveFileOutputStream *outputStream) {
56         mOutputStream = outputStream;
57         bitsPerSample = 24;
58     }
59 
reset()60     void reset() {
61         bytesWritten = 0;
62         headerWritten = false;
63     }
64 
65     /**
66      * @param frameRate default is 44100
67      */
setFrameRate(int32_t frameRate)68     void setFrameRate(int32_t frameRate) {
69         mFrameRate = frameRate;
70     }
71 
getFrameRate()72     int32_t getFrameRate() const {
73         return mFrameRate;
74     }
75 
76     /**
77      * For stereo, set this to 2. Default is mono = 1.
78      * Also known as ChannelCount
79      */
setSamplesPerFrame(int32_t samplesPerFrame)80     void setSamplesPerFrame(int32_t samplesPerFrame) {
81         mSamplesPerFrame = samplesPerFrame;
82     }
83 
getSamplesPerFrame()84     int32_t getSamplesPerFrame() const {
85         return mSamplesPerFrame;
86     }
87 
88     /** Only 16 or 24 bit samples supported at the moment. Default is 16. */
setBitsPerSample(int32_t bits)89     void setBitsPerSample(int32_t bits) {
90         assert((bits == 16) || (bits == 24));
91         bitsPerSample = bits;
92     }
93 
getBitsPerSample()94     int32_t getBitsPerSample() const {
95         return bitsPerSample;
96     }
97 
close()98     void close() {
99     }
100 
101     /** Write single audio data value to the WAV capture buffer. */
102     void write(float value);
103 
104     /**
105      * Write a buffer to the WAV capture buffer.
106      */
107     void write(float *buffer, int32_t startSample, int32_t numSamples);
108 
109 private:
110     /**
111      * Write a 32 bit integer to the stream in Little Endian format.
112      */
113     void writeIntLittle(int32_t n);
114 
115     /**
116      * Write a 16 bit integer to the stream in Little Endian format.
117      */
118     void writeShortLittle(int16_t n);
119 
120     /**
121      * Write an 'fmt ' chunk to the WAV file containing the given information.
122      */
123     void writeFormatChunk();
124 
125     /**
126      * Write a 'data' chunk header to the WAV file. This should be followed by call to
127      * writeShortLittle() to write the data to the chunk.
128      */
129     void writeDataChunkHeader();
130 
131     /**
132      * Write a simple WAV header for PCM data.
133      */
134     void writeHeader();
135 
136     // Write lower 8 bits. Upper bits ignored.
137     void writeByte(uint8_t b);
138 
139     void writePCM24(float value);
140 
141     void writePCM16(float value);
142 
143     /**
144      * Write a 'RIFF' file header and a 'WAVE' ID to the WAV file.
145      */
146     void writeRiffHeader();
147 
148     static constexpr int WAVE_FORMAT_PCM = 1;
149     WaveFileOutputStream *mOutputStream = nullptr;
150     int32_t mFrameRate = 48000;
151     int32_t mSamplesPerFrame = 1;
152     int32_t bitsPerSample = 16;
153     int32_t bytesWritten = 0;
154     bool headerWritten = false;
155     static constexpr int32_t PCM24_MIN = -(1 << 23);
156     static constexpr int32_t PCM24_MAX = (1 << 23) - 1;
157 
158 };
159 
160 #endif /* UTIL_WAVE_FILE_WRITER */
161 
162