2012-05-26 14:49:10 +02:00
//=============================================================================
// MusE Score
// Linux Music Score Editor
// $Id: pm.cpp 4874 2011-10-21 12:18:42Z wschweer $
//
// Copyright (C) 2002-2007 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
2013-05-17 18:02:34 +02:00
# if defined(Q_OS_WIN)
2012-05-26 14:49:10 +02:00
# include <windows.h>
# include <mmsystem.h>
# endif
2016-08-09 00:25:42 +02:00
# if defined(Q_OS_MAC) || defined(Q_OS_WIN)
# include "portmidi/porttime/porttime.h"
# else
# include <porttime.h>
# endif
2012-05-26 14:49:10 +02:00
# include "preferences.h"
# include "pm.h"
# include "musescore.h"
# include "seq.h"
2013-05-13 18:49:17 +02:00
namespace Ms {
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// PortMidiDriver
//---------------------------------------------------------
PortMidiDriver : : PortMidiDriver ( Seq * s )
: MidiDriver ( s )
{
2017-05-14 17:43:28 +02:00
inputId = - 1 ;
outputId = - 1 ;
2012-05-26 14:49:10 +02:00
timer = 0 ;
2017-05-14 17:43:28 +02:00
inputStream = 0 ;
outputStream = 0 ;
2012-05-26 14:49:10 +02:00
}
PortMidiDriver : : ~ PortMidiDriver ( )
{
if ( inputStream ) {
Pt_Stop ( ) ;
Pm_Close ( inputStream ) ;
}
}
//---------------------------------------------------------
// init
// return false on error
//---------------------------------------------------------
bool PortMidiDriver : : init ( )
{
2017-11-29 08:21:36 +01:00
inputId = getDeviceIn ( preferences . getString ( PREF_IO_PORTMIDI_INPUTDEVICE ) ) ;
2017-05-14 17:43:28 +02:00
if ( inputId = = - 1 )
inputId = Pm_GetDefaultInputDeviceID ( ) ;
2012-05-26 14:49:10 +02:00
if ( inputId = = pmNoDevice )
return false ;
2017-11-29 08:21:36 +01:00
outputId = getDeviceOut ( preferences . getString ( PREF_IO_PORTMIDI_OUTPUTDEVICE ) ) ; // Note: allow init even if outputId == pmNoDevice, since input is more important than output.
2017-05-14 17:43:28 +02:00
2012-05-26 14:49:10 +02:00
static const int DRIVER_INFO = 0 ;
static const int TIME_INFO = 0 ;
Pt_Start ( 20 , 0 , 0 ) ; // timer started, 20 millisecond accuracy
PmError error = Pm_OpenInput ( & inputStream ,
inputId ,
2017-05-14 17:43:28 +02:00
( void * ) DRIVER_INFO ,
2017-11-29 08:21:36 +01:00
preferences . getInt ( PREF_IO_PORTMIDI_INPUTBUFFERCOUNT ) ,
2016-08-09 00:25:42 +02:00
( ( PmTimeProcPtr ) Pt_Time ) ,
2013-02-14 00:36:40 +01:00
( void * ) TIME_INFO ) ;
2012-05-26 14:49:10 +02:00
if ( error ! = pmNoError ) {
const char * p = Pm_GetErrorText ( error ) ;
2014-03-25 13:33:47 +01:00
qDebug ( " PortMidi: open input (id=%d) failed: %s " , int ( inputId ) , p ) ;
2012-05-26 14:49:10 +02:00
Pt_Stop ( ) ;
return false ;
}
Pm_SetFilter ( inputStream , PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX ) ;
PmEvent buffer [ 1 ] ;
while ( Pm_Poll ( inputStream ) )
Pm_Read ( inputStream , buffer , 1 ) ;
2017-05-14 17:43:28 +02:00
if ( outputId ! = pmNoDevice ) {
error = Pm_OpenOutput ( & outputStream ,
outputId ,
( void * ) DRIVER_INFO ,
2017-11-29 08:21:36 +01:00
preferences . getInt ( PREF_IO_PORTMIDI_OUTPUTBUFFERCOUNT ) ,
2017-05-14 17:43:28 +02:00
( ( PmTimeProcPtr ) Pt_Time ) ,
( void * ) TIME_INFO ,
2017-11-29 08:21:36 +01:00
preferences . getInt ( PREF_IO_PORTMIDI_OUTPUTLATENCYMILLISECONDS ) ) ;
2017-05-14 17:43:28 +02:00
if ( error ! = pmNoError ) {
const char * p = Pm_GetErrorText ( error ) ;
qDebug ( " PortMidi: open output (id=%d) failed: %s " , int ( outputId ) , p ) ;
Pt_Stop ( ) ;
return false ;
}
}
2012-05-26 14:49:10 +02:00
timer = new QTimer ( ) ;
timer - > setInterval ( 20 ) ; // 20 msec
timer - > start ( ) ;
timer - > connect ( timer , SIGNAL ( timeout ( ) ) , seq , SLOT ( midiInputReady ( ) ) ) ;
return true ;
}
//---------------------------------------------------------
// registerOutPort
//---------------------------------------------------------
Port PortMidiDriver : : registerOutPort ( const QString & )
{
return Port ( ) ;
}
//---------------------------------------------------------
// registerInPort
//---------------------------------------------------------
Port PortMidiDriver : : registerInPort ( const QString & )
{
return Port ( ) ;
}
//---------------------------------------------------------
// getInputPollFd
//---------------------------------------------------------
void PortMidiDriver : : getInputPollFd ( struct pollfd * * , int * n )
{
* n = 0 ;
}
//---------------------------------------------------------
// getOutputPollFd
//---------------------------------------------------------
void PortMidiDriver : : getOutputPollFd ( struct pollfd * * , int * n )
{
* n = 0 ;
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void PortMidiDriver : : read ( )
{
if ( ! inputStream )
return ;
PmEvent buffer [ 1 ] ;
while ( Pm_Poll ( inputStream ) ) {
int n = Pm_Read ( inputStream , buffer , 1 ) ;
if ( n > 0 ) {
int status = Pm_MessageStatus ( buffer [ 0 ] . message ) ;
int type = status & 0xF0 ;
int channel = status & 0x0F ;
if ( type = = ME_NOTEON ) {
int pitch = Pm_MessageData1 ( buffer [ 0 ] . message ) ;
int velo = Pm_MessageData2 ( buffer [ 0 ] . message ) ;
mscore - > midiNoteReceived ( channel , pitch , velo ) ;
}
else if ( type = = ME_NOTEOFF ) {
int pitch = Pm_MessageData1 ( buffer [ 0 ] . message ) ;
2014-01-17 14:40:46 +01:00
( void ) Pm_MessageData2 ( buffer [ 0 ] . message ) ; // read but ignore
2012-05-26 14:49:10 +02:00
mscore - > midiNoteReceived ( channel , pitch , 0 ) ;
}
2015-04-19 19:04:38 +02:00
else if ( type = = ME_CONTROLLER ) {
int param = Pm_MessageData1 ( buffer [ 0 ] . message ) ;
int value = Pm_MessageData2 ( buffer [ 0 ] . message ) ;
mscore - > midiCtrlReceived ( param , value ) ;
}
2012-05-26 14:49:10 +02:00
}
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void PortMidiDriver : : write ( const Event & )
{
}
//---------------------------------------------------------
// deviceInList
//---------------------------------------------------------
QStringList PortMidiDriver : : deviceInList ( ) const
{
QStringList il ;
int interf = Pm_CountDevices ( ) ;
for ( PmDeviceID id = 0 ; id < interf ; id + + ) {
const PmDeviceInfo * info = Pm_GetDeviceInfo ( ( PmDeviceID ) id ) ;
if ( info - > input )
2017-05-14 17:43:28 +02:00
il . append ( QString ( info - > interf ) + " , " + QString ( info - > name ) ) ;
2012-05-26 14:49:10 +02:00
}
return il ;
}
2017-05-14 17:43:28 +02:00
//---------------------------------------------------------
// deviceOutList
//---------------------------------------------------------
QStringList PortMidiDriver : : deviceOutList ( ) const
{
QStringList ol ;
int interf = Pm_CountDevices ( ) ;
for ( PmDeviceID id = 0 ; id < interf ; id + + ) {
const PmDeviceInfo * info = Pm_GetDeviceInfo ( ( PmDeviceID ) id ) ;
if ( info - > output )
ol . append ( QString ( info - > interf ) + " , " + QString ( info - > name ) ) ;
}
return ol ;
}
2012-05-26 14:49:10 +02:00
//---------------------------------------------------------
// getDeviceIn
//---------------------------------------------------------
2017-05-14 17:43:28 +02:00
int PortMidiDriver : : getDeviceIn ( const QString & interfaceAndName )
2012-05-26 14:49:10 +02:00
{
int interf = Pm_CountDevices ( ) ;
for ( int id = 0 ; id < interf ; id + + ) {
const PmDeviceInfo * info = Pm_GetDeviceInfo ( ( PmDeviceID ) id ) ;
if ( info - > input ) {
2017-05-14 17:43:28 +02:00
if ( QString ( info - > interf ) + " , " + QString ( info - > name ) = = interfaceAndName )
2012-05-26 14:49:10 +02:00
return id ;
}
}
return - 1 ;
}
2017-05-14 17:43:28 +02:00
//---------------------------------------------------------
// getDeviceOut
//---------------------------------------------------------
int PortMidiDriver : : getDeviceOut ( const QString & interfaceAndName )
{
int interf = Pm_CountDevices ( ) ;
for ( int id = 0 ; id < interf ; id + + ) {
const PmDeviceInfo * info = Pm_GetDeviceInfo ( ( PmDeviceID ) id ) ;
if ( info - > output ) {
if ( QString ( info - > interf ) + " , " + QString ( info - > name ) = = interfaceAndName )
return id ;
}
}
return - 1 ;
}
//---------------------------------------------------------
// isSameCoreMidiIacBus
// determines if both the input and output devices are the same shared CoreMIDI "IAC" bus
//---------------------------------------------------------
bool PortMidiDriver : : isSameCoreMidiIacBus ( const QString & inInterfaceAndName , const QString & outInterfaceAndName )
{
int interf = Pm_CountDevices ( ) ;
const PmDeviceInfo * inInfo = 0 ;
const PmDeviceInfo * outInfo = 0 ;
for ( PmDeviceID id = 0 ; id < interf ; id + + ) {
const PmDeviceInfo * info = Pm_GetDeviceInfo ( ( PmDeviceID ) id ) ;
if ( info - > input & & inInterfaceAndName . contains ( info - > name ) )
inInfo = info ;
if ( info - > output & & outInterfaceAndName . contains ( info - > name ) )
outInfo = info ;
}
if ( inInfo & & outInfo & &
QString ( inInfo - > interf ) = = " CoreMIDI " & & QString ( outInfo - > interf ) = = " CoreMIDI " & &
inInterfaceAndName . contains ( " IAC " ) & & outInterfaceAndName = = inInterfaceAndName )
return true ;
else
return false ;
}
2013-05-13 18:49:17 +02:00
}
2012-05-26 14:49:10 +02:00