Add a WavReader counterpart to WavWriter.
Don't bother with a C interface as we currently have no need to call this from C code. The first use will be in the audioproc tool. R=kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/30829004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7585 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c2c94a9a9f
commit
a3ed713dad
@ -85,8 +85,8 @@ source_set("common_audio") {
|
||||
"vad/vad_sp.h",
|
||||
"wav_header.cc",
|
||||
"wav_header.h",
|
||||
"wav_writer.cc",
|
||||
"wav_writer.h",
|
||||
"wav_file.cc",
|
||||
"wav_file.h",
|
||||
"window_generator.cc",
|
||||
"window_generator.h",
|
||||
]
|
||||
|
@ -99,8 +99,8 @@
|
||||
'vad/vad_sp.h',
|
||||
'wav_header.cc',
|
||||
'wav_header.h',
|
||||
'wav_writer.cc',
|
||||
'wav_writer.h',
|
||||
'wav_file.cc',
|
||||
'wav_file.h',
|
||||
'window_generator.cc',
|
||||
'window_generator.h',
|
||||
],
|
||||
@ -245,7 +245,7 @@
|
||||
'vad/vad_unittest.cc',
|
||||
'vad/vad_unittest.h',
|
||||
'wav_header_unittest.cc',
|
||||
'wav_writer_unittest.cc',
|
||||
'wav_file_unittest.cc',
|
||||
'window_generator_unittest.cc',
|
||||
],
|
||||
'conditions': [
|
||||
|
166
webrtc/common_audio/wav_file.cc
Normal file
166
webrtc/common_audio/wav_file.cc
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/wav_header.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// We write 16-bit PCM WAV files.
|
||||
static const WavFormat kWavFormat = kWavFormatPcm;
|
||||
static const int kBytesPerSample = 2;
|
||||
|
||||
WavReader::WavReader(const std::string& filename)
|
||||
: file_handle_(fopen(filename.c_str(), "rb")) {
|
||||
CHECK(file_handle_);
|
||||
uint8_t header[kWavHeaderSize];
|
||||
const size_t read =
|
||||
fread(header, sizeof(*header), kWavHeaderSize, file_handle_);
|
||||
CHECK_EQ(kWavHeaderSize, read);
|
||||
|
||||
WavFormat format;
|
||||
int bytes_per_sample;
|
||||
CHECK(ReadWavHeader(header, &num_channels_, &sample_rate_, &format,
|
||||
&bytes_per_sample, &num_samples_));
|
||||
CHECK_EQ(kWavFormat, format);
|
||||
CHECK_EQ(kBytesPerSample, bytes_per_sample);
|
||||
}
|
||||
|
||||
WavReader::~WavReader() {
|
||||
Close();
|
||||
}
|
||||
|
||||
size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert samples to big-endian when reading from WAV file"
|
||||
#endif
|
||||
const size_t read =
|
||||
fread(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
// If we didn't read what was requested, ensure we've reached the EOF.
|
||||
CHECK(read == num_samples || feof(file_handle_));
|
||||
return read;
|
||||
}
|
||||
|
||||
size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
|
||||
static const size_t kChunksize = 4096 / sizeof(uint16_t);
|
||||
size_t read = 0;
|
||||
for (size_t i = 0; i < num_samples; i += kChunksize) {
|
||||
int16_t isamples[kChunksize];
|
||||
size_t chunk = std::min(kChunksize, num_samples - i);
|
||||
chunk = ReadSamples(chunk, isamples);
|
||||
for (size_t j = 0; j < chunk; ++j)
|
||||
samples[i + j] = isamples[j];
|
||||
read += chunk;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
void WavReader::Close() {
|
||||
CHECK_EQ(0, fclose(file_handle_));
|
||||
file_handle_ = NULL;
|
||||
}
|
||||
|
||||
WavWriter::WavWriter(const std::string& filename, int sample_rate,
|
||||
int num_channels)
|
||||
: sample_rate_(sample_rate),
|
||||
num_channels_(num_channels),
|
||||
num_samples_(0),
|
||||
file_handle_(fopen(filename.c_str(), "wb")) {
|
||||
CHECK(file_handle_);
|
||||
CHECK(CheckWavParameters(num_channels_,
|
||||
sample_rate_,
|
||||
kWavFormat,
|
||||
kBytesPerSample,
|
||||
num_samples_));
|
||||
|
||||
// Write a blank placeholder header, since we need to know the total number
|
||||
// of samples before we can fill in the real data.
|
||||
static const uint8_t blank_header[kWavHeaderSize] = {0};
|
||||
CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
|
||||
}
|
||||
|
||||
WavWriter::~WavWriter() {
|
||||
Close();
|
||||
}
|
||||
|
||||
void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) {
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert samples to little-endian when writing to WAV file"
|
||||
#endif
|
||||
const size_t written =
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
CHECK_EQ(num_samples, written);
|
||||
num_samples_ += static_cast<uint32_t>(written);
|
||||
CHECK(written <= std::numeric_limits<uint32_t>::max() ||
|
||||
num_samples_ >= written); // detect uint32_t overflow
|
||||
CHECK(CheckWavParameters(num_channels_,
|
||||
sample_rate_,
|
||||
kWavFormat,
|
||||
kBytesPerSample,
|
||||
num_samples_));
|
||||
}
|
||||
|
||||
void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
|
||||
static const size_t kChunksize = 4096 / sizeof(uint16_t);
|
||||
for (size_t i = 0; i < num_samples; i += kChunksize) {
|
||||
int16_t isamples[kChunksize];
|
||||
const size_t chunk = std::min(kChunksize, num_samples - i);
|
||||
FloatS16ToS16(samples + i, chunk, isamples);
|
||||
WriteSamples(isamples, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void WavWriter::Close() {
|
||||
CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
|
||||
uint8_t header[kWavHeaderSize];
|
||||
CHECK(WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
|
||||
kBytesPerSample, num_samples_));
|
||||
CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
|
||||
CHECK_EQ(0, fclose(file_handle_));
|
||||
file_handle_ = NULL;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
rtc_WavWriter* rtc_WavOpen(const char* filename,
|
||||
int sample_rate,
|
||||
int num_channels) {
|
||||
return reinterpret_cast<rtc_WavWriter*>(
|
||||
new webrtc::WavWriter(filename, sample_rate, num_channels));
|
||||
}
|
||||
|
||||
void rtc_WavClose(rtc_WavWriter* wf) {
|
||||
delete reinterpret_cast<webrtc::WavWriter*>(wf);
|
||||
}
|
||||
|
||||
void rtc_WavWriteSamples(rtc_WavWriter* wf,
|
||||
const float* samples,
|
||||
size_t num_samples) {
|
||||
reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
|
||||
}
|
||||
|
||||
int rtc_WavSampleRate(const rtc_WavWriter* wf) {
|
||||
return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
|
||||
}
|
||||
|
||||
int rtc_WavNumChannels(const rtc_WavWriter* wf) {
|
||||
return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
|
||||
}
|
||||
|
||||
uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
|
||||
return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
|
||||
}
|
98
webrtc/common_audio/wav_file.h
Normal file
98
webrtc/common_audio/wav_file.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_WAV_FILE_H_
|
||||
#define WEBRTC_COMMON_AUDIO_WAV_FILE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
|
||||
// by calls to CHECK(), making it unsuitable for anything but debug code.
|
||||
class WavWriter {
|
||||
public:
|
||||
// Open a new WAV file for writing.
|
||||
WavWriter(const std::string& filename, int sample_rate, int num_channels);
|
||||
|
||||
// Close the WAV file, after writing its header.
|
||||
~WavWriter();
|
||||
|
||||
// Write additional samples to the file. Each sample is in the range
|
||||
// [-32768,32767], and there must be the previously specified number of
|
||||
// interleaved channels.
|
||||
void WriteSamples(const float* samples, size_t num_samples);
|
||||
void WriteSamples(const int16_t* samples, size_t num_samples);
|
||||
|
||||
int sample_rate() const { return sample_rate_; }
|
||||
int num_channels() const { return num_channels_; }
|
||||
uint32_t num_samples() const { return num_samples_; }
|
||||
|
||||
private:
|
||||
void Close();
|
||||
const int sample_rate_;
|
||||
const int num_channels_;
|
||||
uint32_t num_samples_; // Total number of samples written to file.
|
||||
FILE* file_handle_; // Output file, owned by this class
|
||||
};
|
||||
|
||||
// Follows the conventions of WavWriter.
|
||||
class WavReader {
|
||||
public:
|
||||
// Opens an existing WAV file for reading.
|
||||
explicit WavReader(const std::string& filename);
|
||||
|
||||
// Close the WAV file.
|
||||
~WavReader();
|
||||
|
||||
// Returns the number of samples read. If this is less than requested,
|
||||
// verifies that the end of the file was reached.
|
||||
size_t ReadSamples(size_t num_samples, float* samples);
|
||||
size_t ReadSamples(size_t num_samples, int16_t* samples);
|
||||
|
||||
int sample_rate() const { return sample_rate_; }
|
||||
int num_channels() const { return num_channels_; }
|
||||
uint32_t num_samples() const { return num_samples_; }
|
||||
|
||||
private:
|
||||
void Close();
|
||||
int sample_rate_;
|
||||
int num_channels_;
|
||||
uint32_t num_samples_; // Total number of samples in the file.
|
||||
FILE* file_handle_; // Input file, owned by this class.
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// C wrappers for the WavWriter class.
|
||||
typedef struct rtc_WavWriter rtc_WavWriter;
|
||||
rtc_WavWriter* rtc_WavOpen(const char* filename,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
void rtc_WavClose(rtc_WavWriter* wf);
|
||||
void rtc_WavWriteSamples(rtc_WavWriter* wf,
|
||||
const float* samples,
|
||||
size_t num_samples);
|
||||
int rtc_WavSampleRate(const rtc_WavWriter* wf);
|
||||
int rtc_WavNumChannels(const rtc_WavWriter* wf);
|
||||
uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_WAV_FILE_H_
|
@ -17,7 +17,7 @@
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/compile_assert.h"
|
||||
#include "webrtc/common_audio/wav_header.h"
|
||||
#include "webrtc/common_audio/wav_writer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
static const float kSamples[] = {0.0, 10.0, 4e4, -1e9};
|
||||
@ -27,7 +27,7 @@ TEST(WavWriterTest, CPP) {
|
||||
const std::string outfile = webrtc::test::OutputPath() + "wavtest1.wav";
|
||||
static const uint32_t kNumSamples = 3;
|
||||
{
|
||||
webrtc::WavFile w(outfile, 14099, 1);
|
||||
webrtc::WavWriter w(outfile, 14099, 1);
|
||||
EXPECT_EQ(14099, w.sample_rate());
|
||||
EXPECT_EQ(1, w.num_channels());
|
||||
EXPECT_EQ(0u, w.num_samples());
|
||||
@ -62,12 +62,24 @@ TEST(WavWriterTest, CPP) {
|
||||
ASSERT_EQ(1u, fread(contents, kContentSize, 1, f));
|
||||
EXPECT_EQ(0, fclose(f));
|
||||
EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize));
|
||||
|
||||
{
|
||||
webrtc::WavReader r(outfile);
|
||||
EXPECT_EQ(14099, r.sample_rate());
|
||||
EXPECT_EQ(1, r.num_channels());
|
||||
EXPECT_EQ(kNumSamples, r.num_samples());
|
||||
static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0};
|
||||
float samples[kNumSamples];
|
||||
EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples));
|
||||
EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples)));
|
||||
EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples));
|
||||
}
|
||||
}
|
||||
|
||||
// Write a tiny WAV file with the C interface and verify the result.
|
||||
TEST(WavWriterTest, C) {
|
||||
const std::string outfile = webrtc::test::OutputPath() + "wavtest2.wav";
|
||||
rtc_WavFile *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
|
||||
rtc_WavWriter *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
|
||||
EXPECT_EQ(11904, rtc_WavSampleRate(w));
|
||||
EXPECT_EQ(2, rtc_WavNumChannels(w));
|
||||
EXPECT_EQ(0u, rtc_WavNumSamples(w));
|
||||
@ -125,7 +137,7 @@ TEST(WavWriterTest, LargeFile) {
|
||||
samples[i + 1] = std::pow(std::cos(t * 2 * 2 * M_PI), 10) * x;
|
||||
}
|
||||
{
|
||||
webrtc::WavFile w(outfile, kSampleRate, kNumChannels);
|
||||
webrtc::WavWriter w(outfile, kSampleRate, kNumChannels);
|
||||
EXPECT_EQ(kSampleRate, w.sample_rate());
|
||||
EXPECT_EQ(kNumChannels, w.num_channels());
|
||||
EXPECT_EQ(0u, w.num_samples());
|
||||
@ -134,4 +146,18 @@ TEST(WavWriterTest, LargeFile) {
|
||||
}
|
||||
EXPECT_EQ(sizeof(int16_t) * kNumSamples + webrtc::kWavHeaderSize,
|
||||
webrtc::test::GetFileSize(outfile));
|
||||
|
||||
{
|
||||
webrtc::WavReader r(outfile);
|
||||
EXPECT_EQ(kSampleRate, r.sample_rate());
|
||||
EXPECT_EQ(kNumChannels, r.num_channels());
|
||||
EXPECT_EQ(kNumSamples, r.num_samples());
|
||||
|
||||
float read_samples[kNumSamples];
|
||||
EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, read_samples));
|
||||
for (size_t i = 0; i < kNumSamples; ++i)
|
||||
EXPECT_NEAR(samples[i], read_samples[i], 1);
|
||||
|
||||
EXPECT_EQ(0u, r.ReadSamples(kNumSamples, read_samples));
|
||||
}
|
||||
}
|
@ -18,9 +18,11 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
struct ChunkHeader {
|
||||
uint32_t ID;
|
||||
@ -28,6 +30,34 @@ struct ChunkHeader {
|
||||
};
|
||||
COMPILE_ASSERT(sizeof(ChunkHeader) == 8, chunk_header_size);
|
||||
|
||||
// We can't nest this definition in WavHeader, because VS2013 gives an error
|
||||
// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
|
||||
struct FmtSubchunk {
|
||||
ChunkHeader header;
|
||||
uint16_t AudioFormat;
|
||||
uint16_t NumChannels;
|
||||
uint32_t SampleRate;
|
||||
uint32_t ByteRate;
|
||||
uint16_t BlockAlign;
|
||||
uint16_t BitsPerSample;
|
||||
};
|
||||
COMPILE_ASSERT(sizeof(FmtSubchunk) == 24, fmt_subchunk_size);
|
||||
const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
|
||||
|
||||
struct WavHeader {
|
||||
struct {
|
||||
ChunkHeader header;
|
||||
uint32_t Format;
|
||||
} riff;
|
||||
FmtSubchunk fmt;
|
||||
struct {
|
||||
ChunkHeader header;
|
||||
} data;
|
||||
};
|
||||
COMPILE_ASSERT(sizeof(WavHeader) == kWavHeaderSize, no_padding_in_header);
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CheckWavParameters(int num_channels,
|
||||
int sample_rate,
|
||||
WavFormat format,
|
||||
@ -91,54 +121,54 @@ static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
|
||||
| static_cast<uint32_t>(c) << 16
|
||||
| static_cast<uint32_t>(d) << 24;
|
||||
}
|
||||
|
||||
static inline uint16_t ReadLE16(uint16_t x) { return x; }
|
||||
static inline uint32_t ReadLE32(uint32_t x) { return x; }
|
||||
static inline std::string ReadFourCC(uint32_t x) {
|
||||
return std::string(reinterpret_cast<char*>(&x), 4);
|
||||
}
|
||||
#else
|
||||
#error "Write be-to-le conversion functions"
|
||||
#endif
|
||||
|
||||
void WriteWavHeader(uint8_t* buf,
|
||||
static inline uint32_t RiffChunkSize(uint32_t bytes_in_payload) {
|
||||
return bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader);
|
||||
}
|
||||
|
||||
static inline uint32_t ByteRate(int num_channels, int sample_rate,
|
||||
int bytes_per_sample) {
|
||||
return static_cast<uint32_t>(num_channels) * sample_rate * bytes_per_sample;
|
||||
}
|
||||
|
||||
static inline uint16_t BlockAlign(int num_channels, int bytes_per_sample) {
|
||||
return num_channels * bytes_per_sample;
|
||||
}
|
||||
|
||||
bool WriteWavHeader(uint8_t* buf,
|
||||
int num_channels,
|
||||
int sample_rate,
|
||||
WavFormat format,
|
||||
int bytes_per_sample,
|
||||
uint32_t num_samples) {
|
||||
assert(CheckWavParameters(num_channels, sample_rate, format,
|
||||
bytes_per_sample, num_samples));
|
||||
|
||||
struct {
|
||||
struct {
|
||||
ChunkHeader header;
|
||||
uint32_t Format;
|
||||
} riff;
|
||||
struct {
|
||||
ChunkHeader header;
|
||||
uint16_t AudioFormat;
|
||||
uint16_t NumChannels;
|
||||
uint32_t SampleRate;
|
||||
uint32_t ByteRate;
|
||||
uint16_t BlockAlign;
|
||||
uint16_t BitsPerSample;
|
||||
} fmt;
|
||||
struct {
|
||||
ChunkHeader header;
|
||||
} data;
|
||||
} header;
|
||||
COMPILE_ASSERT(sizeof(header) == kWavHeaderSize, no_padding_in_header);
|
||||
if (!CheckWavParameters(num_channels, sample_rate, format,
|
||||
bytes_per_sample, num_samples))
|
||||
return false;
|
||||
|
||||
WavHeader header;
|
||||
const uint32_t bytes_in_payload = bytes_per_sample * num_samples;
|
||||
|
||||
WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
|
||||
WriteLE32(&header.riff.header.Size,
|
||||
bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
|
||||
WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
|
||||
WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
|
||||
|
||||
WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
|
||||
WriteLE32(&header.fmt.header.Size, sizeof(header.fmt) - sizeof(ChunkHeader));
|
||||
WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
|
||||
WriteLE16(&header.fmt.AudioFormat, format);
|
||||
WriteLE16(&header.fmt.NumChannels, num_channels);
|
||||
WriteLE32(&header.fmt.SampleRate, sample_rate);
|
||||
WriteLE32(&header.fmt.ByteRate, (static_cast<uint32_t>(num_channels)
|
||||
* sample_rate * bytes_per_sample));
|
||||
WriteLE16(&header.fmt.BlockAlign, num_channels * bytes_per_sample);
|
||||
WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
|
||||
bytes_per_sample));
|
||||
WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
|
||||
WriteLE16(&header.fmt.BitsPerSample, 8 * bytes_per_sample);
|
||||
|
||||
WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
|
||||
@ -147,6 +177,52 @@ void WriteWavHeader(uint8_t* buf,
|
||||
// Do an extra copy rather than writing everything to buf directly, since buf
|
||||
// might not be correctly aligned.
|
||||
memcpy(buf, &header, kWavHeaderSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadWavHeader(const uint8_t* buf,
|
||||
int* num_channels,
|
||||
int* sample_rate,
|
||||
WavFormat* format,
|
||||
int* bytes_per_sample,
|
||||
uint32_t* num_samples) {
|
||||
WavHeader header;
|
||||
memcpy(&header, buf, kWavHeaderSize);
|
||||
|
||||
// Parse needed fields.
|
||||
*format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
|
||||
*num_channels = ReadLE16(header.fmt.NumChannels);
|
||||
*sample_rate = ReadLE32(header.fmt.SampleRate);
|
||||
*bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
|
||||
const uint32_t bytes_in_payload = ReadLE32(header.data.header.Size);
|
||||
if (*bytes_per_sample <= 0)
|
||||
return false;
|
||||
*num_samples = bytes_in_payload / *bytes_per_sample;
|
||||
|
||||
// Sanity check remaining fields.
|
||||
if (ReadFourCC(header.riff.header.ID) != "RIFF")
|
||||
return false;
|
||||
if (ReadFourCC(header.riff.Format) != "WAVE")
|
||||
return false;
|
||||
if (ReadFourCC(header.fmt.header.ID) != "fmt ")
|
||||
return false;
|
||||
if (ReadFourCC(header.data.header.ID) != "data")
|
||||
return false;
|
||||
|
||||
if (ReadLE32(header.riff.header.Size) != RiffChunkSize(bytes_in_payload))
|
||||
return false;
|
||||
if (ReadLE32(header.fmt.header.Size) != kFmtSubchunkSize)
|
||||
return false;
|
||||
if (ReadLE32(header.fmt.ByteRate) !=
|
||||
ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
|
||||
return false;
|
||||
if (ReadLE16(header.fmt.BlockAlign) !=
|
||||
BlockAlign(*num_channels, *bytes_per_sample))
|
||||
return false;
|
||||
|
||||
return CheckWavParameters(*num_channels, *sample_rate, *format,
|
||||
*bytes_per_sample, *num_samples);
|
||||
}
|
||||
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -11,11 +11,12 @@
|
||||
#ifndef WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
|
||||
#define WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
static const int kWavHeaderSize = 44;
|
||||
static const size_t kWavHeaderSize = 44;
|
||||
|
||||
enum WavFormat {
|
||||
kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample
|
||||
@ -33,14 +34,23 @@ bool CheckWavParameters(int num_channels,
|
||||
// Write a kWavHeaderSize bytes long WAV header to buf. The payload that
|
||||
// follows the header is supposed to have the specified number of interleaved
|
||||
// channels and contain the specified total number of samples of the specified
|
||||
// type.
|
||||
void WriteWavHeader(uint8_t* buf,
|
||||
// type. Returns false if any of the input parameters are invalid.
|
||||
bool WriteWavHeader(uint8_t* buf,
|
||||
int num_channels,
|
||||
int sample_rate,
|
||||
WavFormat format,
|
||||
int bytes_per_sample,
|
||||
uint32_t num_samples);
|
||||
|
||||
// Read a kWavHeaderSize bytes long WAV header from buf and parse the values
|
||||
// into the provided output parameters. Returns false if the header is invalid.
|
||||
bool ReadWavHeader(const uint8_t* buf,
|
||||
int* num_channels,
|
||||
int* sample_rate,
|
||||
WavFormat* format,
|
||||
int* bytes_per_sample,
|
||||
uint32_t* num_samples);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
|
||||
|
@ -48,13 +48,85 @@ TEST(WavHeaderTest, CheckWavParameters) {
|
||||
webrtc::CheckWavParameters(3, 8000, webrtc::kWavFormatPcm, 1, 5));
|
||||
}
|
||||
|
||||
TEST(WavHeaderTest, ReadWavHeader) {
|
||||
int num_channels = 0;
|
||||
int sample_rate = 0;
|
||||
webrtc::WavFormat format = webrtc::kWavFormatPcm;
|
||||
int bytes_per_sample = 0;
|
||||
uint32_t num_samples = 0;
|
||||
|
||||
// Test a few ways the header can be invalid. We start with the valid header
|
||||
// used in WriteAndReadWavHeader, and invalidate one field per test. The
|
||||
// invalid field is indicated in the array name, and in the comments with
|
||||
// *BAD*.
|
||||
static const uint8_t kBadRiffID[] = {
|
||||
'R', 'i', 'f', 'f', // *BAD*
|
||||
0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
|
||||
'W', 'A', 'V', 'E',
|
||||
'f', 'm', 't', ' ',
|
||||
16, 0, 0, 0, // size of fmt block - 8: 24 - 8
|
||||
6, 0, // format: A-law (6)
|
||||
17, 0, // channels: 17
|
||||
0x39, 0x30, 0, 0, // sample rate: 12345
|
||||
0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
|
||||
17, 0, // block align: NumChannels * BytesPerSample
|
||||
8, 0, // bits per sample: 1 * 8
|
||||
'd', 'a', 't', 'a',
|
||||
0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
|
||||
0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
|
||||
};
|
||||
EXPECT_FALSE(
|
||||
webrtc::ReadWavHeader(kBadRiffID, &num_channels, &sample_rate,
|
||||
&format, &bytes_per_sample, &num_samples));
|
||||
|
||||
static const uint8_t kBadBitsPerSample[] = {
|
||||
'R', 'I', 'F', 'F',
|
||||
0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
|
||||
'W', 'A', 'V', 'E',
|
||||
'f', 'm', 't', ' ',
|
||||
16, 0, 0, 0, // size of fmt block - 8: 24 - 8
|
||||
6, 0, // format: A-law (6)
|
||||
17, 0, // channels: 17
|
||||
0x39, 0x30, 0, 0, // sample rate: 12345
|
||||
0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
|
||||
17, 0, // block align: NumChannels * BytesPerSample
|
||||
1, 0, // bits per sample: *BAD*
|
||||
'd', 'a', 't', 'a',
|
||||
0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
|
||||
0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
|
||||
};
|
||||
EXPECT_FALSE(
|
||||
webrtc::ReadWavHeader(kBadBitsPerSample, &num_channels, &sample_rate,
|
||||
&format, &bytes_per_sample, &num_samples));
|
||||
|
||||
static const uint8_t kBadByteRate[] = {
|
||||
'R', 'I', 'F', 'F',
|
||||
0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
|
||||
'W', 'A', 'V', 'E',
|
||||
'f', 'm', 't', ' ',
|
||||
16, 0, 0, 0, // size of fmt block - 8: 24 - 8
|
||||
6, 0, // format: A-law (6)
|
||||
17, 0, // channels: 17
|
||||
0x39, 0x30, 0, 0, // sample rate: 12345
|
||||
0x00, 0x33, 0x03, 0, // byte rate: *BAD*
|
||||
17, 0, // block align: NumChannels * BytesPerSample
|
||||
8, 0, // bits per sample: 1 * 8
|
||||
'd', 'a', 't', 'a',
|
||||
0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
|
||||
0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
|
||||
};
|
||||
EXPECT_FALSE(
|
||||
webrtc::ReadWavHeader(kBadByteRate, &num_channels, &sample_rate,
|
||||
&format, &bytes_per_sample, &num_samples));
|
||||
}
|
||||
|
||||
// Try writing a WAV header and make sure it looks OK.
|
||||
TEST(WavHeaderTest, WriteWavHeader) {
|
||||
TEST(WavHeaderTest, WriteAndReadWavHeader) {
|
||||
static const int kSize = 4 + webrtc::kWavHeaderSize + 4;
|
||||
uint8_t buf[kSize];
|
||||
memset(buf, 0xa4, sizeof(buf));
|
||||
webrtc::WriteWavHeader(
|
||||
buf + 4, 17, 12345, webrtc::kWavFormatALaw, 1, 123457689);
|
||||
EXPECT_TRUE(webrtc::WriteWavHeader(
|
||||
buf + 4, 17, 12345, webrtc::kWavFormatALaw, 1, 123457689));
|
||||
static const uint8_t kExpectedBuf[] = {
|
||||
0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header
|
||||
'R', 'I', 'F', 'F',
|
||||
@ -74,4 +146,18 @@ TEST(WavHeaderTest, WriteWavHeader) {
|
||||
};
|
||||
COMPILE_ASSERT(sizeof(kExpectedBuf) == kSize, buf_size);
|
||||
EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
|
||||
|
||||
int num_channels = 0;
|
||||
int sample_rate = 0;
|
||||
webrtc::WavFormat format = webrtc::kWavFormatPcm;
|
||||
int bytes_per_sample = 0;
|
||||
uint32_t num_samples = 0;
|
||||
EXPECT_TRUE(
|
||||
webrtc::ReadWavHeader(buf + 4, &num_channels, &sample_rate, &format,
|
||||
&bytes_per_sample, &num_samples));
|
||||
EXPECT_EQ(17, num_channels);
|
||||
EXPECT_EQ(12345, sample_rate);
|
||||
EXPECT_EQ(webrtc::kWavFormatALaw, format);
|
||||
EXPECT_EQ(1, bytes_per_sample);
|
||||
EXPECT_EQ(123457689u, num_samples);
|
||||
}
|
||||
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/common_audio/wav_writer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/wav_header.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// We write 16-bit PCM WAV files.
|
||||
static const WavFormat kWavFormat = kWavFormatPcm;
|
||||
static const int kBytesPerSample = 2;
|
||||
|
||||
WavFile::WavFile(const std::string& filename, int sample_rate, int num_channels)
|
||||
: sample_rate_(sample_rate),
|
||||
num_channels_(num_channels),
|
||||
num_samples_(0),
|
||||
file_handle_(fopen(filename.c_str(), "wb")) {
|
||||
CHECK(file_handle_);
|
||||
CHECK(CheckWavParameters(num_channels_,
|
||||
sample_rate_,
|
||||
kWavFormat,
|
||||
kBytesPerSample,
|
||||
num_samples_));
|
||||
|
||||
// Write a blank placeholder header, since we need to know the total number
|
||||
// of samples before we can fill in the real data.
|
||||
static const uint8_t blank_header[kWavHeaderSize] = {0};
|
||||
CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
|
||||
}
|
||||
|
||||
WavFile::~WavFile() {
|
||||
Close();
|
||||
}
|
||||
|
||||
void WavFile::WriteSamples(const int16_t* samples, size_t num_samples) {
|
||||
#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#error "Need to convert samples to little-endian when writing to WAV file"
|
||||
#endif
|
||||
const size_t written =
|
||||
fwrite(samples, sizeof(*samples), num_samples, file_handle_);
|
||||
CHECK_EQ(num_samples, written);
|
||||
num_samples_ += static_cast<uint32_t>(written);
|
||||
CHECK(written <= std::numeric_limits<uint32_t>::max() ||
|
||||
num_samples_ >= written); // detect uint32_t overflow
|
||||
CHECK(CheckWavParameters(num_channels_,
|
||||
sample_rate_,
|
||||
kWavFormat,
|
||||
kBytesPerSample,
|
||||
num_samples_));
|
||||
}
|
||||
|
||||
void WavFile::WriteSamples(const float* samples, size_t num_samples) {
|
||||
static const size_t kChunksize = 4096 / sizeof(uint16_t);
|
||||
for (size_t i = 0; i < num_samples; i += kChunksize) {
|
||||
int16_t isamples[kChunksize];
|
||||
const size_t chunk = std::min(kChunksize, num_samples - i);
|
||||
FloatS16ToS16(samples + i, chunk, isamples);
|
||||
WriteSamples(isamples, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void WavFile::Close() {
|
||||
CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
|
||||
uint8_t header[kWavHeaderSize];
|
||||
WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
|
||||
kBytesPerSample, num_samples_);
|
||||
CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
|
||||
CHECK_EQ(0, fclose(file_handle_));
|
||||
file_handle_ = NULL;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
rtc_WavFile* rtc_WavOpen(const char* filename,
|
||||
int sample_rate,
|
||||
int num_channels) {
|
||||
return reinterpret_cast<rtc_WavFile*>(
|
||||
new webrtc::WavFile(filename, sample_rate, num_channels));
|
||||
}
|
||||
|
||||
void rtc_WavClose(rtc_WavFile* wf) {
|
||||
delete reinterpret_cast<webrtc::WavFile*>(wf);
|
||||
}
|
||||
|
||||
void rtc_WavWriteSamples(rtc_WavFile* wf,
|
||||
const float* samples,
|
||||
size_t num_samples) {
|
||||
reinterpret_cast<webrtc::WavFile*>(wf)->WriteSamples(samples, num_samples);
|
||||
}
|
||||
|
||||
int rtc_WavSampleRate(const rtc_WavFile* wf) {
|
||||
return reinterpret_cast<const webrtc::WavFile*>(wf)->sample_rate();
|
||||
}
|
||||
|
||||
int rtc_WavNumChannels(const rtc_WavFile* wf) {
|
||||
return reinterpret_cast<const webrtc::WavFile*>(wf)->num_channels();
|
||||
}
|
||||
|
||||
uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) {
|
||||
return reinterpret_cast<const webrtc::WavFile*>(wf)->num_samples();
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
|
||||
#define WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Simple C++ class for writing 16-bit PCM WAV files. All error handling is
|
||||
// by calls to CHECK(), making it unsuitable for anything but debug code.
|
||||
class WavFile {
|
||||
public:
|
||||
// Open a new WAV file for writing.
|
||||
WavFile(const std::string& filename, int sample_rate, int num_channels);
|
||||
|
||||
// Close the WAV file, after writing its header.
|
||||
~WavFile();
|
||||
|
||||
// Write additional samples to the file. Each sample is in the range
|
||||
// [-32768,32767], and there must be the previously specified number of
|
||||
// interleaved channels.
|
||||
void WriteSamples(const float* samples, size_t num_samples);
|
||||
void WriteSamples(const int16_t* samples, size_t num_samples);
|
||||
|
||||
int sample_rate() const { return sample_rate_; }
|
||||
int num_channels() const { return num_channels_; }
|
||||
uint32_t num_samples() const { return num_samples_; }
|
||||
|
||||
private:
|
||||
void Close();
|
||||
const int sample_rate_;
|
||||
const int num_channels_;
|
||||
uint32_t num_samples_; // total number of samples written to file
|
||||
FILE* file_handle_; // output file, owned by this class
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// C wrappers for the WavFile class.
|
||||
typedef struct rtc_WavFile rtc_WavFile;
|
||||
rtc_WavFile* rtc_WavOpen(const char* filename,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
void rtc_WavClose(rtc_WavFile* wf);
|
||||
void rtc_WavWriteSamples(rtc_WavFile* wf,
|
||||
const float* samples,
|
||||
size_t num_samples);
|
||||
int rtc_WavSampleRate(const rtc_WavFile* wf);
|
||||
int rtc_WavNumChannels(const rtc_WavFile* wf);
|
||||
uint32_t rtc_WavNumSamples(const rtc_WavFile* wf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_WAV_WRITER_H_
|
@ -1351,7 +1351,7 @@ int WebRtcAec_FreeAec(AecCore* aec) {
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
// Open a new Wav file for writing. If it was already open with a different
|
||||
// sample frequency, close it first.
|
||||
static void ReopenWav(rtc_WavFile** wav_file,
|
||||
static void ReopenWav(rtc_WavWriter** wav_file,
|
||||
const char* name,
|
||||
int seq1,
|
||||
int seq2,
|
||||
|
@ -11,7 +11,7 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
|
||||
#include "webrtc/common_audio/wav_writer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
#include "webrtc/modules/audio_processing/utility/ring_buffer.h"
|
||||
@ -147,10 +147,10 @@ struct AecCore {
|
||||
int debug_dump_count;
|
||||
|
||||
RingBuffer* far_time_buf;
|
||||
rtc_WavFile* farFile;
|
||||
rtc_WavFile* nearFile;
|
||||
rtc_WavFile* outFile;
|
||||
rtc_WavFile* outLinearFile;
|
||||
rtc_WavWriter* farFile;
|
||||
rtc_WavWriter* nearFile;
|
||||
rtc_WavWriter* outFile;
|
||||
rtc_WavWriter* outLinearFile;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -489,7 +489,7 @@ void void_main(int argc, char* argv[]) {
|
||||
FILE* aecm_echo_path_in_file = NULL;
|
||||
FILE* aecm_echo_path_out_file = NULL;
|
||||
|
||||
scoped_ptr<WavFile> output_wav_file;
|
||||
scoped_ptr<WavWriter> output_wav_file;
|
||||
scoped_ptr<RawFile> output_raw_file;
|
||||
|
||||
if (pb_filename) {
|
||||
@ -637,9 +637,9 @@ void void_main(int argc, char* argv[]) {
|
||||
if (!raw_output) {
|
||||
// The WAV file needs to be reset every time, because it cant change
|
||||
// it's sample rate or number of channels.
|
||||
output_wav_file.reset(new WavFile(out_filename + ".wav",
|
||||
output_sample_rate,
|
||||
msg.num_output_channels()));
|
||||
output_wav_file.reset(new WavWriter(out_filename + ".wav",
|
||||
output_sample_rate,
|
||||
msg.num_output_channels()));
|
||||
}
|
||||
|
||||
} else if (event_msg.type() == Event::REVERSE_STREAM) {
|
||||
@ -876,9 +876,9 @@ void void_main(int argc, char* argv[]) {
|
||||
if (!raw_output) {
|
||||
// The WAV file needs to be reset every time, because it can't change
|
||||
// it's sample rate or number of channels.
|
||||
output_wav_file.reset(new WavFile(out_filename + ".wav",
|
||||
sample_rate_hz,
|
||||
num_capture_output_channels));
|
||||
output_wav_file.reset(new WavWriter(out_filename + ".wav",
|
||||
sample_rate_hz,
|
||||
num_capture_output_channels));
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
@ -1029,9 +1029,9 @@ void void_main(int argc, char* argv[]) {
|
||||
output_raw_file.reset(new RawFile(out_filename + ".pcm"));
|
||||
}
|
||||
if (!raw_output && !output_wav_file) {
|
||||
output_wav_file.reset(new WavFile(out_filename + ".wav",
|
||||
sample_rate_hz,
|
||||
num_capture_output_channels));
|
||||
output_wav_file.reset(new WavWriter(out_filename + ".wav",
|
||||
sample_rate_hz,
|
||||
num_capture_output_channels));
|
||||
}
|
||||
WriteIntData(near_frame.data_,
|
||||
size,
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "webrtc/audio_processing/debug.pb.h"
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/wav_writer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/common.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
@ -50,7 +50,7 @@ class RawFile {
|
||||
|
||||
static inline void WriteIntData(const int16_t* data,
|
||||
size_t length,
|
||||
WavFile* wav_file,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
if (wav_file) {
|
||||
wav_file->WriteSamples(data, length);
|
||||
@ -63,7 +63,7 @@ static inline void WriteIntData(const int16_t* data,
|
||||
static inline void WriteFloatData(const float* const* data,
|
||||
size_t samples_per_channel,
|
||||
int num_channels,
|
||||
WavFile* wav_file,
|
||||
WavWriter* wav_file,
|
||||
RawFile* raw_file) {
|
||||
size_t length = num_channels * samples_per_channel;
|
||||
scoped_ptr<float[]> buffer(new float[length]);
|
||||
|
@ -73,9 +73,9 @@ int do_main(int argc, char* argv[]) {
|
||||
int num_reverse_channels = 0;
|
||||
int num_input_channels = 0;
|
||||
int num_output_channels = 0;
|
||||
scoped_ptr<WavFile> reverse_wav_file;
|
||||
scoped_ptr<WavFile> input_wav_file;
|
||||
scoped_ptr<WavFile> output_wav_file;
|
||||
scoped_ptr<WavWriter> reverse_wav_file;
|
||||
scoped_ptr<WavWriter> input_wav_file;
|
||||
scoped_ptr<WavWriter> output_wav_file;
|
||||
scoped_ptr<RawFile> reverse_raw_file;
|
||||
scoped_ptr<RawFile> input_raw_file;
|
||||
scoped_ptr<RawFile> output_raw_file;
|
||||
@ -235,15 +235,15 @@ int do_main(int argc, char* argv[]) {
|
||||
if (!FLAGS_raw) {
|
||||
// The WAV files need to be reset every time, because they cant change
|
||||
// their sample rate or number of channels.
|
||||
reverse_wav_file.reset(new WavFile(FLAGS_reverse_file + ".wav",
|
||||
reverse_sample_rate,
|
||||
num_reverse_channels));
|
||||
input_wav_file.reset(new WavFile(FLAGS_input_file + ".wav",
|
||||
input_sample_rate,
|
||||
num_input_channels));
|
||||
output_wav_file.reset(new WavFile(FLAGS_output_file + ".wav",
|
||||
output_sample_rate,
|
||||
num_output_channels));
|
||||
reverse_wav_file.reset(new WavWriter(FLAGS_reverse_file + ".wav",
|
||||
reverse_sample_rate,
|
||||
num_reverse_channels));
|
||||
input_wav_file.reset(new WavWriter(FLAGS_input_file + ".wav",
|
||||
input_sample_rate,
|
||||
num_input_channels));
|
||||
output_wav_file.reset(new WavWriter(FLAGS_output_file + ".wav",
|
||||
output_sample_rate,
|
||||
num_output_channels));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user