Make audio channel a separate class

This commit is contained in:
Nikita Lisitsa 2022-10-05 22:39:54 +03:00
parent cab34558ce
commit 26b44a9fa3
4 changed files with 81 additions and 56 deletions

View file

@ -5,6 +5,8 @@
#include <psemek/audio/wave/square.hpp>
#include <psemek/audio/wave/triangle.hpp>
#include <psemek/audio/effect/volume.hpp>
#include <psemek/audio/effect/fade_in.hpp>
#include <psemek/audio/effect/fade_out.hpp>
#include <psemek/audio/duplicate.hpp>
#include <psemek/audio/stereo.hpp>
#include <psemek/audio/mixer.hpp>
@ -19,6 +21,16 @@ using namespace psemek;
static std::map<SDL_Keycode, int> const key_to_midi
{
{SDLK_z, 59},
{SDLK_x, 60},
{SDLK_c, 61},
{SDLK_v, 62},
{SDLK_b, 63},
{SDLK_n, 64},
{SDLK_m, 65},
{SDLK_COMMA, 66},
{SDLK_PERIOD, 67},
{SDLK_SLASH, 68},
{SDLK_a, 69},
{SDLK_s, 70},
{SDLK_d, 71},
@ -30,6 +42,18 @@ static std::map<SDL_Keycode, int> const key_to_midi
{SDLK_l, 77},
{SDLK_SEMICOLON, 78},
{SDLK_QUOTE, 79},
{SDLK_q, 80},
{SDLK_w, 81},
{SDLK_e, 82},
{SDLK_r, 83},
{SDLK_t, 84},
{SDLK_y, 85},
{SDLK_u, 86},
{SDLK_i, 87},
{SDLK_o, 88},
{SDLK_p, 89},
{SDLK_LEFTBRACKET, 90},
{SDLK_RIGHTBRACKET, 91},
};
struct audio_app
@ -41,8 +65,8 @@ struct audio_app
mixer_ = audio::make_mixer();
auto [ dup1, dup2 ] = audio::duplicate(mixer_);
left_volume_ = audio::volume(dup1, 0.f, 0.1f);
right_volume_ = audio::volume(dup2, 0.f, 0.1f);
left_volume_ = audio::volume(dup1, 0.5f, 0.1f);
right_volume_ = audio::volume(dup2, 0.5f, 0.1f);
auto result = audio::stereo(left_volume_, right_volume_);
engine_.output(result);
}
@ -55,7 +79,7 @@ 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(tone);
channels_[key] = mixer_->add(audio::fade_in(tone, 0.01f));
}
}
@ -65,7 +89,8 @@ struct audio_app
if (channels_.contains(key))
{
channels_[key]->stop();
auto & ch = channels_[key];
ch->stream(audio::fade_out(ch->stream(), 0.01f));
channels_.erase(key);
}
}
@ -83,7 +108,7 @@ private:
audio::engine engine_;
audio::mixer_ptr mixer_;
std::shared_ptr<audio::volume_control> left_volume_, right_volume_;
std::map<SDL_Keycode, audio::mixer::channel_ptr> channels_;
std::map<SDL_Keycode, audio::channel_ptr> channels_;
util::clock<> clock_;
};

View file

@ -0,0 +1,43 @@
#pragma once
#include <psemek/audio/stream.hpp>
#include <atomic>
#include <memory>
namespace psemek::audio
{
struct channel
{
channel(stream_ptr stream)
: stream_(std::move(stream))
{}
stream_ptr stream() const
{
return std::atomic_load(&stream_);
}
stream_ptr stream(stream_ptr new_stream)
{
return std::atomic_exchange(&stream_, std::move(new_stream));
}
stream_ptr stop()
{
return stream(nullptr);
}
bool is_stopped() const
{
return stream() != nullptr;
}
private:
stream_ptr stream_;
};
using channel_ptr = std::shared_ptr<channel>;
}

View file

@ -1,7 +1,7 @@
#pragma once
#include <psemek/audio/stream.hpp>
#include <psemek/util/function.hpp>
#include <psemek/audio/channel.hpp>
#include <memory>
@ -11,19 +11,6 @@ namespace psemek::audio
struct mixer
: stream
{
struct channel
{
virtual void stop() = 0;
virtual bool is_stopped() const = 0;
virtual void replace(util::function<stream_ptr(stream_ptr)> modifier) = 0;
virtual ~channel() {}
};
using channel_ptr = std::shared_ptr<channel>;
virtual channel_ptr add(stream_ptr stream) = 0;
};

View file

@ -10,35 +10,6 @@ namespace psemek::audio
namespace
{
struct channel_impl final
: mixer::channel
{
stream_ptr stream;
void stop() override;
bool is_stopped() const override;
void replace(util::function<stream_ptr(stream_ptr)> modifier) override;
};
void channel_impl::stop()
{
std::atomic_store(&stream, stream_ptr());
}
bool channel_impl::is_stopped() const
{
return std::atomic_load(&stream) != nullptr;
}
void channel_impl::replace(util::function<stream_ptr(stream_ptr)> modifier)
{
stream_ptr stream = std::atomic_load(&(this->stream));
stream = modifier(std::move(stream));
std::atomic_store(&(this->stream), std::move(stream));
}
struct mixer_impl final
: mixer
, std::enable_shared_from_this<mixer_impl>
@ -48,19 +19,18 @@ namespace psemek::audio
std::size_t read(float * data, std::size_t sample_count) override;
private:
std::vector<std::shared_ptr<channel_impl>> channels_;
std::vector<std::shared_ptr<channel_impl>> alive_channels_;
std::vector<channel_ptr> channels_;
std::vector<channel_ptr> alive_channels_;
std::vector<float> buffer_;
std::mutex new_channels_mutex_;
std::vector<std::shared_ptr<channel_impl>> new_channels_;
std::vector<channel_ptr> new_channels_;
};
mixer::channel_ptr mixer_impl::add(stream_ptr stream)
channel_ptr mixer_impl::add(stream_ptr stream)
{
auto result = std::make_shared<channel_impl>();
result->stream = std::move(stream);
auto result = std::make_shared<channel>(std::move(stream));
{
std::lock_guard lock{new_channels_mutex_};
@ -73,7 +43,7 @@ namespace psemek::audio
std::size_t mixer_impl::read(float * data, std::size_t sample_count)
{
{
std::vector<std::shared_ptr<channel_impl>> new_channels;
std::vector<channel_ptr> new_channels;
{
std::lock_guard lock{new_channels_mutex_};
new_channels = std::move(new_channels_);
@ -88,7 +58,7 @@ namespace psemek::audio
for (auto & ch : channels_)
{
auto stream = std::atomic_load(&(ch->stream));
auto stream = ch->stream();
if (!stream)
continue;