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.

357 lines
9.8KB

  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 reverbs.
  28. #ifndef CLOUDS_DSP_FX_FX_ENGINE_H_
  29. #define CLOUDS_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 clouds {
  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. inline void SoftLimit() {
  188. accumulator_ = stmlib::SoftLimit(accumulator_);
  189. }
  190. template<typename D>
  191. inline void Interpolate(D& d, float offset, float scale) {
  192. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  193. MAKE_INTEGRAL_FRACTIONAL(offset);
  194. float a = DataType<format>::Decompress(
  195. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  196. float b = DataType<format>::Decompress(
  197. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  198. float x = a + (b - a) * offset_fractional;
  199. previous_read_ = x;
  200. accumulator_ += x * scale;
  201. }
  202. template<typename D>
  203. inline void InterpolateHermite(D& d, float offset, float scale) {
  204. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  205. MAKE_INTEGRAL_FRACTIONAL(offset);
  206. float xm1 = DataType<format>::Decompress(
  207. buffer_[(write_ptr_ + offset_integral + D::base - 1) & MASK]);
  208. float x0 = DataType<format>::Decompress(
  209. buffer_[(write_ptr_ + offset_integral + D::base + 0) & MASK]);
  210. float x1 = DataType<format>::Decompress(
  211. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  212. float x2 = DataType<format>::Decompress(
  213. buffer_[(write_ptr_ + offset_integral + D::base + 2) & MASK]);
  214. float c = (x1 - xm1) * 0.5f;
  215. float v = x0 - x1;
  216. float w = c + v;
  217. float a = w + v + (x2 - x0) * 0.5f;
  218. float b_neg = w + a;
  219. float t = offset_fractional;
  220. float x = (((a * t) - b_neg) * t + c) * t + x0;
  221. previous_read_ = x;
  222. accumulator_ += x * scale;
  223. }
  224. template<typename D>
  225. inline void Interpolate(
  226. D& d, float offset, LFOIndex index, float amplitude, float scale) {
  227. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  228. offset += amplitude * lfo_value_[index];
  229. MAKE_INTEGRAL_FRACTIONAL(offset);
  230. float a = DataType<format>::Decompress(
  231. buffer_[(write_ptr_ + offset_integral + D::base) & MASK]);
  232. float b = DataType<format>::Decompress(
  233. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  234. float x = a + (b - a) * offset_fractional;
  235. previous_read_ = x;
  236. accumulator_ += x * scale;
  237. }
  238. template<typename D>
  239. inline void InterpolateHermite(
  240. D& d, float offset, LFOIndex index, float amplitude, float scale) {
  241. STATIC_ASSERT(D::base + D::length <= size, delay_memory_full);
  242. offset += amplitude * lfo_value_[index];
  243. MAKE_INTEGRAL_FRACTIONAL(offset);
  244. float xm1 = DataType<format>::Decompress(
  245. buffer_[(write_ptr_ + offset_integral + D::base - 1) & MASK]);
  246. float x0 = DataType<format>::Decompress(
  247. buffer_[(write_ptr_ + offset_integral + D::base + 0) & MASK]);
  248. float x1 = DataType<format>::Decompress(
  249. buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]);
  250. float x2 = DataType<format>::Decompress(
  251. buffer_[(write_ptr_ + offset_integral + D::base + 2) & MASK]);
  252. float c = (x1 - xm1) * 0.5f;
  253. float v = x0 - x1;
  254. float w = c + v;
  255. float a = w + v + (x2 - x0) * 0.5f;
  256. float b_neg = w + a;
  257. float t = offset_fractional;
  258. float x = (((a * t) - b_neg) * t + c) * t + x0;
  259. previous_read_ = x;
  260. accumulator_ += x * scale;
  261. }
  262. private:
  263. float accumulator_;
  264. float previous_read_;
  265. float lfo_value_[2];
  266. T* buffer_;
  267. int32_t write_ptr_;
  268. DISALLOW_COPY_AND_ASSIGN(Context);
  269. };
  270. inline void SetLFOFrequency(LFOIndex index, float frequency) {
  271. lfo_[index].template Init<stmlib::COSINE_OSCILLATOR_APPROXIMATE>(
  272. frequency * 32.0f);
  273. }
  274. inline void Start(Context* c) {
  275. --write_ptr_;
  276. if (write_ptr_ < 0) {
  277. write_ptr_ += size;
  278. }
  279. c->accumulator_ = 0.0f;
  280. c->previous_read_ = 0.0f;
  281. c->buffer_ = buffer_;
  282. c->write_ptr_ = write_ptr_;
  283. if ((write_ptr_ & 31) == 0) {
  284. c->lfo_value_[0] = lfo_[0].Next();
  285. c->lfo_value_[1] = lfo_[1].Next();
  286. } else {
  287. c->lfo_value_[0] = lfo_[0].value();
  288. c->lfo_value_[1] = lfo_[1].value();
  289. }
  290. }
  291. private:
  292. enum {
  293. MASK = size - 1
  294. };
  295. int32_t write_ptr_;
  296. T* buffer_;
  297. stmlib::CosineOscillator lfo_[2];
  298. DISALLOW_COPY_AND_ASSIGN(FxEngine);
  299. };
  300. } // namespace clouds
  301. #endif // CLOUDS_DSP_FX_FX_ENGINE_H_