The function below is run on an std::thread that is detached. The code itself is written using the JUCE API (Hence Array<> object & MidiMessage).
void triggerMidiMessages(Array<Array<MidiMessage>> messageBundle)
{
//for each group of messages (bar) within the bundle
for(int bar = 0; bar < messageBundle.size(); bar ++)
{
//store our message from the bundle for playback
Array<MidiMessage> messages;
messages.clear();
messages = messageBundle[bar];
//intialise start time
double timestart = Time::getMillisecondCounterHiRes();
//for each midi inside a single "gene"
for(int i = 0; i <= messages.size();)
{
double elapsedTime = Time::getMillisecondCounterHiRes() - timestart;
//output message whens appropriate
if(elapsedTime > messages[i].getTimeStamp())
{
//output this message
masterMidiOutput->sendMessageNow(messages[i]);
//increment through the array
i++;
}
}
}
}
I need the midi messages to be output in real time but without having to run through the loop condition so much that the CPU runs super hot.
Any ideas? I'm stuck for how to playback the messages in such an order that doesn't require constant checking with a timer.
Thanks in advance.
//===================================================================== update trying to sleep the thread...
void triggerMidiMessages(Array<Array<MidiMessage>> messageBundle)
{
//for each group of messages (bar) within a bundle
for(int bar = 0; bar < messageBundle.size(); bar ++)
{
//store our message from the bundle for playback
Array<MidiMessage> messages;
messages.clear();
messages = messageBundle[bar];
}
//intialise start time
double previousTimeStamp = 0;
//for each midi inside a single "gene"
for(int i = 0; i <= messages.size();)
{
//fire off all note on messages
while(messages[i].isNoteOn())
{
masterMidiOutput->sendMessageNow(messages[i]);
i++; //increment to the next
}
//fire off all note off messages
while(!messages[i].isNoteOn())
{
masterMidiOutput->sendMessageNow(messages[i]);
i++; // do the next one
//if the next message is back to a note on command
if(messages[i+1].isNoteOn() == true)
{
//sleep for x amount of time
int sleepTime = messages[i].getTimeStamp() - previousTimeStamp;
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
previousTimeStamp = messages[i].getTimeStamp();
}
}
}
}
}
To stop the build up within the thread it is better to turn on and off a timer object and trigger each message one by one.
Broadcast messages (Action Broadcaster )can then be used to keep track of the index.
Here is some example code to give the general idea :
MIDIThing::MIDIThing ()
{
startTimer(1); //start a timer
}
void MIDIThing::start ()
{
playstate = 1;
startTime = Time::getCurrentTime().toMilliseconds();
}
void MIDIThing::timerCallback()
{
if (playstate == 1) {
Time::getMillisecondCounterHiRes();
int64 target;
if (Time::getCurrentTime().toMilliseconds() > target) {
//fire off the message
}
//ended (possibly on a condition)
ActionBroadcaster::sendActionMessage(FINISHED_PLAYBACK);
}
}