summaryrefslogtreecommitdiffstats
path: root/media/tools/wav_ola_test.cc
blob: 9d99802c10667eafbb4684d4d7539db9bc267d36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This application is a test for AudioRendererAlgorithmOLA. It reads in a
// specified wav file (so far only 8, 16 and 32 bit are supported) and uses
// ARAO to scale the playback by a specified rate. Then it outputs the result
// to the specified location. Command line calls should be as follows:
//
//    wav_ola_test RATE INFILE OUTFILE

#include <iostream>
#include <string>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "media/base/data_buffer.h"
#include "media/filters/audio_renderer_algorithm_ola.h"

using file_util::ScopedFILE;
using media::AudioRendererAlgorithmOLA;
using media::DataBuffer;

const double kDefaultWindowLength = 0.08;

struct WavHeader {
  int32 riff;
  int32 chunk_size;
  char unused0[8];
  int32 subchunk1_size;
  int16 audio_format;
  int16 channels;
  int32 sample_rate;
  char unused1[6];
  int16 bit_rate;
  char unused2[4];
  int32 subchunk2_size;
};

// Dummy class to feed data to OLA algorithm. Necessary to create callback.
class Dummy {
 public:
  Dummy(FILE* in, AudioRendererAlgorithmOLA* ola, size_t window_size)
      : input_(in),
        ola_(ola),
        window_size_(window_size) {
  }

  void ReadDataForAlg() {
    scoped_refptr<DataBuffer> buffer(new DataBuffer(window_size_));
    buffer->SetDataSize(window_size_);
    uint8* buf = buffer->GetWritableData();
    if (fread(buf, 1, window_size_, input_) > 0) {
      ola_->EnqueueBuffer(buffer.get());
    }
  }

 private:
  FILE* input_;
  AudioRendererAlgorithmOLA* ola_;
  size_t window_size_;

  DISALLOW_COPY_AND_ASSIGN(Dummy);
};

int main(int argc, const char** argv) {
  AudioRendererAlgorithmOLA ola;
  CommandLine::Init(argc, argv);
  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();

  std::vector<std::wstring> filenames(cmd_line->GetLooseValues());
  if (filenames.empty()) {
    std::cerr << "Usage: wav_ola_test RATE INFILE OUTFILE\n"
              << std::endl;
    return 1;
  }

  // Retrieve command line options.
  std::string in_path(WideToUTF8(filenames[1]));
  std::string out_path(WideToUTF8(filenames[2]));
  double playback_rate = 0.0;

  // Determine speed of rerecord.
  if (!StringToDouble(WideToUTF8(filenames[0]), &playback_rate))
    playback_rate = 0.0;

  // Open input file.
  ScopedFILE input(file_util::OpenFile(in_path.c_str(), "rb"));
  if (!(input.get())) {
    LOG(ERROR) << "could not open input";
    return 1;
  }

  // Open output file.
  ScopedFILE output(file_util::OpenFile(out_path.c_str(), "wb"));
  if (!(output.get())) {
    LOG(ERROR) << "could not open output";
    return 1;
  }

  // Read in header.
  WavHeader wav;
  if (fread(&wav, sizeof(wav), 1, input.get()) < 1) {
    LOG(ERROR) << "could not read WAV header";
    return 1;
  }

  size_t window_size = static_cast<size_t>(wav.sample_rate
                                           * (wav.bit_rate / 8)
                                           * wav.channels
                                           * kDefaultWindowLength);

  // Instantiate dummy class and callback to feed data to |ola|.
  Dummy guy(input.get(), &ola, window_size);
  AudioRendererAlgorithmOLA::RequestReadCallback* cb =
      NewCallback(&guy, &Dummy::ReadDataForAlg);
  ola.Initialize(wav.channels,
                 wav.sample_rate,
                 wav.bit_rate,
                 static_cast<float>(playback_rate),
                 cb);
  ola.FlushBuffers();

  // Print out input format.
  std::cout << in_path << "\n"
            << "Channels: " << wav.channels << "\n"
            << "Sample Rate: " << wav.sample_rate << "\n"
            << "Bit Rate: " << wav.bit_rate << "\n"
            << "\n"
            << "Scaling audio by " << playback_rate << "x..." << std::endl;

  // Write the header back out again.
  if (fwrite(&wav, sizeof(wav), 1, output.get()) < 1) {
    LOG(ERROR) << "could not write WAV header";
    return 1;
  }

  // Create buffer to be filled by |ola|.
  scoped_array<uint8> buf(new uint8[window_size]);

  CHECK(buf.get());

  // Keep track of bytes written to disk and bytes copied to |b|.
  size_t bytes_written = 0;
  size_t bytes;
  while ((bytes = ola.FillBuffer(buf.get(), window_size)) > 0) {
    if (fwrite(buf.get(), 1, bytes, output.get()) != bytes) {
      LOG(ERROR) << "could not write data after " << bytes_written;
    } else {
      bytes_written += bytes;
    }
  }

  // Seek back to the beginning of our output file and update the header.
  wav.chunk_size = 36 + bytes_written;
  wav.subchunk1_size = 16;
  wav.subchunk2_size = bytes_written;
  fseek(output.get(), 0, SEEK_SET);
  if (fwrite(&wav, sizeof(wav), 1, output.get()) < 1) {
    LOG(ERROR) << "could not write wav header.";
    return 1;
  }

  return 0;
}