Make audio overload types float-only, initial boo2 switchover

This commit is contained in:
Jack Andersen 2020-09-28 10:42:51 -10:00
parent 5112228abd
commit 6da262355a
16 changed files with 112 additions and 237 deletions

View File

@ -77,12 +77,8 @@ add_library(amuse
include/amuse/VolumeTable.hpp
)
target_atdna(amuse atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
target_atdna(amuse atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
target_atdna(amuse atdna_AudioGroupSampleDirectory.cpp include/amuse/AudioGroupSampleDirectory.hpp)
target_include_directories(amuse PUBLIC include)
target_link_libraries(amuse
target_link_libraries(amuse PUBLIC
athena-core
lzokay
${ZLIB_LIBRARIES}
@ -92,11 +88,15 @@ if(NX)
target_sources(amuse PRIVATE include/switch_math.hpp)
endif()
if(TARGET boo)
if(TARGET boo2)
target_sources(amuse PRIVATE lib/BooBackend.cpp include/amuse/BooBackend.hpp)
target_link_libraries(amuse boo)
target_link_libraries(amuse PUBLIC boo2)
endif()
target_atdna(amuse atdna_AudioGroupPool.cpp include/amuse/AudioGroupPool.hpp)
target_atdna(amuse atdna_AudioGroupProject.cpp include/amuse/AudioGroupProject.hpp)
target_atdna(amuse atdna_AudioGroupSampleDirectory.cpp include/amuse/AudioGroupSampleDirectory.hpp)
if (MSVC)
target_compile_options(amuse PRIVATE
# Enforce various standards compliant behavior.

View File

@ -27,7 +27,7 @@ namespace amuse {
class Engine;
}
namespace boo {
namespace boo2 {
struct IAudioVoiceEngine;
}

View File

@ -854,7 +854,7 @@ void EventCallback::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods,
m_app.m_engine->setVolume(m_app.m_volume);
m_app.m_updateDisp = true;
break;
case boo::ESpecialKey::Esc:
case boo2::Keycode::ESC:
m_app.m_breakout = true;
break;
default:

View File

@ -13,10 +13,10 @@
#include "amuse/IBackendSubmix.hpp"
#include "amuse/IBackendVoiceAllocator.hpp"
#include <boo/audiodev/IAudioSubmix.hpp>
#include <boo/audiodev/IAudioVoiceEngine.hpp>
#include <boo/audiodev/IMIDIReader.hpp>
#include <boo/audiodev/MIDIDecoder.hpp>
#include "boo2/audiodev/IAudioSubmix.hpp"
#include "boo2/audiodev/IAudioVoiceEngine.hpp"
#include "boo2/audiodev/IMIDIReader.hpp"
#include "boo2/audiodev/MIDIDecoder.hpp"
namespace amuse {
@ -24,19 +24,19 @@ namespace amuse {
class BooBackendVoice : public IBackendVoice {
friend class BooBackendVoiceAllocator;
Voice& m_clientVox;
struct VoiceCallback : boo::IAudioVoiceCallback {
struct VoiceCallback : boo2::IAudioVoiceCallback {
BooBackendVoice& m_parent;
void preSupplyAudio(boo::IAudioVoice& voice, double dt) override;
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data) override;
void preSupplyAudio(boo2::IAudioVoice& voice, double dt) override;
size_t supplyAudio(boo2::IAudioVoice& voice, size_t frames, int16_t* data) override;
void routeAudio(size_t frames, size_t channels, double dt, int busId, int16_t* in, int16_t* out) override;
void routeAudio(size_t frames, size_t channels, double dt, int busId, int32_t* in, int32_t* out) override;
void routeAudio(size_t frames, size_t channels, double dt, int busId, float* in, float* out) override;
VoiceCallback(BooBackendVoice& parent) : m_parent(parent) {}
} m_cb;
boo::ObjToken<boo::IAudioVoice> m_booVoice;
boo2::ObjToken<boo2::IAudioVoice> m_booVoice;
public:
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch);
BooBackendVoice(boo2::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch);
void resetSampleRate(double sampleRate) override;
void resetChannelLevels() override;
@ -51,35 +51,30 @@ class BooBackendSubmix : public IBackendSubmix {
friend class BooBackendVoiceAllocator;
friend class BooBackendVoice;
Submix& m_clientSmx;
struct SubmixCallback : boo::IAudioSubmixCallback {
struct SubmixCallback : boo2::IAudioSubmixCallback {
BooBackendSubmix& m_parent;
bool canApplyEffect() const override;
void applyEffect(int16_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
double sampleRate) const override;
void applyEffect(int32_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
double sampleRate) const override;
void applyEffect(float* audio, size_t frameCount, const boo::ChannelMap& chanMap, double sampleRate) const override;
void applyEffect(float* audio, size_t frameCount, const boo2::ChannelMap& chanMap, double sampleRate) const override;
void resetOutputSampleRate(double sampleRate) override;
SubmixCallback(BooBackendSubmix& parent) : m_parent(parent) {}
} m_cb;
boo::ObjToken<boo::IAudioSubmix> m_booSubmix;
boo2::ObjToken<boo2::IAudioSubmix> m_booSubmix;
public:
BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId);
BooBackendSubmix(boo2::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId);
void setSendLevel(IBackendSubmix* submix, float level, bool slew) override;
double getSampleRate() const override;
SubmixFormat getSampleFormat() const override;
};
/** Backend MIDI event reader for controlling sequencer with external hardware / software */
class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader {
class BooBackendMIDIReader : public IMIDIReader, public boo2::IMIDIReader {
friend class BooBackendVoiceAllocator;
protected:
Engine& m_engine;
std::unordered_map<std::string, std::unique_ptr<boo::IMIDIIn>> m_midiIns;
std::unique_ptr<boo::IMIDIIn> m_virtualIn;
boo::MIDIDecoder m_decoder;
std::unordered_map<std::string, std::unique_ptr<boo2::IMIDIIn>> m_midiIns;
std::unique_ptr<boo2::IMIDIIn> m_virtualIn;
boo2::MIDIDecoder m_decoder;
bool m_useLock;
std::list<std::pair<double, std::vector<uint8_t>>> m_queue;
@ -127,15 +122,15 @@ public:
};
/** Backend voice allocator implementation for boo mixer */
class BooBackendVoiceAllocator : public IBackendVoiceAllocator, public boo::IAudioVoiceEngineCallback {
class BooBackendVoiceAllocator : public IBackendVoiceAllocator, public boo2::IAudioVoiceEngineCallback {
friend class BooBackendMIDIReader;
protected:
boo::IAudioVoiceEngine& m_booEngine;
boo2::IAudioVoiceEngine& m_booEngine;
Engine* m_cbInterface = nullptr;
public:
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
BooBackendVoiceAllocator(boo2::IAudioVoiceEngine& booEngine);
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch) override;
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut, int busId) override;
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices() override;
@ -143,7 +138,7 @@ public:
void setCallbackInterface(Engine* engine) override;
AudioChannelSet getAvailableSet() override;
void setVolume(float vol) override;
void on5MsInterval(boo::IAudioVoiceEngine& engine, double dt) override;
void onPumpCycleComplete(boo::IAudioVoiceEngine& engine) override;
void on5MsInterval(boo2::IAudioVoiceEngine& engine, double dt) override;
void onPumpCycleComplete(boo2::IAudioVoiceEngine& engine) override;
};
} // namespace amuse

View File

@ -368,23 +368,6 @@ inline int CompareCaseInsensitive(const SystemChar* a, const SystemChar* b) {
#endif
}
template <typename T>
constexpr T ClampFull(float in) noexcept {
if (std::is_floating_point<T>()) {
return in;
} else {
constexpr T MAX = std::numeric_limits<T>::max();
constexpr T MIN = std::numeric_limits<T>::min();
if (in < MIN)
return MIN;
else if (in > MAX)
return MAX;
else
return in;
}
}
#ifndef M_PIF
#define M_PIF 3.14159265358979323846f /* pi */
#endif

View File

@ -5,16 +5,11 @@ struct ChannelMap;
enum class EffectType { Invalid, ReverbStd, ReverbHi, Delay, Chorus, EffectTypeMAX };
class EffectBaseTypeless {
class EffectBase {
public:
virtual ~EffectBaseTypeless() = default;
virtual ~EffectBase() = default;
virtual void resetOutputSampleRate(double sampleRate) = 0;
virtual EffectType Isa() const = 0;
};
template <typename T>
class EffectBase : public EffectBaseTypeless {
public:
virtual void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) = 0;
virtual void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) = 0;
};
} // namespace amuse

View File

@ -8,7 +8,6 @@
#include "amuse/IBackendVoice.hpp"
namespace amuse {
template <typename T>
class EffectChorusImp;
#define AMUSE_CHORUS_NUM_BLOCKS 3
@ -31,13 +30,11 @@ class EffectChorus {
uint32_t x98_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */
bool m_dirty = true; /**< needs update of internal parameter data */
template <typename T>
friend class EffectChorusImp;
EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
public:
template <typename T>
using ImpType = EffectChorusImp<T>;
using ImpType = EffectChorusImp;
void setBaseDelay(uint32_t baseDelay) {
baseDelay = std::clamp(baseDelay, 5u, 15u);
@ -68,13 +65,12 @@ public:
};
/** Type-specific implementation of chorus effect */
template <typename T>
class EffectChorusImp : public EffectBase<T>, public EffectChorus {
class EffectChorusImp : public EffectBase, public EffectChorus {
/** Evenly-allocated pointer-table for each channel's delay */
std::array<std::array<T*, AMUSE_CHORUS_NUM_BLOCKS>, NumChannels> x0_lastChans{};
std::array<std::array<float*, AMUSE_CHORUS_NUM_BLOCKS>, NumChannels> x0_lastChans{};
uint8_t x24_currentLast = 1; /**< Last 5ms block-idx to be processed */
std::array<std::array<T, 4>, NumChannels> x28_oldChans{}; /**< Unprocessed history of previous 4 samples */
std::array<std::array<float, 4>, NumChannels> x28_oldChans{}; /**< Unprocessed history of previous 4 samples */
uint32_t x58_currentPosLo = 0; /**< 16.7 fixed-point low-part of sample index */
uint32_t x5c_currentPosHi = 0; /**< 16.7 fixed-point high-part of sample index */
@ -84,9 +80,9 @@ class EffectChorusImp : public EffectBase<T>, public EffectChorus {
uint32_t x68_pitchOffsetPeriod; /**< intermediate block window quantity for calculating SRC state */
struct SrcInfo {
T* x6c_dest; /**< selected channel's live buffer */
T* x70_smpBase; /**< selected channel's delay buffer */
T* x74_old; /**< selected channel's 4-sample history buffer */
float* x6c_dest; /**< selected channel's live buffer */
float* x70_smpBase; /**< selected channel's delay buffer */
float* x74_old; /**< selected channel's 4-sample history buffer */
uint32_t x78_posLo; /**< 16.7 fixed-point low-part of sample index */
uint32_t x7c_posHi; /**< 16.7 fixed-point high-part of sample index */
uint32_t x80_pitchLo; /**< 16.7 fixed-point low-part of sample-rate conversion differential */
@ -111,7 +107,7 @@ public:
EffectChorusImp(const EffectChorusInfo& info, double sampleRate)
: EffectChorusImp(info.baseDelay, info.variation, info.period, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override;
void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) override;
void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); }
EffectType Isa() const override { return EffectType::Chorus; }

View File

@ -10,7 +10,6 @@
#include "amuse/IBackendVoice.hpp"
namespace amuse {
template <typename T>
class EffectDelayImp;
/** Parameters needed to create EffectDelay */
@ -50,8 +49,7 @@ protected:
bool m_dirty = true; /**< needs update of internal parameter data */
public:
template <typename T>
using ImpType = EffectDelayImp<T>;
using ImpType = EffectDelayImp;
void setDelay(uint32_t delay) {
delay = std::clamp(delay, 10u, 5000u);
@ -102,14 +100,13 @@ public:
};
/** Type-specific implementation of delay effect */
template <typename T>
class EffectDelayImp : public EffectBase<T>, public EffectDelay {
class EffectDelayImp : public EffectBase, public EffectDelay {
std::array<uint32_t, NumChannels> x0_currentSize; /**< per-channel delay-line buffer sizes */
std::array<uint32_t, NumChannels> xc_currentPos; /**< per-channel block-index */
std::array<uint32_t, NumChannels> x18_currentFeedback; /**< [0, 128] feedback attenuator */
std::array<uint32_t, NumChannels> x24_currentOutput; /**< [0, 128] total attenuator */
std::array<std::unique_ptr<T[]>, NumChannels> x30_chanLines; /**< delay-line buffers for each channel */
std::array<std::unique_ptr<float[]>, NumChannels> x30_chanLines; /**< delay-line buffers for each channel */
uint32_t m_sampsPerMs; /**< canonical count of samples per ms for the current backend */
uint32_t m_blockSamples; /**< count of samples in a 5ms block */
@ -120,7 +117,7 @@ public:
EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate);
EffectDelayImp(const EffectDelayInfo& info, double sampleRate);
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override;
void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) override;
void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); }
EffectType Isa() const override { return EffectType::Delay; }

View File

@ -49,10 +49,7 @@ struct ReverbDelayLine {
void setdelay(int32_t delay);
};
template <typename T>
class EffectReverbStdImp;
template <typename T>
class EffectReverbHiImp;
/** Reverb effect with configurable reflection filtering */
@ -66,15 +63,12 @@ protected:
float x150_x1d8_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */
bool m_dirty = true; /**< needs update of internal parameter data */
template <typename T>
friend class EffectReverbStdImp;
template <typename T>
friend class EffectReverbHiImp;
EffectReverbStd(float coloration, float mix, float time, float damping, float preDelay);
public:
template <typename T>
using ImpType = EffectReverbStdImp<T>;
using ImpType = EffectReverbStdImp;
void setColoration(float coloration) {
x140_x1c8_coloration = std::clamp(coloration, 0.f, 1.f);
@ -119,13 +113,11 @@ public:
class EffectReverbHi : public EffectReverbStd {
float x1dc_crosstalk; /**< [0.0, 1.0] factor defining how much reflections are allowed to bleed to other channels */
template <typename T>
friend class EffectReverbHiImp;
EffectReverbHi(float coloration, float mix, float time, float damping, float preDelay, float crosstalk);
public:
template <typename T>
using ImpType = EffectReverbHiImp<T>;
using ImpType = EffectReverbHiImp;
void setCrosstalk(float crosstalk) {
x1dc_crosstalk = std::clamp(crosstalk, 0.f, 1.f);
@ -144,8 +136,7 @@ public:
};
/** Standard-quality 2-stage reverb */
template <typename T>
class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd {
class EffectReverbStdImp : public EffectBase, public EffectReverbStd {
using CombCoeffArray = std::array<std::array<float, 2>, NumChannels>;
using ReverbDelayArray = std::array<std::array<ReverbDelayLine, 2>, NumChannels>;
using PreDelayArray = std::array<std::unique_ptr<float[]>, NumChannels>;
@ -170,15 +161,14 @@ public:
EffectReverbStdImp(const EffectReverbStdInfo& info, double sampleRate)
: EffectReverbStdImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override;
void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) override;
void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); }
EffectType Isa() const override { return EffectType::ReverbStd; }
};
/** High-quality 3-stage reverb with per-channel low-pass and crosstalk */
template <typename T>
class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi {
class EffectReverbHiImp : public EffectBase, public EffectReverbHi {
using AllPassDelayLines = std::array<std::array<ReverbDelayLine, 2>, NumChannels>;
using CombCoefficients = std::array<std::array<float, 3>, NumChannels>;
using CombDelayLines = std::array<std::array<ReverbDelayLine, 3>, NumChannels>;
@ -201,8 +191,8 @@ class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi {
double m_sampleRate; /**< copy of sample rate */
void _setup(double sampleRate);
void _update();
void _handleReverb(T* audio, int chanIdx, int chanCount, int sampleCount);
void _doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount);
void _handleReverb(float* audio, int chanIdx, int chanCount, int sampleCount);
void _doCrosstalk(float* audio, float wet, float dry, int chanCount, int sampleCount);
public:
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
@ -210,7 +200,7 @@ public:
EffectReverbHiImp(const EffectReverbHiInfo& info, double sampleRate)
: EffectReverbHiImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, info.crosstalk, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) override;
void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) override;
void resetOutputSampleRate(double sampleRate) override { _setup(sampleRate); }
EffectType Isa() const override { return EffectType::ReverbHi; }

View File

@ -2,8 +2,6 @@
namespace amuse {
enum class SubmixFormat { Int16, Int32, Float };
/** Client-implemented submix instance */
class IBackendSubmix {
public:
@ -14,8 +12,5 @@ public:
/** Amuse gets fixed sample rate of submix this way */
virtual double getSampleRate() const = 0;
/** Amuse gets fixed sample format of submix this way */
virtual SubmixFormat getSampleFormat() const = 0;
};
} // namespace amuse

View File

@ -23,36 +23,23 @@ class Submix {
friend class Sequencer;
Engine& m_root;
std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */
std::vector<std::unique_ptr<EffectBase>> m_effectStack; /**< Ordered list of effects to apply to submix */
public:
Submix(Engine& engine);
/** Construct new effect */
template <class T, class... Args>
std::unique_ptr<EffectBaseTypeless> _makeEffect(Args... args) {
switch (m_backendSubmix->getSampleFormat()) {
case SubmixFormat::Int16: {
using ImpType = typename T::template ImpType<int16_t>;
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
case SubmixFormat::Int32:
default: {
using ImpType = typename T::template ImpType<int32_t>;
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
case SubmixFormat::Float: {
using ImpType = typename T::template ImpType<float>;
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
}
std::unique_ptr<EffectBase> _makeEffect(Args... args) {
using ImpType = typename T::ImpType;
return std::make_unique<ImpType>(args..., m_backendSubmix->getSampleRate());
}
/** Add new effect to effect stack and assume ownership */
template <class T, class... Args>
T& makeEffect(Args... args) {
m_effectStack.push_back(_makeEffect<T>(args...));
return static_cast<typename T::template ImpType<float>&>(*m_effectStack.back());
return static_cast<typename T::ImpType&>(*m_effectStack.back());
}
/** Add new chorus effect to effect stack and assume ownership */
@ -85,12 +72,6 @@ public:
/** Returns true when an effect callback is bound */
bool canApplyEffect() const { return m_effectStack.size() != 0; }
/** in/out transformation entry for audio effect */
void applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const;
/** in/out transformation entry for audio effect */
void applyEffect(int32_t* audio, size_t frameCount, const ChannelMap& chanMap) const;
/** in/out transformation entry for audio effect */
void applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) const;
@ -99,6 +80,6 @@ public:
Engine& getEngine() { return m_root; }
std::vector<std::unique_ptr<EffectBaseTypeless>>& getEffectStack() { return m_effectStack; }
std::vector<std::unique_ptr<EffectBase>>& getEffectStack() { return m_effectStack; }
};
} // namespace amuse

View File

@ -6,11 +6,11 @@
namespace amuse {
void BooBackendVoice::VoiceCallback::preSupplyAudio(boo::IAudioVoice&, double dt) {
void BooBackendVoice::VoiceCallback::preSupplyAudio(boo2::IAudioVoice&, double dt) {
m_parent.m_clientVox.preSupplyAudio(dt);
}
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&, size_t frames, int16_t* data) {
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo2::IAudioVoice&, size_t frames, int16_t* data) {
return m_parent.m_clientVox.supplyAudio(frames, data);
}
@ -29,7 +29,7 @@ void BooBackendVoice::VoiceCallback::routeAudio(size_t frames, size_t channels,
m_parent.m_clientVox.routeAudio(frames, dt, busId, in, out);
}
BooBackendVoice::BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch)
BooBackendVoice::BooBackendVoice(boo2::IAudioVoiceEngine& engine, Voice& clientVox, double sampleRate, bool dynamicPitch)
: m_clientVox(clientVox), m_cb(*this), m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch)) {}
void BooBackendVoice::resetSampleRate(double sampleRate) { m_booVoice->resetSampleRate(sampleRate); }
@ -49,17 +49,7 @@ void BooBackendVoice::stop() { m_booVoice->stop(); }
bool BooBackendSubmix::SubmixCallback::canApplyEffect() const { return m_parent.m_clientSmx.canApplyEffect(); }
void BooBackendSubmix::SubmixCallback::applyEffect(int16_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
double) const {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
}
void BooBackendSubmix::SubmixCallback::applyEffect(int32_t* audio, size_t frameCount, const boo::ChannelMap& chanMap,
double) const {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
}
void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, size_t frameCount, const boo::ChannelMap& chanMap,
void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, size_t frameCount, const boo2::ChannelMap& chanMap,
double) const {
return m_parent.m_clientSmx.applyEffect(audio, frameCount, reinterpret_cast<const ChannelMap&>(chanMap));
}
@ -68,7 +58,7 @@ void BooBackendSubmix::SubmixCallback::resetOutputSampleRate(double sampleRate)
m_parent.m_clientSmx.resetOutputSampleRate(sampleRate);
}
BooBackendSubmix::BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId)
BooBackendSubmix::BooBackendSubmix(boo2::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut, int busId)
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(engine.allocateNewSubmix(mainOut, &m_cb, busId)) {}
void BooBackendSubmix::setSendLevel(IBackendSubmix* submix, float level, bool slew) {
@ -78,8 +68,6 @@ void BooBackendSubmix::setSendLevel(IBackendSubmix* submix, float level, bool sl
double BooBackendSubmix::getSampleRate() const { return m_booSubmix->getSampleRate(); }
SubmixFormat BooBackendSubmix::getSampleFormat() const { return SubmixFormat(m_booSubmix->getSampleFormat()); }
BooBackendMIDIReader::~BooBackendMIDIReader() {}
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, bool useLock)
@ -247,7 +235,7 @@ void BooBackendMIDIReader::stopSeq() {}
void BooBackendMIDIReader::reset() {}
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine) : m_booEngine(booEngine) {
BooBackendVoiceAllocator::BooBackendVoiceAllocator(boo2::IAudioVoiceEngine& booEngine) : m_booEngine(booEngine) {
booEngine.setCallbackInterface(this);
}
@ -274,12 +262,12 @@ AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChanne
void BooBackendVoiceAllocator::setVolume(float vol) { m_booEngine.setVolume(vol); }
void BooBackendVoiceAllocator::on5MsInterval(boo::IAudioVoiceEngine& engine, double dt) {
void BooBackendVoiceAllocator::on5MsInterval(boo2::IAudioVoiceEngine& engine, double dt) {
if (m_cbInterface)
m_cbInterface->_on5MsInterval(*this, dt);
}
void BooBackendVoiceAllocator::onPumpCycleComplete(boo::IAudioVoiceEngine& engine) {
void BooBackendVoiceAllocator::onPumpCycleComplete(boo2::IAudioVoiceEngine& engine) {
if (m_cbInterface)
m_cbInterface->_onPumpCycleComplete(*this);
}

View File

@ -145,21 +145,19 @@ EffectChorus::EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t peri
, x94_variation(std::clamp(variation, 0u, 5u))
, x98_period(std::clamp(period, 500u, 10000u)) {}
template <typename T>
EffectChorusImp<T>::EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate)
EffectChorusImp::EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate)
: EffectChorus(baseDelay, variation, period) {
_setup(sampleRate);
}
template <typename T>
void EffectChorusImp<T>::_setup(double sampleRate) {
void EffectChorusImp::_setup(double sampleRate) {
m_sampsPerMs = std::ceil(sampleRate / 1000.0);
m_blockSamples = m_sampsPerMs * 5;
delete[] x0_lastChans[0][0];
const size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
T* buf = new T[chanPitch * NumChannels]();
auto* buf = new float[chanPitch * NumChannels]();
for (size_t c = 0; c < NumChannels; ++c) {
for (size_t i = 0; i < AMUSE_CHORUS_NUM_BLOCKS; ++i) {
@ -172,8 +170,7 @@ void EffectChorusImp<T>::_setup(double sampleRate) {
m_dirty = true;
}
template <typename T>
void EffectChorusImp<T>::_update() {
void EffectChorusImp::_update() {
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
size_t fifteenSamps = 15 * m_sampsPerMs;
@ -189,19 +186,17 @@ void EffectChorusImp<T>::_update() {
m_dirty = false;
}
template <typename T>
EffectChorusImp<T>::~EffectChorusImp() {
EffectChorusImp::~EffectChorusImp() {
delete[] x0_lastChans[0][0];
}
template <typename T>
void EffectChorusImp<T>::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount) {
void EffectChorusImp::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount) {
float old1 = x74_old[0];
float old2 = x74_old[1];
float old3 = x74_old[2];
float cur = x70_smpBase[x7c_posHi];
T* dest = x6c_dest;
auto* dest = x6c_dest;
for (size_t i = 0; i < blockSamples; ++i) {
const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc];
@ -212,7 +207,7 @@ void EffectChorusImp<T>::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount)
++x7c_posHi;
if (x7c_posHi == x88_trigger)
x7c_posHi = x8c_target;
*dest = ClampFull<T>(selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur);
*dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur;
dest += chanCount;
old1 = old2;
old2 = old3;
@ -220,7 +215,7 @@ void EffectChorusImp<T>::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount)
cur = x70_smpBase[x7c_posHi];
} else {
x78_posLo = ovrTest;
*dest = ClampFull<T>(selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur);
*dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur;
dest += chanCount;
}
}
@ -230,14 +225,13 @@ void EffectChorusImp<T>::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount)
x74_old[2] = old3;
}
template <typename T>
void EffectChorusImp<T>::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount) {
void EffectChorusImp::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount) {
float old1 = x74_old[0];
float old2 = x74_old[1];
float old3 = x74_old[2];
float cur = x70_smpBase[x7c_posHi];
T* dest = x6c_dest;
auto* dest = x6c_dest;
for (size_t i = 0; i < blockSamples; ++i) {
const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc];
++x7c_posHi;
@ -258,14 +252,14 @@ void EffectChorusImp<T>::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount)
if (x7c_posHi == x88_trigger)
x7c_posHi = x8c_target;
*dest = ClampFull<T>(selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur);
*dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur;
dest += chanCount;
cur = x70_smpBase[x7c_posHi];
} else {
x78_posLo = ovrTest;
*dest = ClampFull<T>(selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur);
*dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur;
dest += chanCount;
old1 = old2;
@ -284,8 +278,7 @@ void EffectChorusImp<T>::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount)
x74_old[2] = old3;
}
template <typename T>
void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) {
void EffectChorusImp::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) {
if (m_dirty)
_update();
@ -293,12 +286,12 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
for (size_t f = 0; f < frameCount;) {
uint8_t next = x24_currentLast + 1;
uint8_t buf = next % 3;
std::array<T*, 8> bufs{
std::array<float*, 8> bufs{
x0_lastChans[0][buf], x0_lastChans[1][buf], x0_lastChans[2][buf], x0_lastChans[3][buf],
x0_lastChans[4][buf], x0_lastChans[5][buf], x0_lastChans[6][buf], x0_lastChans[7][buf],
};
T* inBuf = audio;
auto* inBuf = audio;
for (size_t s = 0; f < frameCount && s < m_blockSamples; ++s, ++f) {
for (size_t c = 0; c < chanMap.m_channelCount && c < NumChannels; ++c) {
*bufs[c]++ = *inBuf++;
@ -314,7 +307,7 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
x60_pitchOffset = -x60_pitchOffset;
}
T* outBuf = audio;
auto* outBuf = audio;
size_t bs = std::min(remFrames, size_t(m_blockSamples));
for (size_t c = 0; c < chanMap.m_channelCount && c < NumChannels; ++c) {
x6c_src.x7c_posHi = x5c_currentPosHi;
@ -348,7 +341,4 @@ void EffectChorusImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelM
}
}
template class EffectChorusImp<int16_t>;
template class EffectChorusImp<int32_t>;
template class EffectChorusImp<float>;
} // namespace amuse

View File

@ -7,8 +7,7 @@
namespace amuse {
template <typename T>
EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate) {
EffectDelayImp::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate) {
initDelay = std::clamp(initDelay, 10u, 5000u);
initFeedback = std::clamp(initFeedback, 0u, 100u);
initOutput = std::clamp(initOutput, 0u, 100u);
@ -20,8 +19,7 @@ EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uin
_setup(sampleRate);
}
template <typename T>
EffectDelayImp<T>::EffectDelayImp(const EffectDelayInfo& info, double sampleRate) {
EffectDelayImp::EffectDelayImp(const EffectDelayInfo& info, double sampleRate) {
for (size_t i = 0; i < NumChannels; ++i) {
x3c_delay[i] = std::clamp(info.delay[i], 10u, 5000u);
x48_feedback[i] = std::clamp(info.feedback[i], 0u, 100u);
@ -31,40 +29,37 @@ EffectDelayImp<T>::EffectDelayImp(const EffectDelayInfo& info, double sampleRate
_setup(sampleRate);
}
template <typename T>
void EffectDelayImp<T>::_setup(double sampleRate) {
void EffectDelayImp::_setup(double sampleRate) {
m_sampsPerMs = std::ceil(sampleRate / 1000.0);
m_blockSamples = m_sampsPerMs * 5;
_update();
}
template <typename T>
void EffectDelayImp<T>::_update() {
void EffectDelayImp::_update() {
for (size_t i = 0; i < NumChannels; ++i) {
x0_currentSize[i] = ((x3c_delay[i] - 5) * m_sampsPerMs + 159) / 160;
xc_currentPos[i] = 0;
x18_currentFeedback[i] = x48_feedback[i] * 128 / 100;
x24_currentOutput[i] = x54_output[i] * 128 / 100;
x30_chanLines[i] = std::make_unique<T[]>(m_blockSamples * x0_currentSize[i]);
x30_chanLines[i] = std::make_unique<float[]>(m_blockSamples * x0_currentSize[i]);
}
m_dirty = false;
}
template <typename T>
void EffectDelayImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) {
void EffectDelayImp::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) {
if (m_dirty)
_update();
for (size_t f = 0; f < frameCount;) {
for (unsigned c = 0; c < chanMap.m_channelCount; ++c) {
T* chanAud = audio + c;
auto* chanAud = audio + c;
for (unsigned i = 0; i < m_blockSamples && f < frameCount; ++i, ++f) {
T& liveSamp = chanAud[chanMap.m_channelCount * i];
T& samp = x30_chanLines[c][xc_currentPos[c] * m_blockSamples + i];
samp = ClampFull<T>(samp * x18_currentFeedback[c] / 128 + liveSamp);
auto& liveSamp = chanAud[chanMap.m_channelCount * i];
auto& samp = x30_chanLines[c][xc_currentPos[c] * m_blockSamples + i];
samp = samp * x18_currentFeedback[c] / 128 + liveSamp;
liveSamp = samp * x24_currentOutput[c] / 128;
}
xc_currentPos[c] = (xc_currentPos[c] + 1) % x0_currentSize[c];
@ -73,7 +68,4 @@ void EffectDelayImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMa
}
}
template class EffectDelayImp<int16_t>;
template class EffectDelayImp<int32_t>;
template class EffectDelayImp<float>;
} // namespace amuse

View File

@ -62,21 +62,18 @@ EffectReverbStd::EffectReverbStd(float coloration, float mix, float time, float
EffectReverbHi::EffectReverbHi(float coloration, float mix, float time, float damping, float preDelay, float crosstalk)
: EffectReverbStd(coloration, mix, time, damping, preDelay), x1dc_crosstalk(std::clamp(crosstalk, 0.f, 1.0f)) {}
template <typename T>
EffectReverbStdImp<T>::EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay,
EffectReverbStdImp::EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay,
double sampleRate)
: EffectReverbStd(coloration, mix, time, damping, preDelay) {
_setup(sampleRate);
}
template <typename T>
void EffectReverbStdImp<T>::_setup(double sampleRate) {
void EffectReverbStdImp::_setup(double sampleRate) {
m_sampleRate = sampleRate;
_update();
}
template <typename T>
void EffectReverbStdImp<T>::_update() {
void EffectReverbStdImp::_update() {
float timeSamples = x148_x1d0_time * m_sampleRate;
double rateRatio = m_sampleRate / NativeSampleRate;
for (size_t c = 0; c < NumChannels; ++c) {
@ -122,8 +119,7 @@ void EffectReverbStdImp<T>::_update() {
m_dirty = false;
}
template <typename T>
void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) {
void EffectReverbStdImp::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) {
if (m_dirty)
_update();
@ -212,7 +208,7 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
linesAP[1].x4_outPoint = 0;
/* Mix out */
audio[s * chanMap.m_channelCount + c] = ClampFull<T>(dampWet * allPass + dampDry * sample);
audio[s * chanMap.m_channelCount + c] = dampWet * allPass + dampDry * sample;
}
x130_preDelayPtr[c] = preDelayPtr;
}
@ -220,21 +216,18 @@ void EffectReverbStdImp<T>::applyEffect(T* audio, size_t frameCount, const Chann
}
}
template <typename T>
EffectReverbHiImp<T>::EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay,
EffectReverbHiImp::EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay,
float crosstalk, double sampleRate)
: EffectReverbHi(coloration, mix, time, damping, preDelay, crosstalk) {
_setup(sampleRate);
}
template <typename T>
void EffectReverbHiImp<T>::_setup(double sampleRate) {
void EffectReverbHiImp::_setup(double sampleRate) {
m_sampleRate = sampleRate;
_update();
}
template <typename T>
void EffectReverbHiImp<T>::_update() {
void EffectReverbHiImp::_update() {
const float timeSamples = x148_x1d0_time * m_sampleRate;
const double rateRatio = m_sampleRate / NativeSampleRate;
@ -287,8 +280,7 @@ void EffectReverbHiImp<T>::_update() {
m_dirty = false;
}
template <typename T>
void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sampleCount) {
void EffectReverbHiImp::_handleReverb(float* audio, int c, int chanCount, int sampleCount) {
const float dampWet = x19c_level * 0.6f;
const float dampDry = 0.6f - dampWet;
@ -401,28 +393,26 @@ void EffectReverbHiImp<T>::_handleReverb(T* audio, int c, int chanCount, int sam
lineLP.x4_outPoint = 0;
/* Mix out */
audio[s * chanCount + c] = ClampFull<T>(dampWet * allPass + dampDry * sample);
audio[s * chanCount + c] = dampWet * allPass + dampDry * sample;
}
x1b8_preDelayPtr[c] = preDelayPtr;
}
template <typename T>
void EffectReverbHiImp<T>::_doCrosstalk(T* audio, float wet, float dry, int chanCount, int sampleCount) {
void EffectReverbHiImp::_doCrosstalk(float* audio, float wet, float dry, int chanCount, int sampleCount) {
for (int i = 0; i < sampleCount; ++i) {
T* base = &audio[chanCount * i];
auto* base = &audio[chanCount * i];
float allWet = 0;
for (int c = 0; c < chanCount; ++c) {
allWet += base[c] * wet;
base[c] *= dry;
}
for (int c = 0; c < chanCount; ++c)
base[c] = ClampFull<T>(base[c] + allWet);
base[c] = base[c] + allWet;
}
}
template <typename T>
void EffectReverbHiImp<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap) {
void EffectReverbHiImp::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) {
if (m_dirty)
_update();
@ -439,11 +429,4 @@ void EffectReverbHiImp<T>::applyEffect(T* audio, size_t frameCount, const Channe
}
}
template class EffectReverbStdImp<int16_t>;
template class EffectReverbStdImp<int32_t>;
template class EffectReverbStdImp<float>;
template class EffectReverbHiImp<int16_t>;
template class EffectReverbHiImp<int32_t>;
template class EffectReverbHiImp<float>;
} // namespace amuse

View File

@ -29,23 +29,13 @@ EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, fl
EffectReverbHi& Submix::makeReverbHi(const EffectReverbHiInfo& info) { return makeEffect<EffectReverbHi>(info); }
void Submix::applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const {
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
((EffectBase<int16_t>&)*effect).applyEffect(audio, frameCount, chanMap);
}
void Submix::applyEffect(int32_t* audio, size_t frameCount, const ChannelMap& chanMap) const {
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
((EffectBase<int32_t>&)*effect).applyEffect(audio, frameCount, chanMap);
}
void Submix::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) const {
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
((EffectBase<float>&)*effect).applyEffect(audio, frameCount, chanMap);
for (const std::unique_ptr<EffectBase>& effect : m_effectStack)
effect->applyEffect(audio, frameCount, chanMap);
}
void Submix::resetOutputSampleRate(double sampleRate) {
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
for (const std::unique_ptr<EffectBase>& effect : m_effectStack)
effect->resetOutputSampleRate(sampleRate);
}
} // namespace amuse