chorus.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include "config.h"
  2. #include "AL/al.h"
  3. #include "AL/efx.h"
  4. #include "aloptional.h"
  5. #include "core/logging.h"
  6. #include "effects.h"
  7. #include "effects/base.h"
  8. namespace {
  9. static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
  10. static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
  11. inline al::optional<ChorusWaveform> WaveformFromEnum(ALenum type)
  12. {
  13. switch(type)
  14. {
  15. case AL_CHORUS_WAVEFORM_SINUSOID: return al::make_optional(ChorusWaveform::Sinusoid);
  16. case AL_CHORUS_WAVEFORM_TRIANGLE: return al::make_optional(ChorusWaveform::Triangle);
  17. }
  18. return al::nullopt;
  19. }
  20. inline ALenum EnumFromWaveform(ChorusWaveform type)
  21. {
  22. switch(type)
  23. {
  24. case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
  25. case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
  26. }
  27. throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
  28. }
  29. void Chorus_setParami(EffectProps *props, ALenum param, int val)
  30. {
  31. switch(param)
  32. {
  33. case AL_CHORUS_WAVEFORM:
  34. if(auto formopt = WaveformFromEnum(val))
  35. props->Chorus.Waveform = *formopt;
  36. else
  37. throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
  38. break;
  39. case AL_CHORUS_PHASE:
  40. if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
  41. throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
  42. props->Chorus.Phase = val;
  43. break;
  44. default:
  45. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  46. }
  47. }
  48. void Chorus_setParamiv(EffectProps *props, ALenum param, const int *vals)
  49. { Chorus_setParami(props, param, vals[0]); }
  50. void Chorus_setParamf(EffectProps *props, ALenum param, float val)
  51. {
  52. switch(param)
  53. {
  54. case AL_CHORUS_RATE:
  55. if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
  56. throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
  57. props->Chorus.Rate = val;
  58. break;
  59. case AL_CHORUS_DEPTH:
  60. if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
  61. throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
  62. props->Chorus.Depth = val;
  63. break;
  64. case AL_CHORUS_FEEDBACK:
  65. if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
  66. throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
  67. props->Chorus.Feedback = val;
  68. break;
  69. case AL_CHORUS_DELAY:
  70. if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
  71. throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
  72. props->Chorus.Delay = val;
  73. break;
  74. default:
  75. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  76. }
  77. }
  78. void Chorus_setParamfv(EffectProps *props, ALenum param, const float *vals)
  79. { Chorus_setParamf(props, param, vals[0]); }
  80. void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
  81. {
  82. switch(param)
  83. {
  84. case AL_CHORUS_WAVEFORM:
  85. *val = EnumFromWaveform(props->Chorus.Waveform);
  86. break;
  87. case AL_CHORUS_PHASE:
  88. *val = props->Chorus.Phase;
  89. break;
  90. default:
  91. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  92. }
  93. }
  94. void Chorus_getParamiv(const EffectProps *props, ALenum param, int *vals)
  95. { Chorus_getParami(props, param, vals); }
  96. void Chorus_getParamf(const EffectProps *props, ALenum param, float *val)
  97. {
  98. switch(param)
  99. {
  100. case AL_CHORUS_RATE:
  101. *val = props->Chorus.Rate;
  102. break;
  103. case AL_CHORUS_DEPTH:
  104. *val = props->Chorus.Depth;
  105. break;
  106. case AL_CHORUS_FEEDBACK:
  107. *val = props->Chorus.Feedback;
  108. break;
  109. case AL_CHORUS_DELAY:
  110. *val = props->Chorus.Delay;
  111. break;
  112. default:
  113. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  114. }
  115. }
  116. void Chorus_getParamfv(const EffectProps *props, ALenum param, float *vals)
  117. { Chorus_getParamf(props, param, vals); }
  118. const EffectProps genDefaultChorusProps() noexcept
  119. {
  120. EffectProps props{};
  121. props.Chorus.Waveform = *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM);
  122. props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
  123. props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
  124. props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
  125. props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
  126. props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
  127. return props;
  128. }
  129. void Flanger_setParami(EffectProps *props, ALenum param, int val)
  130. {
  131. switch(param)
  132. {
  133. case AL_FLANGER_WAVEFORM:
  134. if(auto formopt = WaveformFromEnum(val))
  135. props->Chorus.Waveform = *formopt;
  136. else
  137. throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
  138. break;
  139. case AL_FLANGER_PHASE:
  140. if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
  141. throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
  142. props->Chorus.Phase = val;
  143. break;
  144. default:
  145. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  146. }
  147. }
  148. void Flanger_setParamiv(EffectProps *props, ALenum param, const int *vals)
  149. { Flanger_setParami(props, param, vals[0]); }
  150. void Flanger_setParamf(EffectProps *props, ALenum param, float val)
  151. {
  152. switch(param)
  153. {
  154. case AL_FLANGER_RATE:
  155. if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
  156. throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
  157. props->Chorus.Rate = val;
  158. break;
  159. case AL_FLANGER_DEPTH:
  160. if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
  161. throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
  162. props->Chorus.Depth = val;
  163. break;
  164. case AL_FLANGER_FEEDBACK:
  165. if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
  166. throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
  167. props->Chorus.Feedback = val;
  168. break;
  169. case AL_FLANGER_DELAY:
  170. if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
  171. throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
  172. props->Chorus.Delay = val;
  173. break;
  174. default:
  175. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  176. }
  177. }
  178. void Flanger_setParamfv(EffectProps *props, ALenum param, const float *vals)
  179. { Flanger_setParamf(props, param, vals[0]); }
  180. void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
  181. {
  182. switch(param)
  183. {
  184. case AL_FLANGER_WAVEFORM:
  185. *val = EnumFromWaveform(props->Chorus.Waveform);
  186. break;
  187. case AL_FLANGER_PHASE:
  188. *val = props->Chorus.Phase;
  189. break;
  190. default:
  191. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  192. }
  193. }
  194. void Flanger_getParamiv(const EffectProps *props, ALenum param, int *vals)
  195. { Flanger_getParami(props, param, vals); }
  196. void Flanger_getParamf(const EffectProps *props, ALenum param, float *val)
  197. {
  198. switch(param)
  199. {
  200. case AL_FLANGER_RATE:
  201. *val = props->Chorus.Rate;
  202. break;
  203. case AL_FLANGER_DEPTH:
  204. *val = props->Chorus.Depth;
  205. break;
  206. case AL_FLANGER_FEEDBACK:
  207. *val = props->Chorus.Feedback;
  208. break;
  209. case AL_FLANGER_DELAY:
  210. *val = props->Chorus.Delay;
  211. break;
  212. default:
  213. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  214. }
  215. }
  216. void Flanger_getParamfv(const EffectProps *props, ALenum param, float *vals)
  217. { Flanger_getParamf(props, param, vals); }
  218. EffectProps genDefaultFlangerProps() noexcept
  219. {
  220. EffectProps props{};
  221. props.Chorus.Waveform = *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM);
  222. props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
  223. props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
  224. props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
  225. props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
  226. props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
  227. return props;
  228. }
  229. } // namespace
  230. DEFINE_ALEFFECT_VTABLE(Chorus);
  231. const EffectProps ChorusEffectProps{genDefaultChorusProps()};
  232. DEFINE_ALEFFECT_VTABLE(Flanger);
  233. const EffectProps FlangerEffectProps{genDefaultFlangerProps()};