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.

170 lines
5.8KB

  1. /* Copyright 2013-2019 Matt Tytel
  2. *
  3. * vital is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * vital is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with vital. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #pragma once
  17. #include "JuceHeader.h"
  18. #include "common.h"
  19. #include <string>
  20. #include <map>
  21. #if !defined(JUCE_AUDIO_DEVICES_H_INCLUDED)
  22. class MidiInput { };
  23. class MidiInputCallback {
  24. public:
  25. virtual ~MidiInputCallback() { }
  26. virtual void handleIncomingMidiMessage(MidiInput *source, const MidiMessage &midi_message) { }
  27. };
  28. class MidiMessageCollector {
  29. public:
  30. void reset(int sample_rate) { }
  31. void removeNextBlockOfMessages(MidiBuffer& buffer, int num_samples) { }
  32. void addMessageToQueue(const MidiMessage &midi_message) { }
  33. };
  34. #endif
  35. class SynthBase;
  36. namespace vital {
  37. class SoundEngine;
  38. struct ValueDetails;
  39. } // namespace vital
  40. class MidiManager : public MidiInputCallback {
  41. public:
  42. typedef std::map<int, std::map<std::string, const vital::ValueDetails*>> midi_map;
  43. enum MidiMainType {
  44. kNoteOff = 0x80,
  45. kNoteOn = 0x90,
  46. kAftertouch = 0xa0,
  47. kController = 0xb0,
  48. kProgramChange = 0xc0,
  49. kChannelPressure = 0xd0,
  50. kPitchWheel = 0xe0,
  51. };
  52. enum MidiSecondaryType {
  53. kBankSelect = 0x00,
  54. kModWheel = 0x01,
  55. kFolderSelect = 0x20,
  56. kSustainPedal = 0x40,
  57. kSostenutoPedal = 0x42,
  58. kSoftPedalOn = 0x43,
  59. kSlide = 0x4a,
  60. kLsbPressure = 0x66,
  61. kLsbSlide = 0x6a,
  62. kAllSoundsOff = 0x78,
  63. kAllControllersOff = 0x79,
  64. kAllNotesOff = 0x7b,
  65. };
  66. class Listener {
  67. public:
  68. virtual ~Listener() { }
  69. virtual void valueChangedThroughMidi(const std::string& name, vital::mono_float value) = 0;
  70. virtual void pitchWheelMidiChanged(vital::mono_float value) = 0;
  71. virtual void modWheelMidiChanged(vital::mono_float value) = 0;
  72. virtual void presetChangedThroughMidi(File preset) = 0;
  73. };
  74. MidiManager(SynthBase* synth, MidiKeyboardState* keyboard_state,
  75. std::map<std::string, String>* gui_state, Listener* listener = nullptr);
  76. virtual ~MidiManager();
  77. void armMidiLearn(std::string name);
  78. void cancelMidiLearn();
  79. void clearMidiLearn(const std::string& name);
  80. void midiInput(int control, vital::mono_float value);
  81. void processMidiMessage(const MidiMessage &midi_message, int sample_position = 0);
  82. bool isMidiMapped(const std::string& name) const;
  83. void setSampleRate(double sample_rate);
  84. void removeNextBlockOfMessages(MidiBuffer& buffer, int num_samples);
  85. void replaceKeyboardMessages(MidiBuffer& buffer, int num_samples);
  86. void processAllNotesOff(const MidiMessage& midi_message, int sample_position, int channel);
  87. void processAllSoundsOff();
  88. void processSustain(const MidiMessage& midi_message, int sample_position, int channel);
  89. void processSostenuto(const MidiMessage& midi_message, int sample_position, int channel);
  90. void processPitchBend(const MidiMessage& midi_message, int sample_position, int channel);
  91. void processPressure(const MidiMessage& midi_message, int sample_position, int channel);
  92. void processSlide(const MidiMessage& midi_message, int sample_position, int channel);
  93. bool isMpeChannelMasterLowerZone(int channel);
  94. bool isMpeChannelMasterUpperZone(int channel);
  95. force_inline int lowerZoneStartChannel() { return mpe_zone_layout_.getLowerZone().getFirstMemberChannel() - 1; }
  96. force_inline int upperZoneStartChannel() { return mpe_zone_layout_.getUpperZone().getLastMemberChannel() - 1; }
  97. force_inline int lowerZoneEndChannel() { return mpe_zone_layout_.getLowerZone().getLastMemberChannel() - 1; }
  98. force_inline int upperZoneEndChannel() { return mpe_zone_layout_.getUpperZone().getFirstMemberChannel() - 1; }
  99. force_inline int lowerMasterChannel() { return mpe_zone_layout_.getLowerZone().getMasterChannel() - 1; }
  100. force_inline int upperMasterChannel() { return mpe_zone_layout_.getUpperZone().getMasterChannel() - 1; }
  101. void setMpeEnabled(bool enabled) { mpe_enabled_ = enabled; }
  102. midi_map getMidiLearnMap() { return midi_learn_map_; }
  103. void setMidiLearnMap(const midi_map& midi_learn_map) { midi_learn_map_ = midi_learn_map; }
  104. // MidiInputCallback
  105. void handleIncomingMidiMessage(MidiInput *source, const MidiMessage &midi_message) override;
  106. struct PresetLoadedCallback : public CallbackMessage {
  107. PresetLoadedCallback(Listener* lis, File pre) : listener(lis), preset(std::move(pre)) { }
  108. void messageCallback() override {
  109. if (listener)
  110. listener->presetChangedThroughMidi(preset);
  111. }
  112. Listener* listener;
  113. File preset;
  114. };
  115. protected:
  116. void readMpeMessage(const MidiMessage& message);
  117. SynthBase* synth_;
  118. vital::SoundEngine* engine_;
  119. MidiKeyboardState* keyboard_state_;
  120. MidiMessageCollector midi_collector_;
  121. std::map<std::string, String>* gui_state_;
  122. Listener* listener_;
  123. int current_bank_;
  124. int current_folder_;
  125. int current_preset_;
  126. const vital::ValueDetails* armed_value_;
  127. midi_map midi_learn_map_;
  128. int msb_pressure_values_[vital::kNumMidiChannels];
  129. int lsb_pressure_values_[vital::kNumMidiChannels];
  130. int msb_slide_values_[vital::kNumMidiChannels];
  131. int lsb_slide_values_[vital::kNumMidiChannels];
  132. bool mpe_enabled_;
  133. MPEZoneLayout mpe_zone_layout_;
  134. MidiRPNDetector rpn_detector_;
  135. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiManager)
  136. };