1
/******************************************/
4
Realtime MIDI I/O Object for STK,
5
by Gary P. Scavone, 1998-2000.
6
Based in part on code by Perry
7
Cook (SGI), Paul Leonard (Linux),
8
the RoseGarden team (Linux), and
9
Bill Putnam (Win95/NT).
11
At the moment, this object only
12
handles MIDI input, though MIDI
13
output code can go here when someone
14
decides they need it (and writes it).
16
This object opens a MIDI input device
17
and parses MIDI messages into a MIDI
18
buffer. Time stamp info is converted
19
to deltaTime. MIDI data is stored as
20
MY_FLOAT to conform with SKINI.
22
An optional argument to the constructor
23
can be used to specify a device or card.
24
When no argument is given, a default
25
device is opened or a list of available
26
devices is printed to allow selection
29
/******************************************/
33
#if defined(__STK_REALTIME_)
35
#define MIDI_BUFFER_SIZE 1024
39
#if defined(__OS_IRIX_)
41
/*************************************/
43
/*************************************/
46
#include <dmedia/midi.h>
47
#include <sys/types.h>
54
pthread_t midi_input_thread;
56
void *midiInputThread(void *)
62
mdReceive(inport, &newMessage, 1);
63
status = (newMessage.msg[0] & MD_STATUSMASK);
64
// Ignore all system messages
66
midiBuffer[writeOffset] = newMessage;
69
if( writeOffset >= MIDI_BUFFER_SIZE )
75
RtMidi :: RtMidi(int device)
79
char *device_name = 0;
83
sprintf(msg, "RtMidi: No SGI MIDI device available.\n");
84
throw StkError(msg, StkError::MIDICARD_NOT_FOUND);
88
// open default MIDI interface
89
inport = mdOpenInPort(NULL);
91
sprintf(msg, "RtMidi: Cannot open default SGI MIDI device.\n");
92
throw StkError(msg, StkError::MIDICARD_CONTROL);
97
if ( (card < 0) || (card >= nports) ) {
99
for (card=0; card<nports; card++) {
100
device_name = mdGetName(card);
101
printf("MIDI interface %d: %s\n", card, device_name);
104
printf("\nType a MIDI interface number from above: ");
105
fgets(choice, 16, stdin);
109
inport = mdOpenInPort(mdGetName(card));
110
if (inport == NULL) {
111
sprintf(msg, "RtMidi: Cannot open SGI MIDI interface %d.\n",
113
throw StkError(msg, StkError::MIDICARD_CONTROL);
117
mdSetStampMode(inport, MD_NOSTAMP);
119
// Set up the circular buffer for the Midi Input Messages
120
midiBuffer = new MDevent[MIDI_BUFFER_SIZE];
124
if (pthread_create(&midi_input_thread, NULL, midiInputThread, NULL)) {
125
sprintf(msg, "RtMidi: unable to create MIDI input thread.\n");
126
throw StkError(msg, StkError::PROCESS_THREAD);
132
pthread_cancel(midi_input_thread);
133
pthread_join(midi_input_thread, NULL);
135
delete [] midiBuffer;
138
int RtMidi :: nextMessage()
144
static unsigned long long lastTimeStamp = 0;
146
if ( readOffset == writeOffset ) return 0;
148
lastEvent = midiBuffer[readOffset];
151
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
153
status = (lastEvent.msg[0] & MD_STATUSMASK);
154
byte1 = lastEvent.msg[1];
155
byte2 = lastEvent.msg[2];
156
channel = (lastEvent.msg[0] & MD_CHANNELMASK);
158
if ((status == MD_PROGRAMCHANGE) ||
159
(status == MD_CHANNELPRESSURE))
161
messageType = status;
162
byteTwo = (float) byte1;
163
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
164
lastTimeStamp = lastEvent.stamp;
166
else if ((status == MD_NOTEON) || (status == MD_NOTEOFF) ||
167
(status == MD_CONTROLCHANGE) || (status == MD_POLYKEYPRESSURE))
169
messageType = status;
170
byteTwo = (float) byte1;
171
byteThree = (float) byte2;
172
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
173
lastTimeStamp = lastEvent.stamp;
175
else if (status == MD_PITCHBENDCHANGE)
177
messageType = status;
178
byteTwo = (float) byte1 * NORM_7;
179
byteTwo += (float) byte2;
180
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
181
lastTimeStamp = lastEvent.stamp;
192
#elif ( defined(__OSS_API_) || defined(__ALSA_API_) )
194
/*************************************/
195
/* OSS & ALSA MIDI INPUT */
196
/*************************************/
199
#include <sys/time.h>
201
#if defined(__OSS_API_)
205
#include <sys/ioctl.h>
206
#include <sys/types.h>
207
#include <linux/soundcard.h>
213
#include <sys/asoundlib.h>
214
snd_rawmidi_t *midi_in = 0;
218
typedef unsigned char byte;
220
/* MIDI System Messages */
221
#define MD_SYSTEM_MSG ((byte)0xF0)
222
#define MD_PGM_CHANGE ((byte)0xC0)
223
#define MD_CHN_PRESSURE ((byte)0xD0)
224
#define MD_PITCH_BEND ((byte)0xE0)
225
#define MessageType(MSG) (byte)((MSG) & ((byte)0xF0))
232
MIDIMESSAGE *midiBuffer;
234
pthread_t midi_input_thread;
236
void *midiInputThread(void *)
238
int numArgs = 2, argsLeft = 0;
239
double lastTime = 0.0, newTime = 0.0;
241
MIDIMESSAGE newMessage;
245
(void)gettimeofday(&tv, (struct timezone *)NULL);
246
lastTime = (double) (tv.tv_sec + (tv.tv_usec * 0.000001));
250
#if defined(__OSS_API_)
252
// Normally, you should check the return value of this read() call.
253
// A return of -1 usually indicates an error. However, for OSS
254
// compatability in ALSA, we need to ignore such values.
256
n = read(midi_in, &newByte, 1);
260
if ((n = snd_rawmidi_read(midi_in, &newByte, 1)) == -1) {
262
sprintf(msg, "RtMidi: Error reading ALSA raw MIDI device.\n");
263
throw StkError(msg, StkError::MIDICARD_CAPS);
269
if (newByte & 0x80) { // status byte
270
if (MessageType(newByte) == MD_SYSTEM_MSG) {
274
else if (MessageType(newByte) == MD_PGM_CHANGE ||
275
MessageType(newByte) == MD_CHN_PRESSURE) {
281
newMessage.data[0] = newByte;
282
newMessage.data[1] = 0;
283
newMessage.data[2] = 0;
287
if ( argsLeft == numArgs )
288
newMessage.data[1] = newByte;
290
newMessage.data[2] = newByte;
294
if ( !argsLeft ) { // MIDI message complete
295
// setup for running status mode (another event of the
296
// same type without status byte)
297
if (MessageType(newMessage.data[0]) == (int) MD_PGM_CHANGE ||
298
MessageType(newMessage.data[0]) == (int) MD_CHN_PRESSURE) {
305
// determine the delta time since the last event
306
(void)gettimeofday(&tv, (struct timezone *)NULL);
307
newTime = (double) ((double)tv.tv_sec + (((double)tv.tv_usec) * 0.000001));
308
newMessage.delta_time = (float) (newTime - lastTime);
311
// Put newMessage in the circular buffer
312
midiBuffer[writeOffset] = newMessage;
315
if( writeOffset >= MIDI_BUFFER_SIZE )
324
#if defined(__OSS_API_)
327
#define MAX_MIDI_DEVS 8
328
#define MIDI_NAME "/dev/cua/0"
330
RtMidi :: RtMidi(int device)
332
int card = 0, err = 0, nChoices = 0;
335
char device_name[16];
336
bool print_list = FALSE;
338
// /dev/midi should be a link to the default midi device under OSS
339
strcpy(device_name, MIDI_NAME);
341
// The OSS API doesn't really give us a means for probing the
342
// capabilities of devices. Thus, we'll just pursue a brute
343
// force method of opening devices until we either find something
344
// that doesn't complain or we have to give up. We'll start with
345
// the default device, then try /dev/midi00, /dev/midi01, etc...
348
// check device specified as argument
349
sprintf(device_name, "%s%d%d", MIDI_NAME, 0, device);
350
// try to open this device
351
if((midi_in = open(device_name, O_RDONLY, 0)) == -1) {
352
// Open device failed ... either busy or doesn't exist
358
goto have_good_device;
362
while (card < MAX_MIDI_DEVS) {
363
// if the default device doesn't work, try some others
364
if (card > 0) sprintf(device_name, "%s%d%d", MIDI_NAME, 0, card-1);
366
if ((midi_in = open(device_name, O_RDONLY, 0)) == -1) {
367
// Open device failed ... either busy or doesn't exist
368
if (errno == EBUSY && print_list == FALSE)
369
fprintf(stderr,"RtMidi: OSS MIDI device (%s) is busy and cannot be opened.\n",
377
printf("MIDI Card %d: %s\n", card-1, device_name);
383
// This device appears to be OK
384
goto have_good_device;
387
if (print_list && nChoices) {
389
printf("\nType a MIDI card number from above: ");
390
fgets(choice, 16, stdin);
393
sprintf(device_name, "%s%d%d", MIDI_NAME, 0, card);
394
if ((midi_in = open(device_name, O_RDONLY, 0)) == -1) {
395
sprintf(msg, "RtMidi: Unable to open OSS device (%s) for MIDI input!\n",
397
throw StkError(msg, StkError::MIDICARD_CONTROL);
399
goto have_good_device;
402
// If we got here, no device was found to meet the requested functionality
403
sprintf(msg, "RtMidi: no OSS device found for MIDI input!\n");
404
throw StkError(msg, StkError::MIDICARD_CAPS);
406
have_good_device: // the current device is what we will use
408
printf("oss midi device found\n");
410
// Set up the circular buffer for the MIDI input messages
411
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
415
printf("create input thread\n");
416
err = pthread_create(&midi_input_thread, NULL, midiInputThread, NULL);
418
printf("ERROR create thread\n");
420
sprintf(msg, "RtMidi: unable to create MIDI input thread.\n");
421
throw StkError(msg, StkError::PROCESS_THREAD);
424
printf("allles OK!\n");
429
RtMidi :: RtMidi(int device)
431
int err = 0, nChoices = 0;
436
bool print_list = FALSE;
439
struct snd_ctl_hw_info info;
440
snd_rawmidi_info_t midiinfo;
442
mask = snd_cards_mask();
444
sprintf(msg, "RtMidi: no ALSA sound/MIDI cards reported available.\n");
445
throw StkError(msg, StkError::MIDICARD_NOT_FOUND);
449
default_card = snd_defaults_rawmidi_card();
451
else { // check device specified as argument
452
if (!(mask & (1<<device))) {
458
default_card = device;
462
card = default_card; // start with default card
463
while (card<SND_CARDS) {
464
if (mask & (1<<card)) {
465
if ((err = snd_ctl_open(&chandle, card)) < 0) {
466
fprintf(stderr,"RtMidi: ALSA error on control open (%d): %s\n",
467
card, snd_strerror(err));
470
if ((err = snd_ctl_hw_info(chandle, &info)) < 0) {
471
fprintf(stderr,"RtMidi: ALSA error on control hardware info (%d): %s\n",
472
card, snd_strerror(err));
473
snd_ctl_close(chandle);
476
for (dev=0; dev<(int)info.mididevs; dev++) {
477
/* get information for each device */
478
if ((err = snd_ctl_rawmidi_info(chandle, dev, &midiinfo)) < 0) {
479
fprintf(stderr,"RtMidi: ALSA error on control MIDI info (%d): %s\n",
480
card, snd_strerror(err));
483
if (midiinfo.flags & SND_RAWMIDI_INFO_INPUT) {
484
// this device can handle MIDI input
486
printf("MIDI Card %d, Device %d: %s\n", card, dev, info.name);
490
goto have_good_device;
492
else { // this device wont' work
497
if (default_card == 0) card++;
498
else { // default card != 0, now start with card 0 and keep searching
499
if (card == default_card) card = 0; // first time only
502
if (card == default_card) card++; // skip over default card
507
if (print_list && nChoices) {
509
printf("\nType a MIDI card number from above: ");
510
fgets(choice, 16, stdin);
512
printf("Select a device for the same card: ");
513
fgets(choice, 16, stdin);
516
goto have_good_device;
519
// if we got here, no devices were found to meet the requested functionality
520
sprintf(msg, "RtMidi: no ALSA device found for MIDI input!\n");
521
throw StkError(msg, StkError::MIDICARD_CAPS);
523
have_good_device: // the current value of card and dev are what we will use
525
err = snd_rawmidi_open(&midi_in, card, dev, O_RDONLY);
527
sprintf(msg, "RtMidi: Error opening ALSA raw MIDI device: card %d, device %d.\n",
529
throw StkError(msg, StkError::MIDICARD_CONTROL);
533
// Set up the circular buffer for the MIDI input messages
534
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
538
err = pthread_create(&midi_input_thread, NULL, midiInputThread, NULL);
540
sprintf(msg, "RtMidi: unable to create MIDI input thread.\n");
541
throw StkError(msg, StkError::PROCESS_THREAD);
549
pthread_cancel(midi_input_thread);
550
delete [] midiBuffer;
551
#if defined(__OSS_API_)
552
#if defined(__MIDIATOR_)
555
if (midi_in != 0) close(midi_in);
558
snd_rawmidi_close(midi_in);
562
int RtMidi::nextMessage()
564
MIDIMESSAGE lastEvent;
566
if ( readOffset == writeOffset ) return 0;
568
lastEvent = midiBuffer[readOffset];
571
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
573
messageType = (int) (lastEvent.data[0] & 0xf0);
574
channel = (int) (lastEvent.data[0] & 0x0f);
575
byteTwo = (float) lastEvent.data[1];
576
if (messageType == (int) MD_PITCH_BEND)
577
byteTwo = (float) lastEvent.data[2] + (byteTwo * NORM_7);
579
byteThree = (float) lastEvent.data[2];
580
deltaTime = (float) lastEvent.delta_time;
585
#if defined(__MIDIATOR_)
587
void initializeMidiator()
589
struct termios info; /* serial port configuration info */
590
int status; /* Serial port status */
591
struct timeval tv; /* to do a little time delay */
594
/* Get the current serial port attributes, so we can change
595
* the ones we care about.
597
if (tcgetattr(midi_in, &info) < 0) {
598
sprintf(msg, "RtMidi: ioctl to get tty info failed (MIDIator support)!\n");
599
throw StkError(msg, StkError::MIDICARD_CAPS);
602
bzero(&info, sizeof(info));
603
info.c_cflag = BAUD_RATE | CRTSCTS | CS8 | CLOCAL | CREAD;
604
info.c_iflag &= ~IGNCR;
605
info.c_oflag &= ~IGNCR;
607
/* set input mode (non-canonical, no echo,...) */
610
info.c_cc[VTIME] = 1; /* inter-character timer unused */
611
info.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
613
tcflush(midi_in, TCIFLUSH);
615
/* Set the attributes */
616
tcsetattr(midi_in, TCSANOW, &info);
618
/* Startup sequence, as per ron@MIDI_DEV's instructions */
619
/* Many thanks to Ron for supporting Linux */
623
/* deassert DTR and RTS */
624
ioctl(midi_in, TIOCMGET, &status);
625
status &= ~TIOCM_DTR;
626
status &= ~TIOCM_RTS;
627
ioctl(midi_in, TIOCMSET, status);
628
/* Wait 600 ms to make sure everything is stable */
631
select(0, NULL, NULL, NULL, &tv);
636
ioctl(midi_in, TIOCMGET, &status);
638
ioctl(midi_in, TIOCMSET, status);
639
/* Wait 300 ms to make sure everything is stable */
642
select(0, NULL, NULL, NULL, &tv);
646
ioctl(midi_in, TIOCMGET, &status);
647
status &= ~TIOCM_DTR;
649
ioctl(midi_in, TIOCMSET, status);
650
/* Wait 40 us to make sure everything is stable */
653
select(0, NULL, NULL, NULL, &tv);
657
ioctl(midi_in, TIOCMGET, &status);
660
ioctl(midi_in, TIOCMSET, status);
661
/* Wait 40 us to make sure everything is stable */
664
select(0, NULL, NULL, NULL, &tv);
667
/* Set output mode */
668
/* Bitval = RTS, clock = DTR */
671
ioctl(midi_in, TIOCMGET, &status);
672
status &= ~TIOCM_DTR; /* 0 */
673
status |= TIOCM_RTS; /* 1 */
674
ioctl(midi_in, TIOCMSET, status);
675
/* Wait 40 us to make sure everything is stable */
678
select(0, NULL, NULL, NULL, &tv);
680
ioctl(midi_in, TIOCMGET, &status);
681
status |= TIOCM_DTR; /* 1 rising edge clock */
682
status |= TIOCM_RTS; /* 1 */
683
ioctl(midi_in, TIOCMSET, status);
684
/* Wait 40 us to make sure everything is stable */
687
select(0, NULL, NULL, NULL, &tv);
690
ioctl(midi_in, TIOCMGET, &status);
691
status &= ~TIOCM_DTR; /* 0 */
692
status |= TIOCM_RTS; /* 1 */
693
ioctl(midi_in, TIOCMSET, status);
694
/* Wait 40 us to make sure everything is stable */
697
select(0, NULL, NULL, NULL, &tv);
699
ioctl(midi_in, TIOCMGET, &status);
700
status |= TIOCM_DTR; /* 1 rising edge clock */
701
status |= TIOCM_RTS; /* 1 */
702
ioctl(midi_in, TIOCMSET, status);
703
/* Wait 40 us to make sure everything is stable */
706
select(0, NULL, NULL, NULL, &tv);
709
ioctl(midi_in, TIOCMGET, &status);
710
status &= ~TIOCM_DTR; /* 0 */
711
status &= ~TIOCM_RTS; /* 0 */
712
ioctl(midi_in, TIOCMSET, status);
713
/* Wait 40 us to make sure everything is stable */
716
select(0, NULL, NULL, NULL, &tv);
718
ioctl(midi_in, TIOCMGET, &status);
719
status |= TIOCM_DTR; /* 1 rising edge clock */
720
status &= ~TIOCM_RTS; /* 0 */
721
ioctl(midi_in, TIOCMSET, status);
722
/* Wait 40 us to make sure everything is stable */
725
select(0, NULL, NULL, NULL, &tv);
727
/* Step 6 ... necessary ?*/
728
/* Set RTS=0,DTR=1 ... but they already are from previous ^ */
730
ioctl(midi_in, TIOCMGET, &status);
731
status |= TIOCM_DTR; /* 1 rising edge clock */
732
status &= ~TIOCM_RTS; /* 0 */
733
ioctl(midi_in, TIOCMSET, status);
734
/* Wait 40 us to make sure everything is stable */
737
select(0, NULL, NULL, NULL, &tv);
741
ioctl(midi_in, TIOCMGET, &status);
743
ioctl(midi_in, TIOCMSET, status);
744
/* Wait 100 ms to make sure everything is stable */
747
select(0, NULL, NULL, NULL, &tv);
748
/* End Midiator startup sequence -- midi_dev_type = MIDIATOR */
752
#elif defined(__OS_Win_)
754
/*************************************/
755
/* Windoze MIDI INPUT */
756
/*************************************/
758
#define MIDI_NOTEON 0x90
759
#define MIDI_NOTEOFF 0x80
760
#define MIDI_POLYKEYPRESSURE 0xA0
761
#define MIDI_CHANNELPRESSURE 0xD0
762
#define MIDI_PROGRAMCHANGE 0xC0
763
#define MIDI_CONTROLCHANGE 0xB0
764
#define MIDI_PITCHBEND 0xE0
771
MIDIMESSAGE *midiBuffer;
773
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
774
DWORD instancePtr, DWORD midiMessage, DWORD timestamp)
776
MIDIMESSAGE newMessage;
778
switch (inputStatus) {
782
// Ignore Active Sensing messages
783
if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) {
786
newMessage.data = midiMessage;
787
newMessage.time = timestamp;
789
// Put newMessage in the circular buffer
790
midiBuffer[writeOffset] = newMessage;
793
if( writeOffset >= MIDI_BUFFER_SIZE )
802
HMIDIIN hMidiIn ; // Handle to Midi Output Device
804
RtMidi :: RtMidi(int device)
808
MIDIINCAPS deviceCaps;
812
uDeviceID = midiInGetNumDevs();
814
sprintf(msg, "RtMidi: No windoze MIDI device available.\n");
815
throw StkError(msg, StkError::MIDICARD_NOT_FOUND);
818
/* Our normal scheme is to use the default device if no argument
819
is supplied to RtMidi() or if the argument = -1. However,
820
there is no way to specify a default MIDI device under windoze.
821
So, I'm going to print the list if device = -1.
823
if ( (device != -1) && (device < uDeviceID) ) {
824
// try to open device specified as argument
825
result = midiInOpen(&hMidiIn, device,
826
(DWORD)&midiInputCallback,
829
if (result == MMSYSERR_NOERROR)
830
goto have_good_device;
833
printf("\nMIDI input interfaces available: %i\n",uDeviceID);
834
for (i=0; i<uDeviceID; i++) {
835
result = midiInGetDevCaps(i, &deviceCaps, sizeof(MIDIINCAPS));
836
printf(" MIDI interface %d is %s\n", i, deviceCaps.szPname);
841
printf("\nType the MIDI interface to open: ");
842
fgets(choice, 16, stdin);
843
uDeviceID = (UINT) atoi(choice);
847
// Open the port and return any errors
848
result = midiInOpen(&hMidiIn, uDeviceID,
849
(DWORD)&midiInputCallback,
852
if (result != MMSYSERR_NOERROR) {
853
sprintf(msg, "RtMidi: Cannot open Windoze MIDI interface %d.\n",
855
throw StkError(msg, StkError::MIDICARD_CONTROL);
858
have_good_device: // the current device is what we will use
860
// Set up the circular buffer for the Midi Input Messages
861
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
865
midiInStart( hMidiIn );
870
midiInReset( hMidiIn );
871
midiInStop( hMidiIn );
872
midiInClose( hMidiIn );
873
delete [] midiBuffer;
876
int RtMidi :: nextMessage()
881
MIDIMESSAGE lastEvent;
882
static DWORD lastTime = 0;
883
static DWORD newTime = 0;
885
if ( readOffset == writeOffset ) return 0;
887
lastEvent = midiBuffer[readOffset];
890
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
892
status = (int) (lastEvent.data & 0xff);
893
byte1 = (int) (lastEvent.data & 0xff00) >> 8;
894
byte2 = (int) (lastEvent.data & 0xff0000) >> 16;
895
channel = (int) (status & 0x0f);
896
status &= 0xf0; // Clear lower byte of status
897
newTime = lastEvent.time;
898
deltaTime = (float) (newTime - lastTime) * 0.001;
901
if ((status == MIDI_PROGRAMCHANGE) ||
902
(status == MIDI_CHANNELPRESSURE))
904
messageType = status;
905
byteTwo = (float) byte1;
907
else if ((status == MIDI_NOTEON) || (status == MIDI_NOTEOFF) ||
908
(status == MIDI_CONTROLCHANGE) || (status == MIDI_POLYKEYPRESSURE))
910
messageType = status;
911
byteTwo = (float) byte1;
912
byteThree = (float) byte2;
914
else if (status == MIDI_PITCHBEND)
916
messageType = status;
917
byteTwo = (float) (byte1 * NORM_7);
918
byteTwo += (float) byte2;
930
void RtMidi :: printMessage()
932
printf("type = %d, channel = %d, byte2 = %f, byte3 = %f\n",
933
this->getType(), this->getChannel(), this->getByteTwo(),
934
this->getByteThree());
937
int RtMidi :: getType()
942
int RtMidi :: getChannel()
947
MY_FLOAT RtMidi :: getByteTwo()
952
MY_FLOAT RtMidi :: getByteThree()
957
MY_FLOAT RtMidi :: getDeltaTime()