1 // Copyright 2015 Emilie Gillet. 2 // 3 // Author: Emilie Gillet (emilie.o.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 // Sequence of random values. 28 29 #ifndef MARBLES_RANDOM_RANDOM_SEQUENCE_H_ 30 #define MARBLES_RANDOM_RANDOM_SEQUENCE_H_ 31 32 #include "stmlib/stmlib.h" 33 34 #include "marbles/random/random_stream.h" 35 36 #include <algorithm> 37 38 namespace marbles { 39 40 const int kDejaVuBufferSize = 16; 41 const int kHistoryBufferSize = 16; 42 43 const float kMaxUint32 = 4294967296.0f; 44 45 class RandomSequence { 46 public: RandomSequence()47 RandomSequence() { } ~RandomSequence()48 ~RandomSequence() { } 49 Init(RandomStream * random_stream)50 inline void Init(RandomStream* random_stream) { 51 random_stream_ = random_stream; 52 for (int i = 0; i < kDejaVuBufferSize; ++i) { 53 loop_[i] = random_stream_->GetFloat(); 54 } 55 std::fill(&history_[0], &history_[kHistoryBufferSize], 0.0f); 56 57 loop_write_head_ = 0; 58 length_ = 8; 59 step_ = 0; 60 61 record_head_ = 0; 62 replay_head_ = -1; 63 replay_start_ = 0; 64 deja_vu_ = 0.0f; 65 replay_hash_ = replay_shift_ = 0; 66 67 redo_read_ptr_ = &loop_[0]; 68 redo_write_ptr_ = NULL; 69 redo_write_history_ptr_ = NULL; 70 } 71 Clone(const RandomSequence & source)72 inline void Clone(const RandomSequence& source) { 73 random_stream_ = source.random_stream_; 74 75 std::copy( 76 &source.loop_[0], 77 &source.loop_[kDejaVuBufferSize], 78 &loop_[0]); 79 std::copy( 80 &source.history_[0], 81 &source.history_[kHistoryBufferSize], 82 &history_[0]); 83 84 loop_write_head_ = source.loop_write_head_; 85 length_ = source.length_; 86 step_ = source.step_; 87 88 record_head_ = source.record_head_; 89 replay_head_ = source.replay_head_; 90 replay_start_ = source.replay_start_; 91 replay_hash_ = source.replay_hash_; 92 replay_shift_ = source.replay_shift_; 93 94 deja_vu_ = source.deja_vu_; 95 96 redo_read_ptr_ = source.redo_read_ptr_ 97 ? &loop_[source.redo_read_ptr_ - &source.loop_[0]] 98 : NULL; 99 redo_write_ptr_ = source.redo_write_ptr_ 100 ? &loop_[source.redo_write_ptr_ - &source.loop_[0]] 101 : NULL; 102 redo_write_history_ptr_ = source.redo_write_history_ptr_ 103 ? &history_[source.redo_write_history_ptr_ - &source.history_[0]] 104 : NULL; 105 } 106 Record()107 inline void Record() { 108 replay_start_ = record_head_; 109 replay_head_ = -1; 110 } 111 ReplayPseudoRandom(uint32_t hash)112 inline void ReplayPseudoRandom(uint32_t hash) { 113 replay_head_ = replay_start_; 114 replay_hash_ = hash; 115 replay_shift_ = 0; 116 } 117 ReplayShifted(uint32_t shift)118 inline void ReplayShifted(uint32_t shift) { 119 replay_head_ = replay_start_; 120 replay_hash_ = 0; 121 replay_shift_ = shift; 122 } 123 GetReplayValue()124 inline float GetReplayValue() const { 125 uint32_t h = (replay_head_ - 1 - replay_shift_ + \ 126 2 * kHistoryBufferSize) % kHistoryBufferSize; 127 if (!replay_hash_) { 128 return history_[h]; 129 } else { 130 uint32_t word = static_cast<float>(history_[h] * kMaxUint32); 131 word = (word ^ replay_hash_) * 1664525L + 1013904223L; 132 return static_cast<float>(word) / kMaxUint32; 133 } 134 } 135 RewriteValue(float value)136 inline float RewriteValue(float value) { 137 // RewriteValue(x) returns what the most recent call to NextValue would have 138 // returned if its second argument were x instead. This is used to "rewrite 139 // history" when the module acquires data from an external source (ASR, 140 // randomizer or quantizer mode). 141 if (replay_head_ >= 0) { 142 return GetReplayValue(); 143 } 144 145 if (redo_write_ptr_) { 146 *redo_write_ptr_ = 1.0f + value; 147 } 148 float result = *redo_read_ptr_; 149 if (result >= 1.0f) { 150 result -= 1.0f; 151 } else { 152 result = 0.5f; 153 } 154 if (redo_write_history_ptr_) { 155 *redo_write_history_ptr_ = result; 156 } 157 return result; 158 } 159 NextValue(bool deterministic,float value)160 inline float NextValue(bool deterministic, float value) { 161 if (replay_head_ >= 0) { 162 replay_head_ = (replay_head_ + 1) % kHistoryBufferSize; 163 return GetReplayValue(); 164 } 165 166 const float p_sqrt = 2.0f * deja_vu_ - 1.0f; 167 const float p = p_sqrt * p_sqrt; 168 169 if (random_stream_->GetFloat() <= p && deja_vu_ <= 0.5f) { 170 // Generate a new value and put it at the end of the loop. 171 redo_write_ptr_ = &loop_[loop_write_head_]; 172 *redo_write_ptr_ = deterministic 173 ? 1.0f + value 174 : random_stream_->GetFloat(); 175 loop_write_head_ = (loop_write_head_ + 1) % kDejaVuBufferSize; 176 step_ = length_ - 1; 177 } else { 178 // Do not generate a new value, just replay the loop or jump randomly. 179 // through it. 180 redo_write_ptr_ = NULL; 181 if (random_stream_->GetFloat() <= p) { 182 step_ = static_cast<int>( 183 random_stream_->GetFloat() * static_cast<float>(length_)); 184 } else { 185 step_ = step_ + 1; 186 if (step_ >= length_) { 187 step_ = 0; 188 } 189 } 190 } 191 uint32_t i = loop_write_head_ + kDejaVuBufferSize - length_ + step_; 192 redo_read_ptr_ = &loop_[i % kDejaVuBufferSize]; 193 float result = *redo_read_ptr_; 194 if (result >= 1.0f) { 195 result -= 1.0f; 196 } else if (deterministic) { 197 // We ask for a deterministic value (shift register), but the loop 198 // contain random values. return 0.5f in this case! 199 result = 0.5f; 200 } 201 redo_write_history_ptr_ = &history_[record_head_]; 202 *redo_write_history_ptr_ = result; 203 record_head_ = (record_head_ + 1) % kHistoryBufferSize; 204 return result; 205 } 206 NextVector(float * destination,size_t size)207 inline void NextVector(float* destination, size_t size) { 208 float seed = NextValue(false, 0.0f); 209 uint32_t word = static_cast<float>(seed * kMaxUint32); 210 while (size--) { 211 *destination++ = static_cast<float>(word) / kMaxUint32; 212 word = word * 1664525L + 1013904223L; 213 } 214 } 215 set_deja_vu(float deja_vu)216 inline void set_deja_vu(float deja_vu) { 217 deja_vu_ = deja_vu; 218 } 219 set_length(int length)220 inline void set_length(int length) { 221 if (length < 1 || length > kDejaVuBufferSize) { 222 return; 223 } 224 length_ = length; 225 step_ = step_ % length; 226 } 227 deja_vu()228 inline float deja_vu() const { 229 return deja_vu_; 230 } 231 length()232 inline int length() const { 233 return length_; 234 } 235 236 private: 237 RandomStream* random_stream_; 238 float loop_[kDejaVuBufferSize]; 239 float history_[kHistoryBufferSize]; 240 int loop_write_head_; 241 int length_; 242 int step_; 243 244 // Allows to go back in the past and get the same results again from NextValue 245 // calls. Allows the 3 X channels to be locked to the same random loop. 246 int record_head_; 247 int replay_head_; 248 int replay_start_; 249 uint32_t replay_hash_; 250 uint32_t replay_shift_; 251 252 float deja_vu_; 253 254 float* redo_read_ptr_; 255 float* redo_write_ptr_; 256 float* redo_write_history_ptr_; 257 258 DISALLOW_COPY_AND_ASSIGN(RandomSequence); 259 }; 260 261 } // namespace marbles 262 263 #endif // MARBLES_RANDOM_RANDOM_SEQUENCE_H_ 264