diff --git a/CMakeLists.txt b/CMakeLists.txt index 2346ea2..298c6ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,6 +200,7 @@ add_library(boo include/boo/IWindow.hpp include/boo/IApplication.hpp include/boo/ThreadLocalPtr.hpp + include/boo/DeferredWindowEvents.hpp include/boo/System.hpp include/boo/boo.hpp InputDeviceClasses.cpp diff --git a/include/boo/DeferredWindowEvents.hpp b/include/boo/DeferredWindowEvents.hpp new file mode 100644 index 0000000..289840f --- /dev/null +++ b/include/boo/DeferredWindowEvents.hpp @@ -0,0 +1,273 @@ +#ifndef BOO_DEFERREDWINDOWEVENTS_HPP +#define BOO_DEFERREDWINDOWEVENTS_HPP + +#include +#include +#include + +namespace boo +{ + +template +struct DeferredWindowEvents : public IWindowCallback +{ + Receiver& m_rec; + std::mutex m_mt; + std::condition_variable m_resizeCv; + DeferredWindowEvents(Receiver& rec) : m_rec(rec) {} + + bool m_destroyed = false; + void destroyed() + { + m_destroyed = true; + } + + bool m_hasResize = false; + SWindowRect m_latestResize; + void resized(const SWindowRect& rect) + { + std::unique_lock lk(m_mt); + m_latestResize = rect; + m_hasResize = true; + m_resizeCv.wait_for(lk, std::chrono::milliseconds(500)); + } + + struct Command + { + enum class Type + { + MouseDown, + MouseUp, + MouseMove, + MouseEnter, + MouseLeave, + Scroll, + TouchDown, + TouchUp, + TouchMove, + CharKeyDown, + CharKeyUp, + SpecialKeyDown, + SpecialKeyUp, + ModKeyDown, + ModKeyUp + } m_type; + + SWindowCoord m_coord; + EMouseButton m_button; + EModifierKey m_mods; + SScrollDelta m_scroll; + STouchCoord m_tCoord; + uintptr_t m_tid; + unsigned long m_charcode; + ESpecialKey m_special; + bool m_isRepeat; + + void dispatch(Receiver& rec) const + { + switch (m_type) + { + case Type::MouseDown: + rec.mouseDown(m_coord, m_button, m_mods); + break; + case Type::MouseUp: + rec.mouseUp(m_coord, m_button, m_mods); + break; + case Type::MouseMove: + rec.mouseMove(m_coord); + break; + case Type::MouseEnter: + rec.mouseEnter(m_coord); + break; + case Type::MouseLeave: + rec.mouseLeave(m_coord); + break; + case Type::Scroll: + rec.scroll(m_coord, m_scroll); + break; + case Type::TouchDown: + rec.touchDown(m_tCoord, m_tid); + break; + case Type::TouchUp: + rec.touchUp(m_tCoord, m_tid); + break; + case Type::TouchMove: + rec.touchMove(m_tCoord, m_tid); + break; + case Type::CharKeyDown: + rec.charKeyDown(m_charcode, m_mods, m_isRepeat); + break; + case Type::CharKeyUp: + rec.charKeyUp(m_charcode, m_mods); + break; + case Type::SpecialKeyDown: + rec.specialKeyDown(m_special, m_mods, m_isRepeat); + break; + case Type::SpecialKeyUp: + rec.specialKeyUp(m_special, m_mods); + break; + case Type::ModKeyDown: + rec.modKeyDown(m_mods, m_isRepeat); + break; + case Type::ModKeyUp: + rec.modKeyUp(m_mods); + break; + default: break; + } + } + + Command(Type tp) : m_type(tp) {} + }; + std::vector m_cmds; + + void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseDown); + m_cmds.back().m_coord = coord; + m_cmds.back().m_button = button; + m_cmds.back().m_mods = mods; + } + + void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseUp); + m_cmds.back().m_coord = coord; + m_cmds.back().m_button = button; + m_cmds.back().m_mods = mods; + } + + void mouseMove(const SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseMove); + m_cmds.back().m_coord = coord; + } + + void mouseEnter(const SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseEnter); + m_cmds.back().m_coord = coord; + } + + void mouseLeave(const SWindowCoord& coord) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::MouseLeave); + m_cmds.back().m_coord = coord; + } + + void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::Scroll); + m_cmds.back().m_coord = coord; + m_cmds.back().m_scroll = scroll; + } + + void touchDown(const STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchDown); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void touchUp(const STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchUp); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void touchMove(const STouchCoord& coord, uintptr_t tid) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::TouchMove); + m_cmds.back().m_tCoord = coord; + m_cmds.back().m_tid = tid; + } + + void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::CharKeyDown); + m_cmds.back().m_charcode = charCode; + m_cmds.back().m_mods = mods; + m_cmds.back().m_isRepeat = isRepeat; + } + + void charKeyUp(unsigned long charCode, EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::CharKeyUp); + m_cmds.back().m_charcode = charCode; + m_cmds.back().m_mods = mods; + } + + void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::SpecialKeyDown); + m_cmds.back().m_special = key; + m_cmds.back().m_mods = mods; + m_cmds.back().m_isRepeat = isRepeat; + } + + void specialKeyUp(ESpecialKey key, EModifierKey mods) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::SpecialKeyUp); + m_cmds.back().m_special = key; + m_cmds.back().m_mods = mods; + } + + void modKeyDown(EModifierKey mod, bool isRepeat) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::ModKeyDown); + m_cmds.back().m_mods = mod; + m_cmds.back().m_isRepeat = isRepeat; + } + + void modKeyUp(EModifierKey mod) + { + std::unique_lock lk(m_mt); + m_cmds.emplace_back(Command::Type::ModKeyUp); + m_cmds.back().m_mods = mod; + } + + ITextInputCallback* getTextInputCallback() {return m_rec.getTextInputCallback();} + + void dispatchEvents() + { + std::unique_lock lk(m_mt); + bool destroyed = m_destroyed; + bool hasResize = m_hasResize; + if (hasResize) + m_hasResize = false; + SWindowRect latestResize = m_latestResize; + std::vector cmds; + m_cmds.swap(cmds); + lk.unlock(); + + if (destroyed) + { + m_rec.destroyed(); + return; + } + + if (hasResize) + m_rec.resized(latestResize, latestResize); + + for (const Command& cmd : cmds) + cmd.dispatch(m_rec); + } +}; + +} + +#endif // BOO_DEFERREDWINDOWEVENTS_HPP diff --git a/include/boo/audiodev/IAudioVoice.hpp b/include/boo/audiodev/IAudioVoice.hpp index 6c02d1f..e4ab240 100644 --- a/include/boo/audiodev/IAudioVoice.hpp +++ b/include/boo/audiodev/IAudioVoice.hpp @@ -56,6 +56,9 @@ struct IAudioVoice { virtual ~IAudioVoice() = default; + /** Set sample rate into voice (may result in audio discontinuities) */ + virtual void resetSampleRate(double sampleRate)=0; + /** Reset channel-gains to voice defaults */ virtual void setDefaultMatrixCoefficients()=0; diff --git a/include/boo/boo.hpp b/include/boo/boo.hpp index 91000c2..195bfc1 100644 --- a/include/boo/boo.hpp +++ b/include/boo/boo.hpp @@ -8,5 +8,6 @@ #include "inputdev/DualshockPad.hpp" #include "graphicsdev/IGraphicsCommandQueue.hpp" #include "graphicsdev/IGraphicsDataFactory.hpp" +#include "DeferredWindowEvents.hpp" #endif // BOO_HPP diff --git a/lib/audiodev/AudioVoice.cpp b/lib/audiodev/AudioVoice.cpp index afcc883..69a57d5 100644 --- a/lib/audiodev/AudioVoice.cpp +++ b/lib/audiodev/AudioVoice.cpp @@ -18,6 +18,7 @@ AudioVoice::~AudioVoice() void AudioVoice::setPitchRatio(double ratio) { + m_pitchRatio = ratio; if (m_dynamicRate) { soxr_error_t err = soxr_set_io_ratio(m_src, ratio, m_parent.mixInfo().m_periodFrames); @@ -52,11 +53,18 @@ AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IA double sampleRate, bool dynamicRate) : AudioVoice(root, parent, cb, dynamicRate) { - soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat); - soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0); + resetSampleRate(sampleRate); +} + +void AudioVoiceMono::resetSampleRate(double sampleRate) +{ + soxr_delete(m_src); + + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, m_parent.mixInfo().m_sampleFormat); + soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); soxr_error_t err; - m_src = soxr_create(sampleRate, parent.mixInfo().m_sampleRate, 1, + m_src = soxr_create(sampleRate, m_parent.mixInfo().m_sampleRate, 1, &err, &ioSpec, &qSpec, nullptr); if (err) @@ -66,6 +74,7 @@ AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IA } soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); + setPitchRatio(m_pitchRatio); } size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) @@ -146,11 +155,18 @@ AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent double sampleRate, bool dynamicRate) : AudioVoice(root, parent, cb, dynamicRate) { - soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat); - soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0); + resetSampleRate(sampleRate); +} + +void AudioVoiceStereo::resetSampleRate(double sampleRate) +{ + soxr_delete(m_src); + + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, m_parent.mixInfo().m_sampleFormat); + soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, m_dynamicRate ? SOXR_VR : 0); soxr_error_t err; - m_src = soxr_create(sampleRate, parent.mixInfo().m_sampleRate, 2, + m_src = soxr_create(sampleRate, m_parent.mixInfo().m_sampleRate, 2, &err, &ioSpec, &qSpec, nullptr); if (!m_src) @@ -160,6 +176,7 @@ AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent } soxr_set_input_fn(m_src, soxr_input_fn_t(SRCCallback), this, 0); + setPitchRatio(m_pitchRatio); } size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) diff --git a/lib/audiodev/AudioVoice.hpp b/lib/audiodev/AudioVoice.hpp index 2419a59..5c3eab6 100644 --- a/lib/audiodev/AudioVoice.hpp +++ b/lib/audiodev/AudioVoice.hpp @@ -33,7 +33,8 @@ protected: IAudioVoiceCallback* m_cb; /* Sample-rate converter */ - soxr_t m_src; + soxr_t m_src = nullptr; + double m_pitchRatio = 1.0; bool m_dynamicRate; /* Running bool */ @@ -56,6 +57,7 @@ public: class AudioVoiceMono : public AudioVoice { AudioMatrixMono m_matrix; + void resetSampleRate(double sampleRate); static size_t SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t requestedLen); @@ -75,6 +77,7 @@ public: class AudioVoiceStereo : public AudioVoice { AudioMatrixStereo m_matrix; + void resetSampleRate(double sampleRate); static size_t SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t requestedLen);