2018-10-07 03:36:44 +00:00
|
|
|
#pragma once
|
2016-05-07 04:28:32 +00:00
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
#include <array>
|
2019-08-19 23:08:54 +00:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
2019-08-17 17:39:39 +00:00
|
|
|
#include <list>
|
|
|
|
#include <mutex>
|
2016-07-13 03:03:52 +00:00
|
|
|
#include <unordered_map>
|
2019-08-17 17:39:39 +00:00
|
|
|
#include <vector>
|
2019-08-19 23:08:54 +00:00
|
|
|
|
|
|
|
#include "boo/audiodev/IAudioSubmix.hpp"
|
|
|
|
#include "lib/audiodev/Common.hpp"
|
2016-07-13 03:03:52 +00:00
|
|
|
|
2021-04-18 15:59:34 +00:00
|
|
|
#if defined(__x86_64__) || defined(_M_AMD64)
|
2017-12-19 03:04:47 +00:00
|
|
|
#include <immintrin.h>
|
2021-04-18 15:59:34 +00:00
|
|
|
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
|
|
#define __SSE__ 1
|
|
|
|
#include "sse2neon.h"
|
2016-07-13 03:03:52 +00:00
|
|
|
#endif
|
2016-05-07 04:28:32 +00:00
|
|
|
|
2016-06-08 04:37:21 +00:00
|
|
|
struct AudioUnitVoiceEngine;
|
2016-06-15 03:53:37 +00:00
|
|
|
struct VSTVoiceEngine;
|
2016-07-06 21:29:06 +00:00
|
|
|
struct WAVOutVoiceEngine;
|
2016-06-08 04:37:21 +00:00
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
namespace boo {
|
2016-05-07 04:28:32 +00:00
|
|
|
class BaseAudioVoiceEngine;
|
|
|
|
class AudioVoice;
|
2016-07-13 03:03:52 +00:00
|
|
|
struct AudioVoiceEngineMixInfo;
|
|
|
|
/* Output gains for each mix-send/channel */
|
2016-05-07 04:28:32 +00:00
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
class AudioSubmix : public ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix> {
|
|
|
|
friend class BaseAudioVoiceEngine;
|
|
|
|
friend class AudioVoiceMono;
|
|
|
|
friend class AudioVoiceStereo;
|
|
|
|
friend struct WASAPIAudioVoiceEngine;
|
|
|
|
friend struct ::AudioUnitVoiceEngine;
|
|
|
|
friend struct ::VSTVoiceEngine;
|
|
|
|
friend struct ::WAVOutVoiceEngine;
|
|
|
|
|
|
|
|
/* Mixer-engine relationships */
|
|
|
|
int m_busId;
|
|
|
|
bool m_mainOut;
|
|
|
|
|
|
|
|
/* Callback (effect source, optional) */
|
|
|
|
IAudioSubmixCallback* m_cb;
|
|
|
|
|
|
|
|
/* Slew state for output gains */
|
|
|
|
size_t m_slewFrames = 0;
|
|
|
|
size_t m_curSlewFrame = 0;
|
|
|
|
|
|
|
|
/* Output gains for each mix-send/channel */
|
|
|
|
std::unordered_map<IAudioSubmix*, std::array<float, 2>> m_sendGains;
|
|
|
|
|
|
|
|
/* Temporary scratch buffers for accumulating submix audio */
|
|
|
|
std::vector<int16_t> m_scratch16;
|
|
|
|
std::vector<int32_t> m_scratch32;
|
|
|
|
std::vector<float> m_scratchFlt;
|
|
|
|
template <typename T>
|
|
|
|
std::vector<T>& _getScratch();
|
|
|
|
|
|
|
|
/* Override scratch buffers with alternate destination */
|
|
|
|
int16_t* m_redirect16 = nullptr;
|
|
|
|
int32_t* m_redirect32 = nullptr;
|
|
|
|
float* m_redirectFlt = nullptr;
|
|
|
|
template <typename T>
|
|
|
|
T*& _getRedirect();
|
|
|
|
|
|
|
|
/* C3-linearization support (to mitigate a potential diamond problem on 'clever' submix routes) */
|
|
|
|
bool _isDirectDependencyOf(AudioSubmix* send);
|
|
|
|
std::list<AudioSubmix*> _linearizeC3();
|
|
|
|
static bool _mergeC3(std::list<AudioSubmix*>& output, std::vector<std::list<AudioSubmix*>>& lists);
|
|
|
|
|
|
|
|
/* Fill scratch buffers with silence for new mix cycle */
|
|
|
|
template <typename T>
|
|
|
|
void _zeroFill();
|
|
|
|
|
|
|
|
/* Receive audio from a single voice / submix */
|
|
|
|
template <typename T>
|
|
|
|
T* _getMergeBuf(size_t frames);
|
|
|
|
|
|
|
|
/* Mix scratch buffers into sends */
|
|
|
|
template <typename T>
|
|
|
|
size_t _pumpAndMix(size_t frames);
|
|
|
|
|
|
|
|
void _resetOutputSampleRate();
|
2016-06-01 04:53:57 +00:00
|
|
|
|
2016-05-07 04:28:32 +00:00
|
|
|
public:
|
2018-12-08 05:17:51 +00:00
|
|
|
static AudioSubmix*& _getHeadPtr(BaseAudioVoiceEngine* head);
|
|
|
|
static std::unique_lock<std::recursive_mutex> _getHeadLock(BaseAudioVoiceEngine* head);
|
|
|
|
|
|
|
|
AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut);
|
2019-08-13 00:52:20 +00:00
|
|
|
~AudioSubmix() override;
|
2018-12-08 05:17:51 +00:00
|
|
|
|
2019-08-13 00:52:20 +00:00
|
|
|
void resetSendLevels() override;
|
|
|
|
void setSendLevel(IAudioSubmix* submix, float level, bool slew) override;
|
2018-12-08 05:17:51 +00:00
|
|
|
const AudioVoiceEngineMixInfo& mixInfo() const;
|
2019-08-13 00:52:20 +00:00
|
|
|
double getSampleRate() const override;
|
|
|
|
SubmixFormat getSampleFormat() const override;
|
2016-05-07 04:28:32 +00:00
|
|
|
};
|
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
template <>
|
|
|
|
inline std::vector<int16_t>& AudioSubmix::_getScratch() {
|
|
|
|
return m_scratch16;
|
|
|
|
}
|
|
|
|
template <>
|
|
|
|
inline std::vector<int32_t>& AudioSubmix::_getScratch() {
|
|
|
|
return m_scratch32;
|
|
|
|
}
|
|
|
|
template <>
|
|
|
|
inline std::vector<float>& AudioSubmix::_getScratch() {
|
|
|
|
return m_scratchFlt;
|
|
|
|
}
|
2017-12-03 06:05:16 +00:00
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
template <>
|
|
|
|
inline int16_t*& AudioSubmix::_getRedirect<int16_t>() {
|
|
|
|
return m_redirect16;
|
|
|
|
}
|
|
|
|
template <>
|
|
|
|
inline int32_t*& AudioSubmix::_getRedirect<int32_t>() {
|
|
|
|
return m_redirect32;
|
|
|
|
}
|
|
|
|
template <>
|
|
|
|
inline float*& AudioSubmix::_getRedirect<float>() {
|
|
|
|
return m_redirectFlt;
|
2016-05-07 04:28:32 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:17:51 +00:00
|
|
|
} // namespace boo
|