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