You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
7.7KB

  1. // Copyright 2014 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. //
  25. // -----------------------------------------------------------------------------
  26. //
  27. // Base class for building reverb.
  28. #ifndef ELEMENTS_DSP_FX_FX_ENGINE_H_
  29. #define ELEMENTS_DSP_FX_FX_ENGINE_H_
  30. #include <algorithm>
  31. #include "stmlib/stmlib.h"
  32. #include "stmlib/dsp/dsp.h"
  33. #include "stmlib/dsp/cosine_oscillator.h"
  34. namespace elements {
  35. #define TAIL , -1
  36. enum Format {
  37. FORMAT_12_BIT,
  38. FORMAT_16_BIT,
  39. FORMAT_32_BIT
  40. };
  41. enum LFOIndex {
  42. LFO_1,
  43. LFO_2
  44. };
  45. template<Format format>
  46. struct DataType { };
  47. template<>
  48. struct DataType<FORMAT_12_BIT> {
  49. typedef uint16_t T;
  50. static inline float Decompress(T value) {
  51. return static_cast<float>(static_cast<int16_t>(value)) / 4096.0f;
  52. }
  53. static inline T Compress(float value) {
  54. return static_cast<uint16_t>(
  55. stmlib::Clip16(static_cast<int32_t>(value * 4096.0f)));
  56. }
  57. };
  58. template<>
  59. struct DataType<FORMAT_16_BIT> {
  60. typedef uint16_t T;
  61. static inline float Decompress(T value) {
  62. return static_cast<float>(static_cast<int16_t>(value)) / 32768.0f;
  63. }
  64. static inline T Compress(float value) {
  65. return static_cast<uint16_t>(
  66. stmlib::Clip16(static_cast<int32_t>(value * 32768.0f)));
  67. }
  68. };
  69. template<>
  70. struct DataType<FORMAT_32_BIT> {
  71. typedef float T;
  72. static inline float Decompress(T value) {
  73. return value;;
  74. }
  75. static inline T Compress(float value) {
  76. return value;
  77. }
  78. };
  79. template<
  80. size_t size,
  81. Format format = FORMAT_12_BIT>
  82. class FxEngine {
  83. public:
  84. typedef typename DataType<format>::T T;
  85. FxEngine() { }
  86. ~FxEngine() { }
  87. void Init(T* buffer) {
  88. buffer_ = buffer;
  89. std::fill(&buffer_[0], &buffer_[size], 0);
  90. write_ptr_ = 0;
  91. }
  92. struct Empty { };
  93. template<int32_t l, typename T = Empty>
  94. struct Reserve {
  95. typedef T Tail;
  96. enum {
  97. length = l
  98. };
  99. };
  100. template<typename Memory, int32_t index>
  101. struct DelayLine {
  102. enum {
  103. length = DelayLine<typename Memory::Tail, index - 1>::length,
  104. base = DelayLine<Memory, index - 1>::base + DelayLine<Memory, index - 1>::length + 1
  105. };
  106. };
  107. template<typename Memory>
  108. struct DelayLine<Memory, 0> {
  109. enum {
  110. length = Memory::length,
  111. base = 0
  112. };
  113. };
  114. class Context {
  115. friend class FxEngine;
  116. public:
  117. Context() { }
  118. ~Context() { }
  119. inline void Load(float value) {
  120. accumulator_ = value;
  121. }
  122. inline void Read(float value, float scale) {
  123. accumulator_ += value * scale;
  124. }
  125. inline void Read(float value) {
  126. accumulator_ += value;
  127. }
  128. inline void Write(float& value) {
  129. value = accumulator_;
  130. }
  131. inline void Write(float& value, float scale) {
  132. value = accumulator_;
  133. accumulator_ *= scale;
  134. }
  135. template<typename D>
  136. inline void Write(D& d, int32_t offset, float scale) {
  137. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  138. T w = DataType<format>::Compress(accumulator_);
  139. if (offset == -1) {
  140. buffer_[(write_ptr_ + D::base + D::length - 1) & MASK] = w;
  141. } else {
  142. buffer_[(write_ptr_ + D::base + offset) & MASK] = w;
  143. }
  144. accumulator_ *= scale;
  145. }
  146. template<typename D>
  147. inline void Write(D& d, float scale) {
  148. Write(d, 0, scale);
  149. }
  150. template<typename D>
  151. inline void WriteAllPass(D& d, int32_t offset, float scale) {
  152. Write(d, offset, scale);
  153. accumulator_ += previous_read_;
  154. }
  155. template<typename D>
  156. inline void WriteAllPass(D& d, float scale) {
  157. WriteAllPass(d, 0, scale);
  158. }
  159. template<typename D>
  160. inline void Read(D& d, int32_t offset, float scale) {
  161. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  162. T r;
  163. if (offset == -1) {
  164. r = buffer_[(write_ptr_ + D::base + D::length - 1) & MASK];
  165. } else {
  166. r = buffer_[(write_ptr_ + D::base + offset) & MASK];
  167. }
  168. float r_f = DataType<format>::Decompress(r);
  169. previous_read_ = r_f;
  170. accumulator_ += r_f * scale;
  171. }
  172. template<typename D>
  173. inline void Read(D& d, float scale) {
  174. Read(d, 0, scale);
  175. }
  176. inline void Lp(float& state, float coefficient) {
  177. state += coefficient * (accumulator_ - state);
  178. accumulator_ = state;
  179. }
  180. inline void Hp(float& state, float coefficient) {
  181. state += coefficient * (accumulator_ - state);
  182. accumulator_ -= state;
  183. }
  184. template<typename D>
  185. inline void Interpolate(D& d, float offset, float scale) {
  186. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  187. MAKE_INTEGRAL_FRACTIONAL(offset);
  188. float a = DataType<format>::Decompress(
  189. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  190. float b = DataType<format>::Decompress(
  191. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  192. float x = a + (b - a) * offset_fractional;
  193. previous_read_ = x;
  194. accumulator_ += x * scale;
  195. }
  196. template<typename D>
  197. inline void Interpolate(
  198. D& d, float offset, LFOIndex index, float amplitude, float scale) {
  199. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  200. offset += amplitude * lfo_value_[index];
  201. MAKE_INTEGRAL_FRACTIONAL(offset);
  202. float a = DataType<format>::Decompress(
  203. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  204. float b = DataType<format>::Decompress(
  205. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  206. float x = a + (b - a) * offset_fractional;
  207. previous_read_ = x;
  208. accumulator_ += x * scale;
  209. }
  210. private:
  211. float accumulator_;
  212. float previous_read_;
  213. float lfo_value_[2];
  214. T* buffer_;
  215. int32_t write_ptr_;
  216. DISALLOW_COPY_AND_ASSIGN(Context);
  217. };
  218. inline void SetLFOFrequency(LFOIndex index, float frequency) {
  219. lfo_[index].Init<stmlib::COSINE_OSCILLATOR_APPROXIMATE>(frequency * 32.0f);
  220. }
  221. inline void Start(Context* c) {
  222. --write_ptr_;
  223. if (write_ptr_ < 0) {
  224. write_ptr_ += size;
  225. }
  226. c->accumulator_ = 0.0f;
  227. c->previous_read_ = 0.0f;
  228. c->buffer_ = buffer_;
  229. c->write_ptr_ = write_ptr_;
  230. if ((write_ptr_ & 31) == 0) {
  231. c->lfo_value_[0] = lfo_[0].Next();
  232. c->lfo_value_[1] = lfo_[1].Next();
  233. } else {
  234. c->lfo_value_[0] = lfo_[0].value();
  235. c->lfo_value_[1] = lfo_[1].value();
  236. }
  237. }
  238. private:
  239. enum {
  240. MASK = size - 1
  241. };
  242. int32_t write_ptr_;
  243. T* buffer_;
  244. stmlib::CosineOscillator lfo_[2];
  245. DISALLOW_COPY_AND_ASSIGN(FxEngine);
  246. };
  247. } // namespace elements
  248. #endif // ELEMENTS_DSP_FX_FX_ENGINE_H_