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