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.

227 lines
6.4KB

  1. // Copyright 2015 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program 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
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #ifndef MARBLES_TEST_FIXTURES_H_
  16. #define MARBLES_TEST_FIXTURES_H_
  17. #include <cstdlib>
  18. #include <vector>
  19. #include "marbles/ramp/ramp_divider.h"
  20. #include "marbles/ramp/ramp_extractor.h"
  21. const size_t kSampleRate = 32000;
  22. const size_t kAudioBlockSize = 8;
  23. namespace marbles {
  24. using namespace std;
  25. using namespace stmlib;
  26. class PulseGenerator {
  27. public:
  28. PulseGenerator() {
  29. counter_ = 0;
  30. previous_state_ = 0;
  31. }
  32. ~PulseGenerator() { }
  33. void AddPulses(int total_duration, int on_duration, int num_repetitions) {
  34. Pulse p;
  35. p.total_duration = total_duration;
  36. p.on_duration = on_duration;
  37. p.num_repetitions = num_repetitions;
  38. pulses_.push_back(p);
  39. }
  40. void Render(GateFlags* clock, size_t size) {
  41. while (size--) {
  42. bool current_state = pulses_.size() && counter_ < pulses_[0].on_duration;
  43. ++counter_;
  44. if (pulses_.size() && counter_ >= pulses_[0].total_duration) {
  45. counter_ = 0;
  46. --pulses_[0].num_repetitions;
  47. if (pulses_[0].num_repetitions == 0) {
  48. pulses_.erase(pulses_.begin());
  49. }
  50. }
  51. previous_state_ = *clock++ = ExtractGateFlags(previous_state_, current_state);
  52. }
  53. }
  54. private:
  55. struct Pulse {
  56. int total_duration;
  57. int on_duration;
  58. int num_repetitions;
  59. };
  60. int counter_;
  61. GateFlags previous_state_;
  62. vector<Pulse> pulses_;
  63. DISALLOW_COPY_AND_ASSIGN(PulseGenerator);
  64. };
  65. enum PatternDifficulty {
  66. FRIENDLY_PATTERNS,
  67. FAST_PATTERNS,
  68. TRICKY_PATTERNS,
  69. PAUSE_PATTERNS,
  70. };
  71. class ClockGeneratorPatterns {
  72. public:
  73. ClockGeneratorPatterns(PatternDifficulty difficulty) {
  74. if (difficulty == FRIENDLY_PATTERNS) {
  75. pulse_generator_.AddPulses(800, 400, 100);
  76. pulse_generator_.AddPulses(400, 32, 100);
  77. for (int i = 0; i < 15; ++i) {
  78. for (int j = 0; j < 5; ++j) {
  79. pulse_generator_.AddPulses(600 - j * 100, 3, 2);
  80. }
  81. }
  82. for (int i = 0; i < 300; ++i) {
  83. int t = 200 + (rand() % 400);
  84. pulse_generator_.AddPulses(t, t / 4, 1);
  85. }
  86. // Completely random clock.
  87. for (int i = 0; i < 400; ++i) {
  88. int t = 200 + (rand() % 800);
  89. int pw = t / 4 + (rand() % (t / 2));
  90. pulse_generator_.AddPulses(t, pw, 1);
  91. }
  92. return;
  93. } else if (difficulty == FAST_PATTERNS) {
  94. pulse_generator_.AddPulses(32, 16, 100);
  95. pulse_generator_.AddPulses(16, 8, 100);
  96. pulse_generator_.AddPulses(12, 6, 100);
  97. pulse_generator_.AddPulses(8, 4, 100);
  98. pulse_generator_.AddPulses(6, 3, 100);
  99. pulse_generator_.AddPulses(4, 2, 100);
  100. pulse_generator_.AddPulses(8, 4, 100);
  101. pulse_generator_.AddPulses(12, 6, 100);
  102. return;
  103. } else if (difficulty == PAUSE_PATTERNS) {
  104. pulse_generator_.AddPulses(800, 400, 100);
  105. pulse_generator_.AddPulses(32000 * 5 + 10, 400, 1);
  106. pulse_generator_.AddPulses(800, 400, 100);
  107. }
  108. // Steady clock
  109. pulse_generator_.AddPulses(400, 200, 250);
  110. pulse_generator_.AddPulses(4000 + (rand() % 1000), 2000, 10);
  111. pulse_generator_.AddPulses(100, 10, 50);
  112. pulse_generator_.AddPulses(16, 5, 100);
  113. // Periodic clock with some jitter
  114. for (int i = 0; i < 50; ++i) {
  115. pulse_generator_.AddPulses(100, 10, 3);
  116. pulse_generator_.AddPulses(400 + (i % 4), 10, 1);
  117. pulse_generator_.AddPulses((i == 40) ? 40 : 300, 10, 1);
  118. }
  119. for (int i = 0; i < 50; ++i) {
  120. pulse_generator_.AddPulses(100 + (i % 10), 10, 3);
  121. pulse_generator_.AddPulses(200 + (i % 4), 10, 2);
  122. pulse_generator_.AddPulses(300, 10, 1);
  123. }
  124. // Really long pattern that hashes well
  125. for (int i = 0; i < 15; ++i) {
  126. for (int j = 0; j < 10; ++j) {
  127. pulse_generator_.AddPulses(100 + j * 30, 10, 1);
  128. }
  129. }
  130. for (int i = 0; i < 15; ++i) {
  131. for (int j = 0; j < 6; ++j) {
  132. pulse_generator_.AddPulses(300 - j * 50, 3, 2);
  133. }
  134. }
  135. // Random clock with reliable pulse width
  136. for (int i = 0; i < 300; ++i) {
  137. int t = 100 + (rand() % 400);
  138. pulse_generator_.AddPulses(t, t / 4, 1);
  139. }
  140. // Completely random clock.
  141. for (int i = 0; i < 400; ++i) {
  142. int t = 100 + (rand() % 400);
  143. int pw = t / 4 + (rand() % (t / 2));
  144. pulse_generator_.AddPulses(t, pw, 1);
  145. }
  146. }
  147. ~ClockGeneratorPatterns() { }
  148. void Render(size_t size) {
  149. pulse_generator_.Render(buffer_, size);
  150. }
  151. GateFlags* clock() { return buffer_; }
  152. private:
  153. GateFlags buffer_[kAudioBlockSize];
  154. PulseGenerator pulse_generator_;
  155. DISALLOW_COPY_AND_ASSIGN(ClockGeneratorPatterns);
  156. };
  157. class MasterSlaveRampGenerator {
  158. public:
  159. MasterSlaveRampGenerator() {
  160. ramp_extractor_.Init(4000.0f / kSampleRate);
  161. ramp_divider_[0].Init();
  162. ramp_divider_[1].Init();
  163. }
  164. ~MasterSlaveRampGenerator() { }
  165. void Process(const GateFlags* clock, size_t size) {
  166. Ratio r = { 1, 1 };
  167. ramp_extractor_.Process(r, true, clock, master_ramp_, size);
  168. r.q = 2;
  169. ramp_divider_[0].Process(r, master_ramp_, slave_ramp_1_, size);
  170. r.p = 1; r.q = 2;
  171. ramp_divider_[1].Process(r, master_ramp_, slave_ramp_2_, size);
  172. }
  173. Ramps ramps() {
  174. Ramps r;
  175. r.external = external_ramp_;
  176. r.master = master_ramp_;
  177. r.slave[0] = slave_ramp_1_;
  178. r.slave[1] = slave_ramp_2_;
  179. return r;
  180. }
  181. float* master_ramp() { return master_ramp_; }
  182. float* slave_ramp_1() { return slave_ramp_1_; }
  183. float* slave_ramp_2() { return slave_ramp_2_; }
  184. private:
  185. RampExtractor ramp_extractor_;
  186. RampDivider ramp_divider_[2];
  187. float external_ramp_[kAudioBlockSize];
  188. float master_ramp_[kAudioBlockSize];
  189. float slave_ramp_1_[kAudioBlockSize];
  190. float slave_ramp_2_[kAudioBlockSize];
  191. DISALLOW_COPY_AND_ASSIGN(MasterSlaveRampGenerator);
  192. };
  193. } // namespace marbles
  194. #endif // MARBLES_TEST_FIXTURES_H_