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.

349 lines
8.6KB

  1. // Copyright 2012 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. // Settings
  28. #ifndef BRAIDS_SETTINGS_H_
  29. #define BRAIDS_SETTINGS_H_
  30. #include "stmlib/stmlib.h"
  31. namespace braids {
  32. enum MacroOscillatorShape {
  33. MACRO_OSC_SHAPE_CSAW,
  34. MACRO_OSC_SHAPE_MORPH,
  35. MACRO_OSC_SHAPE_SAW_SQUARE,
  36. MACRO_OSC_SHAPE_SINE_TRIANGLE,
  37. MACRO_OSC_SHAPE_BUZZ,
  38. MACRO_OSC_SHAPE_SQUARE_SYNC,
  39. MACRO_OSC_SHAPE_SAW_SYNC,
  40. MACRO_OSC_SHAPE_TRIPLE_SAW,
  41. MACRO_OSC_SHAPE_TRIPLE_SQUARE,
  42. MACRO_OSC_SHAPE_TRIPLE_TRIANGLE,
  43. MACRO_OSC_SHAPE_TRIPLE_SINE,
  44. MACRO_OSC_SHAPE_TRIPLE_RING_MOD,
  45. MACRO_OSC_SHAPE_SAW_SWARM,
  46. MACRO_OSC_SHAPE_SAW_COMB,
  47. MACRO_OSC_SHAPE_TOY,
  48. MACRO_OSC_SHAPE_DIGITAL_FILTER_LP,
  49. MACRO_OSC_SHAPE_DIGITAL_FILTER_PK,
  50. MACRO_OSC_SHAPE_DIGITAL_FILTER_BP,
  51. MACRO_OSC_SHAPE_DIGITAL_FILTER_HP,
  52. MACRO_OSC_SHAPE_VOSIM,
  53. MACRO_OSC_SHAPE_VOWEL,
  54. MACRO_OSC_SHAPE_VOWEL_FOF,
  55. MACRO_OSC_SHAPE_HARMONICS,
  56. MACRO_OSC_SHAPE_FM,
  57. MACRO_OSC_SHAPE_FEEDBACK_FM,
  58. MACRO_OSC_SHAPE_CHAOTIC_FEEDBACK_FM,
  59. MACRO_OSC_SHAPE_PLUCKED,
  60. MACRO_OSC_SHAPE_BOWED,
  61. MACRO_OSC_SHAPE_BLOWN,
  62. MACRO_OSC_SHAPE_FLUTED,
  63. MACRO_OSC_SHAPE_STRUCK_BELL,
  64. MACRO_OSC_SHAPE_STRUCK_DRUM,
  65. MACRO_OSC_SHAPE_KICK,
  66. MACRO_OSC_SHAPE_CYMBAL,
  67. MACRO_OSC_SHAPE_SNARE,
  68. MACRO_OSC_SHAPE_WAVETABLES,
  69. MACRO_OSC_SHAPE_WAVE_MAP,
  70. MACRO_OSC_SHAPE_WAVE_LINE,
  71. MACRO_OSC_SHAPE_WAVE_PARAPHONIC,
  72. MACRO_OSC_SHAPE_FILTERED_NOISE,
  73. MACRO_OSC_SHAPE_TWIN_PEAKS_NOISE,
  74. MACRO_OSC_SHAPE_CLOCKED_NOISE,
  75. MACRO_OSC_SHAPE_GRANULAR_CLOUD,
  76. MACRO_OSC_SHAPE_PARTICLE_NOISE,
  77. MACRO_OSC_SHAPE_DIGITAL_MODULATION,
  78. MACRO_OSC_SHAPE_QUESTION_MARK,
  79. // MACRO_OSC_SHAPE_YOUR_ALGO
  80. MACRO_OSC_SHAPE_LAST,
  81. MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META = MACRO_OSC_SHAPE_DIGITAL_MODULATION
  82. };
  83. enum Resolution {
  84. RESOLUTION_2_BIT,
  85. RESOLUTION_3_BIT,
  86. RESOLUTION_4_BIT,
  87. RESOLUTION_6_BIT,
  88. RESOLUTION_8_BIT,
  89. RESOLUTION_12_BIT,
  90. RESOLUTION_16_BIT,
  91. RESOLUTION_LAST
  92. };
  93. enum SampleRate {
  94. SAMPLE_RATE_4K,
  95. SAMPLE_RATE_8K,
  96. SAMPLE_RATE_16K,
  97. SAMPLE_RATE_24k,
  98. SAMPLE_RATE_32k,
  99. SAMPLE_RATE_48K,
  100. SAMPLE_RATE_96K,
  101. SAMPLE_RATE_LAST
  102. };
  103. enum PitchRange {
  104. PITCH_RANGE_EXTERNAL,
  105. PITCH_RANGE_FREE,
  106. PITCH_RANGE_EXTENDED,
  107. PITCH_RANGE_440,
  108. PITCH_RANGE_LFO // This setting is hidden by default!
  109. };
  110. enum Setting {
  111. SETTING_OSCILLATOR_SHAPE,
  112. SETTING_RESOLUTION,
  113. SETTING_SAMPLE_RATE,
  114. SETTING_AD_TIMBRE,
  115. SETTING_TRIG_SOURCE,
  116. SETTING_TRIG_DELAY,
  117. SETTING_META_MODULATION,
  118. SETTING_PITCH_RANGE,
  119. SETTING_PITCH_OCTAVE,
  120. SETTING_QUANTIZER_SCALE,
  121. SETTING_VCO_FLATTEN,
  122. SETTING_VCO_DRIFT,
  123. SETTING_SIGNATURE,
  124. SETTING_BRIGHTNESS,
  125. SETTING_AD_ATTACK,
  126. SETTING_AD_DECAY,
  127. SETTING_AD_FM,
  128. SETTING_AD_COLOR,
  129. SETTING_AD_VCA,
  130. SETTING_QUANTIZER_ROOT,
  131. SETTING_LAST_EDITABLE_SETTING = SETTING_QUANTIZER_ROOT,
  132. // Not settings per-se, but used for menu display!
  133. SETTING_CALIBRATION,
  134. SETTING_CV_TESTER,
  135. SETTING_MARQUEE,
  136. SETTING_VERSION,
  137. SETTING_LAST
  138. };
  139. struct SettingsData {
  140. uint8_t shape;
  141. uint8_t resolution;
  142. uint8_t sample_rate;
  143. uint8_t ad_timbre;
  144. uint8_t auto_trig;
  145. uint8_t trig_delay;
  146. uint8_t meta_modulation;
  147. uint8_t pitch_range;
  148. uint8_t pitch_octave;
  149. uint8_t quantizer_scale;
  150. uint8_t vco_flatten;
  151. uint8_t vco_drift;
  152. uint8_t signature;
  153. uint8_t brightness;
  154. uint8_t ad_attack;
  155. uint8_t ad_decay;
  156. uint8_t ad_fm;
  157. uint8_t ad_color;
  158. uint8_t ad_vca;
  159. uint8_t quantizer_root;
  160. int32_t pitch_cv_offset;
  161. int32_t pitch_cv_scale;
  162. int32_t fm_cv_offset;
  163. char marquee_text[63];
  164. char magic_byte;
  165. };
  166. struct SettingMetadata {
  167. uint8_t min_value;
  168. uint8_t max_value;
  169. const char name[5];
  170. const char* const* strings;
  171. int16_t Clip(int16_t value) const {
  172. if (value > max_value) {
  173. value = max_value;
  174. } else if (value < min_value) {
  175. value = min_value;
  176. }
  177. return value;
  178. }
  179. };
  180. class Settings {
  181. public:
  182. Settings() { }
  183. ~Settings() { }
  184. void Init();
  185. void Save();
  186. void Reset();
  187. void SetValue(Setting setting, uint8_t value) {
  188. uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(&data_));
  189. data[setting] = value;
  190. }
  191. uint8_t GetValue(Setting setting) const {
  192. const uint8_t* data = static_cast<const uint8_t*>(
  193. static_cast<const void*>(&data_));
  194. return data[setting];
  195. }
  196. inline MacroOscillatorShape shape() const {
  197. return static_cast<MacroOscillatorShape>(data_.shape);
  198. }
  199. inline Resolution resolution() const {
  200. return static_cast<Resolution>(data_.resolution);
  201. }
  202. inline SampleRate sample_rate() const {
  203. return static_cast<SampleRate>(data_.sample_rate);
  204. }
  205. inline bool vco_flatten() const {
  206. return data_.vco_flatten;
  207. }
  208. inline uint8_t vco_drift() const {
  209. return data_.vco_drift;
  210. }
  211. inline uint8_t signature() const {
  212. return data_.signature;
  213. }
  214. inline bool meta_modulation() const {
  215. return data_.meta_modulation;
  216. }
  217. inline uint8_t trig_delay() const {
  218. return data_.trig_delay;
  219. }
  220. inline int32_t quantizer_root() const {
  221. return data_.quantizer_root;
  222. }
  223. inline const char* marquee_text() const {
  224. return data_.marquee_text;
  225. }
  226. inline char* mutable_marquee_text() {
  227. return data_.marquee_text;
  228. }
  229. inline const SettingsData& data() const { return data_; }
  230. inline SettingsData* mutable_data() { return &data_; }
  231. void Calibrate(
  232. int32_t adc_code_c2,
  233. int32_t adc_code_c4,
  234. int32_t adc_code_fm) {
  235. if (adc_code_c4 != adc_code_c2) {
  236. int32_t scale = (24 * 128 * 4096L) / (adc_code_c4 - adc_code_c2);
  237. data_.pitch_cv_scale = scale;
  238. data_.pitch_cv_offset = (60 << 7) -
  239. (scale * ((adc_code_c2 + adc_code_c4) >> 1) >> 12);
  240. data_.fm_cv_offset = adc_code_fm;
  241. }
  242. Save();
  243. }
  244. inline int32_t adc_to_pitch(int32_t pitch_adc_code) const {
  245. if (data_.pitch_range == PITCH_RANGE_EXTERNAL ||
  246. data_.pitch_range == PITCH_RANGE_LFO) {
  247. pitch_adc_code = pitch_adc_code * data_.pitch_cv_scale >> 12;
  248. pitch_adc_code += data_.pitch_cv_offset;
  249. } else if (data_.pitch_range == PITCH_RANGE_FREE) {
  250. pitch_adc_code = (pitch_adc_code - 1638);
  251. pitch_adc_code = pitch_adc_code * data_.pitch_cv_scale >> 12;
  252. pitch_adc_code += 60 << 7;
  253. } else if (data_.pitch_range == PITCH_RANGE_440) {
  254. pitch_adc_code = 69 << 7;
  255. } else {
  256. pitch_adc_code = (pitch_adc_code - 1638) * 9 >> 1;
  257. pitch_adc_code += 60 << 7;
  258. }
  259. return pitch_adc_code;
  260. }
  261. inline int32_t pitch_transposition() const {
  262. int32_t t = data_.pitch_range == PITCH_RANGE_LFO ? -36 << 7 : 0;
  263. t += (static_cast<int32_t>(data_.pitch_octave) - 2) * 12 * 128;
  264. return t;
  265. }
  266. inline int32_t adc_to_fm(int32_t fm_adc_code) const {
  267. fm_adc_code -= data_.fm_cv_offset;
  268. fm_adc_code = fm_adc_code * 7680 >> 12;
  269. if (data_.pitch_range == PITCH_RANGE_440) {
  270. fm_adc_code = 0;
  271. }
  272. return fm_adc_code;
  273. }
  274. inline bool paques() const {
  275. return paques_;
  276. }
  277. static const SettingMetadata& metadata(Setting setting) {
  278. return metadata_[setting];
  279. }
  280. static const Setting setting_at_index(int16_t index) {
  281. return settings_order_[index];
  282. }
  283. private:
  284. void CheckPaques();
  285. SettingsData data_;
  286. uint16_t version_token_;
  287. bool paques_;
  288. static const SettingMetadata metadata_[SETTING_LAST];
  289. static const Setting settings_order_[SETTING_LAST];
  290. DISALLOW_COPY_AND_ASSIGN(Settings);
  291. };
  292. extern Settings settings;
  293. } // namespace braids
  294. #endif // BRAIDS_SETTINGS_H_