-
Notifications
You must be signed in to change notification settings - Fork 0
/
CardioidSound.cpp
154 lines (135 loc) · 5.13 KB
/
CardioidSound.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#include "pch.h"
#include "CardioidSound.h"
_Use_decl_annotations_
HRESULT CardioidSound::Initialize(LPCWSTR filename)
{
auto hr = _audioFile.Initialize(filename);
if (SUCCEEDED(hr))
{
// Initialize with "Scaling" fully directional and "Order" with broad radiation pattern.
// As the order goes higher, the cardioid directivity region becomes narrower.
// Any direct path signal outside of the directivity region will be attenuated based on the scaling factor.
// For example, if scaling is set to 1 (fully directional) the direct path signal outside of the directivity
// region will be fully attenuated and only the reflections from the environment will be audible.
hr = ConfigureApo(1.0f, 4.0f);
}
return hr;
}
CardioidSound::~CardioidSound()
{
if (_sourceVoice)
{
_sourceVoice->DestroyVoice();
}
}
_Use_decl_annotations_
HRESULT CardioidSound::ConfigureApo(float scaling, float order)
{
// Directivity is specified at xAPO instance initialization and cannot be changed per frame.
// To change directivity, we'll need to stop audio processing and reinitialize another APO instance with the new directivity.
if (_xaudio2)
{
_xaudio2->StopEngine();
_xaudio2.Reset();
}
if (_hrtfParams)
{
_hrtfParams.Reset();
}
// Cardioid directivity configuration
HrtfDirectivityCardioid cardioid{};
cardioid.directivity.type = HrtfDirectivityType::Cardioid;
cardioid.directivity.scaling = scaling;
cardioid.order = order;
// APO intialization
HrtfApoInit apoInit{};
apoInit.directivity = &cardioid.directivity;
apoInit.distanceDecay = nullptr; // This specifies natural distance decay behavior (simulates real world)
// CreateHrtfApo will fail with E_NOTIMPL on unsupported platforms.
ComPtr<IXAPO> xapo;
auto hr = CreateHrtfApo(&apoInit, &xapo);
if (SUCCEEDED(hr))
{
hr = xapo.As(&_hrtfParams);
}
// Set the initial environment.
// Environment settings configure the "distance cues" used to compute the early and late reverberations.
if (SUCCEEDED(hr))
{
hr = _hrtfParams->SetEnvironment(_environment);
}
// Initialize an XAudio2 graph that hosts the HRTF xAPO.
// The source voice is used to submit audio data and control playback.
if (SUCCEEDED(hr))
{
hr = SetupXAudio2(_audioFile.GetFormat(), xapo.Get(), &_xaudio2, &_sourceVoice);
}
// Submit audio data to the source voice
if (SUCCEEDED(hr))
{
XAUDIO2_BUFFER buffer{};
buffer.AudioBytes = static_cast<UINT32>(_audioFile.GetSize());
buffer.pAudioData = _audioFile.GetData();
buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
hr = _sourceVoice->SubmitSourceBuffer(&buffer);
}
return hr;
}
HRESULT CardioidSound::Start()
{
return _sourceVoice->Start();
}
HRESULT CardioidSound::Stop()
{
return _sourceVoice->Stop();
}
_Use_decl_annotations_
HRESULT CardioidSound::SetEnvironment(HrtfEnvironment environment)
{
// Environment can be changed at any time.
return _hrtfParams->SetEnvironment(environment);
}
//
// This method is called on every dispatcher timer tick.
// Source position is provided in right-handed coordinate system and
// source orientation as Yaw, Pitch, Roll in radians. This information
// is relative to the listener's head (listener is always at {0, 0, 0}).
//
_Use_decl_annotations_
HRESULT CardioidSound::OnUpdate(_In_ float x, _In_ float y, _In_ float z, _In_ float pitch, _In_ float yaw, _In_ float roll)
{
auto hr = S_OK;
if (_hrtfParams)
{
auto position = HrtfPosition{ x, y, z };
hr = _hrtfParams->SetSourcePosition(&position);
if (SUCCEEDED(hr))
{
auto sourceOrientation = OrientationFromAngles(pitch, yaw, roll);
hr = _hrtfParams->SetSourceOrientation(&sourceOrientation);
}
}
return hr;
}
// Helper to translate from pitch, yaw, roll to the rotation matrix.
_Use_decl_annotations_
HrtfOrientation CardioidSound::OrientationFromAngles(_In_ float pitch, _In_ float yaw, _In_ float roll)
{
// Negate all angles for right handed coordinate system.
DirectX::XMFLOAT3 angles{ -pitch, -yaw, -roll };
DirectX::XMVECTOR vector = DirectX::XMLoadFloat3(&angles);
DirectX::XMMATRIX rm = DirectX::XMMatrixRotationRollPitchYawFromVector(vector);
DirectX::XMFLOAT3X3 rm33{};
DirectX::XMStoreFloat3x3(&rm33, rm);
return HrtfOrientation{ rm33._11, rm33._12, rm33._13, rm33._21, rm33._22, rm33._23, rm33._31, rm33._32, rm33._33 };
}