Implement audio pause control

This commit is contained in:
Nikita Lisitsa 2022-10-07 22:03:27 +03:00
parent 81fabbbf02
commit 227236568b
3 changed files with 127 additions and 2 deletions

View file

@ -8,6 +8,7 @@
#include <psemek/audio/effect/fade_in.hpp>
#include <psemek/audio/effect/fade_out.hpp>
#include <psemek/audio/effect/compressor.hpp>
#include <psemek/audio/effect/pause.hpp>
#include <psemek/audio/duplicate.hpp>
#include <psemek/audio/stereo.hpp>
#include <psemek/audio/mixer.hpp>
@ -69,7 +70,9 @@ struct audio_app
{
mixer_ = audio::make_mixer();
volume_control_ = audio::volume_stereo(mixer_, 0.5f, 0.5f, 0.1f);
engine_.output()->stream(audio::compressor(volume_control_, audio::from_db(-2.f), 0.95f, 0.002f, 1.f, audio::from_db(1.f)));
auto compressor = audio::compressor(volume_control_, audio::from_db(-2.f), 0.95f, 0.002f, 1.f, audio::from_db(1.f));
pause_control_ = audio::pause(compressor, false, 0.01f);
engine_.output()->stream(pause_control_);
}
void on_key_down(SDL_Keycode key) override
@ -80,7 +83,12 @@ struct audio_app
{
int midi = key_to_midi.at(key);
auto tone = audio::sine_wave(440.f * std::pow(2.f, (midi - 69) / 12.f));
channels_[key] = mixer_->add(audio::fade_in(tone, 0.01f));
channels_[key] = mixer_->add(audio::fade_in(tone, 0.002f));
}
if (key == SDLK_SPACE)
{
pause_control_->paused(!pause_control_->paused());
}
}
@ -131,6 +139,7 @@ private:
audio::engine engine_;
audio::mixer_ptr mixer_;
std::shared_ptr<audio::volume_control_stereo> volume_control_;
std::shared_ptr<audio::pause_control> pause_control_;
std::map<SDL_Keycode, audio::channel_ptr> channels_;
util::clock<> clock_;

View file

@ -0,0 +1,21 @@
#pragma once
#include <psemek/audio/stream.hpp>
#include <psemek/audio/duration.hpp>
namespace psemek::audio
{
struct pause_control
: stream
{
virtual bool paused() const = 0;
virtual bool paused(bool value) = 0;
virtual void pause() { paused(true); }
virtual void resume() { paused(false); }
};
std::shared_ptr<pause_control> pause(stream_ptr stream, bool paused = false, duration length = 0.01f);
}

View file

@ -0,0 +1,95 @@
#include <psemek/audio/effect/pause.hpp>
#include <psemek/audio/smooth.hpp>
#include <atomic>
namespace psemek::audio
{
namespace
{
struct pause_control_impl
: pause_control
{
pause_control_impl(stream_ptr stream, bool paused, duration length)
: stream_(std::move(stream))
, paused_{paused}
, length_(length)
, level_(paused ? 0 : length_.samples())
{}
bool paused() const override
{
return paused_.load();
}
bool paused(bool value) override
{
return paused_.exchange(value);
}
std::optional<std::size_t> length() const override
{
return stream_->length();
}
std::size_t read(float * data, std::size_t sample_count) override
{
bool const paused = paused_.load();
if (paused)
{
auto result = stream_->read(data, std::min(sample_count, level_));
for (std::size_t i = 0; i < result; i += 2)
{
float gain = static_cast<float>(level_) / length_.samples();
data[i + 0] *= gain;
data[i + 1] *= gain;
level_ -= 2;
}
std::fill(data + result, data + sample_count, 0.f);
return sample_count;
}
else
{
auto result = stream_->read(data, sample_count);
auto const max_level = static_cast<std::size_t>(length_.samples());
for (std::size_t i = 0; i < result; i += 2)
{
float gain = static_cast<float>(level_) / max_level;
data[i + 0] *= gain;
data[i + 1] *= gain;
if (level_ < max_level)
level_ += 2;
}
return result;
}
}
std::size_t played() const override
{
return stream_->played();
}
private:
stream_ptr stream_;
std::atomic<bool> paused_;
duration length_;
std::size_t level_;
};
}
std::shared_ptr<pause_control> pause(stream_ptr stream, bool paused, duration length)
{
return std::make_shared<pause_control_impl>(std::move(stream), paused, length);
}
}