1 #include "audio.h"
2
3 #ifdef HAVE_XAUDIO2
4
5 #include <xaudio2.h>
6 #include <math.h>
7
8 struct AudioContext
9 {
10 IXAudio2 *xaudio2;
11 IXAudio2MasteringVoice *mastering_voice;
12 };
13
14 struct AudioVoice
15 {
16 AudioContext *context;
17 IXAudio2SourceVoice *voice;
18 };
19
20 struct AudioFilter
21 {
22 AudioContext *context;
23 XAUDIO2_FILTER_PARAMETERS params;
24 };
25
xaudio_destroy_context(AudioContext * p_context)26 void xaudio_destroy_context(AudioContext *p_context)
27 {
28 p_context->mastering_voice->DestroyVoice();
29 p_context->xaudio2->Release();
30 delete p_context;
31 }
32
xaudio_create_voice(AudioContext * p_context,float * p_buffer,size_t p_buffer_size,int p_sample_rate,int p_num_channels)33 AudioVoice *xaudio_create_voice(AudioContext *p_context, float *p_buffer, size_t p_buffer_size, int p_sample_rate, int p_num_channels)
34 {
35 // create a source voice
36 WAVEFORMATEX waveFormat;
37 waveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
38 waveFormat.nChannels = p_num_channels;
39 waveFormat.nSamplesPerSec = p_sample_rate;
40 waveFormat.nBlockAlign = p_num_channels * 4;
41 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
42 waveFormat.wBitsPerSample = 32;
43 waveFormat.cbSize = 0;
44
45 IXAudio2SourceVoice *voice;
46 XAUDIO2_SEND_DESCRIPTOR send;
47 XAUDIO2_VOICE_SENDS sends;
48 sends.SendCount = 1;
49 sends.pSends = &send;
50 send.Flags = XAUDIO2_SEND_USEFILTER;
51 send.pOutputVoice = p_context->mastering_voice;
52 HRESULT hr = p_context->xaudio2->CreateSourceVoice(&voice, &waveFormat, XAUDIO2_VOICE_USEFILTER, XAUDIO2_DEFAULT_FREQ_RATIO, NULL, &sends);
53
54 if (FAILED(hr)) {
55 return NULL;
56 }
57
58 voice->SetVolume(0.0f);
59
60 // submit the array
61 XAUDIO2_BUFFER buffer = { 0 };
62 buffer.AudioBytes = 4 * p_buffer_size * p_num_channels;
63 buffer.pAudioData = (byte *)p_buffer;
64 buffer.Flags = XAUDIO2_END_OF_STREAM;
65 buffer.PlayBegin = 0;
66 buffer.PlayLength = 0;
67 buffer.LoopBegin = 0;
68 buffer.LoopLength = 0;
69 buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
70
71 hr = voice->SubmitSourceBuffer(&buffer);
72
73 if (FAILED(hr)) {
74 return NULL;
75 }
76
77 // start the voice playing
78 voice->Start();
79
80 // return a voice struct
81 AudioVoice *result = new AudioVoice();
82 result->context = p_context;
83 result->voice = voice;
84 return result;
85 }
86
xaudio_voice_destroy(AudioVoice * p_voice)87 void xaudio_voice_destroy(AudioVoice *p_voice)
88 {
89
90 }
91
xaudio_voice_set_volume(AudioVoice * p_voice,float p_volume)92 void xaudio_voice_set_volume(AudioVoice *p_voice, float p_volume)
93 {
94 p_voice->voice->SetVolume(p_volume);
95 }
96
xaudio_voice_set_frequency(AudioVoice * p_voice,float p_frequency)97 void xaudio_voice_set_frequency(AudioVoice *p_voice, float p_frequency)
98 {
99 p_voice->voice->SetFrequencyRatio(p_frequency);
100 }
101
xaudio_create_filter(AudioContext * p_context)102 AudioFilter *xaudio_create_filter(AudioContext *p_context)
103 {
104 AudioFilter *filter = new AudioFilter();
105 filter->context = p_context;
106 return filter;
107 }
108
xaudio_filter_update(AudioFilter * p_filter,int p_type,float p_cutoff_frequency,float p_q)109 void xaudio_filter_update(AudioFilter *p_filter, int p_type, float p_cutoff_frequency, float p_q)
110 {
111 if (p_type != -1)
112 {
113 p_filter->params.Type = XAUDIO2_FILTER_TYPE(p_type);
114 p_filter->params.Frequency = (float) (2 * sin(PI * p_cutoff_frequency / 44100));
115 p_filter->params.OneOverQ = (float)(1.0 / p_q);
116 }
117 else
118 {
119 // documentation of XAUDIO2_FILTER_PARAMETERS:
120 // Setting XAUDIO2_FILTER_PARAMETERS with the following values is acoustically equivalent to the filter being fully bypassed.
121 p_filter->params.Type = LowPassFilter;
122 p_filter->params.Frequency = 1.0f;
123 p_filter->params.OneOverQ = 1.0f;
124 }
125 }
126
xaudio_filter_apply(AudioFilter * p_filter,AudioVoice * p_voice)127 void xaudio_filter_apply(AudioFilter *p_filter, AudioVoice *p_voice)
128 {
129 p_voice->voice->SetFilterParameters(&p_filter->params, XAUDIO2_COMMIT_ALL);
130 }
131
xaudio_output_filter_apply(AudioFilter * p_filter,AudioVoice * p_voice)132 void xaudio_output_filter_apply(AudioFilter *p_filter, AudioVoice *p_voice)
133 {
134 p_voice->voice->SetOutputFilterParameters(p_voice->context->mastering_voice, &p_filter->params, XAUDIO2_COMMIT_ALL);
135 }
136
xaudio_create_context()137 AudioContext *xaudio_create_context()
138 {
139 // setup function pointers
140 audio_destroy_context = xaudio_destroy_context;
141 audio_create_voice = xaudio_create_voice;
142 audio_voice_destroy = xaudio_voice_destroy;
143 audio_voice_set_volume = xaudio_voice_set_volume;
144 audio_voice_set_frequency = xaudio_voice_set_frequency;
145 audio_create_filter = xaudio_create_filter;
146 audio_filter_update = xaudio_filter_update;
147 audio_filter_apply = xaudio_filter_apply;
148 audio_output_filter_apply = xaudio_output_filter_apply;
149
150 // create XAudio object
151 IXAudio2 *xaudio2;
152
153 HRESULT hr = XAudio2Create(&xaudio2);
154 if (FAILED(hr))
155 return NULL;
156
157 // create a mastering voice
158 IXAudio2MasteringVoice *mastering_voice;
159
160 hr = xaudio2->CreateMasteringVoice(&mastering_voice);
161 if (FAILED(hr))
162 return NULL;
163
164 // return a context object
165 AudioContext *context = new AudioContext();
166 context->xaudio2 = xaudio2;
167 context->mastering_voice = mastering_voice;
168
169 return context;
170 }
171
172 #endif // HAVE_XAUDIO2
173