1
//=====================================================================================
2
// wxMidi: A MIDI interface based on PortMidi, the Portable Real-Time MIDI Library
3
// --------------------------------------------------------------------------------
5
// Author: Cecilio Salmeron
6
// Copyright: (c) 2005-2007 Cecilio Salmeron
7
// Licence: wxWidgets licence, version 3.1 or later at your choice.
8
//=====================================================================================
9
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
10
#pragma implementation "wxMidi.h"
13
// For compilers that support precompilation, includes "wx.h".
14
#include "wx/wxprec.h"
23
To do, when a new version of portmidi:
24
1. Review error messages (method GetErrorText(), copied and adapted from pormidi.c)
29
// Private global functions
30
//---------------------------------------------------------------------------------
31
wxMidiTimestamp wxMidiGetTime() { return Pt_Time(); }
33
//Define the new command event to inform that MIDI input data is available
34
DEFINE_EVENT_TYPE(wxEVT_MIDI_INPUT)
36
//================================================================================
37
// Implementation of classes wxMidiPmEvent, wxMidiShortEvent and wxMidiSysExEvent
38
//================================================================================
40
#define SYSEX_CHUNK_SIZE 4 // PmEvent size
41
#define SYSEX_BUFFER_SIZE (SYSEX_CHUNK_SIZE * 1024) // alloc in 4K chunks
43
wxMidiSysExMessage::wxMidiSysExMessage()
46
m_type = wxMIDI_SYSEX_MSG;
47
m_pMessage = (wxByte*) NULL;
49
m_nError = wxMIDI_NO_ERROR;
54
wxMidiSysExMessage::wxMidiSysExMessage(wxByte* msg, wxMidiTimestamp timestamp)
57
m_type = wxMIDI_SYSEX_MSG;
58
m_pMessage = (wxByte*) NULL;
60
m_nError = wxMIDI_NO_ERROR;
61
m_timestamp = timestamp;
63
//verify start of message
65
m_nError = wxMIDI_ERROR_BadSysExMsg_Start;
69
//determine size of message
71
for (; m_nSize < 10000 && *pData != 0xF7; pData++) {
74
if (m_nSize == 10000) {
75
m_nError = wxMIDI_ERROR_BadSysExMsg_Length;
79
// allocate the buffer
80
m_nSize++; //include the end of sysex byte 0xF7
81
m_pMessage = new wxByte[m_nSize];
84
memcpy(m_pMessage, msg, m_nSize);
88
wxMidiSysExMessage::~wxMidiSysExMessage()
92
m_pMessage = (wxByte*) NULL;
96
//================================================================================
97
// Implementation of class wxMidiDevice
98
//================================================================================
101
wxMidiDevice::wxMidiDevice(wxMidiDeviceID nDevice)
104
int devices = Pm_CountDevices();
105
if (m_nDevice > devices-1) m_nDevice = 0;
106
m_pInfo = Pm_GetDeviceInfo(m_nDevice);
107
m_stream = (PortMidiStream*)NULL;
110
wxMidiDevice::~wxMidiDevice()
113
WARNING: Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
114
referring to the device specified by id. The returned structure is owned by
115
the PortMidi implementation and must not be manipulated or freed.
117
//if (m_pInfo) delete m_pInfo;
120
const wxString wxMidiDevice::DeviceName()
123
#if defined(_UNICODE) || defined(UNICODE)
124
return wxString(m_pInfo->name, wxConvUTF8);
126
return m_pInfo->name;
130
wxString sMsg = _("Error: Device not properly created");
135
const wxString wxMidiDevice::InterfaceUsed()
138
#if defined(_UNICODE) || defined(UNICODE)
139
return wxString(m_pInfo->interf, wxConvUTF8);
141
return m_pInfo->interf;
145
wxString sMsg = _("Error: Device not properly created");
150
bool wxMidiDevice::IsInputPort()
153
return (m_pInfo->input != 0);
158
bool wxMidiDevice::IsOutputPort()
161
return (m_pInfo->output != 0);
167
//================================================================================
168
// Class wxMidiOutDevice implementation
169
//================================================================================
171
wxMidiError wxMidiOutDevice::Open(long latency, void *DriverInfo)
173
// bufferSize = 0 How to set up an optimum value?
174
return (wxMidiError)Pm_OpenOutput(&m_stream, m_nDevice, DriverInfo,
175
0, NULL, NULL, latency );
178
wxMidiError wxMidiOutDevice::Write(wxMidiShortMessage* pMsg)
180
return (wxMidiError)Pm_Write(m_stream, pMsg->GetBuffer(), 1);
183
wxMidiError wxMidiOutDevice::Write(wxMidiSysExMessage* pMsg)
185
wxMidiError nError = pMsg->Error();
186
if (nError != wxMIDI_NO_ERROR)
189
return (wxMidiError)Pm_WriteSysEx(m_stream,
190
pMsg->GetTimestamp(),
191
(unsigned char *)pMsg->GetMessage() );
194
wxMidiError wxMidiOutDevice::Write(wxByte* msg, wxMidiTimestamp when)
196
return (wxMidiError)Pm_WriteSysEx(m_stream,
198
(unsigned char *)msg );
201
wxMidiError wxMidiOutDevice::NoteOff(int channel, int note, int velocity)
204
wxMidiShortMessage msg(0x80+channel, note, velocity);
208
wxMidiError wxMidiOutDevice::NoteOn(int channel, int note, int velocity)
211
wxMidiShortMessage msg(0x90+channel, note, velocity);
215
wxMidiError wxMidiOutDevice::ProgramChange(int channel, int instrument)
217
//0xC0?0xCF Program change
218
wxMidiShortMessage msg(0xC0+channel, instrument, 0);
222
wxMidiError wxMidiOutDevice::AllSoundsOff()
224
wxMidiPmEvent buffer[32];
225
wxMidiTimestamp now = ::wxMidiGetTime();
227
for (i=0, channel=0; channel < 16; channel++) {
228
buffer[i].message = Pm_Message(0xB0+channel, 0x78, 0);
229
buffer[i].timestamp = now;
231
buffer[i].message = Pm_Message(0xB0+channel, 0x7B, 0);
232
buffer[i].timestamp = now;
235
return (wxMidiError)Pm_Write(m_stream, buffer, 32);
239
//================================================================================
240
// Class wxMidiInDevice implementation
241
//================================================================================
243
wxMidiInDevice::wxMidiInDevice(wxMidiDeviceID nDevice)
244
: wxMidiDevice(nDevice)
246
m_pThread = (wxMidiThread*)NULL;
247
m_SysexBuffer = (wxByte*)NULL;
248
m_fReadingSysex = false;
249
m_fEventPending = false;
252
wxMidiInDevice::~wxMidiInDevice()
257
if (m_SysexBuffer) delete [] m_SysexBuffer;
260
wxMidiError wxMidiInDevice::Open(void *DriverInfo)
262
// bufferSize = 50 How to set up an optimum value?
263
return (wxMidiError)Pm_OpenInput(&m_stream, m_nDevice, DriverInfo,
267
wxMidiError wxMidiInDevice::Read(wxMidiPmEvent *buffer, long* length )
270
If no error, the real number of buffers read is returned in "length" and
271
value PmNoError is returned.
272
In case of error, the error type is returned.
275
int nErr = (int) Pm_Read(m_stream, buffer, *length);
276
/* Pm_Read() retrieves midi data into a buffer, and returns the number
277
of events read. Result is a non-negative number unless an error occurs,
278
in which case a wxMidiError value will be returned. */
281
return (wxMidiError)nErr;
283
*length = (long)nErr;
284
return wxMIDI_NO_ERROR;
289
wxMidiMessage* wxMidiInDevice::Read(wxMidiError* pError)
292
According to pormidi documentation, portmidi is allowed to pass real-time MIDI
293
messages embedded within the chunks of a sysex message, and it is up to the client
294
to detect, process, and remove these messages as they arrive.
296
To deal with this, xMidiInDevice will maintain buffers with data not yet delivered.
297
Flag m_fReadingSysex will signal that a sysex message was interrupted by a real-time one
298
Flag m_fEventPending will signal that there is a PmEvent pending to be processed and
299
delivered, as consecuence of a previous truncated sysex message.
303
// get data from midi stream
307
if (m_fEventPending) {
309
m_fEventPending = false;
312
nError = (wxMidiError) Pm_Read( m_stream, &buffer, 1 );
314
// if read was not successful return the error
315
if (nError < wxMIDI_NO_ERROR) {
317
return (wxMidiMessage*)NULL;
320
// check if something read
322
*pError = wxMIDI_ERROR_NoDataAvailable;
323
return (wxMidiMessage*)NULL;
327
// check what type of message we are receiving
328
if (m_fReadingSysex || (Pm_MessageStatus( buffer.message ) == 0xF0))
330
// Start or continuation of a Sysex message. Move data to buffer and
331
// continue reading until end of message
333
//create the message object
334
wxMidiSysExMessage* pSysExMsg = new wxMidiSysExMessage();
336
if (!m_fReadingSysex)
339
m_timestamp = buffer.timestamp;
341
// alloc a new buffer
342
m_SizeOfSysexBuffer = SYSEX_BUFFER_SIZE;
343
m_SysexBuffer = new wxByte[ m_SizeOfSysexBuffer ];
344
m_CurSysexDataPtr = m_SysexBuffer;
346
m_fReadingSysex = true;
349
//move data to buffer and continue reading until end of sysex message
350
bool fEndSysex = MoveDataToSysExBuffer(buffer.message);
353
nError = (wxMidiError) Pm_Read( m_stream, &buffer, 1 );
354
if (nError < wxMIDI_NO_ERROR) {
357
delete [] m_SysexBuffer;
358
m_SysexBuffer = (wxByte*)NULL;
359
m_fReadingSysex = false;
360
return (wxMidiMessage*)NULL;
363
// check if it is a real-time message inserted into the sysex chunks stream
364
if (Pm_MessageStatus( buffer.message ) == 0xF8) {
365
//it is a real time message. Deliver it inmediately and save sysex buffer
366
*pError = wxMIDI_NO_ERROR;
367
wxMidiShortMessage* pShortMsg = new wxMidiShortMessage(
368
Pm_MessageStatus( buffer.message ),
370
pShortMsg->SetTimestamp( buffer.timestamp );
376
When receiving sysex messages, if you get a non-real-time status byte
377
but there was no EOX byte, it means the sysex message was somehow truncated.
378
This is not considered an error; e.g., a missing EOX can result from the user
379
disconnecting a MIDI cable during sysex transmission.
382
// lets check if there is a status byte different from end-of-sysex
383
if (Pm_MessageStatus( buffer.message ) != 0xF7 &&
384
Pm_MessageStatus( buffer.message ) & 0x80 )
386
//The systex message is somehow truncated. Return the sysex message
387
// and store the new message received
390
m_fEventPending = true;
391
m_event.message = buffer.message;
392
m_event.timestamp = buffer.timestamp;
394
//terminate the current sysex message
398
// it is a chunck of the sysex message. Move data to the sysex buffer
399
fEndSysex = MoveDataToSysExBuffer(buffer.message);
403
//prepare the sysex message to return it
404
pSysExMsg->SetTimestamp( m_timestamp );
405
pSysExMsg->SetBuffer( m_SysexBuffer );
406
pSysExMsg->SetLength( m_CurSysexDataPtr - m_SysexBuffer );
407
*pError = wxMIDI_NO_ERROR;
409
//reset the wxMidiInDevice buffer
410
m_SysexBuffer = (wxByte*)NULL;
411
m_CurSysexDataPtr = (wxByte*)NULL;
412
m_fReadingSysex = false;
418
//it is not a sysex message
419
*pError = wxMIDI_NO_ERROR;
420
wxMidiShortMessage* pShortMsg = new wxMidiShortMessage(
421
Pm_MessageStatus( buffer.message ),
422
Pm_MessageData1( buffer.message ),
423
Pm_MessageData2( buffer.message ) );
424
pShortMsg->SetTimestamp( buffer.timestamp );
430
bool wxMidiInDevice::MoveDataToSysExBuffer(PmMessage message)
433
Moves the chunk received to the sysex buffer, allocating a greater buffer
435
Returns true if with this chunk the sysex message is ended, false otherwise
438
// if we are at the end of the buffer
439
if( m_CurSysexDataPtr > (m_SysexBuffer + m_SizeOfSysexBuffer - SYSEX_CHUNK_SIZE) )
441
// keep previous size for usage
442
long oldSize = m_SizeOfSysexBuffer;
445
m_SizeOfSysexBuffer += SYSEX_BUFFER_SIZE;
447
// allocate the new buffer
448
wxByte* newSysexBuffer = new wxByte[ m_SizeOfSysexBuffer ];
450
//wxLogMessage(wxString::Format(
451
// _T("Increasing buffer size from %d to %d"), oldSize, m_SizeOfSysexBuffer ));
453
// move the data from old buffer
454
memcpy( newSysexBuffer, m_SysexBuffer, oldSize );
456
// delete the old buffer
457
delete [] m_SysexBuffer;
459
// point to the new buffer
460
m_SysexBuffer = newSysexBuffer;
462
// set the write data pointer
463
m_CurSysexDataPtr = m_SysexBuffer + oldSize;
466
// move data to the buffer. See portmidi/pm_test/sysex.c function receive_sysex()
469
for (shift = 0; shift < 32 && (data != 0xF7); shift += 8)
471
data = (message >> shift) & 0xFF;
472
*m_CurSysexDataPtr = data;
476
When receiving sysex messages, the sysex message is terminated
477
by either an EOX status byte (anywhere in the 4 byte messages) or
478
by a non-real-time status byte in the low order byte of the message.
479
If you get a non-real-time status byte but there was no EOX byte, it
480
means the sysex message was somehow truncated. This is not
481
considered an error; e.g., a missing EOX can result from the user
482
disconnecting a MIDI cable during sysex transmission.
485
// if this is a status byte that is not EOX, the sysex
486
// message is incomplete and there is no more sysex data
488
// WARNING: Is this true? Shouldn't portmidi send the status byte
489
// in a new PmEvent? See portmidi/pm_test/sysex.c function receive_sysex()
491
// TODO: if we break without doing anything else, the status byte and
492
// remaining bytes will be lost !!!
493
if (data & 0x80 && data != 0xF0 && data != 0xF7) break;
496
return (data & 0x80 && data != 0xF0);
500
void wxMidiInDevice::Flush()
503
wxMidiPmEvent buffer[1];
506
nNumEvents = 1; //initialize with buffer size before calling Read
507
Read(buffer, &nNumEvents);
512
wxMidiError wxMidiInDevice::StartListening(wxWindow* pWindow, unsigned long nPollingRate)
515
if (m_pThread) return wxMIDI_ERROR_AlreadyListening;
517
//Create a new thread. The thread object is created in the suspended state
518
m_pThread = new wxMidiThread(this, pWindow, nPollingRate);
519
if ( m_pThread->Create() != wxTHREAD_NO_ERROR )
521
return wxMIDI_ERROR_CreateThread; //Can't create thread!
524
//wxCriticalSectionLocker enter(wxGetApp().m_critsect);
526
//Start the thread execution
527
if (m_pThread->Run() != wxTHREAD_NO_ERROR )
529
return wxMIDI_ERROR_StartThread; //Can't start thread!
532
return wxMIDI_NO_ERROR;
535
wxMidiError wxMidiInDevice::StopListening()
537
//stop the thread and wait for its termination
540
m_pThread = (wxMidiThread*)NULL;
541
return wxMIDI_NO_ERROR;
544
//================================================================================
545
// Class wxMidiThread implementation
546
//================================================================================
548
// In MSWin32 all threads are joinable. So for platform independence I will
549
// always use joinable threads
550
wxMidiThread::wxMidiThread(wxMidiInDevice* pDev, wxWindow* pWindow, unsigned long milliseconds)
551
: wxThread(wxTHREAD_JOINABLE)
555
m_nMilliseconds = milliseconds;
558
wxMidiThread::~wxMidiThread()
562
void* wxMidiThread::Entry()
566
// check if the thread was asked to exit and do it
567
if (TestDestroy()) break;
569
// check if Midi data is available
570
if ( m_pDev->Poll() ) {
571
// Data available. Create a Midi event
572
wxCommandEvent event( wxEVT_MIDI_INPUT );
573
::wxPostEvent( m_pWindow, event );
574
//m_pWindow->GetEventHandler()->AddPendingEvent(event); // Add it to the queue
577
// pause the thread execution during polling rate interval
578
wxThread::Sleep(m_nMilliseconds);
586
//================================================================================
587
// Class wxMidiSystem implementation
589
// Acording to documentation Pm_Initialize and Pm_Terminate return a error code, but
590
// looking at the source code they always return pmNoError. So it is useless to
591
// try to preserve the return code by forcing the user to explicitly call
592
// these methods. It is easier to initialize and terminate in
593
// the constructor and destructor, respectively
594
//================================================================================
596
wxMidiSystem* wxMidiSystem::m_pInstance = (wxMidiSystem*)NULL;
598
wxMidiSystem::~wxMidiSystem()
601
wxMidiDatabaseGM* pGM = wxMidiDatabaseGM::GetInstance();
605
wxMidiError wxMidiSystem::Initialize()
607
Pt_Start(1, 0, 0); // start the timer
608
return (wxMidiError)Pm_Initialize(); // initialize portmidi package
611
wxMidiError wxMidiSystem::Terminate()
613
Pt_Stop(); //stop the timer
614
return (wxMidiError)Pm_Terminate();
617
const wxString wxMidiSystem::GetErrorText( wxMidiError errnum )
622
case wxMIDI_NO_ERROR:
623
sError = _T("wxMidi: 'No error'");
625
case wxMIDI_ERROR_HostError:
626
sError = _("PortMidi: `Host error'");
628
case wxMIDI_ERROR_InvalidDeviceId:
629
sError = _("PortMidi: `Invalid device ID'");
631
case wxMIDI_ERROR_InsufficientMemory:
632
sError = _("PortMidi: `Insufficient memory'");
634
case wxMIDI_ERROR_BufferTooSmall:
635
sError = _("PortMidi: 'Buffer too small'");
637
case wxMIDI_ERROR_BadPtr:
638
sError = _("PortMidi: `Bad pointer'");
640
case wxMIDI_ERROR_InternalError:
641
sError = _("PortMidi: 'Internal PortMidi Error'");
643
case wxMIDI_ERROR_BufferOverflow:
644
sError = _("PortMidi: 'Buffer overflow'");
646
case wxMIDI_ERROR_BadData:
647
sError = _("PortMidi: 'Invalid MIDI message Data'");
649
case wxMIDI_ERROR_BufferMaxSize:
650
sError = _("PortMidi: 'Buffer is already as large as it can be'");
653
// Additional error messages for wxMidi
654
case wxMIDI_ERROR_AlreadyListening:
655
sError = _("wxMidi: 'Already lisening!'");
657
case wxMIDI_ERROR_CreateThread:
658
sError = _("wxMidi: 'Error while creating the thread object'");
660
case wxMIDI_ERROR_StartThread:
661
sError = _("wxMidi: 'Error while starting the thread execution'");
663
case wxMIDI_ERROR_BadSysExMsg_Start:
664
sError = _("wxMidi. 'Bad sysex msg: It does not start with 0xF0'");
666
case wxMIDI_ERROR_BadSysExMsg_Length:
667
sError = _("wxMidi. 'Bad sysex msg: Length greater than 10000 or no final byte 0xF7'");
669
case wxMIDI_ERROR_NoDataAvailable:
670
sError = _("wxMidi. 'There are no MIDI messages pending to be read'");
674
sError = _("wxMidi: 'Illegal error number'");
680
wxString wxMidiSystem::GetHostErrorText()
684
Pm_GetHostErrorText(&msg[0], 1000);
685
return wxString( (const wxChar *)&msg[0] );
688
wxMidiSystem* wxMidiSystem::GetInstance()
691
m_pInstance = new wxMidiSystem();
692
m_pInstance->Initialize();