blob: 7eacc2ea67c8c9fb16e1081873110db4a243f358 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/frame_generator.h"
#include "include/util.h"
typedef std::unique_lock<std::mutex> ulock;
namespace autotest_client {
namespace audio {
FrameGenerator::FrameGenerator(const ParamConfig& config)
: terminate_test_(false),
new_freq_(false),
stop_play_tone_(false),
fft_size_(config.fft_size),
sample_rate_(config.sample_rate),
tone_length_(config.tone_length),
cur_volume_(config.start_volume),
num_channels_(config.num_speaker_channels),
active_channels_(config.active_speaker_channels),
format_(config.format),
wave_(config.sample_rate),
num_fade_frames_(0),
is_debug_(config.verbose) {
frames_needed_ = sample_rate_ * tone_length_;
frames_generated_ = 0;
cur_volume_ = config.start_volume;
volume_gap_ =
(config.start_volume - config.end_volume)
/ static_cast<double>(frames_needed_);
const double FadingLengthSec = 0.005;
if (tone_length_ > FadingLengthSec * 4) {
num_fade_frames_ = FadingLengthSec * sample_rate_;
}
}
void FrameGenerator::Run(PlayClient *player) {
double *buffer = new double[fft_size_];
while (!terminate_test_) {
// Wait for new frequency.
ulock lock(change_state_mutex_);
change_state_cond_.wait(lock, [=]{return new_freq_ || terminate_test_;});
new_freq_ = false;
lock.unlock();
if (terminate_test_) break;
if (is_debug_) cerr << "[Generator] Got new frequency to play.\n";
while (!stop_play_tone_ && HasMoreFrames()) {
int written = GetFrames(buffer, fft_size_);
vector< vector<double> > chn_buf;
for (int ch = 0; ch < num_channels_; ++ch) {
if (active_channels_.count(ch) > 0)
chn_buf.push_back(vector<double>(buffer, buffer + fft_size_));
else
chn_buf.push_back(vector<double>(fft_size_, 0.0));
}
if (player->Play(chn_buf, written) < 0) {
cerr << "Play frames error.\n";
assert(false);
}
}
stop_play_tone_ = false;
if (is_debug_) cerr << "[Player] Done play the tone.\n";
}
delete [] buffer;
}
void FrameGenerator::Stop() {
// Close the play thread.
ulock lock(change_state_mutex_);
terminate_test_ = true;
change_state_cond_.notify_all();
lock.unlock();
generating_thread_.join();
}
void FrameGenerator::SetFrequency(double freq) {
wave_.Reset(freq);
frames_generated_ = 0;
// Notify generating thread.
ulock lock(change_state_mutex_);
new_freq_ = true;
change_state_cond_.notify_one();
lock.unlock();
}
unsigned FrameGenerator::GetFrames(double *buf, unsigned num_frames) {
unsigned frame_written;
for (frame_written = 0; frame_written < num_frames; ++frame_written) {
if (!HasMoreFrames()) {
break;
}
buf[frame_written] = GetSample();
++frames_generated_;
}
return frame_written;
}
bool FrameGenerator::HasMoreFrames() const {
return frames_generated_ < frames_needed_;
}
double FrameGenerator::GetSample() {
double magn = 0.0;
// Determined by frequency.
magn += wave_.GetNext();
// Effected by fading & volume.
magn *= FadingMagnitude() * cur_volume_;
cur_volume_ += volume_gap_;
return magn;
}
double FrameGenerator::FadingMagnitude() const {
int frame_border = std::min(
frames_generated_, (frames_needed_ - frames_generated_));
if (frame_border < num_fade_frames_) {
return sin(M_PI / 2 * frame_border / num_fade_frames_);
}
return 1.0;
}
} // namespace audio
} // namespace autotest_client