wxMidi - A MIDI interface based on PortMidi
wxMidi.h
Go to the documentation of this file.
1 //=====================================================================================
2 // wxMidi: A MIDI interface based on PortMidi, the Portable Real-Time MIDI Library
3 // --------------------------------------------------------------------------------
4 //
5 // Author: Cecilio Salmeron <s.cecilio@gmail.com>
6 // Copyright: (c) 2005-2015 Cecilio Salmeron
7 // Licence: wxWidgets license, version 3.1 or later at your choice.
8 //=====================================================================================
11 
12 #ifdef __GNUG__
13 #pragma interface "wxMidi.cpp"
14 #endif
15 
16 #ifndef __WXMIDI_H__ //to avoid nested includes
17 #define __WXMIDI_H__
18 
19 // For compilers that support precompilation, includes "wx/wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25 
26 #ifndef WX_PRECOMP
27 #include "wx/wx.h"
28 #endif
29 
30 /*
31  To do, when a new version of portmidi:
32  1. Review wxMidiError enumeration (copied and adapted from portmidi.h)
33  2. Review filter codes taken from portmidi.h
34 */
35 
36 // MIDI support throgh Portmidi lib
37 #include "portmidi.h"
38 #include "porttime.h"
39 
40 //other
41 #include <time.h>
42 
43 
45 #define wxMIDI_VERSION _T("2.0")
46 #define wxMIDI_MAJOR 2
47 #define wxMIDI_MINOR 0
48 
50 #define wxMidiDeviceID PmDeviceID
51 #define wxMidiTimestamp PmTimestamp
52 #define wxMidiPmMessage PmMessage
53 #define wxMidiPmEvent PmEvent
54 
55 
58 typedef enum
59 {
60  //AWARE: When adding more error codes, remember to update method
61  // wxMidiSystem::GetErrorText()
62 
63  wxMIDI_NO_ERROR = 0,
65  //error codes from portmidi. Name changed from pmXxxx to wxMIDI_ERROR_Xxxx
102  //Additional error codes not in portmidi
125  //wxMIDI_ERROR_BadSysExMsg_Length, //2.0. No longer used. Removed unnecessary limit.
135 } wxMidiError;
136 
137 
138 
139 
140 
141 //Macros
142 //----------------------------------------------------------------------------------
143 
144 //macro Pm_Channel renamed as wxMIDI_CHANNEL
145 /*
146  Pm_SetChannelMask() filters incoming messages based on channel.
147  The mask is a 16-bit bitfield corresponding to appropriate channels
148  The Pm_Channel macro can assist in calling this function.
149  i.e. to set receive only input on channel 1, call with
150  Pm_SetChannelMask(Pm_Channel(1));
151  Multiple channels should be OR'd together, like
152  Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
153 
154  All channels are allowed by default
155 */
168 #define wxMIDI_CHANNEL(channel) (1<<(channel))
169 
173 {
177  wxMIDI_FILT_ACTIVE = PM_FILT_ACTIVE,
179  wxMIDI_FILT_SYSEX = PM_FILT_SYSEX,
181  wxMIDI_FILT_CLOCK = PM_FILT_CLOCK,
183  wxMIDI_FILT_PLAY = PM_FILT_PLAY,
185  wxMIDI_FILT_TICK = PM_FILT_TICK,
187  wxMIDI_FILT_FD = PM_FILT_FD,
189  wxMIDI_FILT_UNDEFINED = PM_FILT_UNDEFINED,
191  wxMIDI_FILT_RESET = PM_FILT_RESET,
195  wxMIDI_FILT_REALTIME = PM_FILT_REALTIME,
197  wxMIDI_FILT_NOTE = PM_FILT_NOTE,
199  wxMIDI_FILT_CHANNEL_AFTERTOUCH = PM_FILT_CHANNEL_AFTERTOUCH,
202  wxMIDI_FILT_POLY_AFTERTOUCH = PM_FILT_POLY_AFTERTOUCH,
205  wxMIDI_FILT_AFTERTOUCH = PM_FILT_AFTERTOUCH,
207  wxMIDI_FILT_PROGRAM = PM_FILT_PROGRAM,
209  wxMIDI_FILT_CONTROL = PM_FILT_CONTROL,
211  wxMIDI_FILT_PITCHBEND = PM_FILT_PITCHBEND,
213  wxMIDI_FILT_MTC = PM_FILT_MTC,
215  wxMIDI_FILT_SONG_POSITION = PM_FILT_SONG_POSITION,
217  wxMIDI_FILT_SONG_SELECT = PM_FILT_SONG_SELECT,
219  wxMIDI_FILT_TUNE = PM_FILT_TUNE,
223  wxMIDI_FILT_SYSTEMCOMMON = PM_FILT_SYSTEMCOMMON,
224 };
225 
226 
227 //Declare a new command event to inform that MIDI input data is available
233 DECLARE_EVENT_TYPE(wxEVT_MIDI_INPUT, -1)
234 
235 enum wxMidiMsgType
237 {
241 };
242 
243 
244 //forward declarations
245 class wxMidiThread;
246 class wxControlWithItems;
247 
248 //-----------------------------------------------------------------------------
259 {
260 public:
264  virtual ~wxMidiMessage() {}
265 
274  virtual void SetTimestamp(wxMidiTimestamp timestamp) = 0;
275 
276  virtual wxMidiTimestamp GetTimestamp() = 0;
277 
280  wxMidiMsgType GetType() { return m_type; }
281 
323  virtual wxByte GetStatus() = 0;
324 
325 
326 protected:
327  wxMidiMsgType m_type;
328 
329 };
330 
331 //-----------------------------------------------------------------------------
336 {
337 public:
340  wxMidiShortMessage(wxByte status, wxByte data1, wxByte data2)
341  : wxMidiMessage()
342  {
343  m_type = wxMIDI_SHORT_MSG;
344  m_buffer.message = (((data2) << 16) & 0xFF0000) |
345  (((data1) << 8) & 0xFF00) |
346  ((status) & 0xFF);
347  m_buffer.timestamp = 0;
348  }
349  ~wxMidiShortMessage() {}
350 
351  //timestamp
352  void SetTimestamp(wxMidiTimestamp timestamp) { m_buffer.timestamp = timestamp; }
353  wxMidiTimestamp GetTimestamp() { return m_buffer.timestamp; }
354 
355  // message data
356  wxByte GetStatus() { return ((m_buffer.message) & 0xFF); }
357 
360  wxByte GetData1() { return (((m_buffer.message) >> 8) & 0xFF); }
361 
364  wxByte GetData2() { return (((m_buffer.message) >> 16) & 0xFF); }
365 
366  //internal usage
367  PmEvent* GetBuffer() { return &m_buffer; }
368 
369 private:
370  PmEvent m_buffer;
371 };
372 
373 //-----------------------------------------------------------------------------
395 {
396 public:
397  wxMidiSysExMessage(wxByte* msg, wxMidiTimestamp timestamp=0);
400 
401  //timestamp
402  void SetTimestamp(wxMidiTimestamp timestamp) { m_timestamp = timestamp; }
403  wxMidiTimestamp GetTimestamp() { return m_timestamp; }
404 
405  // message data
406  wxByte GetStatus() { return *m_pMessage; }
407 
416  wxByte* GetMessage() { return m_pMessage; }
417 
418  // information
431  wxMidiError Error() { return m_nError; }
432 
437  long Length() { return m_nSize; }
438 
439  //two steps construction
451  void SetBuffer(wxByte* pBuffer) { m_pMessage = pBuffer; }
452 
460  void SetLength(long lenght) { m_nSize = lenght; }
461 
462 
463 private:
464  wxByte* m_pMessage;
465  wxMidiTimestamp m_timestamp;
466  wxMidiError m_nError;
467  long m_nSize;
468 };
469 
470 //-----------------------------------------------------------------------------
496 {
497 public:
498 
504  wxMidiDevice(wxMidiDeviceID nDevice);
505 
507  virtual ~wxMidiDevice();
508 
513  wxMidiError Close() { return (wxMidiError)Pm_Close(m_stream); }
514 
515 
516  // Device information
517 
520  const wxString DeviceName();
521 
525  const wxString InterfaceUsed();
526 
529  bool IsInputPort();
530 
533  bool IsOutputPort();
534 
535  // Errors
536 
548  int HasHostError() { return Pm_HasHostError(m_stream); }
549 
550 
551 
552 protected:
553 
554  wxMidiDeviceID m_nDevice;
555  const PmDeviceInfo* m_pInfo;
556  PortMidiStream* m_stream;
557 
558 };
559 
560 //-----------------------------------------------------------------------------
563 {
564 public:
565 
571 
574 
575  // Open the device
576 
597  wxMidiError Open(long latency, void* pDriverInfo=NULL);
598 
599 
600  // Write operations
601 
604  wxMidiError Write(wxMidiShortMessage* pMsg);
605 
608  wxMidiError Write(wxMidiSysExMessage* pMsg);
609 
619  wxMidiError Write(wxByte* msg, wxMidiTimestamp when=0);
620 
624  wxMidiError Write(PmEvent *buffer, long length) {
625  return (wxMidiError)Pm_Write(m_stream, buffer, length);
626  }
627 
628 
629  // Very common channel voice commands
630 
665  wxMidiError NoteOn(int channel, int note, int velocity);
666 
676  wxMidiError NoteOff(int channel, int note, int velocity);
677 
688  wxMidiError ProgramChange(int channel, int instrument);
689 
696  wxMidiError AllSoundsOff();
697 
698 
699  // miscellaneous
700 
704  wxMidiError Abort() { return (wxMidiError)Pm_Abort(m_stream); }
705 
706 
707 private:
708 
709 };
710 
711 
712 //-----------------------------------------------------------------------------
715 {
716 public:
717 
726  wxMidiInDevice(wxMidiDeviceID nDevice, double timeoutSeconds=5.0);
727 
729  ~wxMidiInDevice();
730 
757  wxMidiError Open(void *pDriverInfo = NULL, int buffersize=4096);
758 
759  // Read operations
760 
768  wxMidiMessage* Read(wxMidiError* pError);
769 
774  wxMidiError Read(wxMidiPmEvent *buffer, long* length);
775 
794  wxMidiError SetFilter(long filters )
795  { return (wxMidiError)Pm_SetFilter(m_stream, filters); }
796 
802  { return (wxMidiError)Pm_SetChannelMask(m_stream, mask); }
803 
808  wxMidiError Poll() { return (wxMidiError)Pm_Poll(m_stream); }
809 
811  void Flush();
812 
813  // Polling
814 
827  wxMidiError StartListening(wxWindow* pWindow, unsigned long nPollingRate=50);
828 
832  wxMidiError StopListening();
833 
834 private:
835  bool MoveDataToSysExBuffer(PmMessage message);
836  bool too_much_time_without_receiving_bytes();
837  bool too_much_reads_without_receiving_bytes();
838  bool should_report_timeout();
839  //helpers
840  inline void reset_timeout_counters() { m_timeCounter=time_t(0); m_numNullReads=0; }
841  inline bool use_time_algorithm() { return m_fUseTimeAlgorithm; }
842  inline void switch_to_alternate_algorithm() { m_fUseTimeAlgorithm = false; }
843 
844 
845  wxMidiThread* m_pThread; //thread for polling
846 
847  //for reporting timeout errors
848  bool m_fUseTimeAlgorithm;
849  time_t m_timeCounter; //time when first read failure observed
850  double m_timeoutSeconds; //max time without receiving data before reporting timeout
851  int m_numNullReads; //number of reads without receiving data
852 
853  //buffer for sysex messages
854  long m_SizeOfSysexBuffer;
855  wxByte* m_SysexBuffer;
856  wxByte* m_CurSysexDataPtr;
857  bool m_fReadingSysex; // sysex message interrupted by real-time message
858  wxMidiTimestamp m_timestamp; // timestamp of the interrupted sysex message
859  bool m_fEventPending; // sysex message ended without EOX. There is a PmEvent
860  // .. read but not delivered
861  PmEvent m_event; // event pending to be processed
862 };
863 
864 
865 //-----------------------------------------------------------------------------
869 {
870 public:
871  ~wxMidiDatabaseGM();
872 
876  static wxMidiDatabaseGM* GetInstance();
877 
878  // Populate controls with database items
879 
969  void PopulateWithInstruments(wxControlWithItems* pCtrol, int nSection, int nInstr=0,
970  bool fAddNumber=false);
971 
1014  void PopulateWithPercusionInstr(wxControlWithItems* pCtrol, int iSel=0);
1016  #define PopulateWithPercussionInstr PopulateWithPercusionInstr
1017 
1033  int PopulateWithSections(wxControlWithItems* pCtrol, int nSelInstr=-1);
1034 
1057  void PopulateWithAllInstruments(wxControlWithItems* pCtrol, int nInstr=0);
1058 
1059  // get information about sections and instruments
1060 
1066  int GetNumSections();
1067 
1079  int GetNumInstrumentsInSection(int nSect);
1080 
1118  int GetInstrFromSection(int nSect, int i);
1119 
1131  wxString GetInstrumentName(int nInstr);
1132 
1145  wxString GetSectionName(int nSect);
1146 
1147 
1148 private:
1149  wxMidiDatabaseGM();
1150  void Initialize();
1151 
1152  enum {
1153  NUM_SECTIONS = 16, //number of sections
1154  NUM_INSTRS = 8, //max. number of instruments per section
1155  };
1156  int m_nSectInstr[NUM_SECTIONS][NUM_INSTRS]; //instruments in each section
1157  int m_nNumInstrInSection[NUM_SECTIONS]; //points to last instrument in section
1158  wxString m_sSectName[NUM_SECTIONS]; //section names
1159 
1160  static wxMidiDatabaseGM* m_pInstance; //the only instance of this class
1161 
1162 };
1163 
1164 //-----------------------------------------------------------------------------
1171 {
1172 public:
1174  ~wxMidiSystem();
1175 
1179  static wxMidiSystem* GetInstance();
1180 
1183  wxMidiTimestamp GetTime() { return Pt_Time(); }
1184 
1187  const wxString GetErrorText( wxMidiError errnum );
1188 
1191  wxString GetHostErrorText();
1192 
1237  inline int CountDevices() { return Pm_CountDevices(); }
1238 
1239 protected:
1240  wxMidiSystem() {}
1241 
1242 private:
1243  wxMidiError Initialize();
1244  wxMidiError Terminate();
1245 
1246  static wxMidiSystem* m_pInstance; //the only instance of this class
1247 };
1248 
1249 
1250 //-----------------------------------------------------------------------------
1252 class wxMidiThread : public wxThread
1253 {
1254 public:
1255  wxMidiThread(wxMidiInDevice* pDev, wxWindow* pWindow, unsigned long milliseconds);
1256  ~wxMidiThread();
1257 
1258  // thread execution starts here
1259  void *Entry();
1260 
1261  // called when the thread exits
1262  void OnExit() {}
1263 
1264 public:
1265  wxMidiInDevice* m_pDev; //owner Midi device
1266  wxWindow* m_pWindow; //the window that will receive the events
1267  unsigned long m_nMilliseconds; //Midi-In polling interval, in milliseconds
1268 
1269 };
1270 
1271 
1272 #endif // __WXMIDI_H__
Filter reset messages (0xFF).
Definition: wxMidi.h:191
virtual wxByte GetStatus()=0
Returns the status byte of the message.
Filter all real-time messages.
Definition: wxMidi.h:195
wxMidiError Poll()
Check if there is a received MIDI message waiting to be Read().
Definition: wxMidi.h:808
A database for Midi GM (General MIDI Standard) instruments.
Definition: wxMidi.h:868
PortMidi reports a `Bad pointer error&#39;.
Definition: wxMidi.h:95
Filter Control Change messages (0xB0-0xBF).
Definition: wxMidi.h:209
void SetTimestamp(wxMidiTimestamp timestamp)
Set the message timestamp value.
Definition: wxMidi.h:352
Filter both channel and poly aftertouch.
Definition: wxMidi.h:205
Filter Program change messages (0xC0-0xCF).
Definition: wxMidi.h:207
wxMidiMessage()
Constructor.
Definition: wxMidi.h:262
wxMidiError Error()
Returns the error code for the wxMidiSysExMessage constructor.
Definition: wxMidi.h:431
wxByte GetData1()
Returns the first data byte of the message or 0x00 if the type of message only has the status byte...
Definition: wxMidi.h:360
Represents a MIDI stream on which MIDI data traffic can be sent.
Definition: wxMidi.h:562
int HasHostError()
Check if the wxMidiDevice has a pending host error to be reported.
Definition: wxMidi.h:548
virtual ~wxMidiMessage()
Destructor.
Definition: wxMidi.h:264
Short message (wxMidiShortMessage)
Definition: wxMidi.h:239
wxMidiError Close()
Closes a MIDI stream, flushing any pending messages.
Definition: wxMidi.h:513
Filter undefined 0xFD messages.
Definition: wxMidi.h:187
wxMidiError SetFilter(long filters)
Sets filters on an open wxMidiInDevice to drop selected input types.
Definition: wxMidi.h:794
#define wxMidiDeviceID
Rename some data types inherited from portmidi.
Definition: wxMidi.h:50
Filter per-note aftertouch messages (Ensoniq holds a patent on generating these messages on keyboards...
Definition: wxMidi.h:202
virtual void SetTimestamp(wxMidiTimestamp timestamp)=0
Set the message timestamp value.
~wxMidiOutDevice()
Destructor.
Definition: wxMidi.h:573
Filter play messages (start 0xFA, stop 0xFC, continue 0xFB).
Definition: wxMidi.h:183
SysEx message (wxMidiSysExMessage)
Definition: wxMidi.h:240
Portmidi reported an &#39;Internal Error&#39;.
Definition: wxMidi.h:99
wxMidiFilter
Filter codes, renamed from portmidi.
Definition: wxMidi.h:172
long Length()
Returns the length (number of bytes) of the message returned by GetMessage().
Definition: wxMidi.h:437
Invalid device ID.
Definition: wxMidi.h:79
void SetBuffer(wxByte *pBuffer)
This method is mainly intended for internal use of wxMidi.
Definition: wxMidi.h:451
Filter Song Select messages (0xF3).
Definition: wxMidi.h:217
The wxByte string received as parameter to create a wxMidiSysExMessage object does not start with 0xF...
Definition: wxMidi.h:126
Filter Song Position messages (0xF2).
Definition: wxMidi.h:215
Filter Tuning request messages (0xF6).
Definition: wxMidi.h:219
Represents a system-exclusive MIDI message.
Definition: wxMidi.h:394
wxByte GetStatus()
Returns the status byte of the message.
Definition: wxMidi.h:406
PortMidi reported a &#39;Buffer overflow&#39;.
Definition: wxMidi.h:90
int CountDevices()
Returns the number of MIDI devices present in the system.
Definition: wxMidi.h:1237
Filter real-time clock messages (0xF8 only, does not filter clock start, etc.).
Definition: wxMidi.h:181
Filetr Pitch Bender messages (0xE0-0xEF).
Definition: wxMidi.h:211
wxByte * GetMessage()
Returns a wxByte string containing the raw MIDI message.
Definition: wxMidi.h:416
wxMidiMsgType GetType()
Returns either wxMIDI_SHORT_MSG, or wxMIDI_SYSEX_MSG, identifying the type of the message object...
Definition: wxMidi.h:280
You called method wxMidiInDevice::Read but there is no message waiting to be delivered.
Definition: wxMidi.h:134
Filter system exclusive messages (0xF0).
Definition: wxMidi.h:179
Undefined (invalid wxMidiMessage object)
Definition: wxMidi.h:238
Insufficient memory.
Definition: wxMidi.h:80
wxMidiOutDevice(wxMidiDeviceID nDevice)
Constructor.
Definition: wxMidi.h:570
wxByte GetData2()
Returns the second data byte of the message or 0x00 if the type of message only has one data byte...
Definition: wxMidi.h:364
An error ocurred during a call to wxMidiInDevice::StartListening.
Definition: wxMidi.h:114
Abstract class representing a MIDI device.
Definition: wxMidi.h:495
Represents a MIDI stream on which MIDI data traffic can be read.
Definition: wxMidi.h:714
Portmidi reported a host error.
Definition: wxMidi.h:71
Filter undefined real-time messages = (wxMIDI_FILT_F9 | wxMIDI_FILT_FD).
Definition: wxMidi.h:189
Filter active sensing messages (0xFE).
Definition: wxMidi.h:177
No filter. All MIDI messages will be delivered to user application.
Definition: wxMidi.h:175
Helper class for internal use.
Definition: wxMidi.h:1252
wxMidiError Abort()
Terminates any outgoing message immediately; this call may result in a partial transmission of a MIDI...
Definition: wxMidi.h:704
Portmidi informs that &#39;buffer is already as large as it can be&#39;.
Definition: wxMidi.h:103
wxMidiShortMessage(wxByte status, wxByte data1, wxByte data2)
Constructor.
Definition: wxMidi.h:340
An error ocurred during a call to wxMidiInDevice::StartListening.
Definition: wxMidi.h:120
Class wxMidiSystem is the entry point to the wxMidi library.
Definition: wxMidi.h:1170
wxByte GetStatus()
Returns the status byte of the message.
Definition: wxMidi.h:356
void SetTimestamp(wxMidiTimestamp timestamp)
Set the message timestamp value.
Definition: wxMidi.h:402
PortMidi reported an &#39;Invalid MIDI message Data&#39; such as illegal MIDI data or a missing EOX...
Definition: wxMidi.h:97
Abstract class representing a MIDI message.
Definition: wxMidi.h:258
void SetLength(long lenght)
This method is mainly intended for internal use of wxMidi.
Definition: wxMidi.h:460
wxMidiError
Error codes from portmidi and additional errors from wxMidi.
Definition: wxMidi.h:58
Informative error.
Definition: wxMidi.h:109
Filter undefined 0xF9 messages (some equipment uses this as a 10ms &#39;tick&#39;).
Definition: wxMidi.h:185
Filter channel aftertouch (most MIDI controllers use this) (0xD0-0xDF).
Definition: wxMidi.h:199
wxMidiMsgType
Identifies the MIDI message type.
Definition: wxMidi.h:236
wxMidiShortMessage represents a MIDI short message.
Definition: wxMidi.h:335
wxMidiError SetChannelMask(long mask)
SetChannelMask() filters incoming messages based on channel.
Definition: wxMidi.h:801
Filter note-on and note-off messages (0x90-0x9F and 0x80-0x8F).
Definition: wxMidi.h:197
No error.
Definition: wxMidi.h:66
PortMidi reports a &#39;Buffer too small&#39; error.
Definition: wxMidi.h:85
Filter MIDI Time Code messages (0xF1).
Definition: wxMidi.h:213
wxMidiError Write(PmEvent *buffer, long length)
This method is just a wrapper for the portmidi native Write function.
Definition: wxMidi.h:624
Filter all System Common messages (MTC, song position, song select, tune request).
Definition: wxMidi.h:223