• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_writer.h"
12 
13 #include <algorithm>
14 #include <cstdio>
15 #include <limits>
16 
17 #include "webrtc/base/checks.h"
18 #include "webrtc/common_audio/include/audio_util.h"
19 #include "webrtc/common_audio/wav_header.h"
20 
21 namespace webrtc {
22 
23 // We write 16-bit PCM WAV files.
24 static const WavFormat kWavFormat = kWavFormatPcm;
25 static const int kBytesPerSample = 2;
26 
WavFile(const std::string & filename,int sample_rate,int num_channels)27 WavFile::WavFile(const std::string& filename, int sample_rate, int num_channels)
28     : sample_rate_(sample_rate),
29       num_channels_(num_channels),
30       num_samples_(0),
31       file_handle_(fopen(filename.c_str(), "wb")) {
32   CHECK(file_handle_);
33   CHECK(CheckWavParameters(num_channels_,
34                            sample_rate_,
35                            kWavFormat,
36                            kBytesPerSample,
37                            num_samples_));
38 
39   // Write a blank placeholder header, since we need to know the total number
40   // of samples before we can fill in the real data.
41   static const uint8_t blank_header[kWavHeaderSize] = {0};
42   CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
43 }
44 
~WavFile()45 WavFile::~WavFile() {
46   Close();
47 }
48 
WriteSamples(const int16_t * samples,size_t num_samples)49 void WavFile::WriteSamples(const int16_t* samples, size_t num_samples) {
50 #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
51 #error "Need to convert samples to little-endian when writing to WAV file"
52 #endif
53   const size_t written =
54       fwrite(samples, sizeof(*samples), num_samples, file_handle_);
55   CHECK_EQ(num_samples, written);
56   num_samples_ += static_cast<uint32_t>(written);
57   CHECK(written <= std::numeric_limits<uint32_t>::max() ||
58         num_samples_ >= written);  // detect uint32_t overflow
59   CHECK(CheckWavParameters(num_channels_,
60                            sample_rate_,
61                            kWavFormat,
62                            kBytesPerSample,
63                            num_samples_));
64 }
65 
WriteSamples(const float * samples,size_t num_samples)66 void WavFile::WriteSamples(const float* samples, size_t num_samples) {
67   static const size_t kChunksize = 4096 / sizeof(uint16_t);
68   for (size_t i = 0; i < num_samples; i += kChunksize) {
69     int16_t isamples[kChunksize];
70     const size_t chunk = std::min(kChunksize, num_samples - i);
71     RoundToInt16(samples + i, chunk, isamples);
72     WriteSamples(isamples, chunk);
73   }
74 }
75 
Close()76 void WavFile::Close() {
77   CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
78   uint8_t header[kWavHeaderSize];
79   WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
80                  kBytesPerSample, num_samples_);
81   CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
82   CHECK_EQ(0, fclose(file_handle_));
83   file_handle_ = NULL;
84 }
85 
86 }  // namespace webrtc
87 
rtc_WavOpen(const char * filename,int sample_rate,int num_channels)88 rtc_WavFile* rtc_WavOpen(const char* filename,
89                          int sample_rate,
90                          int num_channels) {
91   return reinterpret_cast<rtc_WavFile*>(
92       new webrtc::WavFile(filename, sample_rate, num_channels));
93 }
94 
rtc_WavClose(rtc_WavFile * wf)95 void rtc_WavClose(rtc_WavFile* wf) {
96   delete reinterpret_cast<webrtc::WavFile*>(wf);
97 }
98 
rtc_WavWriteSamples(rtc_WavFile * wf,const float * samples,size_t num_samples)99 void rtc_WavWriteSamples(rtc_WavFile* wf,
100                          const float* samples,
101                          size_t num_samples) {
102   reinterpret_cast<webrtc::WavFile*>(wf)->WriteSamples(samples, num_samples);
103 }
104 
rtc_WavSampleRate(const rtc_WavFile * wf)105 int rtc_WavSampleRate(const rtc_WavFile* wf) {
106   return reinterpret_cast<const webrtc::WavFile*>(wf)->sample_rate();
107 }
108 
rtc_WavNumChannels(const rtc_WavFile * wf)109 int rtc_WavNumChannels(const rtc_WavFile* wf) {
110   return reinterpret_cast<const webrtc::WavFile*>(wf)->num_channels();
111 }
112 
rtc_WavNumSamples(const rtc_WavFile * wf)113 uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) {
114   return reinterpret_cast<const webrtc::WavFile*>(wf)->num_samples();
115 }
116