modulator.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2009 by Chris Robinson.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <cmath>
  22. #include <cstdlib>
  23. #include <cmath>
  24. #include <algorithm>
  25. #include "al/auxeffectslot.h"
  26. #include "alcmain.h"
  27. #include "alcontext.h"
  28. #include "alu.h"
  29. #include "filters/biquad.h"
  30. #include "vecmat.h"
  31. namespace {
  32. #define MAX_UPDATE_SAMPLES 128
  33. #define WAVEFORM_FRACBITS 24
  34. #define WAVEFORM_FRACONE (1<<WAVEFORM_FRACBITS)
  35. #define WAVEFORM_FRACMASK (WAVEFORM_FRACONE-1)
  36. inline float Sin(ALuint index)
  37. {
  38. constexpr float scale{al::MathDefs<float>::Tau() / WAVEFORM_FRACONE};
  39. return std::sin(static_cast<float>(index) * scale);
  40. }
  41. inline float Saw(ALuint index)
  42. { return static_cast<float>(index)*(2.0f/WAVEFORM_FRACONE) - 1.0f; }
  43. inline float Square(ALuint index)
  44. { return static_cast<float>(static_cast<int>((index>>(WAVEFORM_FRACBITS-2))&2) - 1); }
  45. inline float One(ALuint) { return 1.0f; }
  46. template<float (&func)(ALuint)>
  47. void Modulate(float *RESTRICT dst, ALuint index, const ALuint step, size_t todo)
  48. {
  49. for(size_t i{0u};i < todo;i++)
  50. {
  51. index += step;
  52. index &= WAVEFORM_FRACMASK;
  53. dst[i] = func(index);
  54. }
  55. }
  56. struct ModulatorState final : public EffectState {
  57. void (*mGetSamples)(float*RESTRICT, ALuint, const ALuint, size_t){};
  58. ALuint mIndex{0};
  59. ALuint mStep{1};
  60. struct {
  61. BiquadFilter Filter;
  62. ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]{};
  63. ALfloat TargetGains[MAX_OUTPUT_CHANNELS]{};
  64. } mChans[MAX_AMBI_CHANNELS];
  65. ALboolean deviceUpdate(const ALCdevice *device) override;
  66. void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override;
  67. void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut) override;
  68. DEF_NEWDEL(ModulatorState)
  69. };
  70. ALboolean ModulatorState::deviceUpdate(const ALCdevice*)
  71. {
  72. for(auto &e : mChans)
  73. {
  74. e.Filter.clear();
  75. std::fill(std::begin(e.CurrentGains), std::end(e.CurrentGains), 0.0f);
  76. }
  77. return AL_TRUE;
  78. }
  79. void ModulatorState::update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target)
  80. {
  81. const ALCdevice *device{context->mDevice.get()};
  82. const float step{props->Modulator.Frequency / static_cast<ALfloat>(device->Frequency)};
  83. mStep = fastf2u(clampf(step*WAVEFORM_FRACONE, 0.0f, ALfloat{WAVEFORM_FRACONE-1}));
  84. if(mStep == 0)
  85. mGetSamples = Modulate<One>;
  86. else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
  87. mGetSamples = Modulate<Sin>;
  88. else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
  89. mGetSamples = Modulate<Saw>;
  90. else /*if(props->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
  91. mGetSamples = Modulate<Square>;
  92. ALfloat f0norm{props->Modulator.HighPassCutoff / static_cast<ALfloat>(device->Frequency)};
  93. f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f);
  94. /* Bandwidth value is constant in octaves. */
  95. mChans[0].Filter.setParams(BiquadType::HighPass, 1.0f, f0norm,
  96. BiquadFilter::rcpQFromBandwidth(f0norm, 0.75f));
  97. for(size_t i{1u};i < slot->Wet.Buffer.size();++i)
  98. mChans[i].Filter.copyParamsFrom(mChans[0].Filter);
  99. mOutTarget = target.Main->Buffer;
  100. for(size_t i{0u};i < slot->Wet.Buffer.size();++i)
  101. {
  102. auto coeffs = GetAmbiIdentityRow(i);
  103. ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains);
  104. }
  105. }
  106. void ModulatorState::process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
  107. {
  108. for(size_t base{0u};base < samplesToDo;)
  109. {
  110. alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES];
  111. size_t td{minz(MAX_UPDATE_SAMPLES, samplesToDo-base)};
  112. mGetSamples(modsamples, mIndex, mStep, td);
  113. mIndex += static_cast<ALuint>(mStep * td);
  114. mIndex &= WAVEFORM_FRACMASK;
  115. auto chandata = std::addressof(mChans[0]);
  116. for(const auto &input : samplesIn)
  117. {
  118. alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES];
  119. chandata->Filter.process(temps, &input[base], td);
  120. for(size_t i{0u};i < td;i++)
  121. temps[i] *= modsamples[i];
  122. MixSamples({temps, td}, samplesOut, chandata->CurrentGains, chandata->TargetGains,
  123. samplesToDo-base, base);
  124. ++chandata;
  125. }
  126. base += td;
  127. }
  128. }
  129. void Modulator_setParamf(EffectProps *props, ALCcontext *context, ALenum param, ALfloat val)
  130. {
  131. switch(param)
  132. {
  133. case AL_RING_MODULATOR_FREQUENCY:
  134. if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
  135. SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range");
  136. props->Modulator.Frequency = val;
  137. break;
  138. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  139. if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
  140. SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range");
  141. props->Modulator.HighPassCutoff = val;
  142. break;
  143. default:
  144. context->setError(AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
  145. }
  146. }
  147. void Modulator_setParamfv(EffectProps *props, ALCcontext *context, ALenum param, const ALfloat *vals)
  148. { Modulator_setParamf(props, context, param, vals[0]); }
  149. void Modulator_setParami(EffectProps *props, ALCcontext *context, ALenum param, ALint val)
  150. {
  151. switch(param)
  152. {
  153. case AL_RING_MODULATOR_FREQUENCY:
  154. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  155. Modulator_setParamf(props, context, param, static_cast<ALfloat>(val));
  156. break;
  157. case AL_RING_MODULATOR_WAVEFORM:
  158. if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
  159. SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform");
  160. props->Modulator.Waveform = val;
  161. break;
  162. default:
  163. context->setError(AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
  164. }
  165. }
  166. void Modulator_setParamiv(EffectProps *props, ALCcontext *context, ALenum param, const ALint *vals)
  167. { Modulator_setParami(props, context, param, vals[0]); }
  168. void Modulator_getParami(const EffectProps *props, ALCcontext *context, ALenum param, ALint *val)
  169. {
  170. switch(param)
  171. {
  172. case AL_RING_MODULATOR_FREQUENCY:
  173. *val = static_cast<ALint>(props->Modulator.Frequency);
  174. break;
  175. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  176. *val = static_cast<ALint>(props->Modulator.HighPassCutoff);
  177. break;
  178. case AL_RING_MODULATOR_WAVEFORM:
  179. *val = props->Modulator.Waveform;
  180. break;
  181. default:
  182. context->setError(AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
  183. }
  184. }
  185. void Modulator_getParamiv(const EffectProps *props, ALCcontext *context, ALenum param, ALint *vals)
  186. { Modulator_getParami(props, context, param, vals); }
  187. void Modulator_getParamf(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *val)
  188. {
  189. switch(param)
  190. {
  191. case AL_RING_MODULATOR_FREQUENCY:
  192. *val = props->Modulator.Frequency;
  193. break;
  194. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  195. *val = props->Modulator.HighPassCutoff;
  196. break;
  197. default:
  198. context->setError(AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
  199. }
  200. }
  201. void Modulator_getParamfv(const EffectProps *props, ALCcontext *context, ALenum param, ALfloat *vals)
  202. { Modulator_getParamf(props, context, param, vals); }
  203. DEFINE_ALEFFECT_VTABLE(Modulator);
  204. struct ModulatorStateFactory final : public EffectStateFactory {
  205. EffectState *create() override { return new ModulatorState{}; }
  206. EffectProps getDefaultProps() const noexcept override;
  207. const EffectVtable *getEffectVtable() const noexcept override { return &Modulator_vtable; }
  208. };
  209. EffectProps ModulatorStateFactory::getDefaultProps() const noexcept
  210. {
  211. EffectProps props{};
  212. props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
  213. props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
  214. props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
  215. return props;
  216. }
  217. } // namespace
  218. EffectStateFactory *ModulatorStateFactory_getFactory()
  219. {
  220. static ModulatorStateFactory ModulatorFactory{};
  221. return &ModulatorFactory;
  222. }