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 // Record a note CV distribution - to be used for the quantizer. 28 29 #ifndef MARBLES_SCALE_RECORDER_H_ 30 #define MARBLES_SCALE_RECORDER_H_ 31 32 #include "stmlib/stmlib.h" 33 #include "marbles/random/quantizer.h" 34 35 namespace marbles { 36 37 class ScaleRecorder { 38 public: ScaleRecorder()39 ScaleRecorder() { } ~ScaleRecorder()40 ~ScaleRecorder() { } 41 42 struct Degree { 43 float average_voltage; 44 float total_voltage; 45 float count; 46 47 bool operator< (const Degree& rhs) const { 48 return average_voltage < rhs.average_voltage; 49 } 50 }; 51 Init()52 void Init() { 53 Clear(); 54 } 55 Clear()56 void Clear() { 57 num_degrees_ = 0; 58 current_voltage_ = 0.0f; 59 total_count_ = 0.0f; 60 } 61 NewNote(float v)62 void NewNote(float v) { 63 current_voltage_ = v; 64 } 65 UpdateVoltage(float v)66 void UpdateVoltage(float v) { 67 ONE_POLE(current_voltage_, v, 0.01f); 68 } 69 AcceptNote()70 void AcceptNote() { 71 const float base_interval = 1.0f; 72 float v = current_voltage_; 73 while (v < 0.0f) { 74 v += base_interval; 75 } 76 float octave = static_cast<float>( 77 static_cast<int>(v / base_interval)) * base_interval; 78 v -= octave; 79 80 int nearest_degree = -1; 81 for (int i = 0; i < num_degrees_; ++i) { 82 float av = degrees_[i].average_voltage; 83 const float tolerance = 1.0f / 36.0f; 84 if (fabsf(v - av) < tolerance) { 85 nearest_degree = i; 86 break; 87 } 88 if (fabsf((v - base_interval) - av) < tolerance) { 89 v -= base_interval; 90 nearest_degree = i; 91 break; 92 } 93 } 94 if (nearest_degree == -1 && num_degrees_ != kMaxDegrees) { 95 nearest_degree = num_degrees_; 96 Degree* d = °rees_[nearest_degree]; 97 d->total_voltage = 0.0f; 98 d->average_voltage = 0.0f; 99 d->count = 0.0f; 100 ++num_degrees_; 101 } 102 103 if (nearest_degree != -1) { 104 Degree* d = °rees_[nearest_degree]; 105 d->total_voltage += v; 106 d->count += 1.0f; 107 d->average_voltage = d->total_voltage / d->count; 108 total_count_ += 1.0f; 109 } 110 } 111 ExtractScale(Scale * scale)112 bool ExtractScale(Scale* scale) { 113 if (num_degrees_ < 2) { 114 return false; 115 } 116 std::sort(°rees_[0], °rees_[num_degrees_]); 117 118 float max_count = 0.0f; 119 for (int i = 0; i < num_degrees_; ++i) { 120 max_count = std::max(degrees_[i].count, max_count); 121 } 122 123 scale->base_interval = 1.0f; 124 scale->num_degrees = num_degrees_; 125 for (int i = 0; i < num_degrees_; ++i) { 126 Degree* d = °rees_[i]; 127 scale->degree[i].voltage = d->average_voltage; 128 scale->degree[i].weight = static_cast<uint8_t>( 129 255.0f * d->count / max_count); 130 if (scale->degree[i].weight == 0) { 131 ++scale->degree[i].weight; 132 } 133 } 134 135 return true; 136 } 137 138 private: 139 int num_degrees_; 140 float current_voltage_; 141 float total_count_; 142 Degree degrees_[kMaxDegrees]; 143 144 DISALLOW_COPY_AND_ASSIGN(ScaleRecorder); 145 }; 146 147 } // namespace marbles 148 149 #endif // MARBLES_SCALE_RECORDER_H_ 150