26class MidiDeviceListConnectionBroadcaster final :
private AsyncUpdater
29 ~MidiDeviceListConnectionBroadcaster()
override
31 cancelPendingUpdate();
34 MidiDeviceListConnection::Key add (std::function<
void()> callback)
36 JUCE_ASSERT_MESSAGE_THREAD
37 return callbacks.emplace (key++, std::move (callback)).first->first;
40 void remove (
const MidiDeviceListConnection::Key k)
42 JUCE_ASSERT_MESSAGE_THREAD
50 cancelPendingUpdate();
54 if (std::exchange (lastNotifiedState, newState) != newState)
55 for (
auto it = callbacks.begin(); it != callbacks.end();)
56 NullCheckedInvocation::invoke ((it++)->second);
66 static MidiDeviceListConnectionBroadcaster result;
71 MidiDeviceListConnectionBroadcaster() =
default;
76 auto tie()
const {
return std::tie (ins, outs); }
79 bool operator== (
const State& other)
const {
return tie() == other.tie(); }
80 bool operator!= (
const State& other)
const {
return tie() != other.tie(); }
83 void handleAsyncUpdate()
override
88 std::map<MidiDeviceListConnection::Key, std::function<void()>> callbacks;
89 State lastNotifiedState;
90 MidiDeviceListConnection::Key key = 0;
94MidiDeviceListConnection::~MidiDeviceListConnection() noexcept
96 if (broadcaster !=
nullptr)
97 broadcaster->remove (key);
102 [[maybe_unused]]
const uint8* messageData,
103 [[maybe_unused]]
int numBytesSoFar,
104 [[maybe_unused]]
double timestamp) {}
107MidiOutput::MidiOutput (
const String& deviceName,
const String& deviceIdentifier)
108 :
Thread (
"midi out"), deviceInfo (deviceName, deviceIdentifier)
114 for (
const auto metadata : buffer)
119 double millisecondCounterToStartAt,
120 double samplesPerSecondForBuffer)
126 jassert (millisecondCounterToStartAt > 0);
128 auto timeScaleFactor = 1000.0 / samplesPerSecondForBuffer;
130 for (
const auto metadata : buffer)
132 auto eventTime = millisecondCounterToStartAt + timeScaleFactor * metadata.samplePosition;
133 auto* m =
new PendingMessage (metadata.data, metadata.numBytes, eventTime);
137 if (firstMessage ==
nullptr || firstMessage->message.getTimeStamp() > eventTime)
139 m->next = firstMessage;
144 auto* mm = firstMessage;
146 while (mm->next !=
nullptr && mm->next->message.getTimeStamp() <= eventTime)
161 while (firstMessage !=
nullptr)
163 auto* m = firstMessage;
164 firstMessage = firstMessage->next;
179void MidiOutput::run()
184 uint32 eventTime = 0;
185 uint32 timeToWait = 500;
187 PendingMessage* message;
191 message = firstMessage;
193 if (message !=
nullptr)
195 eventTime = (uint32) roundToInt (message->message.getTimeStamp());
197 if (eventTime > now + 20)
199 timeToWait = eventTime - (now + 20);
204 firstMessage = message->next;
209 if (message !=
nullptr)
211 std::unique_ptr<PendingMessage> messageDeleter (message);
221 if (eventTime > now - 200)
226 jassert (timeToWait < 1000 * 30);
227 wait ((
int) timeToWait);
static MessageManager * getInstance()
void sendBlockOfMessagesNow(const MidiBuffer &buffer)
void stopBackgroundThread()
void clearAllPendingMessages()
void startBackgroundThread()
void sendMessageNow(const MidiMessage &message)
void sendBlockOfMessages(const MidiBuffer &buffer, double millisecondCounterToStartAt, double samplesPerSecondForBuffer)
static Array< MidiDeviceInfo > getAvailableDevices()
bool wait(double timeOutMilliseconds) const
bool threadShouldExit() const
bool stopThread(int timeOutMilliseconds)
bool isThreadRunning() const
static void waitForMillisecondCounter(uint32 targetTime) noexcept
static uint32 getMillisecondCounter() noexcept