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)21void 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)32void 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)38void 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)45void WaveFileWriter::writeShortLittle(int16_t n) { 46 writeByte(n); 47 writeByte(n >> 8); 48 } 49 writeFormatChunk()50void 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()68void 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()78void 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)86void WaveFileWriter::writeByte(uint8_t b) { 87 mOutputStream->write(b); 88 bytesWritten += 1; 89 } 90 writePCM24(float value)91void 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)108void 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()122void 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