1641 lines
47 KiB
Markdown
1641 lines
47 KiB
Markdown
|
|
# XCEngine - 音频模块架构设计文档
|
|||
|
|
|
|||
|
|
> **借鉴 Unity 音频架构概念设计**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 音频流程图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 音频流程 │
|
|||
|
|
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|||
|
|
│ AudioSource │────▶│ Spatialize │────▶│ EffectChain │────▶│ Output │
|
|||
|
|
│ 声源组件 │ │ 3D空间化 │ │ 效果链 │ │ 音频输出 │
|
|||
|
|
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
|||
|
|
│ │ │ │
|
|||
|
|
▼ ▼ ▼ ▼
|
|||
|
|
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
|||
|
|
│ AudioClip │ │ HRTF │ │ FFT │ │ AudioBackend│
|
|||
|
|
│ 音频资源 │ │ 头部相关传输 │ │ 傅里叶变换 │ │ 音频后端 │
|
|||
|
|
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
|||
|
|
│ │
|
|||
|
|
▼ ▼
|
|||
|
|
┌─────────────┐ ┌─────────────┐
|
|||
|
|
│ Reverbation │ │ WASAPI │
|
|||
|
|
│ 混响效果 │ │ OpenAL │
|
|||
|
|
└─────────────┘ │ CoreAudio │
|
|||
|
|
└─────────────┘
|
|||
|
|
|
|||
|
|
流程说明:
|
|||
|
|
1. AudioSourceComponent 负责播放 AudioClip,管理播放状态
|
|||
|
|
2. AudioListenerComponent 接收声音,计算3D空间化参数
|
|||
|
|
3. Spatialize 根据 Listener 位置计算 panning、distance attenuation、doppler
|
|||
|
|
4. EffectChain 处理 DSP 效果链(FFT、Reverb、EQ等)
|
|||
|
|
5. AudioBackend 抽象层负责与具体音频API交互
|
|||
|
|
6. 最终输出到音频设备
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ AudioBackend 抽象层架构 │
|
|||
|
|
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
┌─────────────────┐
|
|||
|
|
│ AudioSystem │ 音频系统入口
|
|||
|
|
└────────┬────────┘
|
|||
|
|
│
|
|||
|
|
┌───────────────────────┼───────────────────────┐
|
|||
|
|
│ │ │
|
|||
|
|
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
|
|||
|
|
│ WASAPIBackend│ │OpenALBackend │ │CoreAudioBackend│
|
|||
|
|
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
|||
|
|
│ │ │
|
|||
|
|
└───────────────────────┼───────────────────────┘
|
|||
|
|
│
|
|||
|
|
┌────────▼────────┐
|
|||
|
|
│ IAudioBackend │ 抽象音频后端接口
|
|||
|
|
└────────┬────────┘
|
|||
|
|
│
|
|||
|
|
┌──────────────────────────────────┼──────────────────────────────────┐
|
|||
|
|
│ │ │ │ │ │ │
|
|||
|
|
┌────▼────┐ ┌───▼────┐ ┌────▼┐ ┌──▼────┐ ┌───▼───┐ ┌───▼────┐ ┌──▼────┐
|
|||
|
|
│AudioBuffer│ │AudioBus │ │Fence│ │Mixer │ │Effect │ │HRTF │ │Resampler│
|
|||
|
|
│ 音频缓冲 │ │ 音频总线 │ │围栏 │ │ 混音器 │ │ 效果 │ │ 空间化 │ │ 重采样 │
|
|||
|
|
└──────────┘ └────────┘ └─────┘ └────────┘ └───────┘ └────────┘ └────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> **重要声明**:本架构借鉴 Unity 音频系统的核心概念与设计模式,包括:
|
|||
|
|
> - `AudioSourceComponent` / `AudioListenerComponent` - 声源与监听器组件
|
|||
|
|
> - `AudioClip` / `AudioMixer` - 音频资源与混音器
|
|||
|
|
> - `EffectChain` - 效果器链
|
|||
|
|
> - `Spatializer` - 3D空间化处理器
|
|||
|
|
> - `AudioBackend` - 音频后端抽象
|
|||
|
|
>
|
|||
|
|
> **注**:Unity底层C++音频架构未公开,本设计基于公开API概念与通用音频引擎模式实现。
|
|||
|
|
>
|
|||
|
|
> 版本: 1.0
|
|||
|
|
> 日期: 2026-03-20
|
|||
|
|
> 目标: 构建专业级游戏引擎音频系统
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第一章 核心类型定义
|
|||
|
|
|
|||
|
|
### 1.1 音频基础类型
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
// ============================================
|
|||
|
|
// 前置类型定义
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
enum class AudioResourceType {
|
|||
|
|
AudioClip,
|
|||
|
|
AudioMixer,
|
|||
|
|
AudioBank
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class AudioLoadState {
|
|||
|
|
Unloaded,
|
|||
|
|
Loading,
|
|||
|
|
Loaded,
|
|||
|
|
Failed
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class AudioFormat {
|
|||
|
|
Unknown,
|
|||
|
|
WAV,
|
|||
|
|
OGG,
|
|||
|
|
MP3,
|
|||
|
|
FLAC,
|
|||
|
|
AAC
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class SpeakerMode {
|
|||
|
|
Mono,
|
|||
|
|
Stereo,
|
|||
|
|
Surround51,
|
|||
|
|
Surround71,
|
|||
|
|
Surround51_2,
|
|||
|
|
Surround71_2
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class AudioChannel {
|
|||
|
|
FrontLeft,
|
|||
|
|
FrontRight,
|
|||
|
|
FrontCenter,
|
|||
|
|
LFE,
|
|||
|
|
BackLeft,
|
|||
|
|
BackRight,
|
|||
|
|
SideLeft,
|
|||
|
|
SideRight
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
struct AudioConfig {
|
|||
|
|
uint32_t sampleRate = 48000;
|
|||
|
|
uint16_t channels = 2;
|
|||
|
|
uint16_t bitsPerSample = 16;
|
|||
|
|
SpeakerMode speakerMode = SpeakerMode::Stereo;
|
|||
|
|
uint32_t bufferSize = 8192;
|
|||
|
|
uint32_t bufferCount = 2;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ============================================
|
|||
|
|
// 3D 音频参数
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
struct Audio3DParams {
|
|||
|
|
float dopplerLevel = 1.0f;
|
|||
|
|
float speedOfSound = 343.0f;
|
|||
|
|
float minDistance = 1.0f;
|
|||
|
|
float maxDistance = 500.0f;
|
|||
|
|
float panLevel = 1.0f;
|
|||
|
|
float spread = 0.0f;
|
|||
|
|
float reverbZoneMix = 1.0f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class PanMode {
|
|||
|
|
Pan3D,
|
|||
|
|
Pan2D
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class VolumeSource {
|
|||
|
|
Direct,
|
|||
|
|
Path Occlusion,
|
|||
|
|
Transmission,
|
|||
|
|
Obstruction
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ============================================
|
|||
|
|
// 音频缓冲区描述
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
struct AudioBufferDesc {
|
|||
|
|
uint32_t size = 0;
|
|||
|
|
uint32_t channels = 2;
|
|||
|
|
uint32_t sampleRate = 48000;
|
|||
|
|
uint16_t bitsPerSample = 16;
|
|||
|
|
bool isFloat = false;
|
|||
|
|
bool isCompressed = false;
|
|||
|
|
AudioFormat format = AudioFormat::Unknown;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ============================================
|
|||
|
|
// 播放状态
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
enum class PlayState {
|
|||
|
|
Stopped,
|
|||
|
|
Playing,
|
|||
|
|
Paused
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class StopMode {
|
|||
|
|
Immediate,
|
|||
|
|
AllowFadeOut
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ============================================
|
|||
|
|
// 空间化参数
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
struct SpatializerParams {
|
|||
|
|
float azimuth = 0.0f;
|
|||
|
|
float elevation = 0.0f;
|
|||
|
|
float distance = 0.0f;
|
|||
|
|
float volumeDb = 0.0f;
|
|||
|
|
float panCartesianX = 0.0f;
|
|||
|
|
float panCartesianY = 0.0f;
|
|||
|
|
bool isOccluded = false;
|
|||
|
|
bool isObstructed = false;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 1.2 IAudioResource 基类
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class IAudioResource {
|
|||
|
|
public:
|
|||
|
|
virtual ~IAudioResource() = default;
|
|||
|
|
|
|||
|
|
virtual void SetName(const String& name) { m_name = name; }
|
|||
|
|
virtual const String& GetName() const { return m_name; }
|
|||
|
|
|
|||
|
|
virtual AudioResourceType GetType() const = 0;
|
|||
|
|
virtual AudioLoadState GetLoadState() const { return m_loadState; }
|
|||
|
|
|
|||
|
|
virtual bool IsValid() const { return m_loadState == AudioLoadState::Loaded; }
|
|||
|
|
virtual void Load() = 0;
|
|||
|
|
virtual void Unload() = 0;
|
|||
|
|
|
|||
|
|
virtual int GetRefCount() const { return m_refCount.load(); }
|
|||
|
|
virtual void AddRef() { m_refCount.fetch_add(1); }
|
|||
|
|
virtual void Release() {
|
|||
|
|
if (m_refCount.fetch_sub(1) == 1) {
|
|||
|
|
delete this;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected:
|
|||
|
|
IAudioResource() : m_loadState(AudioLoadState::Unloaded), m_memoryUsage(0) {}
|
|||
|
|
|
|||
|
|
String m_name;
|
|||
|
|
AudioLoadState m_loadState;
|
|||
|
|
uint64_t m_memoryUsage;
|
|||
|
|
std::atomic<int32_t> m_refCount{1};
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第二章 音频资源
|
|||
|
|
|
|||
|
|
### 2.1 AudioClip
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioClip : public IAudioResource {
|
|||
|
|
public:
|
|||
|
|
AudioClip();
|
|||
|
|
AudioClip(const String& filePath);
|
|||
|
|
~AudioClip();
|
|||
|
|
|
|||
|
|
AudioResourceType GetType() const override { return AudioResourceType::AudioClip; }
|
|||
|
|
|
|||
|
|
void Load() override;
|
|||
|
|
void Unload() override;
|
|||
|
|
|
|||
|
|
// 音频数据访问
|
|||
|
|
const int16_t* GetData() const { return m_data.data(); }
|
|||
|
|
int16_t* GetData() { return m_data.data(); }
|
|||
|
|
|
|||
|
|
const float* GetDataFloat() const { return m_dataFloat.data(); }
|
|||
|
|
float* GetDataFloat() { return m_dataFloat.data(); }
|
|||
|
|
|
|||
|
|
uint32_t GetDataSize() const { return m_dataSize; }
|
|||
|
|
uint32_t GetSampleCount() const { return m_sampleCount; }
|
|||
|
|
uint32_t GetChannelCount() const { return m_channels; }
|
|||
|
|
uint32_t GetSampleRate() const { return m_sampleRate; }
|
|||
|
|
uint16_t GetBitsPerSample() const { return m_bitsPerSample; }
|
|||
|
|
float GetDuration() const { return m_duration; }
|
|||
|
|
|
|||
|
|
AudioFormat GetFormat() const { return m_format; }
|
|||
|
|
bool IsCompressed() const { return m_isCompressed; }
|
|||
|
|
bool IsStreamed() const { return m_isStreamed; }
|
|||
|
|
|
|||
|
|
// 频谱数据查询
|
|||
|
|
bool HasFrequencyData() const { return m_hasFrequencyData; }
|
|||
|
|
const float* GetFrequencyData() const { return m_frequencyData.data(); }
|
|||
|
|
uint32_t GetFrequencyDataSize() const { return m_frequencyData.size(); }
|
|||
|
|
|
|||
|
|
// 资源路径
|
|||
|
|
void SetResourcePath(const String& path) { m_resourcePath = path; }
|
|||
|
|
const String& GetResourcePath() const { return m_resourcePath; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void ProcessWavFile();
|
|||
|
|
void DecodeCompressedData();
|
|||
|
|
void GenerateFrequencyData();
|
|||
|
|
void ConvertToFloat();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
std::vector<int16_t> m_data;
|
|||
|
|
std::vector<float> m_dataFloat;
|
|||
|
|
std::vector<float> m_frequencyData;
|
|||
|
|
|
|||
|
|
uint32_t m_dataSize = 0;
|
|||
|
|
uint32_t m_sampleCount = 0;
|
|||
|
|
uint16_t m_channels = 2;
|
|||
|
|
uint32_t m_sampleRate = 48000;
|
|||
|
|
uint16_t m_bitsPerSample = 16;
|
|||
|
|
float m_duration = 0.0f;
|
|||
|
|
|
|||
|
|
AudioFormat m_format = AudioFormat::Unknown;
|
|||
|
|
bool m_isCompressed = false;
|
|||
|
|
bool m_isStreamed = false;
|
|||
|
|
bool m_hasFrequencyData = false;
|
|||
|
|
|
|||
|
|
String m_resourcePath;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 AudioMixer
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioMixer : public IAudioResource {
|
|||
|
|
public:
|
|||
|
|
AudioMixer();
|
|||
|
|
~AudioMixer();
|
|||
|
|
|
|||
|
|
AudioResourceType GetType() const override { return AudioResourceType::AudioMixer; }
|
|||
|
|
|
|||
|
|
void Load() override;
|
|||
|
|
void Unload() override;
|
|||
|
|
|
|||
|
|
// 混音器参数
|
|||
|
|
float GetVolume() const { return m_volume; }
|
|||
|
|
void SetVolume(float volume, float fadeTime = 0.0f);
|
|||
|
|
|
|||
|
|
bool IsMuted() const { return m_isMuted; }
|
|||
|
|
void SetMuted(bool muted) { m_isMuted = muted; }
|
|||
|
|
|
|||
|
|
// 子混音器组
|
|||
|
|
class MixerGroup* GetGroup(const String& name);
|
|||
|
|
class MixerGroup* CreateGroup(const String& name);
|
|||
|
|
void RemoveGroup(const String& name);
|
|||
|
|
|
|||
|
|
const std::map<String, std::unique_ptr<MixerGroup>>& GetGroups() const { return m_groups; }
|
|||
|
|
|
|||
|
|
// 输出混音器
|
|||
|
|
void SetOutputMixer(AudioMixer* mixer);
|
|||
|
|
AudioMixer* GetOutputMixer() const { return m_outputMixer; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_volume = 1.0f;
|
|||
|
|
bool m_isMuted = false;
|
|||
|
|
|
|||
|
|
std::map<String, std::unique_ptr<MixerGroup>> m_groups;
|
|||
|
|
AudioMixer* m_outputMixer = nullptr;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class MixerGroup {
|
|||
|
|
public:
|
|||
|
|
MixerGroup(const String& name);
|
|||
|
|
~MixerGroup();
|
|||
|
|
|
|||
|
|
const String& GetName() const { return m_name; }
|
|||
|
|
|
|||
|
|
float GetVolume() const { return m_volume; }
|
|||
|
|
void SetVolume(float volume, float fadeTime = 0.0f);
|
|||
|
|
|
|||
|
|
bool IsMuted() const { return m_isMuted; }
|
|||
|
|
void SetMuted(bool muted) { m_isMuted = muted; }
|
|||
|
|
|
|||
|
|
bool IsSoloed() const { return m_isSoloed; }
|
|||
|
|
void SetSoloed(bool soloed) { m_isSoloed = soloed; }
|
|||
|
|
|
|||
|
|
// 效果器
|
|||
|
|
void AddEffect(IAudioEffect* effect, size_t index = SIZE_MAX);
|
|||
|
|
void RemoveEffect(IAudioEffect* effect);
|
|||
|
|
void SetEffectEnabled(IAudioEffect* effect, bool enabled);
|
|||
|
|
|
|||
|
|
const std::vector<IAudioEffect*>& GetEffects() const { return m_effects; }
|
|||
|
|
|
|||
|
|
// 音频处理
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
String m_name;
|
|||
|
|
float m_volume = 1.0f;
|
|||
|
|
bool m_isMuted = false;
|
|||
|
|
bool m_isSoloed = false;
|
|||
|
|
|
|||
|
|
std::vector<IAudioEffect*> m_effects;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.3 AudioBank (用于分段加载)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioBank : public IAudioResource {
|
|||
|
|
public:
|
|||
|
|
AudioBank();
|
|||
|
|
~AudioBank();
|
|||
|
|
|
|||
|
|
AudioResourceType GetType() const override { return AudioResourceType::AudioBank; }
|
|||
|
|
|
|||
|
|
void Load() override;
|
|||
|
|
void Unload() override;
|
|||
|
|
|
|||
|
|
// 事件触发
|
|||
|
|
void TriggerEvent(const String& eventName);
|
|||
|
|
void TriggerEvent(int eventId);
|
|||
|
|
|
|||
|
|
// 获取嵌入的音频片段
|
|||
|
|
AudioClip* GetClip(const String& name);
|
|||
|
|
AudioClip* GetClip(int id);
|
|||
|
|
|
|||
|
|
const std::map<String, AudioClip*>& GetAllClips() const { return m_clips; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
std::map<String, AudioClip*> m_clips;
|
|||
|
|
std::map<String, int> m_eventMap;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第三章 DSP 效果系统
|
|||
|
|
|
|||
|
|
### 3.1 IAudioEffect 接口
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
virtual ~IAudioEffect() = default;
|
|||
|
|
|
|||
|
|
virtual const char* GetName() const = 0;
|
|||
|
|
virtual void Process(float* buffer, uint32_t sampleCount, uint32_t channels) = 0;
|
|||
|
|
|
|||
|
|
virtual void SetEnabled(bool enabled) { m_enabled = enabled; }
|
|||
|
|
virtual bool IsEnabled() const { return m_enabled; }
|
|||
|
|
|
|||
|
|
virtual void SetParameter(const char* name, float value) = 0;
|
|||
|
|
virtual float GetParameter(const char* name) const = 0;
|
|||
|
|
|
|||
|
|
virtual size_t GetParameterCount() const = 0;
|
|||
|
|
virtual const char* GetParameterName(size_t index) const = 0;
|
|||
|
|
|
|||
|
|
protected:
|
|||
|
|
bool m_enabled = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 FFTFilter (频谱分析)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class FFTFilter : public IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
FFTFilter(size_t fftSize = 1024);
|
|||
|
|
~FFTFilter();
|
|||
|
|
|
|||
|
|
const char* GetName() const override { return "FFTFilter"; }
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels) override;
|
|||
|
|
|
|||
|
|
void SetEnabled(bool enabled) override;
|
|||
|
|
|
|||
|
|
void SetFFTSize(size_t size);
|
|||
|
|
size_t GetFFTSize() const { return m_fftSize; }
|
|||
|
|
|
|||
|
|
void SetParameter(const char* name, float value) override;
|
|||
|
|
float GetParameter(const char* name) const override;
|
|||
|
|
size_t GetParameterCount() const override;
|
|||
|
|
const char* GetParameterName(size_t index) const override;
|
|||
|
|
|
|||
|
|
// 频谱数据访问
|
|||
|
|
const float* GetMagnitudeSpectrum() const { return m_magnitudeSpectrum.data(); }
|
|||
|
|
const float* GetPhaseSpectrum() const { return m_phaseSpectrum.data(); }
|
|||
|
|
size_t GetSpectrumSize() const { return m_spectrumSize; }
|
|||
|
|
|
|||
|
|
// 设置时域核(用于滤波)
|
|||
|
|
void SetTimeDomainKernel(const std::vector<float>& kernel);
|
|||
|
|
void AddTimeDomainKernel(const std::vector<float>& kernel);
|
|||
|
|
|
|||
|
|
// 频域核
|
|||
|
|
void SetFreqDomainKernel(const std::vector<float>& kernel);
|
|||
|
|
void AddFreqDomainKernel(const std::vector<float>& kernel);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void Init();
|
|||
|
|
void ComplexVectorProduct(const std::vector<kiss_fft_cpx>& inputA,
|
|||
|
|
const std::vector<kiss_fft_cpx>& inputB,
|
|||
|
|
std::vector<kiss_fft_cpx>* result);
|
|||
|
|
void InverseFFTScaling(std::vector<float>* signal);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
size_t m_fftSize;
|
|||
|
|
size_t m_spectrumSize;
|
|||
|
|
|
|||
|
|
bool m_analysisMode = true;
|
|||
|
|
|
|||
|
|
std::vector<float> m_magnitudeSpectrum;
|
|||
|
|
std::vector<float> m_phaseSpectrum;
|
|||
|
|
|
|||
|
|
std::vector<float> m_filterState;
|
|||
|
|
std::vector<float> m_window;
|
|||
|
|
|
|||
|
|
bool m_kernelDefined = false;
|
|||
|
|
std::vector<kiss_fft_scalar> m_kernelTimeDomainBuffer;
|
|||
|
|
std::vector<kiss_fft_cpx> m_kernelFreqDomainBuffer;
|
|||
|
|
|
|||
|
|
int m_bufferSelector = 0;
|
|||
|
|
std::vector<std::vector<kiss_fft_scalar>> m_signalTimeDomainBuffer;
|
|||
|
|
std::vector<std::vector<kiss_fft_cpx>> m_signalFreqDomainBuffer;
|
|||
|
|
std::vector<kiss_fft_cpx> m_filteredFreqDomainBuffer;
|
|||
|
|
|
|||
|
|
kiss_fftr_cfg m_forwardFFT = nullptr;
|
|||
|
|
kiss_fftr_cfg m_inverseFFT = nullptr;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 Reverbation (混响)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class Reverbation : public IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
Reverbation(int blockSize = 1024, int samplingRate = 48000, float reverbTime = 2.0f);
|
|||
|
|
~Reverbation();
|
|||
|
|
|
|||
|
|
const char* GetName() const override { return "Reverbation"; }
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels) override;
|
|||
|
|
|
|||
|
|
void SetParameter(const char* name, float value) override;
|
|||
|
|
float GetParameter(const char* name) const override;
|
|||
|
|
size_t GetParameterCount() const override;
|
|||
|
|
const char* GetParameterName(size_t index) const override;
|
|||
|
|
|
|||
|
|
// 混响参数
|
|||
|
|
void SetReverbTime(float seconds);
|
|||
|
|
float GetReverbTime() const { return m_reverbTime; }
|
|||
|
|
|
|||
|
|
void SetDecay(float decay) { m_decay = decay; }
|
|||
|
|
float GetDecay() const { return m_decay; }
|
|||
|
|
|
|||
|
|
void SetPreDelay(float ms);
|
|||
|
|
float GetPreDelay() const { return m_preDelayMs; }
|
|||
|
|
|
|||
|
|
void SetHighFreqDamping(float ratio);
|
|||
|
|
float GetHighFreqDamping() const { return m_highFreqDamping; }
|
|||
|
|
|
|||
|
|
// 脉冲响应
|
|||
|
|
const std::vector<float>& GetImpulseResponseLeft() const { return m_impulseResponseLeft; }
|
|||
|
|
const std::vector<float>& GetImpulseResponseRight() const { return m_impulseResponseRight; }
|
|||
|
|
|
|||
|
|
float GetQuietPeriod() const { return m_quietPeriodSec; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void RenderImpulseResponse(int blockSize, int samplingRate, float reverbTime);
|
|||
|
|
static float FloatRand();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
int m_blockSize;
|
|||
|
|
float m_reverbTime = 2.0f;
|
|||
|
|
float m_decay = 0.7f;
|
|||
|
|
float m_preDelayMs = 20.0f;
|
|||
|
|
float m_highFreqDamping = 0.5f;
|
|||
|
|
|
|||
|
|
std::vector<float> m_impulseResponseLeft;
|
|||
|
|
std::vector<float> m_impulseResponseRight;
|
|||
|
|
float m_quietPeriodSec;
|
|||
|
|
|
|||
|
|
std::unique_ptr<FFTFilter> m_leftReverbFilter;
|
|||
|
|
std::unique_ptr<FFTFilter> m_rightReverbFilter;
|
|||
|
|
|
|||
|
|
std::vector<float> m_reverbInput;
|
|||
|
|
std::vector<float> m_reverbOutputLeft;
|
|||
|
|
std::vector<float> m_reverbOutputRight;
|
|||
|
|
int m_reverbOutputReadPos = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.4 EQ (均衡器)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class Equalizer : public IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
Equalizer();
|
|||
|
|
~Equalizer();
|
|||
|
|
|
|||
|
|
const char* GetName() const override { return "Equalizer"; }
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels) override;
|
|||
|
|
|
|||
|
|
void SetParameter(const char* name, float value) override;
|
|||
|
|
float GetParameter(const char* name) const override;
|
|||
|
|
size_t GetParameterCount() const override;
|
|||
|
|
const char* GetParameterName(size_t index) const override;
|
|||
|
|
|
|||
|
|
// 频段控制
|
|||
|
|
enum class Band {
|
|||
|
|
LowPass,
|
|||
|
|
HighPass,
|
|||
|
|
BandPass,
|
|||
|
|
Notch,
|
|||
|
|
LowShelf,
|
|||
|
|
HighShelf,
|
|||
|
|
Peaking
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void SetBand(size_t index, Band type, float frequency, float gainDb, float Q);
|
|||
|
|
void SetBandEnabled(size_t index, bool enabled);
|
|||
|
|
|
|||
|
|
struct BandParams {
|
|||
|
|
Band type = Band::Peaking;
|
|||
|
|
float frequency = 1000.0f;
|
|||
|
|
float gainDb = 0.0f;
|
|||
|
|
float Q = 1.0f;
|
|||
|
|
bool enabled = true;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const BandParams& GetBand(size_t index) const { return m_bands[index]; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void UpdateCoefficients(size_t index);
|
|||
|
|
void ProcessBand(float* buffer, uint32_t sampleCount, size_t bandIndex);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
static constexpr size_t MaxBands = 10;
|
|||
|
|
std::array<BandParams, MaxBands> m_bands;
|
|||
|
|
std::array<std::array<float, 5>, MaxBands> m_coefficients;
|
|||
|
|
|
|||
|
|
std::vector<float> m_x1, m_x2, m_y1, m_y2;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.5 Dynamics (动态效果器)
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class Compressor : public IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
Compressor();
|
|||
|
|
~Compressor();
|
|||
|
|
|
|||
|
|
const char* GetName() const override { return "Compressor"; }
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels) override;
|
|||
|
|
|
|||
|
|
void SetParameter(const char* name, float value) override;
|
|||
|
|
float GetParameter(const char* name) const override;
|
|||
|
|
size_t GetParameterCount() const override;
|
|||
|
|
const char* GetParameterName(size_t index) const override;
|
|||
|
|
|
|||
|
|
void SetThreshold(float db);
|
|||
|
|
float GetThreshold() const { return m_thresholdDb; }
|
|||
|
|
|
|||
|
|
void SetRatio(float ratio);
|
|||
|
|
float GetRatio() const { return m_ratio; }
|
|||
|
|
|
|||
|
|
void SetAttack(float ms);
|
|||
|
|
float GetAttack() const { return m_attackMs; }
|
|||
|
|
|
|||
|
|
void SetRelease(float ms);
|
|||
|
|
float GetRelease() const { return m_releaseMs; }
|
|||
|
|
|
|||
|
|
float GetGainReduction() const { return m_gainReduction; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_thresholdDb = -20.0f;
|
|||
|
|
float m_ratio = 4.0f;
|
|||
|
|
float m_attackMs = 10.0f;
|
|||
|
|
float m_releaseMs = 100.0f;
|
|||
|
|
|
|||
|
|
float m_gainReduction = 0.0f;
|
|||
|
|
float m_envelope = 0.0f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
class Limiter : public IAudioEffect {
|
|||
|
|
public:
|
|||
|
|
Limiter();
|
|||
|
|
~Limiter();
|
|||
|
|
|
|||
|
|
const char* GetName() const override { return "Limiter"; }
|
|||
|
|
void Process(float* buffer, uint32_t sampleCount, uint32_t channels) override;
|
|||
|
|
|
|||
|
|
void SetParameter(const char* name, float value) override;
|
|||
|
|
float GetParameter(const char* name) const override;
|
|||
|
|
size_t GetParameterCount() const override;
|
|||
|
|
const char* GetParameterName(size_t index) const override;
|
|||
|
|
|
|||
|
|
void SetCeiling(float db);
|
|||
|
|
float GetCeiling() const { return m_ceilingDb; }
|
|||
|
|
|
|||
|
|
void SetRelease(float ms);
|
|||
|
|
float GetRelease() const { return m_releaseMs; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_ceilingDb = -0.3f;
|
|||
|
|
float m_releaseMs = 50.0f;
|
|||
|
|
float m_envelope = 0.0f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第四章 3D 空间音频
|
|||
|
|
|
|||
|
|
### 4.1 SpatializerParams 空间化参数
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
struct SpatializerParams {
|
|||
|
|
Vector3 listenerPosition;
|
|||
|
|
Quaternion listenerRotation;
|
|||
|
|
Vector3 listenerVelocity;
|
|||
|
|
|
|||
|
|
Vector3 sourcePosition;
|
|||
|
|
Vector3 sourceVelocity;
|
|||
|
|
Quaternion sourceRotation;
|
|||
|
|
|
|||
|
|
Audio3DParams params;
|
|||
|
|
|
|||
|
|
float GetDistanceAttenuation() const;
|
|||
|
|
float GetPan() const;
|
|||
|
|
float GetDopplerShift() const;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 HRTF 空间化
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class HRTF {
|
|||
|
|
public:
|
|||
|
|
HRTF();
|
|||
|
|
~HRTF();
|
|||
|
|
|
|||
|
|
// 方向设置
|
|||
|
|
void SetDirection(int elevation, int azimuth);
|
|||
|
|
void GetDirection(int& elevation, int& azimuth);
|
|||
|
|
|
|||
|
|
// HRTF 脉冲响应
|
|||
|
|
void GetLeftEarTimeHRTF(std::vector<float>& data);
|
|||
|
|
void GetLeftEarFreqHRTF(std::vector<float>& data);
|
|||
|
|
void GetRightEarTimeHRTF(std::vector<float>& data);
|
|||
|
|
void GetRightEarFreqHRTF(std::vector<float>& data);
|
|||
|
|
|
|||
|
|
// 空间化处理
|
|||
|
|
void Process(const float* input, float* outputLeft, float* outputRight,
|
|||
|
|
size_t sampleCount, size_t channels);
|
|||
|
|
|
|||
|
|
// 淡入淡出处理
|
|||
|
|
void ApplyFadeWindow(const std::vector<float>& blockLast,
|
|||
|
|
const std::vector<float>& blockNext,
|
|||
|
|
std::vector<float>* fadeResult);
|
|||
|
|
|
|||
|
|
// 重采样
|
|||
|
|
void Resample(const float* input, float* output, size_t inputSize,
|
|||
|
|
size_t outputSize, size_t channels);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void BuildReacherTree();
|
|||
|
|
int SearchNearestIndex(int elevation, int azimuth);
|
|||
|
|
double CalculateSphereDistance(int elev1, int azim1, int elev2, int azim2);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
int m_realAzimuth = 0;
|
|||
|
|
int m_realElevation = 0;
|
|||
|
|
int m_azimuth = 0;
|
|||
|
|
int m_elevation = 0;
|
|||
|
|
bool m_isSwapLeftRight = false;
|
|||
|
|
int m_directionIndex = 0;
|
|||
|
|
|
|||
|
|
using ResampledHRTFT = std::vector<float>;
|
|||
|
|
using ResampledHRTFPairT = std::pair<ResampledHRTFT, ResampledHRTFT>;
|
|||
|
|
|
|||
|
|
std::vector<ResampledHRTFPairT> m_hrtfResampledTimeDomain;
|
|||
|
|
std::vector<ResampledHRTFPairT> m_hrtfResampledFreqDomain;
|
|||
|
|
|
|||
|
|
std::map<int, std::pair<std::vector<int>, std::vector<int>>> m_hrtfDirections;
|
|||
|
|
|
|||
|
|
std::unique_ptr<FFTFilter> m_filter;
|
|||
|
|
std::unique_ptr<FFTFilter> m_hrtfFilterLeft;
|
|||
|
|
std::unique_ptr<FFTFilter> m_hrtfFilterRight;
|
|||
|
|
|
|||
|
|
std::vector<float> m_fadeWindow;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 DopplerEffect 多普勒效应
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class DopplerEffect {
|
|||
|
|
public:
|
|||
|
|
DopplerEffect();
|
|||
|
|
~DopplerEffect();
|
|||
|
|
|
|||
|
|
void SetSpeedOfSound(float metersPerSecond);
|
|||
|
|
float GetSpeedOfSound() const { return m_speedOfSound; }
|
|||
|
|
|
|||
|
|
void SetDopplerLevel(float level);
|
|||
|
|
float GetDopplerLevel() const { return m_dopplerLevel; }
|
|||
|
|
|
|||
|
|
float CalculatePitchShift(const Vector3& sourceVelocity,
|
|||
|
|
const Vector3& listenerVelocity,
|
|||
|
|
const Vector3& sourceToListener);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_speedOfSound = 343.0f;
|
|||
|
|
float m_dopplerLevel = 1.0f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 OcclusionSystem 遮蔽系统
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class OcclusionSystem {
|
|||
|
|
public:
|
|||
|
|
OcclusionSystem();
|
|||
|
|
~OcclusionSystem();
|
|||
|
|
|
|||
|
|
// 遮蔽计算
|
|||
|
|
float CalculateOcclusion(const Vector3& sourcePos, const Vector3& listenerPos,
|
|||
|
|
const std::vector<Vector3>& obstaclePositions);
|
|||
|
|
|
|||
|
|
float CalculateObstruction(const Vector3& sourcePos, const Vector3& listenerPos,
|
|||
|
|
const Vector3& obstaclePos);
|
|||
|
|
|
|||
|
|
// 遮蔽参数
|
|||
|
|
void SetOcclusionHighFreqAbsorption(float value);
|
|||
|
|
float GetOcclusionHighFreqAbsorption() const { return m_occlusionHighFreqAbsorb; }
|
|||
|
|
|
|||
|
|
void SetObstructionHighFreqDamping(float value);
|
|||
|
|
float GetObstructionHighFreqDamping() const { return m_obstructionHighFreqDamp; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_occlusionHighFreqAbsorb = 0.5f;
|
|||
|
|
float m_obstructionHighFreqDamp = 0.5f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第五章 音频后端抽象层
|
|||
|
|
|
|||
|
|
### 5.1 IAudioBackend 接口
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class IAudioBackend {
|
|||
|
|
public:
|
|||
|
|
virtual ~IAudioBackend() = default;
|
|||
|
|
|
|||
|
|
// 初始化与销毁
|
|||
|
|
virtual bool Initialize(const AudioConfig& config) = 0;
|
|||
|
|
virtual void Shutdown() = 0;
|
|||
|
|
|
|||
|
|
// 设备查询
|
|||
|
|
virtual String GetDeviceName() const = 0;
|
|||
|
|
virtual void GetAvailableDevices(std::vector<String>& devices) = 0;
|
|||
|
|
virtual bool SetDevice(const String& deviceName) = 0;
|
|||
|
|
|
|||
|
|
// 混音器控制
|
|||
|
|
virtual float GetMasterVolume() const = 0;
|
|||
|
|
virtual void SetMasterVolume(float volume) = 0;
|
|||
|
|
|
|||
|
|
virtual bool IsMuted() const = 0;
|
|||
|
|
virtual void SetMuted(bool muted) = 0;
|
|||
|
|
|
|||
|
|
// 播放控制
|
|||
|
|
virtual void Start() = 0;
|
|||
|
|
virtual void Stop() = 0;
|
|||
|
|
virtual void Suspend() = 0;
|
|||
|
|
virtual void Resume() = 0;
|
|||
|
|
|
|||
|
|
// 音频处理
|
|||
|
|
virtual void ProcessAudio(float* buffer, uint32_t bufferSize,
|
|||
|
|
uint32_t channels, uint32_t sampleRate) = 0;
|
|||
|
|
|
|||
|
|
// 状态查询
|
|||
|
|
virtual bool IsRunning() const = 0;
|
|||
|
|
virtual AudioConfig GetConfig() const = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 WASAPI 后端
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
namespace WASAPI {
|
|||
|
|
|
|||
|
|
class WASAPIBackend : public IAudioBackend {
|
|||
|
|
public:
|
|||
|
|
WASAPIBackend();
|
|||
|
|
~WASAPIBackend() override;
|
|||
|
|
|
|||
|
|
bool Initialize(const AudioConfig& config) override;
|
|||
|
|
void Shutdown() override;
|
|||
|
|
|
|||
|
|
String GetDeviceName() const override;
|
|||
|
|
void GetAvailableDevices(std::vector<String>& devices) override;
|
|||
|
|
bool SetDevice(const String& deviceName) override;
|
|||
|
|
|
|||
|
|
float GetMasterVolume() const override;
|
|||
|
|
void SetMasterVolume(float volume) override;
|
|||
|
|
|
|||
|
|
bool IsMuted() const override;
|
|||
|
|
void SetMuted(bool muted) override;
|
|||
|
|
|
|||
|
|
void Start() override;
|
|||
|
|
void Stop() override;
|
|||
|
|
void Suspend() override;
|
|||
|
|
void Resume() override;
|
|||
|
|
|
|||
|
|
void ProcessAudio(float* buffer, uint32_t bufferSize,
|
|||
|
|
uint32_t channels, uint32_t sampleRate) override;
|
|||
|
|
|
|||
|
|
bool IsRunning() const override { return m_isRunning; }
|
|||
|
|
AudioConfig GetConfig() const override { return m_config; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
MMRESULT InitDevice();
|
|||
|
|
MMRESULT InitClient();
|
|||
|
|
MMRESULT InitBuffer();
|
|||
|
|
|
|||
|
|
static DWORD WINAPI AudioThreadProc(LPVOID lpParameter);
|
|||
|
|
void AudioThread();
|
|||
|
|
|
|||
|
|
void OnAudioCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
|
|||
|
|
DWORD_PTR dwParam1, DWORD_PTR dwParam2);
|
|||
|
|
static void CALLBACK StaticAudioCallback(HWAVEOUT hwo, UINT uMsg,
|
|||
|
|
DWORD_PTR dwInstance,
|
|||
|
|
DWORD_PTR dwParam1, DWORD_PTR dwParam2);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
bool m_isRunning = false;
|
|||
|
|
std::thread m_audioThread;
|
|||
|
|
|
|||
|
|
AudioConfig m_config;
|
|||
|
|
|
|||
|
|
WAVEFORMATEX m_waveFormat = {};
|
|||
|
|
HWAVEOUT m_hWaveOut = nullptr;
|
|||
|
|
HANDLE m_hEvent = nullptr;
|
|||
|
|
|
|||
|
|
std::vector<float> m_mixBuffer;
|
|||
|
|
uint32_t m_mixBufferSize = 0;
|
|||
|
|
|
|||
|
|
std::vector<WAVEOUTCAPS> m_waveOutCaps;
|
|||
|
|
String m_deviceName;
|
|||
|
|
|
|||
|
|
IAudioEffect* m_masterEffect = nullptr;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace WASAPI
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3 OpenAL 后端
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
namespace OpenAL {
|
|||
|
|
|
|||
|
|
class OpenALBackend : public IAudioBackend {
|
|||
|
|
public:
|
|||
|
|
OpenALBackend();
|
|||
|
|
~OpenALBackend() override;
|
|||
|
|
|
|||
|
|
bool Initialize(const AudioConfig& config) override;
|
|||
|
|
void Shutdown() override;
|
|||
|
|
|
|||
|
|
String GetDeviceName() const override;
|
|||
|
|
void GetAvailableDevices(std::vector<String>& devices) override;
|
|||
|
|
bool SetDevice(const String& deviceName) override;
|
|||
|
|
|
|||
|
|
float GetMasterVolume() const override;
|
|||
|
|
void SetMasterVolume(float volume) override;
|
|||
|
|
|
|||
|
|
bool IsMuted() const override;
|
|||
|
|
void SetMuted(bool muted) override;
|
|||
|
|
|
|||
|
|
void Start() override;
|
|||
|
|
void Stop() override;
|
|||
|
|
void Suspend() override;
|
|||
|
|
void Resume() override;
|
|||
|
|
|
|||
|
|
void ProcessAudio(float* buffer, uint32_t bufferSize,
|
|||
|
|
uint32_t channels, uint32_t sampleRate) override;
|
|||
|
|
|
|||
|
|
bool IsRunning() const override { return m_isRunning; }
|
|||
|
|
AudioConfig GetConfig() const override { return m_config; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
bool m_isRunning = false;
|
|||
|
|
AudioConfig m_config;
|
|||
|
|
|
|||
|
|
ALCdevice* m_device = nullptr;
|
|||
|
|
ALCcontext* m_context = nullptr;
|
|||
|
|
ALuint m_source = 0;
|
|||
|
|
ALuint m_buffers[2];
|
|||
|
|
|
|||
|
|
std::vector<float> m_mixBuffer;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace OpenAL
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第六章 音频系统核心
|
|||
|
|
|
|||
|
|
### 6.1 AudioSystem
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioSystem {
|
|||
|
|
public:
|
|||
|
|
static AudioSystem& Get();
|
|||
|
|
|
|||
|
|
void Initialize(const AudioConfig& config);
|
|||
|
|
void Shutdown();
|
|||
|
|
|
|||
|
|
void Update(float deltaTime);
|
|||
|
|
|
|||
|
|
// 后端控制
|
|||
|
|
void SetBackend(std::unique_ptr<IAudioBackend> backend);
|
|||
|
|
IAudioBackend* GetBackend() const { return m_backend.get(); }
|
|||
|
|
|
|||
|
|
// 设备控制
|
|||
|
|
String GetCurrentDevice() const;
|
|||
|
|
void SetDevice(const String& deviceName);
|
|||
|
|
void GetAvailableDevices(std::vector<String>& devices);
|
|||
|
|
|
|||
|
|
// 全局混音控制
|
|||
|
|
float GetMasterVolume() const;
|
|||
|
|
void SetMasterVolume(float volume);
|
|||
|
|
|
|||
|
|
bool IsMuted() const;
|
|||
|
|
void SetMuted(bool muted);
|
|||
|
|
|
|||
|
|
// 音频处理
|
|||
|
|
void ProcessAudio(float* buffer, uint32_t sampleCount, uint32_t channels);
|
|||
|
|
|
|||
|
|
// 资源管理
|
|||
|
|
AudioClip* LoadAudioClip(const String& filePath);
|
|||
|
|
void UnloadAudioClip(AudioClip* clip);
|
|||
|
|
|
|||
|
|
AudioMixer* CreateMixer(const String& name);
|
|||
|
|
void DestroyMixer(AudioMixer* mixer);
|
|||
|
|
|
|||
|
|
// 空间化
|
|||
|
|
void SetListenerTransform(const Vector3& position, const Quaternion& rotation);
|
|||
|
|
void SetListenerVelocity(const Vector3& velocity);
|
|||
|
|
|
|||
|
|
const Vector3& GetListenerPosition() const { return m_listenerPosition; }
|
|||
|
|
const Quaternion& GetListenerRotation() const { return m_listenerRotation; }
|
|||
|
|
const Vector3& GetListenerVelocity() const { return m_listenerVelocity; }
|
|||
|
|
|
|||
|
|
// 统计信息
|
|||
|
|
struct Stats {
|
|||
|
|
uint32_t activeSources;
|
|||
|
|
uint32_t totalSources;
|
|||
|
|
uint64_t memoryUsage;
|
|||
|
|
float cpuUsage;
|
|||
|
|
};
|
|||
|
|
const Stats& GetStats() const { return m_stats; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
AudioSystem() = default;
|
|||
|
|
~AudioSystem() = default;
|
|||
|
|
|
|||
|
|
AudioSystem(const AudioSystem&) = delete;
|
|||
|
|
AudioSystem& operator=(const AudioSystem&) = delete;
|
|||
|
|
|
|||
|
|
void ProcessSource(AudioSourceComponent* source);
|
|||
|
|
void ApplyGlobalEffects(float* buffer, uint32_t sampleCount, uint32_t channels);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
std::unique_ptr<IAudioBackend> m_backend;
|
|||
|
|
|
|||
|
|
Vector3 m_listenerPosition = Vector3::Zero();
|
|||
|
|
Quaternion m_listenerRotation = Quaternion::Identity();
|
|||
|
|
Vector3 m_listenerVelocity = Vector3::Zero();
|
|||
|
|
|
|||
|
|
std::vector<std::unique_ptr<AudioClip>> m_loadedClips;
|
|||
|
|
std::map<String, std::unique_ptr<AudioMixer>> m_mixers;
|
|||
|
|
|
|||
|
|
std::vector<AudioSourceComponent*> m_activeSources;
|
|||
|
|
|
|||
|
|
Stats m_stats = {};
|
|||
|
|
float m_deltaTime = 0.0f;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 AudioSourceComponent
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Components {
|
|||
|
|
|
|||
|
|
class AudioSourceComponent : public Component {
|
|||
|
|
public:
|
|||
|
|
AudioSourceComponent();
|
|||
|
|
~AudioSourceComponent();
|
|||
|
|
|
|||
|
|
// 播放控制
|
|||
|
|
void Play();
|
|||
|
|
void Pause();
|
|||
|
|
void Stop(StopMode mode = StopMode::Immediate);
|
|||
|
|
bool IsPlaying() const { return m_playState == Audio::PlayState::Playing; }
|
|||
|
|
bool IsPaused() const { return m_playState == Audio::PlayState::Paused; }
|
|||
|
|
|
|||
|
|
// 音频剪辑
|
|||
|
|
void SetClip(Audio::AudioClip* clip);
|
|||
|
|
Audio::AudioClip* GetClip() const { return m_clip; }
|
|||
|
|
|
|||
|
|
// 播放参数
|
|||
|
|
void SetVolume(float volume);
|
|||
|
|
float GetVolume() const { return m_volume; }
|
|||
|
|
|
|||
|
|
void SetPitch(float pitch);
|
|||
|
|
float GetPitch() const { return m_pitch; }
|
|||
|
|
|
|||
|
|
void SetPan(float pan);
|
|||
|
|
float GetPan() const { return m_pan; }
|
|||
|
|
|
|||
|
|
// 循环
|
|||
|
|
void SetLooping(bool loop);
|
|||
|
|
bool IsLooping() const { return m_isLooping; }
|
|||
|
|
|
|||
|
|
// 3D 空间化
|
|||
|
|
void SetSpatialize(bool spatialize);
|
|||
|
|
bool IsSpatialize() const { return m_spatialize; }
|
|||
|
|
|
|||
|
|
void Set3DParams(const Audio::Audio3DParams& params);
|
|||
|
|
const Audio::Audio3DParams& Get3DParams() const { return m_3DParams; }
|
|||
|
|
|
|||
|
|
void SetDopplerLevel(float level);
|
|||
|
|
float GetDopplerLevel() const { return m_3DParams.dopplerLevel; }
|
|||
|
|
|
|||
|
|
void SetSpread(float spread);
|
|||
|
|
float GetSpread() const { return m_3DParams.spread; }
|
|||
|
|
|
|||
|
|
void SetReverbZoneMix(float mix);
|
|||
|
|
float GetReverbZoneMix() const { return m_3DParams.reverbZoneMix; }
|
|||
|
|
|
|||
|
|
// 混音器
|
|||
|
|
void SetOutputMixer(Audio::AudioMixer* mixer);
|
|||
|
|
Audio::AudioMixer* GetOutputMixer() const { return m_outputMixer; }
|
|||
|
|
|
|||
|
|
// 播放位置
|
|||
|
|
void SetTime(float seconds);
|
|||
|
|
float GetTime() const;
|
|||
|
|
float GetDuration() const;
|
|||
|
|
|
|||
|
|
// 能量检测
|
|||
|
|
float GetEnergy() const { return m_energy; }
|
|||
|
|
void StartEnergyDetect();
|
|||
|
|
void StopEnergyDetect();
|
|||
|
|
bool IsEnergyDetecting() const { return m_isEnergyDetecting; }
|
|||
|
|
|
|||
|
|
// Component 虚函数
|
|||
|
|
void Update(float deltaTime) override;
|
|||
|
|
void OnEnable() override;
|
|||
|
|
void OnDisable() override;
|
|||
|
|
void OnDestroy() override;
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
void Apply3DAttenuation();
|
|||
|
|
void ProcessEffects(float* buffer, uint32_t sampleCount);
|
|||
|
|
void UpdateEnergy(const float* buffer, uint32_t sampleCount);
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
Audio::AudioClip* m_clip = nullptr;
|
|||
|
|
Audio::AudioMixer* m_outputMixer = nullptr;
|
|||
|
|
|
|||
|
|
PlayState m_playState = PlayState::Stopped;
|
|||
|
|
bool m_isLooping = false;
|
|||
|
|
|
|||
|
|
float m_volume = 1.0f;
|
|||
|
|
float m_pitch = 1.0f;
|
|||
|
|
float m_pan = 0.0f;
|
|||
|
|
bool m_spatialize = true;
|
|||
|
|
|
|||
|
|
Audio::Audio3DParams m_3DParams;
|
|||
|
|
|
|||
|
|
// 播放状态
|
|||
|
|
uint64_t m_samplePosition = 0;
|
|||
|
|
double m_lastingTime = 0.0;
|
|||
|
|
|
|||
|
|
// 能量检测
|
|||
|
|
bool m_isEnergyDetecting = false;
|
|||
|
|
float m_energy = 0.0f;
|
|||
|
|
float m_maxEnergy = 5.0f;
|
|||
|
|
std::deque<float> m_energyHistory;
|
|||
|
|
|
|||
|
|
// 效果链
|
|||
|
|
std::vector<Audio::IAudioEffect*> m_effects;
|
|||
|
|
std::unique_ptr<Audio::HRTF> m_hrtf;
|
|||
|
|
std::unique_ptr<Audio::DopplerEffect> m_doppler;
|
|||
|
|
|
|||
|
|
// 输出缓冲
|
|||
|
|
static constexpr size_t BufferSize = 8192;
|
|||
|
|
std::vector<float> m_outputBuffer;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Components
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 AudioListenerComponent
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Components {
|
|||
|
|
|
|||
|
|
class AudioListenerComponent : public Component {
|
|||
|
|
public:
|
|||
|
|
AudioListenerComponent();
|
|||
|
|
~AudioListenerComponent();
|
|||
|
|
|
|||
|
|
// 能量检测
|
|||
|
|
float GetEnergy() const { return m_energy; }
|
|||
|
|
const float* GetFrequencyData() const { return m_frequencyData.data(); }
|
|||
|
|
size_t GetFrequencyDataSize() const { return m_frequencyData.size(); }
|
|||
|
|
|
|||
|
|
// 全局参数
|
|||
|
|
void SetMasterVolume(float volume);
|
|||
|
|
float GetMasterVolume() const { return m_masterVolume; }
|
|||
|
|
|
|||
|
|
void SetMute(bool mute);
|
|||
|
|
bool IsMute() const { return m_mute; }
|
|||
|
|
|
|||
|
|
// 空间化参数
|
|||
|
|
void SetDopplerLevel(float level);
|
|||
|
|
float GetDopplerLevel() const { return m_dopplerLevel; }
|
|||
|
|
|
|||
|
|
void SetSpeedOfSound(float metersPerSecond);
|
|||
|
|
float GetSpeedOfSound() const { return m_speedOfSound; }
|
|||
|
|
|
|||
|
|
// 混响
|
|||
|
|
void SetReverbLevel(float level);
|
|||
|
|
float GetReverbLevel() const { return m_reverbLevel; }
|
|||
|
|
|
|||
|
|
void SetReverb(Audio::AudioMixer* reverb);
|
|||
|
|
Audio::AudioMixer* GetReverb() const { return m_reverb; }
|
|||
|
|
|
|||
|
|
// Component 虚函数
|
|||
|
|
void Update(float deltaTime) override;
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
float m_masterVolume = 1.0f;
|
|||
|
|
bool m_mute = false;
|
|||
|
|
float m_dopplerLevel = 1.0f;
|
|||
|
|
float m_speedOfSound = 343.0f;
|
|||
|
|
float m_reverbLevel = 1.0f;
|
|||
|
|
|
|||
|
|
Audio::AudioMixer* m_reverb = nullptr;
|
|||
|
|
|
|||
|
|
float m_energy = 0.0f;
|
|||
|
|
std::vector<float> m_frequencyData;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Components
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第七章 事件系统
|
|||
|
|
|
|||
|
|
### 7.1 AudioEvent
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioEvent {
|
|||
|
|
public:
|
|||
|
|
AudioEvent() = default;
|
|||
|
|
AudioEvent(const String& name) : m_name(name) {}
|
|||
|
|
|
|||
|
|
using Callback = std::function<void()>;
|
|||
|
|
using FloatCallback = std::function<void(float)>;
|
|||
|
|
|
|||
|
|
uint64_t Subscribe(Callback callback);
|
|||
|
|
uint64_t Subscribe(FloatCallback callback, float param);
|
|||
|
|
|
|||
|
|
void Unsubscribe(uint64_t id);
|
|||
|
|
void ProcessUnsubscribes();
|
|||
|
|
|
|||
|
|
void Invoke() const;
|
|||
|
|
void Invoke(float param) const;
|
|||
|
|
|
|||
|
|
void Clear();
|
|||
|
|
|
|||
|
|
const String& GetName() const { return m_name; }
|
|||
|
|
void SetName(const String& name) { m_name = name; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
struct ListenerBase {
|
|||
|
|
virtual ~ListenerBase() = default;
|
|||
|
|
virtual void Call() = 0;
|
|||
|
|
virtual void CallFloat(float) = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
template<typename Func>
|
|||
|
|
struct Listener : ListenerBase {
|
|||
|
|
Listener(Func&& f) : func(std::move(f)) {}
|
|||
|
|
void Call() override { func(); }
|
|||
|
|
void CallFloat(float) override {
|
|||
|
|
if constexpr (std::is_invocable_v<Func, float>) {
|
|||
|
|
func(0.0f);
|
|||
|
|
} else {
|
|||
|
|
func();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Func func;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
String m_name;
|
|||
|
|
std::vector<std::pair<uint64_t, std::unique_ptr<ListenerBase>>> m_listeners;
|
|||
|
|
std::vector<uint64_t> m_pendingUnsubscribes;
|
|||
|
|
uint64_t m_nextId = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 AudioEventSystem
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Audio {
|
|||
|
|
|
|||
|
|
class AudioEventSystem {
|
|||
|
|
public:
|
|||
|
|
static AudioEventSystem& Get();
|
|||
|
|
|
|||
|
|
void Initialize();
|
|||
|
|
void Shutdown();
|
|||
|
|
|
|||
|
|
// 事件创建
|
|||
|
|
AudioEvent* CreateEvent(const String& name);
|
|||
|
|
AudioEvent* GetEvent(const String& name);
|
|||
|
|
AudioEvent* GetEvent(uint64_t id);
|
|||
|
|
|
|||
|
|
void DestroyEvent(const String& name);
|
|||
|
|
void DestroyEvent(uint64_t id);
|
|||
|
|
|
|||
|
|
// 触发事件
|
|||
|
|
void TriggerEvent(const String& name);
|
|||
|
|
void TriggerEvent(uint64_t id);
|
|||
|
|
void TriggerEvent(const String& name, float param);
|
|||
|
|
void TriggerEvent(uint64_t id, float param);
|
|||
|
|
|
|||
|
|
// 订阅
|
|||
|
|
uint64_t Subscribe(const String& eventName, AudioEvent::Callback callback);
|
|||
|
|
uint64_t Subscribe(const String& eventName, AudioEvent::FloatCallback callback, float param);
|
|||
|
|
|
|||
|
|
// 状态
|
|||
|
|
bool HasEvent(const String& name) const;
|
|||
|
|
bool HasEvent(uint64_t id) const;
|
|||
|
|
size_t GetEventCount() const { return m_events.size(); }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
AudioEventSystem() = default;
|
|||
|
|
~AudioEventSystem() = default;
|
|||
|
|
|
|||
|
|
std::map<String, std::unique_ptr<AudioEvent>> m_events;
|
|||
|
|
std::map<uint64_t, AudioEvent*> m_idToEvent;
|
|||
|
|
uint64_t m_nextEventId = 0;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Audio
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第八章 资源管理集成
|
|||
|
|
|
|||
|
|
### 8.1 AudioClipLoader
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Resources {
|
|||
|
|
|
|||
|
|
class AudioClipLoader : public IResourceLoader {
|
|||
|
|
public:
|
|||
|
|
AudioClipLoader();
|
|||
|
|
~AudioClipLoader() override;
|
|||
|
|
|
|||
|
|
bool CanLoad(const String& extension) const override;
|
|||
|
|
IResource* Load(const String& filePath) override;
|
|||
|
|
bool LoadAsync(const String& filePath, std::function<void(IResource*)> callback) override;
|
|||
|
|
void Unload(IResource* resource) override;
|
|||
|
|
|
|||
|
|
// 获取支持的文件格式
|
|||
|
|
static const std::vector<String>& GetSupportedExtensions();
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
static std::vector<String> s_supportedExtensions;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Resources
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 ResourceManager 集成
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
namespace XCEngine {
|
|||
|
|
namespace Resources {
|
|||
|
|
|
|||
|
|
// 在 ResourceManager 中添加音频相关接口
|
|||
|
|
|
|||
|
|
template<>
|
|||
|
|
class ResourceHandle<Audio::AudioClip> {
|
|||
|
|
public:
|
|||
|
|
ResourceHandle() = default;
|
|||
|
|
explicit ResourceHandle(Audio::AudioClip* resource);
|
|||
|
|
|
|||
|
|
Audio::AudioClip* Get() const { return m_resource; }
|
|||
|
|
Audio::AudioClip* operator->() const { return m_resource; }
|
|||
|
|
|
|||
|
|
explicit operator bool() const { return m_resource != nullptr; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
Audio::AudioClip* m_resource = nullptr;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace Resources
|
|||
|
|
} // namespace XCEngine
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 第九章 目录结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
XCEngine/
|
|||
|
|
├── engine/ # 引擎核心库
|
|||
|
|
│ ├── include/XCEngine/
|
|||
|
|
│ │ ├── Audio/ # 音频模块
|
|||
|
|
│ │ │ ├── AudioSystem.h # 音频系统入口
|
|||
|
|
│ │ │ ├── AudioConfig.h # 配置结构
|
|||
|
|
│ │ │ ├── AudioTypes.h # 基础类型定义
|
|||
|
|
│ │ │ ├── IAudioBackend.h # 后端抽象接口
|
|||
|
|
│ │ │ ├── AudioBackendFactory.h # 后端工厂
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ ├── AudioClip.h # 音频剪辑资源
|
|||
|
|
│ │ │ ├── AudioMixer.h # 混音器
|
|||
|
|
│ │ │ ├── AudioBank.h # 音频银行
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ ├── IAudioEffect.h # 效果器接口
|
|||
|
|
│ │ │ ├── FFTFilter.h # FFT频谱分析
|
|||
|
|
│ │ │ ├── Reverbation.h # 混响效果
|
|||
|
|
│ │ │ ├── Equalizer.h # 均衡器
|
|||
|
|
│ │ │ ├── Compressor.h # 压缩器
|
|||
|
|
│ │ │ ├── Limiter.h # 限制器
|
|||
|
|
│ │ │ ├── DopplerEffect.h # 多普勒效应
|
|||
|
|
│ │ │ ├── OcclusionSystem.h # 遮蔽系统
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ ├── Spatializer.h # 空间化处理
|
|||
|
|
│ │ │ ├── HRTF.h # HRTF实现
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ ├── AudioEvent.h # 音频事件
|
|||
|
|
│ │ │ ├── AudioEventSystem.h # 事件系统
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ ├── WASAPI/
|
|||
|
|
│ │ │ │ └── WASAPIBackend.h # WASAPI后端
|
|||
|
|
│ │ │ └── OpenAL/
|
|||
|
|
│ │ │ └── OpenALBackend.h # OpenAL后端
|
|||
|
|
│ │ │ │
|
|||
|
|
│ │ │ └── XCEngineAudio.h # 主头文件
|
|||
|
|
│ │ │
|
|||
|
|
│ │ └── Components/
|
|||
|
|
│ │ ├── AudioSourceComponent.h # 声源组件
|
|||
|
|
│ │ └── AudioListenerComponent.h # 监听器组件
|
|||
|
|
│ │
|
|||
|
|
│ └── src/Audio/
|
|||
|
|
│ ├── AudioSystem.cpp
|
|||
|
|
│ ├── AudioClip.cpp
|
|||
|
|
│ ├── AudioMixer.cpp
|
|||
|
|
│ ├── FFTFilter.cpp
|
|||
|
|
│ ├── Reverbation.cpp
|
|||
|
|
│ ├── Equalizer.cpp
|
|||
|
|
│ ├── HRTF.cpp
|
|||
|
|
│ ├── DopplerEffect.cpp
|
|||
|
|
│ ├── OcclusionSystem.cpp
|
|||
|
|
│ ├── AudioEventSystem.cpp
|
|||
|
|
│ ├── WASAPI/
|
|||
|
|
│ │ └── WASAPIBackend.cpp
|
|||
|
|
│ └── OpenAL/
|
|||
|
|
│ └── OpenALBackend.cpp
|
|||
|
|
│
|
|||
|
|
├── mvs/ # 示例应用
|
|||
|
|
│ └── Music fluctuations/ # 音频示例(参考)
|
|||
|
|
│ ├── source/
|
|||
|
|
│ │ ├── audio/ # 基础音频
|
|||
|
|
│ │ ├── audio3d/ # 3D音频
|
|||
|
|
│ │ ├── kissfft/ # FFT库
|
|||
|
|
│ │ └── libsamplerate/ # 重采样库
|
|||
|
|
│ └── res/ # 音频资源
|
|||
|
|
│
|
|||
|
|
└── tests/Audio/ # 音频模块测试
|
|||
|
|
├── AudioSystemTest.cpp
|
|||
|
|
├── AudioClipTest.cpp
|
|||
|
|
├── SpatializerTest.cpp
|
|||
|
|
└── HRTFTest.cpp
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 附录:实现优先级
|
|||
|
|
|
|||
|
|
### 第一阶段 - 基础音频
|
|||
|
|
1. AudioSystem 核心框架
|
|||
|
|
2. AudioClip 资源加载(WAV格式)
|
|||
|
|
3. AudioSourceComponent 播放控制
|
|||
|
|
4. AudioListenerComponent 监听器
|
|||
|
|
5. WASAPI 后端实现
|
|||
|
|
|
|||
|
|
### 第二阶段 - 3D 空间音频
|
|||
|
|
1. HRTF 空间化
|
|||
|
|
2. DopplerEffect 多普勒效应
|
|||
|
|
3. OcclusionSystem 遮蔽系统
|
|||
|
|
4. 距离衰减
|
|||
|
|
|
|||
|
|
### 第三阶段 - 效果系统
|
|||
|
|
1. FFTFilter 频谱分析
|
|||
|
|
2. Reverbation 混响
|
|||
|
|
3. Equalizer 均衡器
|
|||
|
|
4. Compressor/Limiter 动态效果
|
|||
|
|
5. 效果链系统
|
|||
|
|
|
|||
|
|
### 第四阶段 - 混音与事件
|
|||
|
|
1. AudioMixer 混音器
|
|||
|
|
2. AudioEvent 事件系统
|
|||
|
|
3. AudioBank 分段加载
|
|||
|
|
4. OpenAL 后端实现
|
|||
|
|
|
|||
|
|
### 第五阶段 - 优化与扩展
|
|||
|
|
1. 资源异步加载
|
|||
|
|
2. 性能优化
|
|||
|
|
3. profiler 集成
|
|||
|
|
4. 更多音频格式支持
|