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.

259 lines
8.3KB

  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. // Granular playback of audio stored in a buffer.
  28. #ifndef CLOUDS_DSP_GRANULAR_SAMPLE_PLAYER_H_
  29. #define CLOUDS_DSP_GRANULAR_SAMPLE_PLAYER_H_
  30. #include "stmlib/stmlib.h"
  31. #include <algorithm>
  32. #include "stmlib/dsp/atan.h"
  33. #include "stmlib/dsp/units.h"
  34. #include "stmlib/utils/random.h"
  35. #include "clouds/dsp/audio_buffer.h"
  36. #include "clouds/dsp/frame.h"
  37. #include "clouds/dsp/grain.h"
  38. #include "clouds/dsp/parameters.h"
  39. #include "clouds/resources.h"
  40. namespace clouds {
  41. const int32_t kMaxNumGrains = 40;
  42. using namespace stmlib;
  43. class GranularSamplePlayer {
  44. public:
  45. GranularSamplePlayer() { }
  46. ~GranularSamplePlayer() { }
  47. void Init(int32_t num_channels, int32_t max_num_grains) {
  48. max_num_grains_ = max_num_grains;
  49. num_midfi_grains_ = 3 * max_num_grains / 4;
  50. gain_normalization_ = 1.0f;
  51. for (int32_t i = 0; i < kMaxNumGrains; ++i) {
  52. grains_[i].Init();
  53. }
  54. num_grains_ = 0.0f;
  55. num_channels_ = num_channels;
  56. grain_size_hint_ = 1024.0f;
  57. }
  58. template<Resolution resolution>
  59. void Play(
  60. const AudioBuffer<resolution>* buffer,
  61. const Parameters& parameters,
  62. float* out, size_t size) {
  63. float overlap = parameters.granular.overlap;
  64. overlap = (overlap * overlap) * (overlap * overlap);
  65. float target_num_grains = max_num_grains_ * overlap;
  66. float p = target_num_grains / static_cast<float>(grain_size_hint_);
  67. float space_between_grains = grain_size_hint_ / target_num_grains;
  68. if (parameters.granular.use_deterministic_seed) {
  69. p = -1.0f;
  70. } else {
  71. grain_rate_phasor_ = -1000.0f;
  72. }
  73. // Build a list of available grains.
  74. int32_t num_available_grains = FillAvailableGrainsList();
  75. // Try to schedule new grains.
  76. bool seed_trigger = parameters.trigger;
  77. for (size_t t = 0; t < size; ++t) {
  78. grain_rate_phasor_ += 1.0f;
  79. bool seed_probabilistic = Random::GetFloat() < p
  80. && target_num_grains > num_grains_;
  81. bool seed_deterministic = grain_rate_phasor_ >= space_between_grains;
  82. bool seed = seed_probabilistic || seed_deterministic || seed_trigger;
  83. if (num_available_grains && seed) {
  84. --num_available_grains;
  85. int32_t index = available_grains_[num_available_grains];
  86. GrainQuality quality;
  87. if (num_available_grains < num_midfi_grains_) {
  88. quality = GRAIN_QUALITY_MEDIUM;
  89. } else {
  90. quality = GRAIN_QUALITY_HIGH;
  91. }
  92. Grain* g = &grains_[index];
  93. ScheduleGrain(
  94. g,
  95. parameters,
  96. t,
  97. buffer->size(),
  98. buffer->head() - size + t,
  99. quality);
  100. grain_rate_phasor_ = 0.0f;
  101. seed_trigger = false;
  102. }
  103. }
  104. // Overlap grains.
  105. std::fill(&out[0], &out[size * 2], 0.0f);
  106. float* e = envelope_buffer_;
  107. for (int32_t i = 0; i < max_num_grains_; ++i) {
  108. Grain* g = &grains_[i];
  109. if (g->recommended_quality() == GRAIN_QUALITY_HIGH) {
  110. if (num_channels_ == 1) {
  111. g->OverlapAdd<1, GRAIN_QUALITY_HIGH>(buffer, out, e, size);
  112. } else {
  113. g->OverlapAdd<2, GRAIN_QUALITY_HIGH>(buffer, out, e, size);
  114. }
  115. } else if (g->recommended_quality() == GRAIN_QUALITY_MEDIUM) {
  116. if (num_channels_ == 1) {
  117. g->OverlapAdd<1, GRAIN_QUALITY_MEDIUM>(buffer, out, e, size);
  118. } else {
  119. g->OverlapAdd<2, GRAIN_QUALITY_MEDIUM>(buffer, out, e, size);
  120. }
  121. } else {
  122. if (num_channels_ == 1) {
  123. g->OverlapAdd<1, GRAIN_QUALITY_LOW>(buffer, out, e, size);
  124. } else {
  125. g->OverlapAdd<2, GRAIN_QUALITY_LOW>(buffer, out, e, size);
  126. }
  127. }
  128. }
  129. // Compute normalization factor.
  130. int32_t active_grains = max_num_grains_ - num_available_grains;
  131. SLOPE(num_grains_, static_cast<float>(active_grains), 0.9f, 0.2f);
  132. float gain_normalization = num_grains_ > 2.0f
  133. ? fast_rsqrt_carmack(num_grains_ - 1.0f)
  134. : 1.0f;
  135. float window_gain = 1.0f + 2.0f * parameters.granular.window_shape;
  136. CONSTRAIN(window_gain, 1.0f, 2.0f);
  137. gain_normalization *= Crossfade(
  138. 1.0f, window_gain, parameters.granular.overlap);
  139. // Apply gain normalization.
  140. for (size_t t = 0; t < size; ++t) {
  141. ONE_POLE(gain_normalization_, gain_normalization, 0.01f)
  142. *out++ *= gain_normalization_;
  143. *out++ *= gain_normalization_;
  144. }
  145. }
  146. private:
  147. int32_t FillAvailableGrainsList() {
  148. int32_t num_available_grains = 0;
  149. for (int32_t i = 0; i < max_num_grains_; ++i) {
  150. if (!grains_[i].active()) {
  151. available_grains_[num_available_grains] = i;
  152. ++num_available_grains;
  153. }
  154. }
  155. return num_available_grains;
  156. }
  157. void ScheduleGrain(
  158. Grain* grain,
  159. const Parameters& parameters,
  160. int32_t pre_delay,
  161. int32_t buffer_size,
  162. int32_t buffer_head,
  163. GrainQuality quality) {
  164. float position = parameters.position;
  165. float pitch = parameters.pitch;
  166. float window_shape = parameters.granular.window_shape;
  167. float grain_size = Interpolate(lut_grain_size, parameters.size, 256.0f);
  168. float pitch_ratio = SemitonesToRatio(pitch);
  169. float inv_pitch_ratio = SemitonesToRatio(-pitch);
  170. float pan = 0.5f + parameters.stereo_spread * (Random::GetFloat() - 0.5f);
  171. float gain_l, gain_r;
  172. if (num_channels_ == 1) {
  173. gain_l = Interpolate(lut_sin, pan, 256.0f);
  174. gain_r = Interpolate(lut_sin + 256, pan, 256.0f);
  175. } else {
  176. if (pan < 0.5f) {
  177. gain_l = 1.0f;
  178. gain_r = 2.0f * pan;
  179. } else {
  180. gain_r = 1.0f;
  181. gain_l = 2.0f * (1.0f - pan);
  182. }
  183. }
  184. if (pitch_ratio > 1.0f) {
  185. // The grain's play-head moves faster than the buffer record-head.
  186. // we must make sure that the grain will not consume too much data.
  187. // In some situations, it might be necessary to reduce the size of the
  188. // grain.
  189. grain_size = std::min(grain_size, buffer_size * 0.25f * inv_pitch_ratio);
  190. }
  191. float eaten_by_play_head = grain_size * pitch_ratio;
  192. float eaten_by_recording_head = grain_size;
  193. float available = 0.0;
  194. available += static_cast<float>(buffer_size);
  195. available -= eaten_by_play_head;
  196. available -= eaten_by_recording_head;
  197. bool reverse = parameters.granular.reverse;
  198. int32_t size = static_cast<int32_t>(grain_size) & ~1;
  199. int32_t start = buffer_head - static_cast<int32_t>(
  200. position * available + eaten_by_play_head);
  201. grain->Start(
  202. pre_delay,
  203. buffer_size,
  204. start,
  205. size,
  206. reverse,
  207. static_cast<uint32_t>(pitch_ratio * 65536.0f),
  208. window_shape,
  209. gain_l,
  210. gain_r,
  211. quality);
  212. grain_size_hint_ = grain_size;
  213. }
  214. int32_t max_num_grains_;
  215. int32_t num_midfi_grains_;
  216. int32_t num_channels_;
  217. float num_grains_;
  218. float gain_normalization_;
  219. float grain_size_hint_;
  220. float grain_rate_phasor_;
  221. Grain grains_[kMaxNumGrains];
  222. int32_t available_grains_[kMaxNumGrains];
  223. float envelope_buffer_[kMaxBlockSize];
  224. DISALLOW_COPY_AND_ASSIGN(GranularSamplePlayer);
  225. };
  226. } // namespace clouds
  227. #endif // CLOUDS_DSP_GRANULAR_SAMPLE_PLAYER_H_