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.

445 lines
12KB

  1. // Copyright 2013 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. // Multi.
  28. #ifndef YARNS_MULTI_H_
  29. #define YARNS_MULTI_H_
  30. #include "stmlib/stmlib.h"
  31. #include "yarns/internal_clock.h"
  32. #include "yarns/layout_configurator.h"
  33. #include "yarns/part.h"
  34. #include "yarns/voice.h"
  35. namespace yarns {
  36. const uint8_t kNumParts = 4;
  37. const uint8_t kNumVoices = 4;
  38. const uint8_t kMaxBarDuration = 32;
  39. struct MultiSettings {
  40. uint8_t layout;
  41. uint8_t clock_tempo;
  42. uint8_t clock_swing;
  43. uint8_t clock_input_division;
  44. uint8_t clock_output_division;
  45. uint8_t clock_bar_duration;
  46. uint8_t clock_override;
  47. int8_t custom_pitch_table[12];
  48. uint8_t remote_control_channel;
  49. uint8_t padding[12];
  50. };
  51. enum MultiSetting {
  52. MULTI_LAYOUT,
  53. MULTI_CLOCK_TEMPO,
  54. MULTI_CLOCK_SWING,
  55. MULTI_CLOCK_INPUT_DIVISION,
  56. MULTI_CLOCK_OUTPUT_DIVISION,
  57. MULTI_CLOCK_BAR_DURATION,
  58. MULTI_CLOCK_OVERRIDE,
  59. MULTI_PITCH_1,
  60. MULTI_PITCH_2,
  61. MULTI_PITCH_3,
  62. MULTI_PITCH_4,
  63. MULTI_PITCH_5,
  64. MULTI_PITCH_6,
  65. MULTI_PITCH_7,
  66. MULTI_PITCH_8,
  67. MULTI_PITCH_9,
  68. MULTI_PITCH_10,
  69. MULTI_PITCH_11,
  70. MULTI_PITCH_12,
  71. MULTI_REMOTE_CONTROL_CHANNEL
  72. };
  73. enum Layout {
  74. LAYOUT_MONO,
  75. LAYOUT_DUAL_MONO,
  76. LAYOUT_QUAD_MONO,
  77. LAYOUT_DUAL_POLY,
  78. LAYOUT_QUAD_POLY,
  79. LAYOUT_DUAL_POLYCHAINED,
  80. LAYOUT_QUAD_POLYCHAINED,
  81. LAYOUT_OCTAL_POLYCHAINED,
  82. LAYOUT_QUAD_TRIGGERS,
  83. LAYOUT_QUAD_VOLTAGES,
  84. LAYOUT_THREE_ONE,
  85. LAYOUT_LAST
  86. };
  87. class Multi {
  88. public:
  89. Multi() { }
  90. ~Multi() { }
  91. void Init();
  92. inline uint8_t paques() const {
  93. return settings_.clock_tempo == 49 && \
  94. settings_.clock_swing == 49 && \
  95. settings_.clock_output_division == 3 && \
  96. settings_.clock_bar_duration == 9;
  97. }
  98. bool NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
  99. layout_configurator_.RegisterNote(channel, note);
  100. bool thru = true;
  101. bool received = false;
  102. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  103. if (part_[i].accepts(channel, note, velocity)) {
  104. received = true;
  105. thru = part_[i].NoteOn(channel, note, velocity) && thru;
  106. }
  107. }
  108. if (received && !running() && internal_clock()) {
  109. // Start the arpeggiators.
  110. Start(true);
  111. }
  112. stop_count_down_ = 0;
  113. return thru;
  114. }
  115. bool NoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
  116. bool thru = true;
  117. bool has_notes = false;
  118. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  119. if (part_[i].accepts(channel, note)) {
  120. thru = part_[i].NoteOff(channel, note) && thru;
  121. }
  122. has_notes = has_notes || part_[i].has_notes();
  123. }
  124. if (!has_notes && internal_clock() && started_by_keyboard_) {
  125. stop_count_down_ = 12;
  126. }
  127. return thru;
  128. }
  129. bool ControlChange(uint8_t channel, uint8_t controller, uint8_t value);
  130. bool PitchBend(uint8_t channel, uint16_t pitch_bend) {
  131. bool thru = true;
  132. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  133. if (part_[i].accepts(channel)) {
  134. thru = part_[i].PitchBend(channel, pitch_bend) && thru;
  135. }
  136. }
  137. return thru;
  138. }
  139. bool Aftertouch(uint8_t channel, uint8_t note, uint8_t velocity) {
  140. bool thru = true;
  141. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  142. if (part_[i].accepts(channel, note)) {
  143. thru = part_[i].Aftertouch(channel, note, velocity) && thru;
  144. }
  145. }
  146. return thru;
  147. }
  148. bool Aftertouch(uint8_t channel, uint8_t velocity) {
  149. bool thru = true;
  150. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  151. if (part_[i].accepts(channel)) {
  152. thru = part_[i].Aftertouch(channel, velocity) && thru;
  153. }
  154. }
  155. return thru;
  156. }
  157. void Reset() {
  158. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  159. part_[i].Reset();
  160. }
  161. }
  162. void Clock();
  163. // A start initiated by a MIDI 0xfa event or the front panel start button will
  164. // start the sequencers. A start initiated by the keyboard will not start
  165. // the sequencers, and give priority to the arpeggiator. This allows the
  166. // arpeggiator to be played without erasing a sequence.
  167. void Start(bool started_by_keyboard);
  168. void Stop();
  169. void Continue() {
  170. Start(false);
  171. }
  172. void StartRecording(uint8_t part) {
  173. if (!recording_) {
  174. // Do not record while the arpeggiator is running!
  175. if (started_by_keyboard_ && running()) {
  176. Stop();
  177. }
  178. part_[part].StartRecording();
  179. recording_ = true;
  180. }
  181. }
  182. void StopRecording(uint8_t part) {
  183. if (recording_) {
  184. part_[part].StopRecording();
  185. recording_ = false;
  186. }
  187. }
  188. inline void Latch() {
  189. if (!latched_) {
  190. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  191. part_[i].Latch();
  192. }
  193. latched_ = true;
  194. }
  195. }
  196. inline void Unlatch() {
  197. if (latched_) {
  198. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  199. part_[i].Unlatch();
  200. }
  201. latched_ = false;
  202. }
  203. }
  204. void PushItNoteOn(uint8_t note) {
  205. uint8_t mask = recording_ ? 0x80 : 0;
  206. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  207. if (settings_.layout == LAYOUT_QUAD_TRIGGERS) {
  208. note = part_[i].midi_settings().min_note;
  209. }
  210. if (!recording_ || part_[i].recording()) {
  211. part_[i].NoteOn(part_[i].tx_channel() | mask, note, 127);
  212. }
  213. }
  214. if (!running() && internal_clock()) {
  215. // Start the arpeggiators.
  216. Start(true);
  217. }
  218. }
  219. void PushItNoteOff(uint8_t note) {
  220. uint8_t mask = recording_ ? 0x80 : 0;
  221. bool has_notes = false;
  222. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  223. if (settings_.layout == LAYOUT_QUAD_TRIGGERS) {
  224. note = part_[i].midi_settings().min_note;
  225. }
  226. if (!recording_ || part_[i].recording()) {
  227. part_[i].NoteOff(part_[i].tx_channel() | mask, note);
  228. }
  229. has_notes = has_notes || part_[i].has_notes();
  230. }
  231. if (!has_notes && internal_clock()) {
  232. Stop();
  233. }
  234. }
  235. void Touch();
  236. void Refresh();
  237. void RefreshInternalClock() {
  238. if (running() && internal_clock() && internal_clock_.Process()) {
  239. ++internal_clock_ticks_;
  240. }
  241. }
  242. void ProcessInternalClockEvents() {
  243. while (internal_clock_ticks_) {
  244. Clock();
  245. --internal_clock_ticks_;
  246. }
  247. }
  248. inline void RenderAudio() {
  249. for (uint8_t i = 0; i < kNumVoices; ++i) {
  250. voice_[i].RenderAudio();
  251. }
  252. }
  253. void Set(uint8_t address, uint8_t value);
  254. inline uint8_t Get(uint8_t address) const {
  255. const uint8_t* bytes;
  256. bytes = static_cast<const uint8_t*>(static_cast<const void*>(&settings_));
  257. return bytes[address];
  258. }
  259. inline Layout layout() const { return static_cast<Layout>(settings_.layout); }
  260. inline bool internal_clock() const { return settings_.clock_tempo >= 40; }
  261. inline uint8_t tempo() const { return settings_.clock_tempo; }
  262. inline bool running() const { return running_; }
  263. inline bool latched() const { return latched_; }
  264. inline bool recording() const { return recording_; }
  265. inline bool clock() const { return clock_pulse_counter_ > 0; }
  266. inline bool reset() const {
  267. return reset_pulse_counter_ > 0;
  268. }
  269. inline bool reset_or_playing_flag() const {
  270. return reset() || ((settings_.clock_bar_duration == 0) && running_);
  271. }
  272. inline const Part& part(uint8_t index) const { return part_[index]; }
  273. inline const Voice& voice(uint8_t index) const { return voice_[index]; }
  274. inline const MultiSettings& settings() const { return settings_; }
  275. inline uint8_t num_active_parts() const { return num_active_parts_; }
  276. inline Voice* mutable_voice(uint8_t index) { return &voice_[index]; }
  277. inline Part* mutable_part(uint8_t index) { return &part_[index]; }
  278. inline MultiSettings* mutable_settings() { return &settings_; }
  279. void set_custom_pitch(uint8_t pitch_class, int8_t correction) {
  280. settings_.custom_pitch_table[pitch_class] = correction;
  281. }
  282. // Returns true when no part does anything fancy with the MIDI stream (such
  283. // as producing arpeggiated notes, or suppressing messages). This means that
  284. // the MIDI dispatcher can just copy to the MIDI out a MIDI data byte as soon
  285. // as it is received. Otherwise, merging and message reformatting will be
  286. // necessary and the output stream will be delayed :(
  287. inline bool direct_thru() const {
  288. for (uint8_t i = 0; i < num_active_parts_; ++i) {
  289. if (!part_[i].direct_thru()) {
  290. return false;
  291. }
  292. }
  293. return true;
  294. }
  295. void GetCvGate(uint16_t* cv, bool* gate);
  296. bool GetAudioSource(uint8_t* audio_source);
  297. void GetLedsBrightness(uint8_t* brightness);
  298. template<typename T>
  299. void Serialize(T* stream_buffer) {
  300. stream_buffer->Write(settings());
  301. for (uint8_t i = 0; i < kNumParts; ++i) {
  302. stream_buffer->Write(part_[i].midi_settings());
  303. stream_buffer->Write(part_[i].voicing_settings());
  304. stream_buffer->Write(part_[i].sequencer_settings());
  305. }
  306. };
  307. template<typename T>
  308. void Deserialize(T* stream_buffer) {
  309. Stop();
  310. stream_buffer->Read(mutable_settings());
  311. for (uint8_t i = 0; i < kNumParts; ++i) {
  312. stream_buffer->Read(part_[i].mutable_midi_settings());
  313. stream_buffer->Read(part_[i].mutable_voicing_settings());
  314. stream_buffer->Read(part_[i].mutable_sequencer_settings());
  315. }
  316. Touch();
  317. };
  318. template<typename T>
  319. void SerializeCalibration(T* stream_buffer) {
  320. for (uint8_t i = 0; i < kNumVoices; ++i) {
  321. for (uint8_t j = 0; j < kNumOctaves; ++j) {
  322. stream_buffer->Write(voice_[i].calibration_dac_code(j));
  323. }
  324. }
  325. };
  326. template<typename T>
  327. void DeserializeCalibration(T* stream_buffer) {
  328. for (uint8_t i = 0; i < kNumVoices; ++i) {
  329. for (uint8_t j = 0; j < kNumOctaves; ++j) {
  330. uint16_t v;
  331. stream_buffer->Read(&v);
  332. voice_[i].set_calibration_dac_code(j, v);
  333. }
  334. }
  335. };
  336. void StartLearning() {
  337. layout_configurator_.StartLearning();
  338. }
  339. void StopLearning() {
  340. layout_configurator_.StopLearning(this);
  341. }
  342. inline bool learning() const {
  343. return layout_configurator_.learning();
  344. }
  345. void StartSong();
  346. private:
  347. void ChangeLayout(Layout old_layout, Layout new_layout);
  348. void UpdateLayout();
  349. void ClockSong();
  350. void HandleRemoteControlCC(uint8_t controller, uint8_t value);
  351. MultiSettings settings_;
  352. bool running_;
  353. bool started_by_keyboard_;
  354. bool latched_;
  355. bool recording_;
  356. InternalClock internal_clock_;
  357. uint8_t internal_clock_ticks_;
  358. uint8_t clock_input_prescaler_;
  359. uint8_t clock_output_prescaler_;
  360. uint16_t bar_position_;
  361. uint8_t stop_count_down_;
  362. uint16_t clock_pulse_counter_;
  363. uint16_t reset_pulse_counter_;
  364. // Indicates that a setting has been changed and that the multi should
  365. // be saved in memory.
  366. bool dirty_;
  367. uint8_t num_active_parts_;
  368. Part part_[kNumParts];
  369. Voice voice_[kNumVoices];
  370. LayoutConfigurator layout_configurator_;
  371. const uint8_t* song_pointer_;
  372. uint32_t song_clock_;
  373. uint8_t song_delta_;
  374. DISALLOW_COPY_AND_ASSIGN(Multi);
  375. };
  376. extern Multi multi;
  377. } // namespace yarns
  378. #endif // YARNS_MULTI_H_