1 /* 2 * Copyright 2019 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/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 } 58 59 /** 60 * @param frameRate default is 44100 61 */ setFrameRate(int32_t frameRate)62 void setFrameRate(int32_t frameRate) { 63 mFrameRate = frameRate; 64 } 65 getFrameRate()66 int32_t getFrameRate() const { 67 return mFrameRate; 68 } 69 70 /** 71 * For stereo, set this to 2. Default is mono = 1. 72 * Also known as ChannelCount 73 */ setSamplesPerFrame(int32_t samplesPerFrame)74 void setSamplesPerFrame(int32_t samplesPerFrame) { 75 mSamplesPerFrame = samplesPerFrame; 76 } 77 getSamplesPerFrame()78 int32_t getSamplesPerFrame() const { 79 return mSamplesPerFrame; 80 } 81 82 /** Only 16 or 24 bit samples supported at the moment. Default is 16. */ setBitsPerSample(int32_t bits)83 void setBitsPerSample(int32_t bits) { 84 assert((bits == 16) || (bits == 24)); 85 bitsPerSample = bits; 86 } 87 getBitsPerSample()88 int32_t getBitsPerSample() const { 89 return bitsPerSample; 90 } 91 close()92 void close() { 93 } 94 95 /** Write single audio data value to the WAV file. */ 96 void write(float value); 97 98 /** 99 * Write a buffer to the WAV file. 100 */ 101 void write(float *buffer, int32_t startSample, int32_t numSamples); 102 103 private: 104 /** 105 * Write a 32 bit integer to the stream in Little Endian format. 106 */ 107 void writeIntLittle(int32_t n); 108 109 /** 110 * Write a 16 bit integer to the stream in Little Endian format. 111 */ 112 void writeShortLittle(int16_t n); 113 114 /** 115 * Write an 'fmt ' chunk to the WAV file containing the given information. 116 */ 117 void writeFormatChunk(); 118 119 /** 120 * Write a 'data' chunk header to the WAV file. This should be followed by call to 121 * writeShortLittle() to write the data to the chunk. 122 */ 123 void writeDataChunkHeader(); 124 125 /** 126 * Write a simple WAV header for PCM data. 127 */ 128 void writeHeader(); 129 130 // Write lower 8 bits. Upper bits ignored. 131 void writeByte(uint8_t b); 132 133 void writePCM24(float value); 134 135 void writePCM16(float value); 136 137 /** 138 * Write a 'RIFF' file header and a 'WAVE' ID to the WAV file. 139 */ 140 void writeRiffHeader(); 141 142 static constexpr int WAVE_FORMAT_PCM = 1; 143 WaveFileOutputStream *mOutputStream = nullptr; 144 int32_t mFrameRate = 48000; 145 int32_t mSamplesPerFrame = 1; 146 int32_t bitsPerSample = 16; 147 int32_t bytesWritten = 0; 148 bool headerWritten = false; 149 static constexpr int32_t PCM24_MIN = -(1 << 23); 150 static constexpr int32_t PCM24_MAX = (1 << 23) - 1; 151 152 }; 153 154 #endif /* UTIL_WAVE_FILE_WRITER */ 155 156