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_MidiOutput.h"
31 #include "../../core/juce_Time.h"
34 //==============================================================================
35 struct MidiOutput::PendingMessage
37 PendingMessage (const void* const data
, const int len
, const double timeStamp
)
38 : message (data
, len
, timeStamp
)
45 MidiOutput::MidiOutput()
46 : Thread ("midi out"),
48 firstMessage (nullptr)
52 void MidiOutput::sendBlockOfMessages (const MidiBuffer
& buffer
,
53 const double millisecondCounterToStartAt
,
54 double samplesPerSecondForBuffer
)
56 // You've got to call startBackgroundThread() for this to actually work..
57 jassert (isThreadRunning());
59 // this needs to be a value in the future - RTFM for this method!
60 jassert (millisecondCounterToStartAt
> 0);
62 const double timeScaleFactor
= 1000.0 / samplesPerSecondForBuffer
;
64 MidiBuffer::Iterator
i (buffer
);
69 while (i
.getNextEvent (data
, len
, time
))
71 const double eventTime
= millisecondCounterToStartAt
+ timeScaleFactor
* time
;
73 PendingMessage
* const m
= new PendingMessage (data
, len
, eventTime
);
75 const ScopedLock
sl (lock
);
77 if (firstMessage
== nullptr || firstMessage
->message
.getTimeStamp() > eventTime
)
79 m
->next
= firstMessage
;
84 PendingMessage
* mm
= firstMessage
;
86 while (mm
->next
!= nullptr && mm
->next
->message
.getTimeStamp() <= eventTime
)
97 void MidiOutput::clearAllPendingMessages()
99 const ScopedLock
sl (lock
);
101 while (firstMessage
!= nullptr)
103 PendingMessage
* const m
= firstMessage
;
104 firstMessage
= firstMessage
->next
;
109 void MidiOutput::startBackgroundThread()
114 void MidiOutput::stopBackgroundThread()
119 void MidiOutput::run()
121 while (! threadShouldExit())
123 uint32 now
= Time::getMillisecondCounter();
124 uint32 eventTime
= 0;
125 uint32 timeToWait
= 500;
127 PendingMessage
* message
;
130 const ScopedLock
sl (lock
);
131 message
= firstMessage
;
133 if (message
!= nullptr)
135 eventTime
= roundToInt (message
->message
.getTimeStamp());
137 if (eventTime
> now
+ 20)
139 timeToWait
= eventTime
- (now
+ 20);
144 firstMessage
= message
->next
;
149 if (message
!= nullptr)
153 Time::waitForMillisecondCounter (eventTime
);
155 if (threadShouldExit())
159 if (eventTime
> now
- 200)
160 sendMessageNow (message
->message
);
166 jassert (timeToWait
< 1000 * 30);
171 clearAllPendingMessages();