fshifter.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #include "config.h"
  2. #include <optional>
  3. #include <stdexcept>
  4. #include "AL/al.h"
  5. #include "AL/efx.h"
  6. #include "alc/effects/base.h"
  7. #include "effects.h"
  8. #ifdef ALSOFT_EAX
  9. #include <cassert>
  10. #include "alnumeric.h"
  11. #include "al/eax/effect.h"
  12. #include "al/eax/exception.h"
  13. #include "al/eax/utils.h"
  14. #endif // ALSOFT_EAX
  15. namespace {
  16. constexpr std::optional<FShifterDirection> DirectionFromEmum(ALenum value) noexcept
  17. {
  18. switch(value)
  19. {
  20. case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: return FShifterDirection::Down;
  21. case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return FShifterDirection::Up;
  22. case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return FShifterDirection::Off;
  23. }
  24. return std::nullopt;
  25. }
  26. constexpr ALenum EnumFromDirection(FShifterDirection dir)
  27. {
  28. switch(dir)
  29. {
  30. case FShifterDirection::Down: return AL_FREQUENCY_SHIFTER_DIRECTION_DOWN;
  31. case FShifterDirection::Up: return AL_FREQUENCY_SHIFTER_DIRECTION_UP;
  32. case FShifterDirection::Off: return AL_FREQUENCY_SHIFTER_DIRECTION_OFF;
  33. }
  34. throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
  35. }
  36. constexpr EffectProps genDefaultProps() noexcept
  37. {
  38. FshifterProps props{};
  39. props.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
  40. props.LeftDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION).value();
  41. props.RightDirection = DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION).value();
  42. return props;
  43. }
  44. } // namespace
  45. const EffectProps FshifterEffectProps{genDefaultProps()};
  46. void FshifterEffectHandler::SetParami(FshifterProps &props, ALenum param, int val)
  47. {
  48. switch(param)
  49. {
  50. case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
  51. if(auto diropt = DirectionFromEmum(val))
  52. props.LeftDirection = *diropt;
  53. else
  54. throw effect_exception{AL_INVALID_VALUE,
  55. "Unsupported frequency shifter left direction: 0x%04x", val};
  56. break;
  57. case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
  58. if(auto diropt = DirectionFromEmum(val))
  59. props.RightDirection = *diropt;
  60. else
  61. throw effect_exception{AL_INVALID_VALUE,
  62. "Unsupported frequency shifter right direction: 0x%04x", val};
  63. break;
  64. default:
  65. throw effect_exception{AL_INVALID_ENUM,
  66. "Invalid frequency shifter integer property 0x%04x", param};
  67. }
  68. }
  69. void FshifterEffectHandler::SetParamiv(FshifterProps &props, ALenum param, const int *vals)
  70. { SetParami(props, param, *vals); }
  71. void FshifterEffectHandler::SetParamf(FshifterProps &props, ALenum param, float val)
  72. {
  73. switch(param)
  74. {
  75. case AL_FREQUENCY_SHIFTER_FREQUENCY:
  76. if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
  77. throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
  78. props.Frequency = val;
  79. break;
  80. default:
  81. throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
  82. param};
  83. }
  84. }
  85. void FshifterEffectHandler::SetParamfv(FshifterProps &props, ALenum param, const float *vals)
  86. { SetParamf(props, param, *vals); }
  87. void FshifterEffectHandler::GetParami(const FshifterProps &props, ALenum param, int *val)
  88. {
  89. switch(param)
  90. {
  91. case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
  92. *val = EnumFromDirection(props.LeftDirection);
  93. break;
  94. case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
  95. *val = EnumFromDirection(props.RightDirection);
  96. break;
  97. default:
  98. throw effect_exception{AL_INVALID_ENUM,
  99. "Invalid frequency shifter integer property 0x%04x", param};
  100. }
  101. }
  102. void FshifterEffectHandler::GetParamiv(const FshifterProps &props, ALenum param, int *vals)
  103. { GetParami(props, param, vals); }
  104. void FshifterEffectHandler::GetParamf(const FshifterProps &props, ALenum param, float *val)
  105. {
  106. switch(param)
  107. {
  108. case AL_FREQUENCY_SHIFTER_FREQUENCY:
  109. *val = props.Frequency;
  110. break;
  111. default:
  112. throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
  113. param};
  114. }
  115. }
  116. void FshifterEffectHandler::GetParamfv(const FshifterProps &props, ALenum param, float *vals)
  117. { GetParamf(props, param, vals); }
  118. #ifdef ALSOFT_EAX
  119. namespace {
  120. using FrequencyShifterCommitter = EaxCommitter<EaxFrequencyShifterCommitter>;
  121. struct FrequencyValidator {
  122. void operator()(float flFrequency) const
  123. {
  124. eax_validate_range<FrequencyShifterCommitter::Exception>(
  125. "Frequency",
  126. flFrequency,
  127. EAXFREQUENCYSHIFTER_MINFREQUENCY,
  128. EAXFREQUENCYSHIFTER_MAXFREQUENCY);
  129. }
  130. }; // FrequencyValidator
  131. struct LeftDirectionValidator {
  132. void operator()(unsigned long ulLeftDirection) const
  133. {
  134. eax_validate_range<FrequencyShifterCommitter::Exception>(
  135. "Left Direction",
  136. ulLeftDirection,
  137. EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
  138. EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
  139. }
  140. }; // LeftDirectionValidator
  141. struct RightDirectionValidator {
  142. void operator()(unsigned long ulRightDirection) const
  143. {
  144. eax_validate_range<FrequencyShifterCommitter::Exception>(
  145. "Right Direction",
  146. ulRightDirection,
  147. EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
  148. EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
  149. }
  150. }; // RightDirectionValidator
  151. struct AllValidator {
  152. void operator()(const EAXFREQUENCYSHIFTERPROPERTIES& all) const
  153. {
  154. FrequencyValidator{}(all.flFrequency);
  155. LeftDirectionValidator{}(all.ulLeftDirection);
  156. RightDirectionValidator{}(all.ulRightDirection);
  157. }
  158. }; // AllValidator
  159. } // namespace
  160. template<>
  161. struct FrequencyShifterCommitter::Exception : public EaxException {
  162. explicit Exception(const char *message) : EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
  163. { }
  164. };
  165. template<>
  166. [[noreturn]] void FrequencyShifterCommitter::fail(const char *message)
  167. {
  168. throw Exception{message};
  169. }
  170. bool EaxFrequencyShifterCommitter::commit(const EAXFREQUENCYSHIFTERPROPERTIES &props)
  171. {
  172. if(auto *cur = std::get_if<EAXFREQUENCYSHIFTERPROPERTIES>(&mEaxProps); cur && *cur == props)
  173. return false;
  174. mEaxProps = props;
  175. auto get_direction = [](unsigned long dir) noexcept
  176. {
  177. if(dir == EAX_FREQUENCYSHIFTER_DOWN)
  178. return FShifterDirection::Down;
  179. if(dir == EAX_FREQUENCYSHIFTER_UP)
  180. return FShifterDirection::Up;
  181. return FShifterDirection::Off;
  182. };
  183. mAlProps = [&]{
  184. FshifterProps ret{};
  185. ret.Frequency = props.flFrequency;
  186. ret.LeftDirection = get_direction(props.ulLeftDirection);
  187. ret.RightDirection = get_direction(props.ulRightDirection);
  188. return ret;
  189. }();
  190. return true;
  191. }
  192. void EaxFrequencyShifterCommitter::SetDefaults(EaxEffectProps &props)
  193. {
  194. static constexpr EAXFREQUENCYSHIFTERPROPERTIES defprops{[]
  195. {
  196. EAXFREQUENCYSHIFTERPROPERTIES ret{};
  197. ret.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
  198. ret.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
  199. ret.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
  200. return ret;
  201. }()};
  202. props = defprops;
  203. }
  204. void EaxFrequencyShifterCommitter::Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props)
  205. {
  206. switch(call.get_property_id())
  207. {
  208. case EAXFREQUENCYSHIFTER_NONE: break;
  209. case EAXFREQUENCYSHIFTER_ALLPARAMETERS: call.set_value<Exception>(props); break;
  210. case EAXFREQUENCYSHIFTER_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
  211. case EAXFREQUENCYSHIFTER_LEFTDIRECTION: call.set_value<Exception>(props.ulLeftDirection); break;
  212. case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: call.set_value<Exception>(props.ulRightDirection); break;
  213. default: fail_unknown_property_id();
  214. }
  215. }
  216. void EaxFrequencyShifterCommitter::Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props)
  217. {
  218. switch(call.get_property_id())
  219. {
  220. case EAXFREQUENCYSHIFTER_NONE: break;
  221. case EAXFREQUENCYSHIFTER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  222. case EAXFREQUENCYSHIFTER_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
  223. case EAXFREQUENCYSHIFTER_LEFTDIRECTION: defer<LeftDirectionValidator>(call, props.ulLeftDirection); break;
  224. case EAXFREQUENCYSHIFTER_RIGHTDIRECTION: defer<RightDirectionValidator>(call, props.ulRightDirection); break;
  225. default: fail_unknown_property_id();
  226. }
  227. }
  228. #endif // ALSOFT_EAX