OpenShot Audio Library | OpenShotAudio  0.6.0
juce_MidiKeyboardState.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
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 //==============================================================================
33 {
34  const ScopedLock sl (lock);
35  zerostruct (noteStates);
36  eventsToAdd.clear();
37 }
38 
39 bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
40 {
41  jassert (midiChannel > 0 && midiChannel <= 16);
42 
43  return isPositiveAndBelow (n, 128)
44  && (noteStates[n] & (1 << (midiChannel - 1))) != 0;
45 }
46 
47 bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const int n) const noexcept
48 {
49  return isPositiveAndBelow (n, 128)
50  && (noteStates[n] & midiChannelMask) != 0;
51 }
52 
53 void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
54 {
55  jassert (midiChannel > 0 && midiChannel <= 16);
56  jassert (isPositiveAndBelow (midiNoteNumber, 128));
57 
58  const ScopedLock sl (lock);
59 
60  if (isPositiveAndBelow (midiNoteNumber, 128))
61  {
62  const int timeNow = (int) Time::getMillisecondCounter();
63  eventsToAdd.addEvent (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity), timeNow);
64  eventsToAdd.clear (0, timeNow - 500);
65 
66  noteOnInternal (midiChannel, midiNoteNumber, velocity);
67  }
68 }
69 
70 void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
71 {
72  if (isPositiveAndBelow (midiNoteNumber, 128))
73  {
74  noteStates[midiNoteNumber] = static_cast<uint16> (noteStates[midiNoteNumber] | (1 << (midiChannel - 1)));
75  listeners.call ([&] (Listener& l) { l.handleNoteOn (this, midiChannel, midiNoteNumber, velocity); });
76  }
77 }
78 
79 void MidiKeyboardState::noteOff (const int midiChannel, const int midiNoteNumber, const float velocity)
80 {
81  const ScopedLock sl (lock);
82 
83  if (isNoteOn (midiChannel, midiNoteNumber))
84  {
85  const int timeNow = (int) Time::getMillisecondCounter();
86  eventsToAdd.addEvent (MidiMessage::noteOff (midiChannel, midiNoteNumber), timeNow);
87  eventsToAdd.clear (0, timeNow - 500);
88 
89  noteOffInternal (midiChannel, midiNoteNumber, velocity);
90  }
91 }
92 
93 void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
94 {
95  if (isNoteOn (midiChannel, midiNoteNumber))
96  {
97  noteStates[midiNoteNumber] = static_cast<uint16> (noteStates[midiNoteNumber] & ~(1 << (midiChannel - 1)));
98  listeners.call ([&] (Listener& l) { l.handleNoteOff (this, midiChannel, midiNoteNumber, velocity); });
99  }
100 }
101 
102 void MidiKeyboardState::allNotesOff (const int midiChannel)
103 {
104  const ScopedLock sl (lock);
105 
106  if (midiChannel <= 0)
107  {
108  for (int i = 1; i <= 16; ++i)
109  allNotesOff (i);
110  }
111  else
112  {
113  for (int i = 0; i < 128; ++i)
114  noteOff (midiChannel, i, 0.0f);
115  }
116 }
117 
119 {
120  if (message.isNoteOn())
121  {
122  noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
123  }
124  else if (message.isNoteOff())
125  {
126  noteOffInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
127  }
128  else if (message.isAllNotesOff())
129  {
130  for (int i = 0; i < 128; ++i)
131  noteOffInternal (message.getChannel(), i, 0.0f);
132  }
133 }
134 
136  const int startSample,
137  const int numSamples,
138  const bool injectIndirectEvents)
139 {
140  const ScopedLock sl (lock);
141 
142  for (const auto metadata : buffer)
143  processNextMidiEvent (metadata.getMessage());
144 
145  if (injectIndirectEvents)
146  {
147  const int firstEventToAdd = eventsToAdd.getFirstEventTime();
148  const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd);
149 
150  for (const auto metadata : eventsToAdd)
151  {
152  const auto pos = jlimit (0, numSamples - 1, roundToInt ((metadata.samplePosition - firstEventToAdd) * scaleFactor));
153  buffer.addEvent (metadata.getMessage(), startSample + pos);
154  }
155  }
156 
157  eventsToAdd.clear();
158 }
159 
160 //==============================================================================
162 {
163  const ScopedLock sl (lock);
164  listeners.add (listener);
165 }
166 
168 {
169  const ScopedLock sl (lock);
170  listeners.remove (listener);
171 }
172 
173 } // namespace juce
int getFirstEventTime() const noexcept
int getLastEventTime() const noexcept
bool addEvent(const MidiMessage &midiMessage, int sampleNumber)
void clear() noexcept
void processNextMidiBuffer(MidiBuffer &buffer, int startSample, int numSamples, bool injectIndirectEvents)
void addListener(Listener *listener)
void noteOff(int midiChannel, int midiNoteNumber, float velocity)
void allNotesOff(int midiChannel)
void processNextMidiEvent(const MidiMessage &message)
void removeListener(Listener *listener)
bool isNoteOn(int midiChannel, int midiNoteNumber) const noexcept
void noteOn(int midiChannel, int midiNoteNumber, float velocity)
bool isNoteOnForChannels(int midiChannelMask, int midiNoteNumber) const noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
float getFloatVelocity() const noexcept
int getChannel() const noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
int getNoteNumber() const noexcept
bool isAllNotesOff() const noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
static uint32 getMillisecondCounter() noexcept
Definition: juce_Time.cpp:241