1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include "Effect.h" |
22 | #include "common/Exception.h" |
23 | |
24 | #include <cmath> |
25 | #include <iostream> |
26 | |
27 | namespace love |
28 | { |
29 | namespace audio |
30 | { |
31 | namespace openal |
32 | { |
33 | |
34 | //base class |
35 | Effect::Effect() |
36 | { |
37 | generateEffect(); |
38 | } |
39 | |
40 | Effect::Effect(const Effect &s) |
41 | : Effect() |
42 | { |
43 | setParams(s.getParams()); |
44 | } |
45 | |
46 | Effect::~Effect() |
47 | { |
48 | deleteEffect(); |
49 | } |
50 | |
51 | Effect *Effect::clone() |
52 | { |
53 | return new Effect(*this); |
54 | } |
55 | |
56 | bool Effect::generateEffect() |
57 | { |
58 | #ifdef ALC_EXT_EFX |
59 | if (!alGenEffects) |
60 | return false; |
61 | |
62 | if (effect != AL_EFFECT_NULL) |
63 | return true; |
64 | |
65 | alGenEffects(1, &effect); |
66 | if (alGetError() != AL_NO_ERROR) |
67 | throw love::Exception("Failed to create sound Effect." ); |
68 | |
69 | return true; |
70 | #else |
71 | return false; |
72 | #endif |
73 | } |
74 | |
75 | void Effect::deleteEffect() |
76 | { |
77 | #ifdef ALC_EXT_EFX |
78 | if (effect != AL_EFFECT_NULL) |
79 | alDeleteEffects(1, &effect); |
80 | #endif |
81 | effect = AL_EFFECT_NULL; |
82 | } |
83 | |
84 | ALuint Effect::getEffect() const |
85 | { |
86 | return effect; |
87 | } |
88 | |
89 | bool Effect::setParams(const std::map<Parameter, float> ¶ms) |
90 | { |
91 | this->params = params; |
92 | type = (Type)(int) this->params[EFFECT_TYPE]; |
93 | |
94 | if (!generateEffect()) |
95 | return false; |
96 | |
97 | #ifdef ALC_EXT_EFX |
98 | //parameter table without EFFECT_TYPE entry is illegal |
99 | switch (type) |
100 | { |
101 | case TYPE_REVERB: |
102 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); |
103 | break; |
104 | case TYPE_CHORUS: |
105 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS); |
106 | break; |
107 | case TYPE_DISTORTION: |
108 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION); |
109 | break; |
110 | case TYPE_ECHO: |
111 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO); |
112 | break; |
113 | case TYPE_FLANGER: |
114 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FLANGER); |
115 | break; |
116 | /* |
117 | case TYPE_FREQSHIFTER: |
118 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER); |
119 | break; |
120 | case TYPE_MORPHER: |
121 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER); |
122 | break; |
123 | case TYPE_PITCHSHIFTER: |
124 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER); |
125 | break; |
126 | */ |
127 | case TYPE_MODULATOR: |
128 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR); |
129 | break; |
130 | /* |
131 | case TYPE_AUTOWAH: |
132 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_AUTOWAH); |
133 | break; |
134 | */ |
135 | case TYPE_COMPRESSOR: |
136 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR); |
137 | break; |
138 | case TYPE_EQUALIZER: |
139 | alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER); |
140 | break; |
141 | case TYPE_BASIC: |
142 | case TYPE_MAX_ENUM: |
143 | break; |
144 | } |
145 | |
146 | //failed to make effect specific type - not supported etc. |
147 | if (alGetError() != AL_NO_ERROR) |
148 | { |
149 | deleteEffect(); |
150 | return false; |
151 | } |
152 | |
153 | #define clampf(v,l,h) fmax(fmin((v),(h)),(l)) |
154 | #define PARAMSTR(i,e,v) effect,AL_##e##_##v,clampf(getValue(i,AL_##e##_DEFAULT_##v),AL_##e##_MIN_##v,AL_##e##_MAX_##v) |
155 | switch (type) |
156 | { |
157 | case TYPE_REVERB: |
158 | { |
159 | alEffectf(PARAMSTR(REVERB_GAIN,REVERB,GAIN)); |
160 | alEffectf(PARAMSTR(REVERB_HFGAIN,REVERB,GAINHF)); |
161 | alEffectf(PARAMSTR(REVERB_DENSITY,REVERB,DENSITY)); |
162 | alEffectf(PARAMSTR(REVERB_DIFFUSION,REVERB,DIFFUSION)); |
163 | alEffectf(PARAMSTR(REVERB_DECAY,REVERB,DECAY_TIME)); |
164 | alEffectf(PARAMSTR(REVERB_HFDECAY,REVERB,DECAY_HFRATIO)); |
165 | alEffectf(PARAMSTR(REVERB_EARLYGAIN,REVERB,REFLECTIONS_GAIN)); |
166 | alEffectf(PARAMSTR(REVERB_EARLYDELAY,REVERB,REFLECTIONS_DELAY)); |
167 | alEffectf(PARAMSTR(REVERB_LATEGAIN,REVERB,LATE_REVERB_GAIN)); |
168 | alEffectf(PARAMSTR(REVERB_LATEDELAY,REVERB,LATE_REVERB_DELAY));; |
169 | alEffectf(PARAMSTR(REVERB_ROLLOFF,REVERB,ROOM_ROLLOFF_FACTOR)); |
170 | alEffectf(PARAMSTR(REVERB_AIRHFGAIN,REVERB,AIR_ABSORPTION_GAINHF)); |
171 | alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, getValue(REVERB_HFLIMITER, 0)); |
172 | break; |
173 | } |
174 | case TYPE_CHORUS: |
175 | { |
176 | Waveform wave = static_cast<Waveform>(getValue(CHORUS_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM))); |
177 | if (wave == WAVE_SINE) |
178 | alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_WAVEFORM_SINUSOID); |
179 | else if (wave == WAVE_TRIANGLE) |
180 | alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_WAVEFORM_TRIANGLE); |
181 | else |
182 | alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_DEFAULT_WAVEFORM); |
183 | |
184 | alEffecti(PARAMSTR(CHORUS_PHASE,CHORUS,PHASE)); |
185 | alEffectf(PARAMSTR(CHORUS_RATE,CHORUS,RATE)); |
186 | alEffectf(PARAMSTR(CHORUS_DEPTH,CHORUS,DEPTH)); |
187 | alEffectf(PARAMSTR(CHORUS_FEEDBACK,CHORUS,FEEDBACK)); |
188 | alEffectf(PARAMSTR(CHORUS_DELAY,CHORUS,DELAY)); |
189 | break; |
190 | } |
191 | case TYPE_DISTORTION: |
192 | alEffectf(PARAMSTR(DISTORTION_GAIN,DISTORTION,GAIN)); |
193 | alEffectf(PARAMSTR(DISTORTION_EDGE,DISTORTION,EDGE)); |
194 | alEffectf(PARAMSTR(DISTORTION_LOWCUT,DISTORTION,LOWPASS_CUTOFF)); |
195 | alEffectf(PARAMSTR(DISTORTION_EQCENTER,DISTORTION,EQCENTER)); |
196 | alEffectf(PARAMSTR(DISTORTION_EQBAND,DISTORTION,EQBANDWIDTH)); |
197 | break; |
198 | |
199 | case TYPE_ECHO: |
200 | alEffectf(PARAMSTR(ECHO_DELAY,ECHO,DELAY)); |
201 | alEffectf(PARAMSTR(ECHO_LRDELAY,ECHO,LRDELAY)); |
202 | alEffectf(PARAMSTR(ECHO_DAMPING,ECHO,DAMPING)); |
203 | alEffectf(PARAMSTR(ECHO_FEEDBACK,ECHO,FEEDBACK)); |
204 | alEffectf(PARAMSTR(ECHO_SPREAD,ECHO,SPREAD)); |
205 | break; |
206 | |
207 | case TYPE_FLANGER: |
208 | { |
209 | Waveform wave = static_cast<Waveform>(getValue(FLANGER_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM))); |
210 | if (wave == WAVE_SINE) |
211 | alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_WAVEFORM_SINUSOID); |
212 | else if (wave == WAVE_TRIANGLE) |
213 | alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_WAVEFORM_TRIANGLE); |
214 | else |
215 | alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_DEFAULT_WAVEFORM); |
216 | |
217 | alEffecti(PARAMSTR(FLANGER_PHASE,FLANGER,PHASE)); |
218 | alEffectf(PARAMSTR(FLANGER_RATE,FLANGER,RATE)); |
219 | alEffectf(PARAMSTR(FLANGER_DEPTH,FLANGER,DEPTH)); |
220 | alEffectf(PARAMSTR(FLANGER_FEEDBACK,FLANGER,FEEDBACK)); |
221 | alEffectf(PARAMSTR(FLANGER_DELAY,FLANGER,DELAY)); |
222 | break; |
223 | } |
224 | /* |
225 | case TYPE_FREQSHIFTER: |
226 | { |
227 | alEffectf(PARAMSTR(FREQSHIFTER_FREQ,FREQUENCY_SHIFTER,FREQUENCY)); |
228 | |
229 | Direction dir = static_cast<Direction>(getValue(FREQSHIFTER_LEFTDIR, static_cast<int>(DIR_MAX_ENUM))); |
230 | if (dir == DIR_NONE) |
231 | alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_OFF); |
232 | else if(dir == DIR_UP) |
233 | alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_UP); |
234 | else if(dir == DIR_DOWN) |
235 | alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_DOWN); |
236 | else |
237 | alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION); |
238 | |
239 | dir = static_cast<Direction>(getValue(FREQSHIFTER_RIGHTDIR, static_cast<int>(DIR_MAX_ENUM))); |
240 | if (dir == DIR_NONE) |
241 | alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_OFF); |
242 | else if(dir == DIR_UP) |
243 | alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_UP); |
244 | else if(dir == DIR_DOWN) |
245 | alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_DOWN); |
246 | else |
247 | alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION); |
248 | break; |
249 | } |
250 | case TYPE_MORPHER: |
251 | { |
252 | Waveform wave = static_cast<Waveform>(getValue(MORPHER_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM))); |
253 | if (wave == WAVE_SINE) |
254 | alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_SINUSOID); |
255 | else if (wave == WAVE_TRIANGLE) |
256 | alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE); |
257 | else if (wave == WAVE_SAWTOOTH) |
258 | alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH); |
259 | else |
260 | alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_DEFAULT_WAVEFORM); |
261 | |
262 | Phoneme phoneme = static_cast<Phoneme>(getValue(MORPHER_PHONEMEA, static_cast<int>(PHONEME_MAX_ENUM))); |
263 | if (phoneme == PHONEME_MAX_ENUM) |
264 | alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEA, AL_VOCAL_MORPHER_DEFAULT_PHONEMEA); |
265 | else |
266 | alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEA, phonemeMap[phoneme]); |
267 | |
268 | phoneme = static_cast<Phoneme>(getValue(MORPHER_PHONEMEB, static_cast<int>(PHONEME_MAX_ENUM))); |
269 | if (phoneme == PHONEME_MAX_ENUM) |
270 | alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEB, AL_VOCAL_MORPHER_DEFAULT_PHONEMEB); |
271 | else |
272 | alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEB, phonemeMap[phoneme]); |
273 | |
274 | alEffectf(PARAMSTR(MORPHER_RATE,VOCAL_MORPHER,RATE)); |
275 | alEffecti(PARAMSTR(MORPHER_TUNEA,VOCAL_MORPHER,PHONEMEA_COARSE_TUNING)); |
276 | alEffecti(PARAMSTR(MORPHER_TUNEB,VOCAL_MORPHER,PHONEMEB_COARSE_TUNING)); |
277 | break; |
278 | } |
279 | case TYPE_PITCHSHIFTER: |
280 | { |
281 | float tune = getValue(PITCHSHIFTER_PITCH, (float)AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE + (float)(AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE - 50) / 100.0 ); |
282 | |
283 | int coarse = (int)floor(tune); |
284 | int fine = (int)(fmod(tune, 1.0)*100.0); |
285 | if (fine > 50) |
286 | { |
287 | fine -= 100; |
288 | coarse += 1; |
289 | } |
290 | else if (fine < -50) |
291 | { |
292 | fine += 100; |
293 | coarse -= 1; |
294 | } |
295 | if (coarse > AL_PITCH_SHIFTER_MAX_COARSE_TUNE) |
296 | { |
297 | coarse = AL_PITCH_SHIFTER_MAX_COARSE_TUNE; |
298 | fine = AL_PITCH_SHIFTER_MAX_FINE_TUNE; |
299 | } |
300 | else if (coarse < AL_PITCH_SHIFTER_MIN_COARSE_TUNE) |
301 | { |
302 | coarse = AL_PITCH_SHIFTER_MIN_COARSE_TUNE; |
303 | fine = AL_PITCH_SHIFTER_MIN_FINE_TUNE; |
304 | } |
305 | alEffecti(effect, AL_PITCH_SHIFTER_COARSE_TUNE, coarse); |
306 | alEffecti(effect, AL_PITCH_SHIFTER_FINE_TUNE, fine); |
307 | break; |
308 | } |
309 | */ |
310 | case TYPE_MODULATOR: |
311 | { |
312 | Waveform wave = static_cast<Waveform>(getValue(MODULATOR_WAVEFORM,static_cast<int>(WAVE_MAX_ENUM))); |
313 | if (wave == WAVE_SINE) |
314 | alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SINUSOID); |
315 | else if (wave == WAVE_SAWTOOTH) |
316 | alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SAWTOOTH); |
317 | else if (wave == WAVE_SQUARE) |
318 | alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SQUARE); |
319 | else |
320 | alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_DEFAULT_WAVEFORM); |
321 | |
322 | alEffectf(PARAMSTR(MODULATOR_FREQ,RING_MODULATOR,FREQUENCY)); |
323 | alEffectf(PARAMSTR(MODULATOR_HIGHCUT,RING_MODULATOR,HIGHPASS_CUTOFF)); |
324 | break; |
325 | } |
326 | /* |
327 | case TYPE_AUTOWAH: |
328 | alEffectf(PARAMSTR(AUTOWAH_ATTACK,AUTOWAH,ATTACK_TIME)); |
329 | alEffectf(PARAMSTR(AUTOWAH_RELEASE,AUTOWAH,RELEASE_TIME)); |
330 | alEffectf(PARAMSTR(AUTOWAH_RESONANCE,AUTOWAH,RESONANCE)); |
331 | alEffectf(PARAMSTR(AUTOWAH_PEAKGAIN,AUTOWAH,PEAK_GAIN)); |
332 | break; |
333 | */ |
334 | case TYPE_COMPRESSOR: |
335 | alEffecti(effect, AL_COMPRESSOR_ONOFF, getValue(COMPRESSOR_ENABLE,static_cast<int>(AL_COMPRESSOR_DEFAULT_ONOFF))); |
336 | break; |
337 | |
338 | case TYPE_EQUALIZER: |
339 | alEffectf(PARAMSTR(EQUALIZER_LOWGAIN,EQUALIZER,LOW_GAIN)); |
340 | alEffectf(PARAMSTR(EQUALIZER_LOWCUT,EQUALIZER,LOW_CUTOFF)); |
341 | alEffectf(PARAMSTR(EQUALIZER_MID1GAIN,EQUALIZER,MID1_GAIN)); |
342 | alEffectf(PARAMSTR(EQUALIZER_MID1FREQ,EQUALIZER,MID1_CENTER)); |
343 | alEffectf(PARAMSTR(EQUALIZER_MID1BAND,EQUALIZER,MID1_WIDTH)); |
344 | alEffectf(PARAMSTR(EQUALIZER_MID2GAIN,EQUALIZER,MID2_GAIN)); |
345 | alEffectf(PARAMSTR(EQUALIZER_MID2FREQ,EQUALIZER,MID2_CENTER)); |
346 | alEffectf(PARAMSTR(EQUALIZER_MID2BAND,EQUALIZER,MID2_WIDTH)); |
347 | alEffectf(PARAMSTR(EQUALIZER_HIGHGAIN,EQUALIZER,HIGH_GAIN)); |
348 | alEffectf(PARAMSTR(EQUALIZER_HIGHCUT,EQUALIZER,HIGH_CUTOFF)); |
349 | break; |
350 | case TYPE_BASIC: |
351 | case TYPE_MAX_ENUM: |
352 | break; |
353 | } |
354 | #undef PARAMSTR |
355 | #undef clampf |
356 | //alGetError(); |
357 | |
358 | return true; |
359 | #else |
360 | return false; |
361 | #endif //ALC_EXT_EFX |
362 | } |
363 | |
364 | const std::map<Effect::Parameter, float> &Effect::getParams() const |
365 | { |
366 | return params; |
367 | } |
368 | |
369 | float Effect::getValue(Parameter in, float def) const |
370 | { |
371 | return params.find(in) == params.end() ? def : params.at(in); |
372 | } |
373 | |
374 | int Effect::getValue(Parameter in, int def) const |
375 | { |
376 | return params.find(in) == params.end() ? def : static_cast<int>(params.at(in)); |
377 | } |
378 | |
379 | /* |
380 | std::map<Effect::Phoneme, ALint> Effect::phonemeMap = |
381 | { |
382 | {Effect::PHONEME_A, AL_VOCAL_MORPHER_PHONEME_A}, |
383 | {Effect::PHONEME_E, AL_VOCAL_MORPHER_PHONEME_E}, |
384 | {Effect::PHONEME_I, AL_VOCAL_MORPHER_PHONEME_I}, |
385 | {Effect::PHONEME_O, AL_VOCAL_MORPHER_PHONEME_O}, |
386 | {Effect::PHONEME_U, AL_VOCAL_MORPHER_PHONEME_U}, |
387 | {Effect::PHONEME_AA, AL_VOCAL_MORPHER_PHONEME_AA}, |
388 | {Effect::PHONEME_AE, AL_VOCAL_MORPHER_PHONEME_AE}, |
389 | {Effect::PHONEME_AH, AL_VOCAL_MORPHER_PHONEME_AH}, |
390 | {Effect::PHONEME_AO, AL_VOCAL_MORPHER_PHONEME_AO}, |
391 | {Effect::PHONEME_EH, AL_VOCAL_MORPHER_PHONEME_EH}, |
392 | {Effect::PHONEME_ER, AL_VOCAL_MORPHER_PHONEME_ER}, |
393 | {Effect::PHONEME_IH, AL_VOCAL_MORPHER_PHONEME_IH}, |
394 | {Effect::PHONEME_IY, AL_VOCAL_MORPHER_PHONEME_IY}, |
395 | {Effect::PHONEME_UH, AL_VOCAL_MORPHER_PHONEME_UH}, |
396 | {Effect::PHONEME_UW, AL_VOCAL_MORPHER_PHONEME_UW}, |
397 | {Effect::PHONEME_B, AL_VOCAL_MORPHER_PHONEME_B}, |
398 | {Effect::PHONEME_D, AL_VOCAL_MORPHER_PHONEME_D}, |
399 | {Effect::PHONEME_F, AL_VOCAL_MORPHER_PHONEME_F}, |
400 | {Effect::PHONEME_G, AL_VOCAL_MORPHER_PHONEME_G}, |
401 | {Effect::PHONEME_J, AL_VOCAL_MORPHER_PHONEME_J}, |
402 | {Effect::PHONEME_K, AL_VOCAL_MORPHER_PHONEME_K}, |
403 | {Effect::PHONEME_L, AL_VOCAL_MORPHER_PHONEME_L}, |
404 | {Effect::PHONEME_M, AL_VOCAL_MORPHER_PHONEME_M}, |
405 | {Effect::PHONEME_N, AL_VOCAL_MORPHER_PHONEME_N}, |
406 | {Effect::PHONEME_P, AL_VOCAL_MORPHER_PHONEME_P}, |
407 | {Effect::PHONEME_R, AL_VOCAL_MORPHER_PHONEME_R}, |
408 | {Effect::PHONEME_S, AL_VOCAL_MORPHER_PHONEME_S}, |
409 | {Effect::PHONEME_T, AL_VOCAL_MORPHER_PHONEME_T}, |
410 | {Effect::PHONEME_V, AL_VOCAL_MORPHER_PHONEME_V}, |
411 | {Effect::PHONEME_Z, AL_VOCAL_MORPHER_PHONEME_Z} |
412 | }; |
413 | */ |
414 | |
415 | } //openal |
416 | } //audio |
417 | } //love |
418 | |