37#if defined(H2CORE_HAVE_PORTMIDI) || _DOXYGEN_
40#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
53 __INFOLOG(
"PortMidiDriver_thread starting" );
63 length = Pm_Read( instance->
m_pMidiIn, buffer, 1 );
66 int nEventType = Pm_MessageStatus( buffer[0].message );
68 if ( nEventType > 127 && nEventType != 247 && nEventType < 256 ) {
85 if ( nEventType < 248 ) {
90 if ( nEventType == 240 ) {
94 buffer[0].message ) ) {
102 msg.
m_nData1 = Pm_MessageData1( buffer[0].message );
103 msg.
m_nData2 = Pm_MessageData2( buffer[0].message );
107 else if ( nEventType >= 256 ) {
108 __ERRORLOG( QString(
"Unsupported midi message type: [%1]" )
109 .arg( nEventType ) );
114 buffer[0].message ) ) {
119 else if ( length == 0 ) {
129 __ERRORLOG( QString(
"Error in Pm_Read: [%1]" )
137 pthread_exit(
nullptr );
143 , m_bRunning( false )
144 , m_pMidiIn( nullptr )
145 , m_pMidiOut( nullptr )
147 PmError err = Pm_Initialize();
148 if ( err != pmNoError ) {
149 ERRORLOG( QString(
"Error in Pm_Initialize: [%1]" )
157 PmError err = Pm_Terminate();
158 if ( err != pmNoError ) {
159 ERRORLOG( QString(
"Error in Pm_Terminate: [%1]" )
178 event.message = Pm_Message(0xB0 | channel, param, value);
188 int nInputBufferSize = 100;
191 int nOutDeviceId = -1;
194 int nDevices = Pm_CountDevices();
197 for (
int i = 0; i < nDevices; i++ ) {
198 const PmDeviceInfo *pInfo = Pm_GetDeviceInfo( i );
200 if ( pInfo ==
nullptr ) {
201 ERRORLOG( QString(
"Could not open input device [%1]" ).arg( i ) );
204 if ( pInfo->input == TRUE ) {
205 if ( strcmp( pInfo->name, sMidiPortName.toLocal8Bit().constData() ) == 0 &&
211 if ( pInfo->output == TRUE ) {
212 if ( strcmp( pInfo->name, sMidiOutputPortName.toLocal8Bit().constData() ) == 0 &&
217 INFOLOG( QString(
"%1%2%3device called [%4] using [%5] MIDI API" )
218 .arg( nDeviceId == i || nOutDeviceId == i ?
"Using " :
220 .arg( pInfo->input == TRUE ?
"input " :
"" )
221 .arg( pInfo->output == TRUE ?
"output " :
"" )
222 .arg( pInfo->name ).arg( pInfo->interf ) );
227 if ( nDeviceId != -1 ) {
228 const PmDeviceInfo *info = Pm_GetDeviceInfo( nDeviceId );
229 if ( info ==
nullptr ) {
230 ERRORLOG(
"Error opening midi input device" );
234 PtError startErr = Pt_Start( 1, 0, 0 );
235 if ( startErr != ptNoError ) {
239 sError = QString(
"Host error" );
241 case ptAlreadyStarted:
242 sError = QString(
"Cannot start timer because it is already started" );
244 case ptAlreadyStopped:
245 sError = QString(
"Cannot stop timer because it is already stopped" );
247 case ptInsufficientMemory:
248 sError = QString(
"Memory could not be allocated" );
251 ERRORLOG( QString(
"Error in Pt_Start: [%1]" ).arg( sError ) );
254 PmError err = Pm_OpenInput(
263 if ( err != pmNoError ) {
264 ERRORLOG( QString(
"Error in Pm_OpenInput: [%1]" )
272 WARNINGLOG( QString(
"MIDI input device [%1] not found." )
273 .arg( sMidiPortName ) );
275 INFOLOG( QString(
"No MIDI input device selected" ) );
281 if ( nOutDeviceId != -1 ) {
282 PmError err = Pm_OpenOutput(
292 if ( err != pmNoError ) {
293 ERRORLOG( QString(
"Error in Pm_OpenOutput: [%1]" )
301 WARNINGLOG( QString(
"MIDI output device [%1] not found." )
302 .arg( sMidiOutputPortName ) );
304 INFOLOG( QString(
"No MIDI output device selected" ) );
313 pthread_attr_init( &attr );
326 if ( err != pmNoError ) {
327 ERRORLOG( QString(
"Error in Pm_Close: [%1]" )
335 std::vector<QString> portList;
337 int nDevices = Pm_CountDevices();
338 for (
int i = 0; i < nDevices; i++ ) {
339 const PmDeviceInfo *pInfo = Pm_GetDeviceInfo( i );
340 if ( pInfo ==
nullptr ) {
341 ERRORLOG( QString(
"Could not open output device [%1]" ).arg( i ) );
342 }
else if ( pInfo->output == TRUE ) {
344 portList.push_back( pInfo->name );
353 std::vector<QString> portList;
355 int nDevices = Pm_CountDevices();
356 for (
int i = 0; i < nDevices; i++ ) {
357 const PmDeviceInfo *pInfo = Pm_GetDeviceInfo( i );
358 if ( pInfo ==
nullptr ) {
359 ERRORLOG( QString(
"Could not open input device [%1]" ).arg( i ) );
360 }
else if ( pInfo->input == TRUE ) {
362 portList.push_back( pInfo->name );
387 event.message = Pm_Message(0x80 | channel, key, velocity);
388 PmError err = Pm_Write(
m_pMidiOut, &event, 1);
389 if ( err != pmNoError ) {
390 ERRORLOG( QString(
"Error in Pm_Write for Note off: [%1]" )
395 event.message = Pm_Message(0x90 | channel, key, velocity);
397 if ( err != pmNoError ) {
398 ERRORLOG( QString(
"Error in Pm_Write for Note on: [%1]" )
417 event.message = Pm_Message(0x80 | channel, key, velocity);
418 PmError err = Pm_Write(
m_pMidiOut, &event, 1);
419 if ( err != pmNoError ) {
420 ERRORLOG( QString(
"Error in Pm_Write: [%1]" )
433 unsigned int numInstruments = instList->size();
434 for (
int index = 0; index < numInstruments; ++index) {
435 auto pCurInst = instList->get(index);
437 int channel = pCurInst->get_midi_out_channel();
441 int key = pCurInst->get_midi_out_note();
447 event.message = Pm_Message(0x80 | channel, key, 0);
448 PmError err = Pm_Write(
m_pMidiOut, &event, 1);
449 if ( err != pmNoError ) {
450 ERRORLOG( QString(
"Error for instrument [%1] in Pm_Write: [%2]" )
451 .arg( pCurInst->get_name() )
459 unsigned char eox = 247;
460 unsigned char c = msg & 0x000000ffUL;
466 c = (msg & 0x0000ff00UL) >> 8;
472 c = (msg & 0x00ff0000UL) >> 16;
478 c = (msg & 0xff000000UL) >> 24;
488 QString sRes( Pm_GetErrorText( err ) );
489 if ( err == pmHostError ) {
493 Pm_GetHostErrorText( msg, 100 );
494 sRes.append( QString(
": [%1]" ).arg( msg ) );
497 return std::move( sRes );
std::shared_ptr< Song > getSong() const
Get the current song.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
void setType(int nStatusByte)
Derives and set m_type (and if applicable m_nChannel) using the statusByte of an incoming MIDI messag...
std::vector< unsigned char > m_sysexData
void clear()
Reset message.
A note plays an associated instrument with a velocity left and right pan.
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
int get_midi_key() const
return scaled key for midi output, !!! DO NOT CHECK IF INSTRUMENT IS SET !!!
int get_midi_velocity() const
midi velocity accessor
static bool appendSysExData(MidiMessage *pMidiMessage, PmMessage msg)
Appends the content of msg to MidiMessage::m_sysexData of pMidiMessage till 247 (EOX - end of exclusi...
virtual void open() override
static QString translatePmError(PmError err)
virtual std::vector< QString > getInputPortList() override
virtual void close() override
virtual ~PortMidiDriver()
virtual void handleQueueNoteOff(int channel, int key, int velocity) override
virtual std::vector< QString > getOutputPortList() override
virtual void handleQueueAllNoteOff() override
virtual void handleOutgoingControlChange(int param, int value, int channel) override
virtual void handleQueueNote(Note *pNote) override
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
QString m_sMidiOutputPortName
static QString getNullMidiPort()
Choice of m_sMidiPortName and m_sMidiOutputPortName in case no port/device was selected.
pthread_t PortMidiDriverThread
void * PortMidiDriver_thread(void *param)