Make audio channel a separate class
This commit is contained in:
parent
cab34558ce
commit
26b44a9fa3
4 changed files with 81 additions and 56 deletions
|
|
@ -5,6 +5,8 @@
|
||||||
#include <psemek/audio/wave/square.hpp>
|
#include <psemek/audio/wave/square.hpp>
|
||||||
#include <psemek/audio/wave/triangle.hpp>
|
#include <psemek/audio/wave/triangle.hpp>
|
||||||
#include <psemek/audio/effect/volume.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/duplicate.hpp>
|
||||||
#include <psemek/audio/stereo.hpp>
|
#include <psemek/audio/stereo.hpp>
|
||||||
#include <psemek/audio/mixer.hpp>
|
#include <psemek/audio/mixer.hpp>
|
||||||
|
|
@ -19,6 +21,16 @@ using namespace psemek;
|
||||||
|
|
||||||
static std::map<SDL_Keycode, int> const key_to_midi
|
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_a, 69},
|
||||||
{SDLK_s, 70},
|
{SDLK_s, 70},
|
||||||
{SDLK_d, 71},
|
{SDLK_d, 71},
|
||||||
|
|
@ -30,6 +42,18 @@ static std::map<SDL_Keycode, int> const key_to_midi
|
||||||
{SDLK_l, 77},
|
{SDLK_l, 77},
|
||||||
{SDLK_SEMICOLON, 78},
|
{SDLK_SEMICOLON, 78},
|
||||||
{SDLK_QUOTE, 79},
|
{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
|
struct audio_app
|
||||||
|
|
@ -41,8 +65,8 @@ struct audio_app
|
||||||
mixer_ = audio::make_mixer();
|
mixer_ = audio::make_mixer();
|
||||||
|
|
||||||
auto [ dup1, dup2 ] = audio::duplicate(mixer_);
|
auto [ dup1, dup2 ] = audio::duplicate(mixer_);
|
||||||
left_volume_ = audio::volume(dup1, 0.f, 0.1f);
|
left_volume_ = audio::volume(dup1, 0.5f, 0.1f);
|
||||||
right_volume_ = audio::volume(dup2, 0.f, 0.1f);
|
right_volume_ = audio::volume(dup2, 0.5f, 0.1f);
|
||||||
auto result = audio::stereo(left_volume_, right_volume_);
|
auto result = audio::stereo(left_volume_, right_volume_);
|
||||||
engine_.output(result);
|
engine_.output(result);
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +79,7 @@ struct audio_app
|
||||||
{
|
{
|
||||||
int midi = key_to_midi.at(key);
|
int midi = key_to_midi.at(key);
|
||||||
auto tone = audio::sine_wave(440.f * std::pow(2.f, (midi - 69) / 12.f));
|
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))
|
if (channels_.contains(key))
|
||||||
{
|
{
|
||||||
channels_[key]->stop();
|
auto & ch = channels_[key];
|
||||||
|
ch->stream(audio::fade_out(ch->stream(), 0.01f));
|
||||||
channels_.erase(key);
|
channels_.erase(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +108,7 @@ private:
|
||||||
audio::engine engine_;
|
audio::engine engine_;
|
||||||
audio::mixer_ptr mixer_;
|
audio::mixer_ptr mixer_;
|
||||||
std::shared_ptr<audio::volume_control> left_volume_, right_volume_;
|
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_;
|
util::clock<> clock_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
43
libs/audio/include/psemek/audio/channel.hpp
Normal file
43
libs/audio/include/psemek/audio/channel.hpp
Normal 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>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/audio/stream.hpp>
|
#include <psemek/audio/stream.hpp>
|
||||||
#include <psemek/util/function.hpp>
|
#include <psemek/audio/channel.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -11,19 +11,6 @@ namespace psemek::audio
|
||||||
struct mixer
|
struct mixer
|
||||||
: stream
|
: 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;
|
virtual channel_ptr add(stream_ptr stream) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,35 +10,6 @@ namespace psemek::audio
|
||||||
namespace
|
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
|
struct mixer_impl final
|
||||||
: mixer
|
: mixer
|
||||||
, std::enable_shared_from_this<mixer_impl>
|
, 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;
|
std::size_t read(float * data, std::size_t sample_count) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<channel_impl>> channels_;
|
std::vector<channel_ptr> channels_;
|
||||||
std::vector<std::shared_ptr<channel_impl>> alive_channels_;
|
std::vector<channel_ptr> alive_channels_;
|
||||||
|
|
||||||
std::vector<float> buffer_;
|
std::vector<float> buffer_;
|
||||||
|
|
||||||
std::mutex new_channels_mutex_;
|
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>();
|
auto result = std::make_shared<channel>(std::move(stream));
|
||||||
result->stream = std::move(stream);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock{new_channels_mutex_};
|
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::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_};
|
std::lock_guard lock{new_channels_mutex_};
|
||||||
new_channels = std::move(new_channels_);
|
new_channels = std::move(new_channels_);
|
||||||
|
|
@ -88,7 +58,7 @@ namespace psemek::audio
|
||||||
|
|
||||||
for (auto & ch : channels_)
|
for (auto & ch : channels_)
|
||||||
{
|
{
|
||||||
auto stream = std::atomic_load(&(ch->stream));
|
auto stream = ch->stream();
|
||||||
if (!stream)
|
if (!stream)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue