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.

302 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 RINGS_DSP_FX_FX_ENGINE_H_
  29. #define RINGS_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 rings {
  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. Clear();
  90. }
  91. void Clear() {
  92. std::fill(&buffer_[0], &buffer_[size], 0);
  93. write_ptr_ = 0;
  94. }
  95. struct Empty { };
  96. template<int32_t l, typename T = Empty>
  97. struct Reserve {
  98. typedef T Tail;
  99. enum {
  100. length = l
  101. };
  102. };
  103. template<typename Memory, int32_t index>
  104. struct DelayLine {
  105. enum {
  106. length = DelayLine<typename Memory::Tail, index - 1>::length,
  107. base = DelayLine<Memory, index - 1>::base + DelayLine<Memory, index - 1>::length + 1
  108. };
  109. };
  110. template<typename Memory>
  111. struct DelayLine<Memory, 0> {
  112. enum {
  113. length = Memory::length,
  114. base = 0
  115. };
  116. };
  117. class Context {
  118. friend class FxEngine;
  119. public:
  120. Context() { }
  121. ~Context() { }
  122. inline void Load(float value) {
  123. accumulator_ = value;
  124. }
  125. inline void Read(float value, float scale) {
  126. accumulator_ += value * scale;
  127. }
  128. inline void Read(float value) {
  129. accumulator_ += value;
  130. }
  131. inline void Write(float& value) {
  132. value = accumulator_;
  133. }
  134. inline void Write(float& value, float scale) {
  135. value = accumulator_;
  136. accumulator_ *= scale;
  137. }
  138. template<typename D>
  139. inline void Write(D& d, int32_t offset, float scale) {
  140. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  141. T w = DataType<format>::Compress(accumulator_);
  142. if (offset == -1) {
  143. buffer_[(write_ptr_ + D::base + D::length - 1) & MASK] = w;
  144. } else {
  145. buffer_[(write_ptr_ + D::base + offset) & MASK] = w;
  146. }
  147. accumulator_ *= scale;
  148. }
  149. template<typename D>
  150. inline void Write(D& d, float scale) {
  151. Write(d, 0, scale);
  152. }
  153. template<typename D>
  154. inline void WriteAllPass(D& d, int32_t offset, float scale) {
  155. Write(d, offset, scale);
  156. accumulator_ += previous_read_;
  157. }
  158. template<typename D>
  159. inline void WriteAllPass(D& d, float scale) {
  160. WriteAllPass(d, 0, scale);
  161. }
  162. template<typename D>
  163. inline void Read(D& d, int32_t offset, float scale) {
  164. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  165. T r;
  166. if (offset == -1) {
  167. r = buffer_[(write_ptr_ + D::base + D::length - 1) & MASK];
  168. } else {
  169. r = buffer_[(write_ptr_ + D::base + offset) & MASK];
  170. }
  171. float r_f = DataType<format>::Decompress(r);
  172. previous_read_ = r_f;
  173. accumulator_ += r_f * scale;
  174. }
  175. template<typename D>
  176. inline void Read(D& d, float scale) {
  177. Read(d, 0, scale);
  178. }
  179. inline void Lp(float& state, float coefficient) {
  180. state += coefficient * (accumulator_ - state);
  181. accumulator_ = state;
  182. }
  183. inline void Hp(float& state, float coefficient) {
  184. state += coefficient * (accumulator_ - state);
  185. accumulator_ -= state;
  186. }
  187. template<typename D>
  188. inline void Interpolate(D& d, float offset, float scale) {
  189. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  190. MAKE_INTEGRAL_FRACTIONAL(offset);
  191. float a = DataType<format>::Decompress(
  192. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  193. float b = DataType<format>::Decompress(
  194. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  195. float x = a + (b - a) * offset_fractional;
  196. previous_read_ = x;
  197. accumulator_ += x * scale;
  198. }
  199. template<typename D>
  200. inline void Interpolate(
  201. D& d, float offset, LFOIndex index, float amplitude, float scale) {
  202. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  203. offset += amplitude * lfo_value_[index];
  204. MAKE_INTEGRAL_FRACTIONAL(offset);
  205. float a = DataType<format>::Decompress(
  206. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  207. float b = DataType<format>::Decompress(
  208. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  209. float x = a + (b - a) * offset_fractional;
  210. previous_read_ = x;
  211. accumulator_ += x * scale;
  212. }
  213. private:
  214. float accumulator_;
  215. float previous_read_;
  216. float lfo_value_[2];
  217. T* buffer_;
  218. int32_t write_ptr_;
  219. DISALLOW_COPY_AND_ASSIGN(Context);
  220. };
  221. inline void SetLFOFrequency(LFOIndex index, float frequency) {
  222. lfo_[index].template Init<stmlib::COSINE_OSCILLATOR_APPROXIMATE>(frequency * 32.0f);
  223. }
  224. inline void Start(Context* c) {
  225. --write_ptr_;
  226. if (write_ptr_ < 0) {
  227. write_ptr_ += size;
  228. }
  229. c->accumulator_ = 0.0f;
  230. c->previous_read_ = 0.0f;
  231. c->buffer_ = buffer_;
  232. c->write_ptr_ = write_ptr_;
  233. if ((write_ptr_ & 31) == 0) {
  234. c->lfo_value_[0] = lfo_[0].Next();
  235. c->lfo_value_[1] = lfo_[1].Next();
  236. } else {
  237. c->lfo_value_[0] = lfo_[0].value();
  238. c->lfo_value_[1] = lfo_[1].value();
  239. }
  240. }
  241. private:
  242. enum {
  243. MASK = size - 1
  244. };
  245. int32_t write_ptr_;
  246. T* buffer_;
  247. stmlib::CosineOscillator lfo_[2];
  248. DISALLOW_COPY_AND_ASSIGN(FxEngine);
  249. };
  250. } // namespace rings
  251. #endif // RINGS_DSP_FX_FX_ENGINE_H_