Skip to content

Commit

Permalink
Fix pan and IRateConverters (#281)
Browse files Browse the repository at this point in the history
* Fix pan and IRateConverters

* refactor IMixer

* refactor IMixer

* IMixer add reset channel group (stop)

* update version

* restore sonarcloud ci bot comment on PR

* revert accidental refactor to isPlaying

* revert accidental refactor to isPlaying

* revert accidental refactor to isPlaying

* revert accidental refactor

* revert accidental refactor

* revert accidental refactor

* code rev

* sonarcloud ci rev

* sonarcloud code rev
  • Loading branch information
Raffaello authored Nov 12, 2023
1 parent 1ceb2a6 commit db7430b
Show file tree
Hide file tree
Showing 20 changed files with 105 additions and 45 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
endif()


project ("sdl2-hyper-sonic-drivers" VERSION 0.15.4 DESCRIPTION "SDL2 based Hyper-Sonic Drivers for emulating old soundcards")
project ("sdl2-hyper-sonic-drivers" VERSION 0.16.0 DESCRIPTION "SDL2 based Hyper-Sonic Drivers for emulating old soundcards")
include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
Expand Down
2 changes: 1 addition & 1 deletion sdl2-hyper-sonic-drivers/examples/pcm-example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ int main(int argc, char* argv[])
for (int i = 0, sig = +1; i < 3; i++, sig *= -1)
{
cout << i << ". playing same sound again reversed balance" << endl;
delayMillis(200);
delayMillis(500);
drv.play(wavSound, 150, 127 * sig);
drv.play(vocSound, 255, -127 * sig);
}
Expand Down
14 changes: 13 additions & 1 deletion sdl2-hyper-sonic-drivers/src/HyperSonicDrivers/audio/IMixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace HyperSonicDrivers::audio
IMixer::IMixer(const uint8_t max_channels,
const uint32_t freq, const uint16_t buffer_size) :
max_channels(max_channels),
m_sampleRate(freq), m_samples(buffer_size)
freq(freq), buffer_size(buffer_size)
{
}

Expand All @@ -20,5 +20,17 @@ namespace HyperSonicDrivers::audio
void IMixer::setChannelGroupVolume(const mixer::eChannelGroup group, const uint8_t volume) noexcept
{
m_group_settings.at(group2i(group)).volume = volume;
updateChannelsVolumePan_();
}

int8_t IMixer::getChannelGroupPan(const mixer::eChannelGroup group) const noexcept
{
return m_group_settings.at(group2i(group)).pan;
}

void IMixer::setChannelGroupPan(const mixer::eChannelGroup group, const int8_t pan) noexcept
{
m_group_settings[group2i(group)].pan = pan;
updateChannelsVolumePan_();
}
}
26 changes: 16 additions & 10 deletions sdl2-hyper-sonic-drivers/src/HyperSonicDrivers/audio/IMixer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ namespace HyperSonicDrivers::audio
class IMixer
{
public:
const uint8_t max_channels;
const uint32_t freq;
const uint16_t buffer_size;
const uint8_t bitsDepth = 16; // forced to be 16-bits for now

IMixer(IMixer&) = delete;
IMixer& operator=(IMixer&) = delete;

Expand All @@ -40,16 +45,20 @@ namespace HyperSonicDrivers::audio

virtual void reset() noexcept = 0;
virtual void reset(const uint8_t id) noexcept = 0;
virtual void reset(const mixer::eChannelGroup group) noexcept = 0;

virtual void pause() noexcept = 0;
virtual void pause(const uint8_t id) noexcept = 0;

virtual void unpause() noexcept = 0;
virtual void unpause(const uint8_t id) noexcept = 0;

virtual bool isChannelActive(const uint8_t id) const noexcept = 0;
virtual bool isActive(const uint8_t id) const noexcept = 0;
virtual bool isPaused(const uint8_t id) const noexcept = 0;

virtual bool isActive() const noexcept = 0;
virtual bool isActive(const mixer::eChannelGroup group) = 0;

virtual bool isChannelGroupMuted(const mixer::eChannelGroup group) const noexcept = 0;
virtual void muteChannelGroup(const mixer::eChannelGroup group) noexcept = 0;
virtual void unmuteChannelGroup(const mixer::eChannelGroup group) noexcept = 0;
Expand All @@ -66,27 +75,24 @@ namespace HyperSonicDrivers::audio
uint8_t getChannelGroupVolume(const mixer::eChannelGroup group) const noexcept;
void setChannelGroupVolume(const mixer::eChannelGroup group, const uint8_t volume) noexcept;

// TODO: these 3 methods are useless if those 3 vars are consts...
inline uint32_t getOutputRate() const noexcept { return m_sampleRate; };
inline uint16_t getBufferSize() const noexcept { return m_samples; };
inline uint8_t getBitsDepth() const noexcept { return m_bitsDepth; };
inline uint8_t getMasterVolume() const noexcept { return m_master_volume; };
int8_t getChannelGroupPan(const mixer::eChannelGroup group) const noexcept;
void setChannelGroupPan(const mixer::eChannelGroup group, const int8_t pan) noexcept;

inline uint8_t getMasterVolume() const noexcept { return m_master_volume; };
virtual void setMasterVolume(const uint8_t master_volume) noexcept = 0;

inline void toggleReverseStereo() noexcept { m_reverseStereo = !m_reverseStereo; };

const uint8_t max_channels;
protected:
virtual void updateChannelsVolumePan_() noexcept = 0;

std::array<mixer::channelGroupSettings_t, mixer::eChannelGroup_size> m_group_settings;
bool m_ready = false; // TODO: not really useful if not used anywhere else except init.
// unless remove init method and do it in the constructor
// and then check if it is ready before use the mixer
// otherwise can just be removed.
bool m_reverseStereo = false;
const uint32_t m_sampleRate;
const uint16_t m_samples;
const uint8_t m_bitsDepth = 16; // forced to be 16-bits for now

uint8_t m_master_volume = mixer::Mixer_max_volume;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ namespace HyperSonicDrivers::audio::converters
int16_t out1 = (stereo ? *it++ : out0);

// output left channel
output_channel(obuf[reverseStereo ? 0 : 1], out0, vol_l);
output_channel(obuf[reverseStereo ? 1 : 0], out0, vol_l);
// output right channel
output_channel(obuf[reverseStereo ? 1 : 0], out1, vol_r);
output_channel(obuf[reverseStereo ? 0 : 1], out1, vol_r);
obuf += 2;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ namespace HyperSonicDrivers::audio::converters
const int16_t out0 = interpolate(ilast0, icur0, opos);
const int16_t out1 = stereo ? interpolate(ilast1, icur1, opos) : out0;
// output left channel
output_channel(obuf[reverseStereo ? 0 : 1], out0, vol_l);
output_channel(obuf[reverseStereo ? 1 : 0], out0, vol_l);
// output right channel
output_channel(obuf[reverseStereo ? 1 : 0], out1, vol_r);
output_channel(obuf[reverseStereo ? 0 : 1], out1, vol_r);
obuf += 2;

// Increment output position
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ namespace HyperSonicDrivers::audio::converters
opos += opos_inc;

// output left channel
output_channel(obuf[reverseStereo ? 0 : 1], out0, vol_l);
output_channel(obuf[reverseStereo ? 1 : 0], out0, vol_l);
// output right channel
output_channel(obuf[reverseStereo ? 1 : 0], out1, vol_r);
output_channel(obuf[reverseStereo ? 0 : 1], out1, vol_r);
obuf += 2;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace HyperSonicDrivers::audio::mixer
reset();
m_group = group;
m_stream = stream;
m_converter = converters::makeIRateConverter(m_stream->getRate(), m_mixer.getOutputRate(), m_stream->isStereo(), reverseStereo);
m_converter = converters::makeIRateConverter(m_stream->getRate(), m_mixer.freq, m_stream->isStereo(), reverseStereo);
}

void Channel::setAudioStream(const mixer::eChannelGroup group, const std::shared_ptr<IAudioStream>& stream,
Expand Down Expand Up @@ -118,8 +118,8 @@ namespace HyperSonicDrivers::audio::mixer
const float pan = (127.5f + m_pan) / 255.0f;
// TODO: create different selectable pan laws
// -3dB pan law
m_volL = static_cast<uint16_t>(std::round(sqrt(pan) * vol / ch_max_vol));
m_volR = static_cast<uint16_t>(std::round(sqrt(1 - pan) * vol / ch_max_vol));
m_volL = static_cast<uint16_t>(std::round(sqrt(1 - pan) * vol / ch_max_vol));
m_volR = static_cast<uint16_t>(std::round(sqrt(pan) * vol / ch_max_vol));

// adjust for master volume
const auto m_vol = m_mixer.getMasterVolume();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <algorithm>
#include <ranges>
#include <cstring>
#include <cassert>
#include <HyperSonicDrivers/audio/sdl2/Mixer.hpp>
Expand Down Expand Up @@ -86,6 +87,17 @@ namespace HyperSonicDrivers::audio::sdl2
m_channels[id]->reset();
}

void Mixer::reset(const mixer::eChannelGroup group) noexcept
{
std::scoped_lock lck(m_mutex);

for (const auto& ch : m_channels)
{
if (ch->getChannelGroup() == group)
ch->reset();
}
}

void Mixer::pause() noexcept
{
std::scoped_lock lck(m_mutex);
Expand Down Expand Up @@ -116,7 +128,7 @@ namespace HyperSonicDrivers::audio::sdl2
m_channels[id]->unpause();
}

bool Mixer::isChannelActive(const uint8_t id) const noexcept
bool Mixer::isActive(const uint8_t id) const noexcept
{
std::scoped_lock lck(m_mutex);

Expand All @@ -130,6 +142,24 @@ namespace HyperSonicDrivers::audio::sdl2
return m_channels[id]->isPaused();
}

bool Mixer::isActive() const noexcept
{
std::scoped_lock lck(m_mutex);

return std::ranges::any_of(m_channels, [](const auto& ch)
{ return !ch->isEnded(); });
}

bool Mixer::isActive(const mixer::eChannelGroup group)
{
std::scoped_lock lck(m_mutex);

return std::ranges::any_of(m_channels, [group](const auto& ch)
{ return ch->getChannelGroup() == group && !ch->isEnded(); });

return false;
}

bool Mixer::isChannelGroupMuted(const mixer::eChannelGroup group) const noexcept
{
return m_group_settings[group2i(group)].mute;
Expand Down Expand Up @@ -195,6 +225,12 @@ namespace HyperSonicDrivers::audio::sdl2
updateChannelsVolumePan_();
}

void Mixer::updateChannelsVolumePan_() noexcept
{
for (const auto& ch : m_channels)
ch->updateVolumePan();
}

bool Mixer::init_(SDL_AudioCallback callback, void* userdata)
{
m_ready = false;
Expand All @@ -206,10 +242,10 @@ namespace HyperSonicDrivers::audio::sdl2

// Get the desired audio specs
SDL_AudioSpec desired = {
.freq = static_cast<int>(m_sampleRate),
.freq = static_cast<int>(freq),
.format = AUDIO_S16,
.channels = 2,
.samples = m_samples,
.samples = buffer_size,
.callback = callback,
.userdata = userdata
};
Expand Down Expand Up @@ -244,12 +280,6 @@ namespace HyperSonicDrivers::audio::sdl2
return true;
}

void Mixer::updateChannelsVolumePan_() noexcept
{
for (const auto& ch : m_channels)
ch->updateVolumePan();
}

size_t Mixer::callback(uint8_t* samples, unsigned int len)
{
const std::scoped_lock lck(m_mutex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,19 @@ namespace HyperSonicDrivers::audio::sdl2

void reset() noexcept override;
void reset(const uint8_t id) noexcept override;
void reset(const mixer::eChannelGroup group) noexcept override;

void pause() noexcept override;
void pause(const uint8_t id) noexcept override;

void unpause() noexcept override;
void unpause(const uint8_t id) noexcept override;

bool isChannelActive(const uint8_t id) const noexcept override;
bool isActive(const uint8_t id) const noexcept override;
bool isPaused(const uint8_t id) const noexcept override;

bool isActive() const noexcept override;
bool isActive(const mixer::eChannelGroup group) override;

bool isChannelGroupMuted(const mixer::eChannelGroup group) const noexcept override;;
void muteChannelGroup(const mixer::eChannelGroup group) noexcept override;
Expand All @@ -58,9 +61,11 @@ namespace HyperSonicDrivers::audio::sdl2

void setMasterVolume(const uint8_t master_volume) noexcept override;

protected:
void updateChannelsVolumePan_() noexcept override;

private:
bool init_(SDL_AudioCallback callback, void* userdata);
void updateChannelsVolumePan_() noexcept;

size_t callback(uint8_t* samples, unsigned int len);
static void sdlCallback(void* this_, uint8_t* samples, int len);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace HyperSonicDrivers::audio::sdl2
if (m_buf.empty())
{
m_out->save_prepare(stream->getRate(), stream->isStereo());
m_buf.resize(m_mixer->getBufferSize());
m_buf.resize(m_mixer->buffer_size);
}

const size_t read = stream->readBuffer(m_buf.data(), m_buf.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
namespace HyperSonicDrivers::hardware
{
IHardware::IHardware(const std::shared_ptr<audio::IMixer>& mixer) :
m_mixer(mixer), m_output_rate(m_mixer->getOutputRate())
m_mixer(mixer)
{
if (m_mixer == nullptr)
{
utils::throwLogC<std::runtime_error>("mixer is null");
}

m_output_rate = m_mixer->freq;
}

IHardware::~IHardware()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ namespace HyperSonicDrivers::hardware::mt32
setAudioStream(std::make_shared<audio::streams::EmulatedStream>(
this,
isStereo(),
m_mixer->getOutputRate(),
m_mixer->freq,
setCallbackFrequency(timerFrequency)
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace HyperSonicDrivers::hardware::opl
setAudioStream(std::make_shared<audio::streams::EmulatedStream>(
this,
isStereo(),
m_mixer->getOutputRate(),
m_mixer->freq,
setCallbackFrequency(timerFrequency)
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ namespace HyperSonicDrivers::hardware::opl::mame
_opl = new ymfm::ymf262(_ymfm);

auto rate = _opl->sample_rate(OPL3_INTERNAL_FREQ);
_opl->sample_rate(m_mixer->getOutputRate());
_opl->sample_rate(m_mixer->freq);

_chip = ymf262_init(0, OPL3_INTERNAL_FREQ, m_mixer->getOutputRate());
_chip = ymf262_init(0, OPL3_INTERNAL_FREQ, m_mixer->freq);
//_init = _opl != nullptr;
m_init = _chip != nullptr;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace HyperSonicDrivers::hardware::opl::scummvm::dosbox
return false;

dbopl::InitTables();
m_rate = m_mixer->getOutputRate();
m_rate = m_mixer->freq;
m_emulator->Setup(m_rate);

if (type == OplType::DUAL_OPL2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace HyperSonicDrivers::hardware::opl::scummvm::mame
if (m_init)
return true;

_opl = makeAdLibOPL(m_mixer->getOutputRate());
_opl = makeAdLibOPL(m_mixer->freq);
memset(&_reg, 0, sizeof(_reg));
m_init = (_opl != nullptr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace HyperSonicDrivers::hardware::opl::scummvm::nuked
return true;

memset(&_reg, 0, sizeof(_reg));
_rate = m_mixer->getOutputRate();
_rate = m_mixer->freq;
OPL3_Reset(chip.get(), _rate);

if (type == OplType::DUAL_OPL2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ namespace HyperSonicDrivers::hardware

stop();
if (type == OplType::DUAL_OPL2)
_opl =std::make_unique<SurroundOPL>(m_mixer->getOutputRate());
_opl =std::make_unique<SurroundOPL>(m_mixer->freq);
else
_opl = std::make_unique<WoodyEmuOPL>(m_mixer->getOutputRate());
_opl = std::make_unique<WoodyEmuOPL>(m_mixer->freq);

m_init = _opl != nullptr;

Expand Down
Loading

0 comments on commit db7430b

Please sign in to comment.