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.

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