OpenShot Library | OpenShotAudio  0.2.2
juce_MPEZoneLayout.h
1 
2 /** @weakgroup juce_audio_basics-mpe
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 //==============================================================================
31 /**
32  This class represents the current MPE zone layout of a device capable of handling MPE.
33 
34  An MPE device can have up to two zones: a lower zone with master channel 1 and
35  allocated MIDI channels increasing from channel 2, and an upper zone with master
36  channel 16 and allocated MIDI channels decreasing from channel 15. MPE mode is
37  enabled on a device when one of these zones is active and disabled when both
38  are inactive.
39 
40  Use the MPEMessages helper class to convert the zone layout represented
41  by this object to MIDI message sequences that you can send to an Expressive
42  MIDI device to set its zone layout, add zones etc.
43 
44  @see MPEInstrument
45 
46  @tags{Audio}
47 */
49 {
50 public:
51  /** Default constructor.
52 
53  This will create a layout with inactive lower and upper zones, representing
54  a device with MPE mode disabled.
55 
56  You can set the lower or upper MPE zones using the setZone() method.
57 
58  @see setZone
59  */
60  MPEZoneLayout() noexcept;
61 
62  /** Copy constuctor.
63  This will not copy the listeners registered to the MPEZoneLayout.
64  */
65  MPEZoneLayout (const MPEZoneLayout& other);
66 
67  /** Copy assignment operator.
68  This will not copy the listeners registered to the MPEZoneLayout.
69  */
70  MPEZoneLayout& operator= (const MPEZoneLayout& other);
71 
72  //==============================================================================
73  /**
74  This struct represents an MPE zone.
75 
76  It can either be a lower or an upper zone, where:
77  - A lower zone encompasses master channel 1 and an arbitrary number of ascending
78  MIDI channels, increasing from channel 2.
79  - An upper zone encompasses master channel 16 and an arbitrary number of descending
80  MIDI channels, decreasing from channel 15.
81 
82  It also defines a pitchbend range (in semitones) to be applied for per-note pitchbends and
83  master pitchbends, respectively.
84  */
85  struct Zone
86  {
87  Zone (const Zone& other) = default;
88 
89  bool isLowerZone() const noexcept { return lowerZone; }
90  bool isUpperZone() const noexcept { return ! lowerZone; }
91 
92  bool isActive() const noexcept { return numMemberChannels > 0; }
93 
94  int getMasterChannel() const noexcept { return lowerZone ? 1 : 16; }
95  int getFirstMemberChannel() const noexcept { return lowerZone ? 2 : 15; }
96  int getLastMemberChannel() const noexcept { return lowerZone ? (1 + numMemberChannels)
97  : (16 - numMemberChannels); }
98 
99  bool isUsingChannelAsMemberChannel (int channel) const noexcept
100  {
101  return lowerZone ? (channel > 1 && channel <= 1 + numMemberChannels)
102  : (channel < 16 && channel >= 16 - numMemberChannels);
103  }
104 
105  bool isUsing (int channel) const noexcept
106  {
107  return isUsingChannelAsMemberChannel (channel) || channel == getMasterChannel();
108  }
109 
110  bool operator== (const Zone& other) const noexcept { return lowerZone == other.lowerZone
111  && numMemberChannels == other.numMemberChannels
112  && perNotePitchbendRange == other.perNotePitchbendRange
113  && masterPitchbendRange == other.masterPitchbendRange; }
114 
115  bool operator!= (const Zone& other) const noexcept { return ! operator== (other); }
116 
117  int numMemberChannels;
118  int perNotePitchbendRange;
119  int masterPitchbendRange;
120 
121  private:
122  friend class MPEZoneLayout;
123 
124  Zone (bool lower, int memberChans = 0, int perNotePb = 48, int masterPb = 2) noexcept
125  : numMemberChannels (memberChans),
126  perNotePitchbendRange (perNotePb),
127  masterPitchbendRange (masterPb),
128  lowerZone (lower)
129  {
130  }
131 
132  bool lowerZone;
133  };
134 
135  /** Sets the lower zone of this layout. */
136  void setLowerZone (int numMemberChannels = 0,
137  int perNotePitchbendRange = 48,
138  int masterPitchbendRange = 2) noexcept;
139 
140  /** Sets the upper zone of this layout. */
141  void setUpperZone (int numMemberChannels = 0,
142  int perNotePitchbendRange = 48,
143  int masterPitchbendRange = 2) noexcept;
144 
145  /** Returns a struct representing the lower MPE zone. */
146  const Zone getLowerZone() const noexcept { return lowerZone; }
147 
148  /** Returns a struct representing the upper MPE zone. */
149  const Zone getUpperZone() const noexcept { return upperZone; }
150 
151  /** Clears the lower and upper zones of this layout, making them both inactive
152  and disabling MPE mode.
153  */
154  void clearAllZones();
155 
156  //==============================================================================
157  /** Pass incoming MIDI messages to an object of this class if you want the
158  zone layout to properly react to MPE RPN messages like an
159  MPE device.
160 
161  MPEMessages::rpnNumber will add or remove zones; RPN 0 will
162  set the per-note or master pitchbend ranges.
163 
164  Any other MIDI messages will be ignored by this class.
165 
166  @see MPEMessages
167  */
168  void processNextMidiEvent (const MidiMessage& message);
169 
170  /** Pass incoming MIDI buffers to an object of this class if you want the
171  zone layout to properly react to MPE RPN messages like an
172  MPE device.
173 
174  MPEMessages::rpnNumber will add or remove zones; RPN 0 will
175  set the per-note or master pitchbend ranges.
176 
177  Any other MIDI messages will be ignored by this class.
178 
179  @see MPEMessages
180  */
181  void processNextMidiBuffer (const MidiBuffer& buffer);
182 
183  //==============================================================================
184  /** Listener class. Derive from this class to allow your class to be
185  notified about changes to the zone layout.
186  */
187  class Listener
188  {
189  public:
190  /** Destructor. */
191  virtual ~Listener() = default;
192 
193  /** Implement this callback to be notified about any changes to this
194  MPEZoneLayout. Will be called whenever a zone is added, zones are
195  removed, or any zone's master or note pitchbend ranges change.
196  */
197  virtual void zoneLayoutChanged (const MPEZoneLayout& layout) = 0;
198  };
199 
200  //==============================================================================
201  /** Adds a listener. */
202  void addListener (Listener* const listenerToAdd) noexcept;
203 
204  /** Removes a listener. */
205  void removeListener (Listener* const listenerToRemove) noexcept;
206 
207 private:
208  //==============================================================================
209  Zone lowerZone { true, 0 };
210  Zone upperZone { false, 0 };
211 
212  MidiRPNDetector rpnDetector;
213  ListenerList<Listener> listeners;
214 
215  //==============================================================================
216  void setZone (bool, int, int, int) noexcept;
217 
218  void processRpnMessage (MidiRPNMessage);
219  void processZoneLayoutRpnMessage (MidiRPNMessage);
220  void processPitchbendRangeRpnMessage (MidiRPNMessage);
221 
222  void updateMasterPitchbend (Zone&, int);
223  void updatePerNotePitchbendRange (Zone&, int);
224 
225  void sendLayoutChangeMessage();
226  void checkAndLimitZoneParameters (int, int, int&) noexcept;
227 };
228 
229 } // namespace juce
230 
231 /** @}*/
#define JUCE_API
This macro is added to all JUCE public class declarations.
This class represents the current MPE zone layout of a device capable of handling MPE...
Encapsulates a MIDI message.
This struct represents an MPE zone.
const Zone getUpperZone() const noexcept
Returns a struct representing the upper MPE zone.
Holds a set of objects and can invoke a member function callback on each object in the set with a sin...
const Zone getLowerZone() const noexcept
Returns a struct representing the lower MPE zone.
Represents a MIDI RPN (registered parameter number) or NRPN (non-registered parameter number) message...
Definition: juce_MidiRPN.h:36
Holds a sequence of time-stamped midi events.
Parses a stream of MIDI data to assemble RPN and NRPN messages from their constituent MIDI CC message...
Definition: juce_MidiRPN.h:71