2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
30 #include "juce_MidiKeyboardState.h"
31 #include "../../core/juce_Time.h"
34 //==============================================================================
35 MidiKeyboardState::MidiKeyboardState()
37 zerostruct (noteStates
);
40 MidiKeyboardState::~MidiKeyboardState()
44 //==============================================================================
45 void MidiKeyboardState::reset()
47 const ScopedLock
sl (lock
);
48 zerostruct (noteStates
);
52 bool MidiKeyboardState::isNoteOn (const int midiChannel
, const int n
) const noexcept
54 jassert (midiChannel
>= 0 && midiChannel
<= 16);
56 return isPositiveAndBelow (n
, (int) 128)
57 && (noteStates
[n
] & (1 << (midiChannel
- 1))) != 0;
60 bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask
, const int n
) const noexcept
62 return isPositiveAndBelow (n
, (int) 128)
63 && (noteStates
[n
] & midiChannelMask
) != 0;
66 void MidiKeyboardState::noteOn (const int midiChannel
, const int midiNoteNumber
, const float velocity
)
68 jassert (midiChannel
>= 0 && midiChannel
<= 16);
69 jassert (isPositiveAndBelow (midiNoteNumber
, (int) 128));
71 const ScopedLock
sl (lock
);
73 if (isPositiveAndBelow (midiNoteNumber
, (int) 128))
75 const int timeNow
= (int) Time::getMillisecondCounter();
76 eventsToAdd
.addEvent (MidiMessage::noteOn (midiChannel
, midiNoteNumber
, velocity
), timeNow
);
77 eventsToAdd
.clear (0, timeNow
- 500);
79 noteOnInternal (midiChannel
, midiNoteNumber
, velocity
);
83 void MidiKeyboardState::noteOnInternal (const int midiChannel
, const int midiNoteNumber
, const float velocity
)
85 if (isPositiveAndBelow (midiNoteNumber
, (int) 128))
87 noteStates
[midiNoteNumber
] |= (1 << (midiChannel
- 1));
89 for (int i
= listeners
.size(); --i
>= 0;)
90 listeners
.getUnchecked(i
)->handleNoteOn (this, midiChannel
, midiNoteNumber
, velocity
);
94 void MidiKeyboardState::noteOff (const int midiChannel
, const int midiNoteNumber
)
96 const ScopedLock
sl (lock
);
98 if (isNoteOn (midiChannel
, midiNoteNumber
))
100 const int timeNow
= (int) Time::getMillisecondCounter();
101 eventsToAdd
.addEvent (MidiMessage::noteOff (midiChannel
, midiNoteNumber
), timeNow
);
102 eventsToAdd
.clear (0, timeNow
- 500);
104 noteOffInternal (midiChannel
, midiNoteNumber
);
108 void MidiKeyboardState::noteOffInternal (const int midiChannel
, const int midiNoteNumber
)
110 if (isNoteOn (midiChannel
, midiNoteNumber
))
112 noteStates
[midiNoteNumber
] &= ~(1 << (midiChannel
- 1));
114 for (int i
= listeners
.size(); --i
>= 0;)
115 listeners
.getUnchecked(i
)->handleNoteOff (this, midiChannel
, midiNoteNumber
);
119 void MidiKeyboardState::allNotesOff (const int midiChannel
)
121 const ScopedLock
sl (lock
);
123 if (midiChannel
<= 0)
125 for (int i
= 1; i
<= 16; ++i
)
130 for (int i
= 0; i
< 128; ++i
)
131 noteOff (midiChannel
, i
);
135 void MidiKeyboardState::processNextMidiEvent (const MidiMessage
& message
)
137 if (message
.isNoteOn())
139 noteOnInternal (message
.getChannel(), message
.getNoteNumber(), message
.getFloatVelocity());
141 else if (message
.isNoteOff())
143 noteOffInternal (message
.getChannel(), message
.getNoteNumber());
145 else if (message
.isAllNotesOff())
147 for (int i
= 0; i
< 128; ++i
)
148 noteOffInternal (message
.getChannel(), i
);
152 void MidiKeyboardState::processNextMidiBuffer (MidiBuffer
& buffer
,
153 const int startSample
,
154 const int numSamples
,
155 const bool injectIndirectEvents
)
157 MidiBuffer::Iterator
i (buffer
);
158 MidiMessage
message (0xf4, 0.0);
161 const ScopedLock
sl (lock
);
163 while (i
.getNextEvent (message
, time
))
164 processNextMidiEvent (message
);
166 if (injectIndirectEvents
)
168 MidiBuffer::Iterator
i2 (eventsToAdd
);
169 const int firstEventToAdd
= eventsToAdd
.getFirstEventTime();
170 const double scaleFactor
= numSamples
/ (double) (eventsToAdd
.getLastEventTime() + 1 - firstEventToAdd
);
172 while (i2
.getNextEvent (message
, time
))
174 const int pos
= jlimit (0, numSamples
- 1, roundToInt ((time
- firstEventToAdd
) * scaleFactor
));
175 buffer
.addEvent (message
, startSample
+ pos
);
182 //==============================================================================
183 void MidiKeyboardState::addListener (MidiKeyboardStateListener
* const listener
)
185 const ScopedLock
sl (lock
);
186 listeners
.addIfNotAlreadyThere (listener
);
189 void MidiKeyboardState::removeListener (MidiKeyboardStateListener
* const listener
)
191 const ScopedLock
sl (lock
);
192 listeners
.removeValue (listener
);