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.

159 lines
5.2KB

  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 {
  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. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  71. virtual void pitchWheelMidiChanged(vital::mono_float value) = 0;
  72. virtual void modWheelMidiChanged(vital::mono_float value) = 0;
  73. virtual void presetChangedThroughMidi(File preset) = 0;
  74. #endif
  75. };
  76. MidiManager(SynthBase* synth, MidiKeyboardState* keyboard_state,
  77. std::map<std::string, String>* gui_state, Listener* listener = nullptr);
  78. virtual ~MidiManager();
  79. void processMidiMessage(const MidiMessage &midi_message, int sample_position = 0);
  80. void replaceKeyboardMessages(MidiBuffer& buffer, int num_samples);
  81. void processAllNotesOff(const MidiMessage& midi_message, int sample_position, int channel);
  82. void processAllSoundsOff();
  83. void processSustain(const MidiMessage& midi_message, int sample_position, int channel);
  84. void processSostenuto(const MidiMessage& midi_message, int sample_position, int channel);
  85. void processPitchBend(const MidiMessage& midi_message, int sample_position, int channel);
  86. void processPressure(const MidiMessage& midi_message, int sample_position, int channel);
  87. void processSlide(const MidiMessage& midi_message, int sample_position, int channel);
  88. bool isMpeChannelMasterLowerZone(int channel);
  89. bool isMpeChannelMasterUpperZone(int channel);
  90. force_inline int lowerZoneStartChannel() { return mpe_zone_layout_.getLowerZone().getFirstMemberChannel() - 1; }
  91. force_inline int upperZoneStartChannel() { return mpe_zone_layout_.getUpperZone().getLastMemberChannel() - 1; }
  92. force_inline int lowerZoneEndChannel() { return mpe_zone_layout_.getLowerZone().getLastMemberChannel() - 1; }
  93. force_inline int upperZoneEndChannel() { return mpe_zone_layout_.getUpperZone().getFirstMemberChannel() - 1; }
  94. force_inline int lowerMasterChannel() { return mpe_zone_layout_.getLowerZone().getMasterChannel() - 1; }
  95. force_inline int upperMasterChannel() { return mpe_zone_layout_.getUpperZone().getMasterChannel() - 1; }
  96. void setMpeEnabled(bool enabled) { mpe_enabled_ = enabled; }
  97. #if ! JUCE_AUDIOPROCESSOR_NO_GUI
  98. struct PresetLoadedCallback : public CallbackMessage {
  99. PresetLoadedCallback(Listener* lis, File pre) : listener(lis), preset(std::move(pre)) { }
  100. void messageCallback() override {
  101. if (listener)
  102. listener->presetChangedThroughMidi(preset);
  103. }
  104. Listener* listener;
  105. File preset;
  106. };
  107. #endif
  108. protected:
  109. void readMpeMessage(const MidiMessage& message);
  110. SynthBase* synth_;
  111. vital::SoundEngine* engine_;
  112. MidiKeyboardState* keyboard_state_;
  113. std::map<std::string, String>* gui_state_;
  114. Listener* listener_;
  115. int current_bank_;
  116. int current_folder_;
  117. int current_preset_;
  118. const vital::ValueDetails* armed_value_;
  119. int msb_pressure_values_[vital::kNumMidiChannels];
  120. int lsb_pressure_values_[vital::kNumMidiChannels];
  121. int msb_slide_values_[vital::kNumMidiChannels];
  122. int lsb_slide_values_[vital::kNumMidiChannels];
  123. bool mpe_enabled_;
  124. MPEZoneLayout mpe_zone_layout_;
  125. MidiRPNDetector rpn_detector_;
  126. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiManager)
  127. };