JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_MidiDevices.cpp
Go to the documentation of this file.
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
23namespace juce
24{
25
27{
28public:
30 {
32 }
33
34 MidiDeviceListConnection::Key add (std::function<void()> callback)
35 {
37 return callbacks.emplace (key++, std::move (callback)).first->first;
38 }
39
40 void remove (const MidiDeviceListConnection::Key k)
41 {
43 callbacks.erase (k);
44 }
45
46 void notify()
47 {
48 if (MessageManager::getInstance()->isThisTheMessageThread())
49 {
51
52 const State newState;
53
54 if (std::exchange (lastNotifiedState, newState) != newState)
55 for (auto it = callbacks.begin(); it != callbacks.end();)
56 NullCheckedInvocation::invoke ((it++)->second);
57 }
58 else
59 {
61 }
62 }
63
64 static auto& get()
65 {
67 return result;
68 }
69
70private:
72
73 class State
74 {
76 auto tie() const { return std::tie (ins, outs); }
77
78 public:
79 bool operator== (const State& other) const { return tie() == other.tie(); }
80 bool operator!= (const State& other) const { return tie() != other.tie(); }
81 };
82
83 void handleAsyncUpdate() override
84 {
85 notify();
86 }
87
88 std::map<MidiDeviceListConnection::Key, std::function<void()>> callbacks;
89 State lastNotifiedState;
90 MidiDeviceListConnection::Key key = 0;
91};
92
93//==============================================================================
94MidiDeviceListConnection::~MidiDeviceListConnection() noexcept
95{
96 if (broadcaster != nullptr)
97 broadcaster->remove (key);
98}
99
100//==============================================================================
105
106//==============================================================================
107#if 0 // moved to trkn/juce_audio_devices/native/juce_Midi_linux.cpp
108MidiOutput::MidiOutput (const String& deviceName, const String& deviceIdentifier)
109 : Thread ("midi out"), deviceInfo (deviceName, deviceIdentifier)
110{
111}
112#endif
113
115{
116 for (const auto metadata : buffer)
117 sendMessageNow (metadata.getMessage());
118}
119
123{
124 // You've got to call startBackgroundThread() for this to actually work..
126
127 // this needs to be a value in the future - RTFM for this method!
129
131
132 for (const auto metadata : buffer)
133 {
134 auto eventTime = millisecondCounterToStartAt + timeScaleFactor * metadata.samplePosition;
135 auto* m = new PendingMessage (metadata.data, metadata.numBytes, eventTime);
136
137 const ScopedLock sl (lock);
138
139 if (firstMessage == nullptr || firstMessage->message.getTimeStamp() > eventTime)
140 {
141 m->next = firstMessage;
142 firstMessage = m;
143 }
144 else
145 {
146 auto* mm = firstMessage;
147
148 while (mm->next != nullptr && mm->next->message.getTimeStamp() <= eventTime)
149 mm = mm->next;
150
151 m->next = mm->next;
152 mm->next = m;
153 }
154 }
155
156 notify();
157}
158
160{
161 const ScopedLock sl (lock);
162
163 while (firstMessage != nullptr)
164 {
165 auto* m = firstMessage;
166 firstMessage = firstMessage->next;
167 delete m;
168 }
169}
170
172{
173 startThread (Priority::high);
174}
175
177{
178 stopThread (5000);
179}
180
181void MidiOutput::run()
182{
183 while (! threadShouldExit())
184 {
185 auto now = Time::getMillisecondCounter();
186 uint32 eventTime = 0;
187 uint32 timeToWait = 500;
188
189 PendingMessage* message;
190
191 {
192 const ScopedLock sl (lock);
193 message = firstMessage;
194
195 if (message != nullptr)
196 {
197 eventTime = (uint32) roundToInt (message->message.getTimeStamp());
198
199 if (eventTime > now + 20)
200 {
201 timeToWait = eventTime - (now + 20);
202 message = nullptr;
203 }
204 else
205 {
206 firstMessage = message->next;
207 }
208 }
209 }
210
211 if (message != nullptr)
212 {
214
215 if (eventTime > now)
216 {
218
219 if (threadShouldExit())
220 break;
221 }
222
223 if (eventTime > now - 200)
224 sendMessageNow (message->message);
225 }
226 else
227 {
228 jassert (timeToWait < 1000 * 30);
229 wait ((int) timeToWait);
230 }
231 }
232
234}
235
236} // namespace juce
T begin(T... args)
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
Has a callback method that is triggered asynchronously.
void triggerAsyncUpdate()
Causes the callback to be triggered at a later time.
void cancelPendingUpdate() noexcept
This will stop any pending updates from happening.
Automatically locks and unlocks a mutex object.
static MessageManager * getInstance()
Returns the global instance of the MessageManager.
Holds a sequence of time-stamped midi events.
virtual void handlePartialSysexMessage(MidiInput *source, const uint8 *messageData, int numBytesSoFar, double timestamp)
Notification sent each time a packet of a multi-packet sysex message arrives.
Represents a midi input device.
static Array< MidiDeviceInfo > getAvailableDevices()
Returns a list of the available midi input devices.
void sendBlockOfMessagesNow(const MidiBuffer &buffer)
Sends out a sequence of MIDI messages immediately.
void stopBackgroundThread()
Stops the background thread, and clears any pending midi events.
void clearAllPendingMessages()
Gets rid of any midi messages that had been added by sendBlockOfMessages().
void startBackgroundThread()
Starts up a background thread so that the device can send blocks of data.
void sendMessageNow(const MidiMessage &message)
Sends out a MIDI message immediately.
void sendBlockOfMessages(const MidiBuffer &buffer, double millisecondCounterToStartAt, double samplesPerSecondForBuffer)
This lets you supply a block of messages that will be sent out at some point in the future.
static Array< MidiDeviceInfo > getAvailableDevices()
Returns a list of the available midi output devices.
The JUCE String class!
Definition juce_String.h:53
Encapsulates a thread.
Definition juce_Thread.h:43
bool startThread()
Attempts to start a new thread with default ('Priority::normal') priority.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
bool stopThread(int timeOutMilliseconds)
Attempts to stop the thread running.
void notify() const
Wakes up the thread.
bool isThreadRunning() const
Returns true if the thread is currently active.
static void waitForMillisecondCounter(uint32 targetTime) noexcept
Waits until the getMillisecondCounter() reaches a given value.
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
T emplace(T... args)
T end(T... args)
T erase(T... args)
T exchange(T... args)
#define JUCE_ASSERT_MESSAGE_THREAD
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
#define jassert(expression)
Platform-independent assertion macro.
JUCE Namespace.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
T tie(T... args)
wait