• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "WaveFileWriter.h"
18 
write(float value)19 void WaveFileWriter::WaveFileWriter::write(float value) {
20     if (!mHeaderWritten) {
21         writeHeader();
22     }
23     if (mBitsPerSample == 24) {
24         writePCM24(value);
25     } else {
26         writePCM16(value);
27     }
28 }
29 
write(float * buffer,int32_t startSample,int32_t numSamples)30 void WaveFileWriter::write(float *buffer, int32_t startSample, int32_t numSamples) {
31     for (int32_t i = 0; i < numSamples; i++) {
32         write(buffer[startSample + i]);
33     }
34 }
35 
writeIntLittle(int32_t n)36 void WaveFileWriter::writeIntLittle(int32_t n) {
37     writeByte(n);
38     writeByte(n >> 8);
39     writeByte(n >> 16);
40     writeByte(n >> 24);
41 }
42 
writeShortLittle(int16_t n)43 void WaveFileWriter::writeShortLittle(int16_t n) {
44     writeByte(n);
45     writeByte(n >> 8);
46 }
47 
writeFormatChunk()48 void WaveFileWriter::writeFormatChunk() {
49     int32_t bytesPerSample = (mBitsPerSample + 7) / 8;
50 
51     writeByte('f');
52     writeByte('m');
53     writeByte('t');
54     writeByte(' ');
55     writeIntLittle(16); // chunk size
56     writeShortLittle(WAVE_FORMAT_PCM);
57     writeShortLittle((int16_t) mSamplesPerFrame);
58     writeIntLittle(mFrameRate);
59     // bytes/second
60     writeIntLittle(mFrameRate * mSamplesPerFrame * bytesPerSample);
61     // block align
62     writeShortLittle((int16_t) (mSamplesPerFrame * bytesPerSample));
63     writeShortLittle((int16_t) mBitsPerSample);
64 }
65 
getDataSizeInBytes()66 int32_t WaveFileWriter::getDataSizeInBytes() {
67     if (mFrameCount <= 0) return INT32_MAX;
68     int64_t dataSize = ((int64_t)mFrameCount) * mSamplesPerFrame * mBitsPerSample / 8;
69     return (int32_t)std::min(dataSize, (int64_t)INT32_MAX);
70 }
71 
writeDataChunkHeader()72 void WaveFileWriter::writeDataChunkHeader() {
73     writeByte('d');
74     writeByte('a');
75     writeByte('t');
76     writeByte('a');
77     writeIntLittle(getDataSizeInBytes());
78 }
79 
writeHeader()80 void WaveFileWriter::writeHeader() {
81     writeRiffHeader();
82     writeFormatChunk();
83     writeDataChunkHeader();
84     mHeaderWritten = true;
85 }
86 
87 // Write lower 8 bits. Upper bits ignored.
writeByte(uint8_t b)88 void WaveFileWriter::writeByte(uint8_t b) {
89     mOutputStream->write(b);
90     mBytesWritten += 1;
91 }
92 
writePCM24(float value)93 void WaveFileWriter::writePCM24(float value) {
94     // Offset before casting so that we can avoid using floor().
95     // Also round by adding 0.5 so that very small signals go to zero.
96     float temp = (PCM24_MAX * value) + 0.5 - PCM24_MIN;
97     int32_t sample = ((int) temp) + PCM24_MIN;
98     // clip to 24-bit range
99     if (sample > PCM24_MAX) {
100         sample = PCM24_MAX;
101     } else if (sample < PCM24_MIN) {
102         sample = PCM24_MIN;
103     }
104     // encode as little-endian
105     writeByte(sample); // little end
106     writeByte(sample >> 8); // middle
107     writeByte(sample >> 16); // big end
108 }
109 
writePCM16(float value)110 void WaveFileWriter::writePCM16(float value) {
111     // Offset before casting so that we can avoid using floor().
112     // Also round by adding 0.5 so that very small signals go to zero.
113     float temp = (INT16_MAX * value) + 0.5 - INT16_MIN;
114     int32_t sample = ((int) temp) + INT16_MIN;
115     if (sample > INT16_MAX) {
116         sample = INT16_MAX;
117     } else if (sample < INT16_MIN) {
118         sample = INT16_MIN;
119     }
120     writeByte(sample); // little end
121     writeByte(sample >> 8); // big end
122 }
123 
writeRiffHeader()124 void WaveFileWriter::writeRiffHeader() {
125     writeByte('R');
126     writeByte('I');
127     writeByte('F');
128     writeByte('F');
129     // Maximum size is not strictly correct but is commonly used
130     // when we do not know the final size.
131     const int kExtraHeaderBytes = 36;
132     int32_t dataSize = getDataSizeInBytes();
133     writeIntLittle((dataSize > (INT32_MAX - kExtraHeaderBytes))
134             ? INT32_MAX
135             : dataSize + kExtraHeaderBytes);
136     writeByte('W');
137     writeByte('A');
138     writeByte('V');
139     writeByte('E');
140 }
141