Merge pull request #2228 from rageboge/midi_apple

#1153 (Apple) MIDI Support
This commit is contained in:
Colin Wallace
2015-08-09 08:39:53 -07:00
7 changed files with 828 additions and 0 deletions

View File

@@ -53,6 +53,7 @@ IF(LMMS_BUILD_APPLE)
SET(WANT_VST OFF)
SET(STATUS_ALSA "<not supported on this platform>")
SET(STATUS_PULSEAUDIO "<not supported on this platform>")
SET(STATUS_APPLEMIDI "OK")
# MacPorts: /opt/local/lib
LINK_DIRECTORIES(${LINK_DIRECTORIES} /opt/local/lib)
ENDIF(LMMS_BUILD_APPLE)
@@ -69,6 +70,7 @@ IF(LMMS_BUILD_WIN32)
SET(STATUS_JACK "<not supported on this platform>")
SET(STATUS_PULSEAUDIO "<not supported on this platform>")
SET(STATUS_WINMM "OK")
SET(STATUS_APPLEMIDI "<not supported on this platform>")
ELSE(LMMS_BUILD_WIN32)
SET(STATUS_WINMM "<not supported on this platform>")
ENDIF(LMMS_BUILD_WIN32)
@@ -527,6 +529,7 @@ MESSAGE(
"* ALSA : ${STATUS_ALSA}\n"
"* OSS : ${STATUS_OSS}\n"
"* WinMM : ${STATUS_WINMM}\n"
"* AppleMidi : ${STATUS_APPLEMIDI}\n"
)
MESSAGE(

158
include/MidiApple.h Normal file
View File

@@ -0,0 +1,158 @@
/*
* MidiApple.h - Apple raw MIDI client
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2015 Maurizio Lo Bosco (rageboge on github)
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef MIDI_APPLE_H
#define MIDI_APPLE_H
#include "lmmsconfig.h"
#ifdef LMMS_BUILD_APPLE
#include "MidiClient.h"
#include "MidiPort.h"
#include <CoreMIDI/CoreMIDI.h>
class QLineEdit;
class MidiApple : public QObject, public MidiClient
{
Q_OBJECT
public:
MidiApple();
virtual ~MidiApple();
static QString probeDevice();
inline static QString name()
{
return QT_TRANSLATE_NOOP( "setupWidget", "Apple MIDI" );
}
virtual void processOutEvent( const MidiEvent & _me,
const MidiTime & _time,
const MidiPort * _port );
virtual void applyPortMode( MidiPort * _port );
virtual void removePort( MidiPort * _port );
// list devices as ports
virtual QStringList readablePorts() const
{
return m_inputDevices.keys();
}
virtual QStringList writablePorts() const
{
return m_outputDevices.keys();
}
// return name of port which specified MIDI event came from
virtual QString sourcePortName( const MidiEvent & ) const;
// (un)subscribe given MidiPort to/from destination-port
virtual void subscribeReadablePort( MidiPort * _port,
const QString & _dest,
bool _subscribe = true );
virtual void subscribeWritablePort( MidiPort * _port,
const QString & _dest,
bool _subscribe = true );
virtual void connectRPChanged( QObject * _receiver,
const char * _member )
{
connect( this, SIGNAL( readablePortsChanged() ),
_receiver, _member );
}
virtual void connectWPChanged( QObject * _receiver,
const char * _member )
{
connect( this, SIGNAL( writablePortsChanged() ),
_receiver, _member );
}
virtual bool isRaw() const
{
return false;
}
class setupWidget : public MidiClient::setupWidget
{
public:
setupWidget( QWidget * _parent );
virtual ~setupWidget();
void saveSettings()
{
}
} ;
private:// slots:
void updateDeviceList();
private:
void openDevices();
void closeDevices();
void openMidiReference( MIDIEndpointRef reference, QString refName,bool isIn );
MIDIClientRef getMidiClientRef();
void midiInClose( MIDIEndpointRef reference );
static void NotifyCallback( const MIDINotification *message, void *refCon );
static void ReadCallback( const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon );
void HandleReadCallback( const MIDIPacketList *pktlist, void *srcConnRefCon );
void notifyMidiPortList( MidiPortList portList, MidiEvent midiEvent);
char * getFullName( MIDIEndpointRef &endpoint_ref );
void sendMidiOut( MIDIEndpointRef & endPointRef, const MidiEvent& event );
MIDIPacketList createMidiPacketList( const MidiEvent& event );
MIDIClientRef mClient = 0;
QMap<QString, MIDIEndpointRef> m_inputDevices;
QMap<QString, MIDIEndpointRef> m_outputDevices;
QMap<MIDIEndpointRef, MIDIPortRef> m_sourcePortRef;
// subscriptions
typedef QMap<QString, MidiPortList> SubMap;
SubMap m_inputSubs;
SubMap m_outputSubs;
signals:
void readablePortsChanged();
void writablePortsChanged();
} ;
#endif
#endif

View File

@@ -95,6 +95,10 @@ IF(LMMS_BUILD_WIN32)
SET(EXTRA_LIBRARIES "-lwinmm")
ENDIF()
IF(LMMS_BUILD_APPLE)
SET(EXTRA_LIBRARIES "-framework CoreMIDI")
ENDIF()
SET(LMMS_REQUIRED_LIBS
${CMAKE_THREAD_LIBS_INIT}
${QT_LIBRARIES}

View File

@@ -81,6 +81,7 @@ set(LMMS_SRCS
core/midi/MidiClient.cpp
core/midi/MidiController.cpp
core/midi/MidiOss.cpp
core/midi/MidiApple.cpp
core/midi/MidiPort.cpp
core/midi/MidiTime.cpp
core/midi/MidiWinMM.cpp

View File

@@ -50,6 +50,7 @@
#include "MidiAlsaSeq.h"
#include "MidiOss.h"
#include "MidiWinMM.h"
#include "MidiApple.h"
#include "MidiDummy.h"
#include "MemoryHelper.h"
@@ -894,6 +895,18 @@ MidiClient * Mixer::tryMidiClients()
}
#endif
#ifdef LMMS_BUILD_APPLE
printf( "trying midi apple...\n" );
if( client_name == MidiApple::name() || client_name == "" )
{
MidiApple * mapple = new MidiApple;
m_midiClientName = MidiApple::name();
printf( "Returning midi apple\n" );
return mapple;
}
printf( "midi apple didn't work: client_name=%s\n", client_name.toUtf8().constData());
#endif
printf( "Couldn't create MIDI-client, neither with ALSA nor with "
"OSS. Will use dummy-MIDI-client.\n" );

643
src/core/midi/MidiApple.cpp Normal file
View File

@@ -0,0 +1,643 @@
/*
* MidiApple.cpp - Apple MIDI client
*
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2015 Maurizio Lo Bosco (rageboge on github)
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "MidiApple.h"
#include <QLabel>
#include <QLineEdit>
#include <QtAlgorithms>
#include <algorithm>
#include "ConfigManager.h"
#include "MidiPort.h"
#include "Note.h"
#ifdef LMMS_BUILD_APPLE
#include <CoreMIDI/CoreMIDI.h>
const unsigned int SYSEX_LENGTH=1024;
MidiApple::MidiApple() :
MidiClient(),
m_inputDevices(),
m_outputDevices(),
m_inputSubs(),
m_outputSubs()
{
openDevices();
}
MidiApple::~MidiApple()
{
closeDevices();
}
void MidiApple::processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port )
{
qDebug("MidiApple:processOutEvent displayName:'%s'",port->displayName().toLatin1().constData());
QStringList outDevs;
for( SubMap::ConstIterator it = m_outputSubs.begin(); it != m_outputSubs.end(); ++it )
{
for( MidiPortList::ConstIterator jt = it.value().begin(); jt != it.value().end(); ++jt )
{
if( *jt == port )
{
outDevs += it.key();
break;
}
}
}
for( QMap<QString, MIDIEndpointRef>::Iterator it = m_outputDevices.begin(); it != m_outputDevices.end(); ++it )
{
if( outDevs.contains( it.key() ) )
{
sendMidiOut( it.value(), event );
}
}
}
void MidiApple::sendMidiOut( MIDIEndpointRef &endPointRef, const MidiEvent& event )
{
MIDIPacketList packetList=createMidiPacketList(event);
MIDIPortRef port = m_sourcePortRef.value(endPointRef);
MIDISend(port, endPointRef, &packetList);
}
MIDIPacketList MidiApple::createMidiPacketList( const MidiEvent& event )
{
MIDIPacketList packetList;
packetList.numPackets = 1;
MIDIPacket* firstPacket = &packetList.packet[0];
firstPacket->timeStamp = 0; // send immediately
firstPacket->length = 3;
firstPacket->data[0] = ( event.type() + event.channel() );
firstPacket->data[1] = ( event.param( 0 ) & 0xff );
firstPacket->data[2] = ( event.param( 1 ) & 0xff );
return packetList;
}
void MidiApple::applyPortMode( MidiPort* port )
{
qDebug("applyPortMode displayName:'%s'",port->displayName().toLatin1().constData());
// make sure no subscriptions exist which are not possible with
// current port-mode
if( !port->isInputEnabled() )
{
for( SubMap::Iterator it = m_inputSubs.begin(); it != m_inputSubs.end(); ++it )
{
it.value().removeAll( port );
}
}
if( !port->isOutputEnabled() )
{
for( SubMap::Iterator it = m_outputSubs.begin(); it != m_outputSubs.end(); ++it )
{
it.value().removeAll( port );
}
}
}
void MidiApple::removePort( MidiPort* port )
{
qDebug("removePort displayName:'%s'",port->displayName().toLatin1().constData());
for( SubMap::Iterator it = m_inputSubs.begin(); it != m_inputSubs.end(); ++it )
{
it.value().removeAll( port );
}
for( SubMap::Iterator it = m_outputSubs.begin(); it != m_outputSubs.end(); ++it )
{
it.value().removeAll( port );
}
MidiClient::removePort( port );
}
QString MidiApple::sourcePortName( const MidiEvent& event ) const
{
qDebug("sourcePortName return '%s'?\n", event.sourcePort());
/*
if( event.sourcePort() )
{
return m_inputDevices.value( *static_cast<const HMIDIIN *>( event.sourcePort() ) );
}
*/
return MidiClient::sourcePortName( event );
}
void MidiApple::subscribeReadablePort( MidiPort* port, const QString& dest, bool subscribe )
{
qDebug("subscribeReadablePort %s subscribe=%d",dest.toLatin1().constData(),subscribe);
if( subscribe && port->isInputEnabled() == false )
{
qWarning( "port %s can't be (un)subscribed!", port->displayName().toLatin1().constData() );
return;
}
m_inputSubs[dest].removeAll( port );
if( subscribe )
{
qDebug("Subscribing %s",dest.toLatin1().constData());
m_inputSubs[dest].push_back( port );
}
else
{
MidiPortList list = m_inputSubs[dest];
if(list.empty()){
m_inputSubs.remove(dest);
}
}
}
void MidiApple::subscribeWritablePort( MidiPort* port, const QString& dest, bool subscribe )
{
qDebug("subscribeWritablePort %s", port->displayName().toLatin1().constData());
if( subscribe && port->isOutputEnabled() == false )
{
qWarning( "port %s can't be (un)subscribed!", port->displayName().toLatin1().constData() );
return;
}
m_outputSubs[dest].removeAll( port );
if( subscribe )
{
m_outputSubs[dest].push_back( port );
}
else
{
MidiPortList list = m_outputSubs[dest];
if(list.empty()){
m_outputSubs.remove(dest);
}
}
}
void MidiApple::ReadCallback( const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon )
{
MidiApple *caller = static_cast<MidiApple*>(readProcRefCon);
if (!caller)
{
qDebug("Error: !caller: MidiApple::ReadCallback");
return;
}
caller->HandleReadCallback(pktlist,srcConnRefCon);
}
void MidiApple::HandleReadCallback( const MIDIPacketList *pktlist, void *srcConnRefCon )
{
const char * refName = (const char *) srcConnRefCon;
MIDIEndpointRef endPointRef = m_inputDevices.value(refName);
if( !m_inputSubs.contains( refName ) )
{
// qDebug("HandleReadCallback '%s' not subscribed",refName);
// printQStringKeys("m_inputDevices", m_inputDevices);
return;
}
// qDebug("HandleReadCallback '%s' subscribed",refName);
bool continueSysEx = false;
unsigned int nBytes;
const MIDIPacket *packet = &pktlist->packet[0];
unsigned char sysExMessage[SYSEX_LENGTH];
unsigned int sysExLength = 0;
for (uint32_t i=0; i<pktlist->numPackets; ++i)
{
nBytes = packet->length;
// Check if this is the end of a continued SysEx message
if (continueSysEx) {
unsigned int lengthToCopy = qMin(nBytes, SYSEX_LENGTH - sysExLength);
// Copy the message into our SysEx message buffer,
// making sure not to overrun the buffer
memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy);
sysExLength += lengthToCopy;
// Check if the last byte is SysEx End.
continueSysEx = (packet->data[nBytes - 1] == 0xF7);
if (!continueSysEx || sysExLength == SYSEX_LENGTH) {
// We would process the SysEx message here, as it is we're just ignoring it
sysExLength = 0;
}
}
else
{
UInt16 iByte, size;
iByte = 0;
while (iByte < nBytes)
{
size = 0;
// First byte should be status
unsigned char status = packet->data[iByte];
if (status < 0xC0) {
size = 3;
}
else if (status < 0xE0)
{
size = 2;
}
else if (status < 0xF0)
{
size = 3;
}
else if (status == 0xF0)
{
// MIDI SysEx then we copy the rest of the message into the SysEx message buffer
unsigned int lengthLeftInMessage = nBytes - iByte;
unsigned int lengthToCopy = qMin(lengthLeftInMessage, SYSEX_LENGTH);
memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy);
sysExLength += lengthToCopy;
size = 0;
iByte = nBytes;
// Check whether the message at the end is the end of the SysEx
continueSysEx = (packet->data[nBytes - 1] != 0xF7);
}
else if (status < 0xF3)
{
size = 3;
}
else if (status == 0xF3)
{
size = 2;
}
else
{
size = 1;
}
unsigned char messageChannel = status & 0xF;
const MidiEventTypes cmdtype = static_cast<MidiEventTypes>( status & 0xF0 );
const int par1 = packet->data[iByte + 1];
const int par2 = packet->data[iByte + 2];
switch (cmdtype)
{
case MidiNoteOff: //0x80:
case MidiNoteOn: //0x90:
case MidiKeyPressure: //0xA0:
notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 - KeysPerOctave, par2 & 0xff, &endPointRef ));
break;
case MidiControlChange: //0xB0:
case MidiProgramChange: //0xC0:
case MidiChannelPressure: //0xD0:
notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1, par2 & 0xff, &endPointRef ));
break;
case MidiPitchBend: //0xE0:
notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 + par2 * 128, 0, &endPointRef ));
break;
case MidiActiveSensing: //0xF0
case 0xF0:
break;
default:
qDebug("endPointRef name='%s':Some other message %d", refName, cmdtype);
break;
}
iByte += size;
}
}
packet = MIDIPacketNext(packet);
}
}
void MidiApple::updateDeviceList()
{
closeDevices();
openDevices();
emit readablePortsChanged();
emit writablePortsChanged();
}
void MidiApple::closeDevices()
{
m_inputSubs.clear();
m_outputSubs.clear();
QMapIterator<QString, MIDIEndpointRef> i( m_inputDevices );
while( i.hasNext() )
{
midiInClose( i.next().value() );
}
QMapIterator<QString, MIDIEndpointRef> o( m_outputDevices );
while( o.hasNext() )
{
midiInClose( o.next().value() );
}
m_inputDevices.clear();
m_outputDevices.clear();
}
void MidiApple::midiInClose( MIDIEndpointRef reference )
{
qDebug("midiInClose '%s'", getFullName(reference));
MIDIPortRef portRef = m_sourcePortRef[reference];
MIDIPortDisconnectSource(portRef, reference);
}
char *getName( MIDIObjectRef &object )
{
// Returns the name of a given MIDIObjectRef as char *
CFStringRef name = nil;
if (noErr != MIDIObjectGetStringProperty(object, kMIDIPropertyName, &name))
return nil;
int len = CFStringGetLength(name)+1;
char *value = (char *) malloc(len);
CFStringGetCString(name, value, len, 0);
CFRelease(name);
return value;
}
const void printQStringKeys( char const * mapName, const QMap<QString,MIDIEndpointRef> &inputMap )
{
qDebug("%s:", mapName);
QMapIterator<QString, MIDIEndpointRef> i( inputMap );
while( i.hasNext() )
{
QString key = i.next().key();
qDebug(" key='%s'", key.toLatin1().constData());
}
}
void MidiApple::openDevices()
{
qDebug("openDevices");
m_inputDevices.clear();
// How many MIDI devices do we have?
ItemCount deviceCount = MIDIGetNumberOfDevices();
// Iterate through all MIDI devices
for (ItemCount i = 0 ; i < deviceCount ; ++i)
{
// Grab a reference to current device
MIDIDeviceRef device = MIDIGetDevice(i);
char * deviceName = getName(device);
QString qsDeviceName = QString::fromUtf8((char*)(deviceName));
qDebug("Device name:%s",deviceName);
// Is this device online? (Currently connected?)
SInt32 isOffline = 0;
MIDIObjectGetIntegerProperty(device, kMIDIPropertyOffline, &isOffline);
qDebug(" is online: %s", (isOffline ? "No" : "Yes"));
// How many entities do we have?
ItemCount entityCount = MIDIDeviceGetNumberOfEntities(device);
// Iterate through this device's entities
for (ItemCount j = 0 ; j < entityCount ; ++j)
{
// Grab a reference to an entity
MIDIEntityRef entity = MIDIDeviceGetEntity(device, j);
qDebug(" Entity: %s", getName(entity));
// Iterate through this device's source endpoints (MIDI In)
ItemCount sourceCount = MIDIEntityGetNumberOfSources(entity);
for ( ItemCount k = 0 ; k < sourceCount ; ++k )
{
// Grab a reference to a source endpoint
MIDIEndpointRef source = MIDIEntityGetSource(entity, k);
char * name = getName(source);
qDebug(" Source: '%s'", name);
QString sourceName = qsDeviceName + ":" + QString::fromUtf8((char*)(name));
qDebug(" Source name: '%s'", sourceName.toLatin1().constData() );
m_inputDevices.insert(sourceName, source);
openMidiReference(source,sourceName,true);
}
// Iterate through this device's destination endpoints (MIDI Out)
ItemCount destCount = MIDIEntityGetNumberOfDestinations(entity);
for ( ItemCount k = 0 ; k < destCount ; ++k )
{
// Grab a reference to a destination endpoint
MIDIEndpointRef dest = MIDIEntityGetDestination(entity, k);
char * name = getName(dest);
qDebug(" Destination: '%s'", name);
QString destinationName = qsDeviceName + ":" + QString::fromUtf8((char*)(name));
qDebug(" Destination name: '%s'", destinationName.toLatin1().constData() );
m_outputDevices.insert(destinationName, dest);
openMidiReference(dest,destinationName,false);
}
}
qDebug("------");
}
printQStringKeys("m_inputDevices:",m_inputDevices);
printQStringKeys("m_outputDevices:",m_outputDevices);
}
void MidiApple::openMidiReference( MIDIEndpointRef reference, QString refName, bool isIn )
{
char * registeredName = (char*) malloc(refName.length()+1);
sprintf(registeredName, "%s",refName.toLatin1().constData());
qDebug("openMidiReference refName '%s'",refName.toLatin1().constData());
MIDIClientRef mClient = getMidiClientRef();
MIDIPortRef mPort = 0;
CFStringRef inName = CFStringCreateWithCString(0, registeredName, kCFStringEncodingASCII);
if(isIn)
{
MIDIInputPortCreate(mClient, inName, &MidiApple::ReadCallback, this, &mPort);
}
else
{
MIDIOutputPortCreate(mClient, inName, &mPort);
}
MIDIPortConnectSource(mPort, reference, (void *)registeredName);
m_sourcePortRef.insert(reference, mPort);
CFRelease(inName);
qDebug("openMidiReference registeredName '%s'",registeredName);
}
MIDIClientRef MidiApple::getMidiClientRef()
{
if(mClient==0)
{
CFStringRef deviceClientName = CFSTR("MIDI In Device Client");
MIDIClientCreate(deviceClientName, NotifyCallback, this, &mClient);
CFRelease(deviceClientName);
}
return mClient;
}
void MidiApple::notifyMidiPortList( MidiPortList l, MidiEvent event )
{
for( MidiPortList::ConstIterator it = l.begin(); it != l.end(); ++it )
{
( *it )->processInEvent( event);
}
}
void MidiApple::NotifyCallback( const MIDINotification *message, void *refCon )
{
//refCon is a pointer to MidiApple class
MidiApple *midiApple = (MidiApple *)refCon;
qDebug("MidiApple::NotifyCallback '%d'",message->messageID);
switch (message->messageID)
{
case kMIDIMsgObjectAdded:
{
MIDIObjectAddRemoveNotification* msg = (MIDIObjectAddRemoveNotification*)message ;
MIDIEndpointRef endpoint_ref = (MIDIEndpointRef)msg->child ;
char * fullName = midiApple->getFullName(endpoint_ref);
if (msg->childType == kMIDIObjectType_Source) {
qDebug("kMIDIMsgObjectAdded source '%s'",fullName);
// Here your code to save the new source ref
// and update your internal "clients" (eg
// update a popup menu, a list, ...)
}
if (msg->childType == kMIDIObjectType_Destination) {
qDebug("kMIDIMsgObjectAdded destination '%s'",fullName);
// Here your code to save the new destination ref
// and update your internal "clients"
}
break;
}
case kMIDIMsgObjectRemoved:
{
MIDIObjectAddRemoveNotification*
msg = (MIDIObjectAddRemoveNotification*)message ;
MIDIEndpointRef endpoint_ref = (MIDIEndpointRef)msg->child ;
char * fullName = midiApple->getFullName(endpoint_ref);
if (msg->childType == kMIDIObjectType_Source) {
// Here your code to remove the source ref
// and update your internal "clients"
qDebug("kMIDIMsgObjectRemoved source '%s'",fullName);
}
if (msg->childType == kMIDIObjectType_Destination) {
// Here your code to remove the destination ref
// and update your internal "clients"
qDebug("kMIDIMsgObjectRemoved destination '%s'",fullName); }
break;
}
case kMIDIMsgPropertyChanged:
// Currently ignored
qDebug("kMIDIMsgPropertyChanged");
break;
case kMIDIMsgThruConnectionsChanged:
// Currently ignored
qDebug("kMIDIMsgThruConnectionsChanged");
break;
case kMIDIMsgSerialPortOwnerChanged:
// Currently ignored
qDebug("kMIDIMsgSerialPortOwnerChanged");
break;
default:
qDebug("unhandled message type");
break;
}
}
char * MidiApple::getFullName(MIDIEndpointRef &endpoint_ref)
{
MIDIEntityRef entity = 0;
MIDIEndpointGetEntity(endpoint_ref, &entity); //get the entity
MIDIDeviceRef device = 0;
MIDIEntityGetDevice(entity, &device);
char * deviceName = getName(device);
char * endPointName = getName(endpoint_ref);
qDebug("device name='%s' endpoint name='%s'",deviceName,endPointName);
char * fullName = (char *)malloc(strlen(deviceName) + strlen(endPointName)+1);
sprintf(fullName, "%s:%s", deviceName,endPointName);
return fullName;
}
MidiApple::setupWidget::setupWidget( QWidget* parent ) :
MidiClient::setupWidget( MidiApple::name(), parent )
{
}
MidiApple::setupWidget::~setupWidget()
{
}
#endif

View File

@@ -63,6 +63,7 @@
#include "MidiAlsaSeq.h"
#include "MidiOss.h"
#include "MidiWinMM.h"
#include "MidiApple.h"
#include "MidiDummy.h"
@@ -830,6 +831,11 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
new MidiWinMM::setupWidget( msw );
#endif
#ifdef LMMS_BUILD_APPLE
m_midiIfaceSetupWidgets[MidiApple::name()] =
new MidiApple::setupWidget( msw );
#endif
m_midiIfaceSetupWidgets[MidiDummy::name()] =
new MidiDummy::setupWidget( msw );