1 // Copyright 2014 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 // CV scaler.
28 
29 #ifndef WARPS_CV_SCALER_H_
30 #define WARPS_CV_SCALER_H_
31 
32 #include "stmlib/stmlib.h"
33 
34 #include "warps/drivers/adc.h"
35 #include "warps/drivers/codec.h"
36 #include "warps/drivers/normalization_probe.h"
37 
38 #include "warps/settings.h"
39 
40 namespace warps {
41 
42 class Parameters;
43 
44 class NormalizationDetector {
45  public:
NormalizationDetector()46   NormalizationDetector() { }
~NormalizationDetector()47   ~NormalizationDetector() { }
48 
Init(float lp_coefficient,float threshold)49   void Init(float lp_coefficient, float threshold) {
50     score_ = 0.0f;
51     state_ = false;
52     threshold_ = threshold;
53     lp_coefficient_ = lp_coefficient;
54   }
55 
Process(float x,float y)56   void Process(float x, float y) {
57     // x is supposed to be centered!
58     score_ += lp_coefficient_ * (x * y - score_);
59 
60     float hysteresis = state_ ? -0.05f * threshold_ : 0.0f;
61     state_ = score_ >= (threshold_ + hysteresis);
62   }
63 
normalized()64   inline bool normalized() const { return state_; }
score()65   inline float score() const { return score_; }
66 
67  private:
68   float score_;
69   float lp_coefficient_;
70   float threshold_;
71 
72   bool state_;
73 
74   DISALLOW_COPY_AND_ASSIGN(NormalizationDetector);
75 };
76 
77 class CvScaler {
78  public:
CvScaler()79   CvScaler() { }
~CvScaler()80   ~CvScaler() { }
81 
82   void Init(CalibrationData* calibration_data);
83   void Read(Parameters* parameters);
84 
85   void DetectAudioNormalization(Codec::Frame* in, size_t size);
86 
StartCalibration()87   void StartCalibration() {
88     normalization_probe_enabled_ = false;
89     normalization_probe_forced_state_ = false;
90   }
91 
CalibrateC1()92   void CalibrateC1() {
93     cv_c1_ = adc_.float_value(ADC_LEVEL_1_CV);
94   }
95 
CalibrateOffsets()96   void CalibrateOffsets() {
97     for (size_t i = 1; i < 4; ++i) {
98       calibration_data_->offset[i] = adc_.float_value(i);
99     }
100   }
101 
CalibrateC3()102   bool CalibrateC3() {
103     float c3 = adc_.float_value(ADC_LEVEL_1_CV); // 0.5818181818181818
104     float c1 = cv_c1_; // 0.8
105     float delta = c3 - c1;
106     bool success = delta > -0.4f && delta < -0.1f;
107     if (success) {
108       calibration_data_->pitch_scale = 24.0f / (c3 - c1);
109       calibration_data_->pitch_offset = 12.0f - \
110           calibration_data_->pitch_scale * c1;
111       calibration_data_->offset[0] = c1 + 0.5f * (c1 - c3);
112     }
113     normalization_probe_enabled_ = true;
114     return success;
115   }
116 
StartNormalizationCalibration()117   void StartNormalizationCalibration() {
118     normalization_probe_enabled_ = false;
119     normalization_probe_forced_state_ = false;
120   }
121 
CalibrateLow()122   void CalibrateLow() {
123     cv_low_[0] = adc_.float_value(ADC_LEVEL_1_CV);
124     cv_low_[1] = adc_.float_value(ADC_LEVEL_2_CV);
125     normalization_probe_forced_state_ = true;
126   }
127 
CalibrateHigh()128   bool CalibrateHigh() {
129     bool success = true;
130     for (int i = 0; i < 2; ++i) {
131       float high = adc_.float_value(ADC_LEVEL_1_CV + i);
132       float threshold = (cv_low_[i] + high) * 0.5f;
133       bool within_range = threshold >= 0.8f && threshold <= 0.9f;
134       if (within_range) {
135         calibration_data_->normalization_detection_threshold[i] = threshold;
136       }
137       success = success && within_range;
138     }
139     normalization_probe_enabled_ = true;
140     return success;
141   }
142 
ready_for_calibration()143   inline bool ready_for_calibration() const {
144     return adc_.float_value(ADC_LEVEL_2_CV) > 0.8f && \
145          adc_.float_value(ADC_LEVEL_1_CV) > 0.7f;
146   }
147 
easter_egg_digit()148   inline uint8_t easter_egg_digit() const {
149     if (lp_state_[ADC_LEVEL_1_POT] < 0.05f && \
150         lp_state_[ADC_LEVEL_2_POT] < 0.05f && \
151         lp_state_[ADC_PARAMETER_POT] < 0.05f) {
152       return static_cast<uint8_t>(
153           UnwrapPot(lp_state_[ADC_ALGORITHM_POT]) * 8.0f + 0.5f);
154     } else {
155       return 0;
156     }
157   }
158 
adc_value(size_t index)159   inline uint8_t adc_value(size_t index) const {
160     return adc_.value(index) >> 8;
161   }
162 
normalization(size_t index)163   inline uint8_t normalization(size_t index) const {
164     return normalization_detector_[index].normalized() ? 255 : 0;
165   }
166 
167   float UnwrapPot(float x) const;
168 
169  private:
170   void DetectNormalization();
171 
172   Adc adc_;
173   CalibrationData* calibration_data_;
174   NormalizationProbe normalization_probe_;
175   NormalizationDetector normalization_detector_[4];
176 
177   bool normalization_probe_value_[2];
178   bool normalization_probe_enabled_;
179   bool normalization_probe_forced_state_;
180 
181   float lp_state_[ADC_LAST];
182   float note_cv_;
183   float note_pot_;
184   float note_pot_quantized_;
185   float cv_c1_;
186   float cv_low_[2];
187 
188   DISALLOW_COPY_AND_ASSIGN(CvScaler);
189 };
190 
191 }  // namespace warps
192 
193 #endif  // WARPS_CV_SCALER_H_
194