OpenShot Library | OpenShotAudio  0.2.1
juce_MidiKeyboardState.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 MidiKeyboardState::MidiKeyboardState()
27 {
28  zerostruct (noteStates);
29 }
30 
31 MidiKeyboardState::~MidiKeyboardState()
32 {
33 }
34 
35 //==============================================================================
37 {
38  const ScopedLock sl (lock);
39  zerostruct (noteStates);
40  eventsToAdd.clear();
41 }
42 
43 bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
44 {
45  jassert (midiChannel >= 0 && midiChannel <= 16);
46 
47  return isPositiveAndBelow (n, 128)
48  && (noteStates[n] & (1 << (midiChannel - 1))) != 0;
49 }
50 
51 bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const int n) const noexcept
52 {
53  return isPositiveAndBelow (n, 128)
54  && (noteStates[n] & midiChannelMask) != 0;
55 }
56 
57 void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
58 {
59  jassert (midiChannel >= 0 && midiChannel <= 16);
60  jassert (isPositiveAndBelow (midiNoteNumber, 128));
61 
62  const ScopedLock sl (lock);
63 
64  if (isPositiveAndBelow (midiNoteNumber, 128))
65  {
66  const int timeNow = (int) Time::getMillisecondCounter();
67  eventsToAdd.addEvent (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity), timeNow);
68  eventsToAdd.clear (0, timeNow - 500);
69 
70  noteOnInternal (midiChannel, midiNoteNumber, velocity);
71  }
72 }
73 
74 void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
75 {
76  if (isPositiveAndBelow (midiNoteNumber, 128))
77  {
78  noteStates [midiNoteNumber] |= (1 << (midiChannel - 1));
79 
80  for (int i = listeners.size(); --i >= 0;)
81  listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity);
82  }
83 }
84 
85 void MidiKeyboardState::noteOff (const int midiChannel, const int midiNoteNumber, const float velocity)
86 {
87  const ScopedLock sl (lock);
88 
89  if (isNoteOn (midiChannel, midiNoteNumber))
90  {
91  const int timeNow = (int) Time::getMillisecondCounter();
92  eventsToAdd.addEvent (MidiMessage::noteOff (midiChannel, midiNoteNumber), timeNow);
93  eventsToAdd.clear (0, timeNow - 500);
94 
95  noteOffInternal (midiChannel, midiNoteNumber, velocity);
96  }
97 }
98 
99 void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
100 {
101  if (isNoteOn (midiChannel, midiNoteNumber))
102  {
103  noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1));
104 
105  for (int i = listeners.size(); --i >= 0;)
106  listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber, velocity);
107  }
108 }
109 
110 void MidiKeyboardState::allNotesOff (const int midiChannel)
111 {
112  const ScopedLock sl (lock);
113 
114  if (midiChannel <= 0)
115  {
116  for (int i = 1; i <= 16; ++i)
117  allNotesOff (i);
118  }
119  else
120  {
121  for (int i = 0; i < 128; ++i)
122  noteOff (midiChannel, i, 0.0f);
123  }
124 }
125 
127 {
128  if (message.isNoteOn())
129  {
130  noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
131  }
132  else if (message.isNoteOff())
133  {
134  noteOffInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
135  }
136  else if (message.isAllNotesOff())
137  {
138  for (int i = 0; i < 128; ++i)
139  noteOffInternal (message.getChannel(), i, 0.0f);
140  }
141 }
142 
144  const int startSample,
145  const int numSamples,
146  const bool injectIndirectEvents)
147 {
148  MidiBuffer::Iterator i (buffer);
149  MidiMessage message;
150  int time;
151 
152  const ScopedLock sl (lock);
153 
154  while (i.getNextEvent (message, time))
155  processNextMidiEvent (message);
156 
157  if (injectIndirectEvents)
158  {
159  MidiBuffer::Iterator i2 (eventsToAdd);
160  const int firstEventToAdd = eventsToAdd.getFirstEventTime();
161  const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd);
162 
163  while (i2.getNextEvent (message, time))
164  {
165  const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor));
166  buffer.addEvent (message, startSample + pos);
167  }
168  }
169 
170  eventsToAdd.clear();
171 }
172 
173 //==============================================================================
175 {
176  const ScopedLock sl (lock);
177  listeners.addIfNotAlreadyThere (listener);
178 }
179 
181 {
182  const ScopedLock sl (lock);
183  listeners.removeFirstMatchingValue (listener);
184 }
185 
186 } // namespace juce
Receives events from a MidiKeyboardState object.
Encapsulates a MIDI message.
bool isNoteOn(int midiChannel, int midiNoteNumber) const noexcept
Returns true if the given midi key is currently held down for the given midi channel.
void processNextMidiEvent(const MidiMessage &message)
Looks at a key-up/down event and uses it to update the state of this object.
void removeListener(MidiKeyboardStateListener *listener)
Deregisters a listener.
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
Retrieves a copy of the next event from the buffer.
bool isAllNotesOff() const noexcept
Checks whether this message is an all-notes-off message.
int getFirstEventTime() const noexcept
Returns the sample number of the first event in the buffer.
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
Creates a key-up message.
bool isNoteOnForChannels(int midiChannelMask, int midiNoteNumber) const noexcept
Returns true if the given midi key is currently held down on any of a set of midi channels...
int getChannel() const noexcept
Returns the midi channel associated with the message.
void addListener(MidiKeyboardStateListener *listener)
Registers a listener for callbacks when keys go up or down.
float getFloatVelocity() const noexcept
Returns the velocity of a note-on or note-off message.
void reset()
Resets the state of the object.
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
Returns true if this message is a &#39;key-up&#39; event.
Holds a sequence of time-stamped midi events.
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
Returns true if this message is a &#39;key-down&#39; event.
void allNotesOff(int midiChannel)
This will turn off any currently-down notes for the given midi channel.
int getLastEventTime() const noexcept
Returns the sample number of the last event in the buffer.
void addEvent(const MidiMessage &midiMessage, int sampleNumber)
Adds an event to the buffer.
Used to iterate through the events in a MidiBuffer.
void noteOff(int midiChannel, int midiNoteNumber, float velocity)
Turns a specified note off.
int getNoteNumber() const noexcept
Returns the midi note number for note-on and note-off messages.
Automatically locks and unlocks a mutex object.
void clear() noexcept
Removes all events from the buffer.
void processNextMidiBuffer(MidiBuffer &buffer, int startSample, int numSamples, bool injectIndirectEvents)
Scans a midi stream for up/down events and adds its own events to it.
void noteOn(int midiChannel, int midiNoteNumber, float velocity)
Turns a specified note on.
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
Creates a key-down message (using a floating-point velocity).
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
Definition: juce_Time.cpp:226