1e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org/*
2e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *
4e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org */
10e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org
1129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#include <limits>
1229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
13b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org#include "webrtc/audio_processing/debug.pb.h"
1429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#include "webrtc/common_audio/include/audio_util.h"
1529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#include "webrtc/common_audio/wav_writer.h"
16467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org#include "webrtc/modules/audio_processing/common.h"
17e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
18e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org#include "webrtc/modules/interface/module_common_types.h"
19b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org#include "webrtc/system_wrappers/interface/scoped_ptr.h"
20b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
21b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgnamespace webrtc {
22b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
23b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic const AudioProcessing::Error kNoErr = AudioProcessing::kNoError;
24b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org#define EXPECT_NOERR(expr) EXPECT_EQ(kNoErr, (expr))
25e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org
2629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.orgclass RawFile {
2729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org public:
2829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  RawFile(const std::string& filename)
2929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org      : file_handle_(fopen(filename.c_str(), "wb")) {}
3029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
3129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  ~RawFile() {
3229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    fclose(file_handle_);
3329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
3429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
3529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  void WriteSamples(const int16_t* samples, size_t num_samples) {
3629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
3729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#error "Need to convert samples to little-endian when writing to PCM file"
3829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org#endif
3929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    fwrite(samples, sizeof(*samples), num_samples, file_handle_);
4029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
4129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
4229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  void WriteSamples(const float* samples, size_t num_samples) {
4329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    fwrite(samples, sizeof(*samples), num_samples, file_handle_);
4429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
4529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
4629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org private:
4729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  FILE* file_handle_;
4829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org};
4929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
5029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.orgstatic inline void WriteIntData(const int16_t* data,
5129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                size_t length,
5229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                WavFile* wav_file,
5329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                RawFile* raw_file) {
5429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  if (wav_file) {
5529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    wav_file->WriteSamples(data, length);
5629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
5729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  if (raw_file) {
5829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    raw_file->WriteSamples(data, length);
5929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
6029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org}
6129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
6229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.orgstatic inline void WriteFloatData(const float* const* data,
6329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                  size_t samples_per_channel,
6429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                  int num_channels,
6529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                  WavFile* wav_file,
6629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                                  RawFile* raw_file) {
6729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  size_t length = num_channels * samples_per_channel;
6829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  scoped_ptr<float[]> buffer(new float[length]);
6929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  Interleave(data, samples_per_channel, num_channels, buffer.get());
7029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  if (raw_file) {
7129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    raw_file->WriteSamples(buffer.get(), length);
7229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
7329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  // TODO(aluebs): Use ScaleToInt16Range() from audio_util
7429841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  for (size_t i = 0; i < length; ++i) {
7529841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    buffer[i] = buffer[i] > 0 ?
7629841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                buffer[i] * std::numeric_limits<int16_t>::max() :
7729841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org                -buffer[i] * std::numeric_limits<int16_t>::min();
7829841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
7929841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  if (wav_file) {
8029841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org    wav_file->WriteSamples(buffer.get(), length);
8129841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org  }
8229841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org}
8329841cb8d3a1101cc878debdbc481cee63e75a19aluebs@webrtc.org
84b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org// Exits on failure; do not use in unit tests.
85b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic inline FILE* OpenFile(const std::string& filename, const char* mode) {
86b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  FILE* file = fopen(filename.c_str(), mode);
87b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  if (!file) {
88b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    printf("Unable to open file %s\n", filename.c_str());
89b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    exit(1);
90b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  }
91b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  return file;
92b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}
93b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
94467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.orgstatic inline int SamplesFromRate(int rate) {
95467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  return AudioProcessing::kChunkSizeMs * rate / 1000;
96467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org}
97467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org
98b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic inline void SetFrameSampleRate(AudioFrame* frame,
99b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                                      int sample_rate_hz) {
100e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org  frame->sample_rate_hz_ = sample_rate_hz;
101467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org  frame->samples_per_channel_ = AudioProcessing::kChunkSizeMs *
102467f7567c8befea153861e09f048f69932d6e3bdandrew@webrtc.org      sample_rate_hz / 1000;
103e95dc25b14845cbf00ae363e88459c44e2341c47andrew@webrtc.org}
104b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
105b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgtemplate <typename T>
106b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgvoid SetContainerFormat(int sample_rate_hz,
107b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                        int num_channels,
108b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                        AudioFrame* frame,
109b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                        scoped_ptr<ChannelBuffer<T> >* cb) {
110b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  SetFrameSampleRate(frame, sample_rate_hz);
111b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  frame->num_channels_ = num_channels;
112b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  cb->reset(new ChannelBuffer<T>(frame->samples_per_channel_, num_channels));
113b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}
114b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
115b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic inline AudioProcessing::ChannelLayout LayoutFromChannels(
116b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    int num_channels) {
117b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  switch (num_channels) {
118b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    case 1:
119b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org      return AudioProcessing::kMono;
120b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    case 2:
121b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org      return AudioProcessing::kStereo;
122b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    default:
123b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org      assert(false);
124b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org      return AudioProcessing::kMono;
125b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  }
126b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}
127b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
128b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org// Allocates new memory in the scoped_ptr to fit the raw message and returns the
129b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org// number of bytes read.
130b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic inline size_t ReadMessageBytesFromFile(FILE* file,
131b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                                              scoped_ptr<uint8_t[]>* bytes) {
132b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  // The "wire format" for the size is little-endian. Assume we're running on
133b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  // a little-endian machine.
134b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  int32_t size = 0;
135b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  if (fread(&size, sizeof(size), 1, file) != 1)
136b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    return 0;
137b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  if (size <= 0)
138b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    return 0;
139b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
140b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  bytes->reset(new uint8_t[size]);
141b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  return fread(bytes->get(), sizeof((*bytes)[0]), size, file);
142b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}
143b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
144b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org// Returns true on success, false on error or end-of-file.
145b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.orgstatic inline bool ReadMessageFromFile(FILE* file,
146b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org                                       ::google::protobuf::MessageLite* msg) {
147b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  scoped_ptr<uint8_t[]> bytes;
148b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  size_t size = ReadMessageBytesFromFile(file, &bytes);
149b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  if (!size)
150b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org    return false;
151b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
152b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  msg->Clear();
153b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org  return msg->ParseFromArray(bytes.get(), size);
154b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}
155b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org
156b5b49c0723428d30e68bc8edcc089049a29e0703andrew@webrtc.org}  // namespace webrtc
157