Line data Source code
1 : /*
2 : * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/common_audio/wav_file.h"
12 :
13 : #include <algorithm>
14 : #include <cstdio>
15 : #include <limits>
16 : #include <sstream>
17 :
18 : #include "webrtc/base/checks.h"
19 : #include "webrtc/base/safe_conversions.h"
20 : #include "webrtc/common_audio/include/audio_util.h"
21 : #include "webrtc/common_audio/wav_header.h"
22 :
23 : namespace webrtc {
24 :
25 : // We write 16-bit PCM WAV files.
26 : static const WavFormat kWavFormat = kWavFormatPcm;
27 : static const size_t kBytesPerSample = 2;
28 :
29 : // Doesn't take ownership of the file handle and won't close it.
30 0 : class ReadableWavFile : public ReadableWav {
31 : public:
32 0 : explicit ReadableWavFile(FILE* file) : file_(file) {}
33 0 : virtual size_t Read(void* buf, size_t num_bytes) {
34 0 : return fread(buf, 1, num_bytes, file_);
35 : }
36 :
37 : private:
38 : FILE* file_;
39 : };
40 :
41 0 : std::string WavFile::FormatAsString() const {
42 0 : std::ostringstream s;
43 0 : s << "Sample rate: " << sample_rate() << " Hz, Channels: " << num_channels()
44 0 : << ", Duration: "
45 0 : << (1.f * num_samples()) / (num_channels() * sample_rate()) << " s";
46 0 : return s.str();
47 : }
48 :
49 0 : WavReader::WavReader(const std::string& filename)
50 0 : : file_handle_(fopen(filename.c_str(), "rb")) {
51 0 : RTC_CHECK(file_handle_) << "Could not open wav file for reading.";
52 :
53 0 : ReadableWavFile readable(file_handle_);
54 : WavFormat format;
55 : size_t bytes_per_sample;
56 0 : RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format,
57 0 : &bytes_per_sample, &num_samples_));
58 0 : num_samples_remaining_ = num_samples_;
59 0 : RTC_CHECK_EQ(kWavFormat, format);
60 0 : RTC_CHECK_EQ(kBytesPerSample, bytes_per_sample);
61 0 : }
62 :
63 0 : WavReader::~WavReader() {
64 0 : Close();
65 0 : }
66 :
67 0 : int WavReader::sample_rate() const {
68 0 : return sample_rate_;
69 : }
70 :
71 0 : size_t WavReader::num_channels() const {
72 0 : return num_channels_;
73 : }
74 :
75 0 : size_t WavReader::num_samples() const {
76 0 : return num_samples_;
77 : }
78 :
79 0 : size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
80 : // There could be metadata after the audio; ensure we don't read it.
81 0 : num_samples = std::min(num_samples, num_samples_remaining_);
82 : const size_t read =
83 0 : fread(samples, sizeof(*samples), num_samples, file_handle_);
84 : // If we didn't read what was requested, ensure we've reached the EOF.
85 0 : RTC_CHECK(read == num_samples || feof(file_handle_));
86 0 : RTC_CHECK_LE(read, num_samples_remaining_);
87 0 : num_samples_remaining_ -= read;
88 : #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
89 : //convert to big-endian
90 : for (size_t idx = 0; idx < num_samples; idx++) {
91 : samples[idx] = (samples[idx]<<8) | (samples[idx]>>8);
92 : }
93 : #endif
94 0 : return read;
95 : }
96 :
97 0 : size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
98 : static const size_t kChunksize = 4096 / sizeof(uint16_t);
99 0 : size_t read = 0;
100 0 : for (size_t i = 0; i < num_samples; i += kChunksize) {
101 : int16_t isamples[kChunksize];
102 0 : size_t chunk = std::min(kChunksize, num_samples - i);
103 0 : chunk = ReadSamples(chunk, isamples);
104 0 : for (size_t j = 0; j < chunk; ++j)
105 0 : samples[i + j] = isamples[j];
106 0 : read += chunk;
107 : }
108 0 : return read;
109 : }
110 :
111 0 : void WavReader::Close() {
112 0 : RTC_CHECK_EQ(0, fclose(file_handle_));
113 0 : file_handle_ = NULL;
114 0 : }
115 :
116 0 : WavWriter::WavWriter(const std::string& filename, int sample_rate,
117 0 : size_t num_channels)
118 : : sample_rate_(sample_rate),
119 : num_channels_(num_channels),
120 : num_samples_(0),
121 0 : file_handle_(fopen(filename.c_str(), "wb")) {
122 0 : if (file_handle_) {
123 0 : RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, kWavFormat,
124 0 : kBytesPerSample, num_samples_));
125 :
126 : // Write a blank placeholder header, since we need to know the total number
127 : // of samples before we can fill in the real data.
128 : static const uint8_t blank_header[kWavHeaderSize] = {0};
129 0 : RTC_CHECK_EQ(1, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
130 : }
131 0 : }
132 :
133 0 : WavWriter::~WavWriter() {
134 0 : Close();
135 0 : }
136 :
137 0 : int WavWriter::sample_rate() const {
138 0 : return sample_rate_;
139 : }
140 :
141 0 : size_t WavWriter::num_channels() const {
142 0 : return num_channels_;
143 : }
144 :
145 0 : size_t WavWriter::num_samples() const {
146 0 : return num_samples_;
147 : }
148 :
149 0 : void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) {
150 0 : if (!file_handle_) {
151 0 : return;
152 : }
153 : #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
154 : int16_t * le_samples = new int16_t[num_samples];
155 : for(size_t idx = 0; idx < num_samples; idx++) {
156 : le_samples[idx] = (samples[idx]<<8) | (samples[idx]>>8);
157 : }
158 : const size_t written =
159 : fwrite(le_samples, sizeof(*le_samples), num_samples, file_handle_);
160 : delete []le_samples;
161 : #else
162 : const size_t written =
163 0 : fwrite(samples, sizeof(*samples), num_samples, file_handle_);
164 : #endif
165 0 : RTC_CHECK_EQ(num_samples, written);
166 0 : num_samples_ += written;
167 0 : RTC_CHECK(num_samples_ >= written); // detect size_t overflow
168 : }
169 :
170 0 : void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
171 : static const size_t kChunksize = 4096 / sizeof(uint16_t);
172 0 : for (size_t i = 0; i < num_samples; i += kChunksize) {
173 : int16_t isamples[kChunksize];
174 0 : const size_t chunk = std::min(kChunksize, num_samples - i);
175 0 : FloatS16ToS16(samples + i, chunk, isamples);
176 0 : WriteSamples(isamples, chunk);
177 : }
178 0 : }
179 :
180 0 : void WavWriter::Close() {
181 0 : if (!file_handle_) {
182 0 : return;
183 : }
184 0 : RTC_CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
185 : uint8_t header[kWavHeaderSize];
186 0 : WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
187 0 : kBytesPerSample, num_samples_);
188 0 : RTC_CHECK_EQ(1, fwrite(header, kWavHeaderSize, 1, file_handle_));
189 0 : RTC_CHECK_EQ(0, fclose(file_handle_));
190 0 : file_handle_ = NULL;
191 : }
192 :
193 : } // namespace webrtc
194 :
195 0 : rtc_WavWriter* rtc_WavOpen(const char* filename,
196 : int sample_rate,
197 : size_t num_channels) {
198 : return reinterpret_cast<rtc_WavWriter*>(
199 0 : new webrtc::WavWriter(filename, sample_rate, num_channels));
200 : }
201 :
202 0 : void rtc_WavClose(rtc_WavWriter* wf) {
203 0 : delete reinterpret_cast<webrtc::WavWriter*>(wf);
204 0 : }
205 :
206 0 : void rtc_WavWriteSamples(rtc_WavWriter* wf,
207 : const float* samples,
208 : size_t num_samples) {
209 0 : reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
210 0 : }
211 :
212 0 : int rtc_WavSampleRate(const rtc_WavWriter* wf) {
213 0 : return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
214 : }
215 :
216 0 : size_t rtc_WavNumChannels(const rtc_WavWriter* wf) {
217 0 : return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
218 : }
219 :
220 0 : size_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
221 0 : return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
222 : }
|