diff options
author | Max Horn | 2005-12-26 11:18:25 +0000 |
---|---|---|
committer | Max Horn | 2005-12-26 11:18:25 +0000 |
commit | fcf1af2ffc739d3efa430edc5280f83d3ab270fb (patch) | |
tree | 985b3d847a5df76849d3d2ece0ec82d8c7d2ebf3 /backends | |
parent | 515b69ddb87e5f7236f0e6ec98f65e7c6b4705d3 (diff) | |
download | scummvm-rg350-fcf1af2ffc739d3efa430edc5280f83d3ab270fb.tar.gz scummvm-rg350-fcf1af2ffc739d3efa430edc5280f83d3ab270fb.tar.bz2 scummvm-rg350-fcf1af2ffc739d3efa430edc5280f83d3ab270fb.zip |
New CoreMIDI midi backend for OS X
svn-id: r19832
Diffstat (limited to 'backends')
-rw-r--r-- | backends/midi/coreaudio.cpp | 279 | ||||
-rw-r--r-- | backends/midi/coremidi.cpp | 162 | ||||
-rw-r--r-- | backends/module.mk | 1 |
3 files changed, 265 insertions, 177 deletions
diff --git a/backends/midi/coreaudio.cpp b/backends/midi/coreaudio.cpp index c4f9f791c5..3c7aa64674 100644 --- a/backends/midi/coreaudio.cpp +++ b/backends/midi/coreaudio.cpp @@ -26,7 +26,7 @@ #include "sound/mpu401.h" #include <AudioUnit/AudioUnit.h> -#include <CoreMIDI/CoreMIDI.h>7 + // Activating the following switch disables reverb support in the CoreAudio @@ -35,13 +35,12 @@ // TODO: Maybe make this a config option? //#define COREAUDIO_DISABLE_REVERB +/* +See here to see how to react to a change of the default output unit: +http://cvs.opendarwin.org/cgi-bin/cvsweb.cgi/proj/KDE-Darwin/arts/flow/audioiocoreaudio.cc?rev=HEAD&content-type=text/x-cvsweb-markup + +*/ -// Enable the following switch to make ScummVM try to use native MIDI hardware -// on your computer for MIDI output. This is currently quite hackish, in -// particular you have no way to specify which device is used (it just always -// uses the first output device it can find), nor is there a switch to -// force it to use the soft synth instead of the MIDI HW. -//#define ENABLE_HACKISH_NATIVE_MIDI_SUPPORT 1 /* CoreAudio MIDI driver * Based on code by Benjamin W. Zale @@ -50,7 +49,6 @@ class MidiDriver_CORE : public MidiDriver_MPU401 { public: MidiDriver_CORE(); - ~MidiDriver_CORE(); int open(); void close(); void send(uint32 b); @@ -59,117 +57,90 @@ public: private: AudioUnit au_MusicDevice; AudioUnit au_output; - - MIDIClientRef mClient; - MIDIPortRef mOutPort; - MIDIEndpointRef mDest; }; MidiDriver_CORE::MidiDriver_CORE() - : au_MusicDevice(0), au_output(0), mClient(0), mOutPort(0), mDest(0) { - - OSStatus err; - err = MIDIClientCreate(CFSTR("ScummVM MIDI Driver for OS X"), NULL, NULL, &mClient); -} - -MidiDriver_CORE::~MidiDriver_CORE() { - if (mClient) - MIDIClientDispose(mClient); - mClient = 0; + : au_MusicDevice(0), au_output(0) { } int MidiDriver_CORE::open() { - if (au_output || mDest) + if (au_output) return MERR_ALREADY_OPEN; - OSStatus err = noErr; - - mOutPort = 0; -#ifdef ENABLE_HACKISH_NATIVE_MIDI_SUPPORT - int dests = MIDIGetNumberOfDestinations(); - if (dests > 0 && mClient) { - mDest = MIDIGetDestination(0); - err = MIDIOutputPortCreate( mClient, - CFSTR("scummvm_output_port"), - &mOutPort); - } -#endif - - if (err != noErr || !mOutPort) { - AudioUnitConnection auconnect; - ComponentDescription compdesc; - Component compid; - - // Open the Music Device. - // We use the AudioUnit v1 API, even though it is deprecated, because - // this way we stay compatible with older OS X versions. - // For v2, we'd use kAudioUnitType_MusicDevice and kAudioUnitSubType_DLSSynth - compdesc.componentType = kAudioUnitComponentType; - compdesc.componentSubType = kAudioUnitSubType_MusicDevice; - compdesc.componentManufacturer = kAudioUnitID_DLSSynth; - compdesc.componentFlags = 0; - compdesc.componentFlagsMask = 0; - compid = FindNextComponent(NULL, &compdesc); - au_MusicDevice = static_cast<AudioUnit>(OpenComponent(compid)); - - if (au_MusicDevice == 0) - error("Failed opening CoreAudio music device"); - - // Load custom soundfont, if specified - // FIXME: This is kind of a temporary hack. Better (IMO) would be to - // query QuickTime for whatever custom soundfont was set in the - // QuickTime Preferences, and use that automatically. - if (ConfMan.hasKey("soundfont")) { - FSRef fsref; - FSSpec fsSpec; - const char *soundfont = ConfMan.get("soundfont").c_str(); - - err = FSPathMakeRef ((const byte *)soundfont, &fsref, NULL); - - if (err == noErr) { - err = FSGetCatalogInfo (&fsref, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL); - } - - if (err == noErr) { - err = AudioUnitSetProperty ( - au_MusicDevice, - kMusicDeviceProperty_SoundBankFSSpec, kAudioUnitScope_Global, - 0, - &fsSpec, sizeof(fsSpec) - ); - } - - if (err != noErr) - warning("Failed loading custom sound font '%s' (error %d)\n", soundfont, err); + AudioUnitConnection auconnect; + ComponentDescription compdesc; + Component compid; + OSErr err; + + // Open the Music Device. + // We use the AudioUnit v1 API, even though it is deprecated, because + // this way we stay compatible with older OS X versions. + // For v2, we'd use kAudioUnitType_MusicDevice and kAudioUnitSubType_DLSSynth + compdesc.componentType = kAudioUnitComponentType; + compdesc.componentSubType = kAudioUnitSubType_MusicDevice; + compdesc.componentManufacturer = kAudioUnitID_DLSSynth; + compdesc.componentFlags = 0; + compdesc.componentFlagsMask = 0; + compid = FindNextComponent(NULL, &compdesc); + au_MusicDevice = static_cast<AudioUnit>(OpenComponent(compid)); + + if (au_MusicDevice == 0) + error("Failed opening CoreAudio music device"); + + // Load custom soundfont, if specified + // FIXME: This is kind of a temporary hack. Better (IMO) would be to + // query QuickTime for whatever custom soundfont was set in the + // QuickTime Preferences, and use that automatically. + if (ConfMan.hasKey("soundfont")) { + FSRef fsref; + FSSpec fsSpec; + const char *soundfont = ConfMan.get("soundfont").c_str(); + + err = FSPathMakeRef ((const byte *)soundfont, &fsref, NULL); + + if (err == noErr) { + err = FSGetCatalogInfo (&fsref, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL); } - // open the output unit - au_output = (AudioUnit) OpenDefaultComponent(kAudioUnitComponentType, kAudioUnitSubType_Output); - if (au_output == 0) - error("Failed opening output audio unit"); + if (err == noErr) { + err = AudioUnitSetProperty ( + au_MusicDevice, + kMusicDeviceProperty_SoundBankFSSpec, kAudioUnitScope_Global, + 0, + &fsSpec, sizeof(fsSpec) + ); + } - // connect the units - auconnect.sourceAudioUnit = au_MusicDevice; - auconnect.sourceOutputNumber = 0; - auconnect.destInputNumber = 0; - err = - AudioUnitSetProperty(au_output, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, - (void *)&auconnect, sizeof(AudioUnitConnection)); + if (err != noErr) + warning("Failed loading custom sound font '%s' (error %d)\n", soundfont, err); + } - #ifdef COREAUDIO_DISABLE_REVERB - UInt32 usesReverb = 0; - AudioUnitSetProperty (au_MusicDevice, kMusicDeviceProperty_UsesInternalReverb, - kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb)); - #endif + // open the output unit + au_output = (AudioUnit) OpenDefaultComponent(kAudioUnitComponentType, kAudioUnitSubType_Output); + if (au_output == 0) + error("Failed opening output audio unit"); + + // connect the units + auconnect.sourceAudioUnit = au_MusicDevice; + auconnect.sourceOutputNumber = 0; + auconnect.destInputNumber = 0; + err = + AudioUnitSetProperty(au_output, kAudioUnitProperty_MakeConnection, kAudioUnitScope_Input, 0, + (void *)&auconnect, sizeof(AudioUnitConnection)); + +#ifdef COREAUDIO_DISABLE_REVERB + UInt32 usesReverb = 0; + AudioUnitSetProperty (au_MusicDevice, kMusicDeviceProperty_UsesInternalReverb, + kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb)); +#endif - // initialize the units - AudioUnitInitialize(au_MusicDevice); - AudioUnitInitialize(au_output); + // initialize the units + AudioUnitInitialize(au_MusicDevice); + AudioUnitInitialize(au_output); - // start the output - AudioOutputUnitStart(au_output); + // start the output + AudioOutputUnitStart(au_output); - } return 0; } @@ -177,91 +148,45 @@ int MidiDriver_CORE::open() { void MidiDriver_CORE::close() { MidiDriver_MPU401::close(); - if (mOutPort && mDest) { - MIDIPortDispose(mOutPort); - mOutPort = 0; - mDest = 0; - } else { - // Stop the output - AudioOutputUnitStop(au_output); - - // Cleanup - CloseComponent(au_output); - au_output = 0; - CloseComponent(au_MusicDevice); - au_MusicDevice = 0; - } + // Stop the output + AudioOutputUnitStop(au_output); + + // Cleanup + CloseComponent(au_output); + au_output = 0; + CloseComponent(au_MusicDevice); + au_MusicDevice = 0; } void MidiDriver_CORE::send(uint32 b) { + assert(au_output != NULL); + assert(au_MusicDevice != NULL); + byte status_byte = (b & 0x000000FF); byte first_byte = (b & 0x0000FF00) >> 8; byte second_byte = (b & 0x00FF0000) >> 16; - if (mOutPort && mDest) { - MIDIPacketList packetList; - MIDIPacket *packet = &packetList.packet[0]; - - packetList.numPackets = 1; - - packet->timeStamp = 0; - packet->length = 3; - packet->data[0] = status_byte; - packet->data[1] = first_byte; - packet->data[2] = second_byte; - - MIDISend(mOutPort, mDest, &packetList); - } else { - assert(au_output != NULL); - assert(au_MusicDevice != NULL); - MusicDeviceMIDIEvent(au_MusicDevice, status_byte, first_byte, second_byte, 0); - } + MusicDeviceMIDIEvent(au_MusicDevice, status_byte, first_byte, second_byte, 0); } void MidiDriver_CORE::sysEx(byte *msg, uint16 length) { + assert(au_output != NULL); + assert(au_MusicDevice != NULL); + + // Add SysEx frame if missing + byte *buf = 0; + if (*msg != 0xF0) { + buf = (byte *)malloc(length + 2); + buf[0] = 0xF0; + memcpy(buf+1, msg, length); + buf[length+1] = 0xF7; + msg = buf; + length += 2; + } - if (mOutPort && mDest) { - byte buf[384]; - MIDIPacketList *packetList = (MIDIPacketList *)buf; - MIDIPacket *packet = packetList->packet; - - assert(sizeof(buf) >= sizeof(UInt32) + sizeof(MIDITimeStamp) + sizeof(UInt16) + length + 2); - - packetList->numPackets = 1; - - packet->timeStamp = 0; - - // Add SysEx frame if missing - if (*msg != 0xF0) { - packet->length = length + 2; - packet->data[0] = 0xF0; - memcpy(packet->data + 1, msg, length); - packet->data[length + 1] = 0xF7; - } else { - packet->length = length; - memcpy(packet->data, msg, length); - } - - MIDISend(mOutPort, mDest, packetList); - } else { - assert(au_output != NULL); - assert(au_MusicDevice != NULL); - - // Add SysEx frame if missing - byte *buf = 0; - if (*msg != 0xF0) { - buf = (byte *)malloc(length + 2); - buf[0] = 0xF0; - memcpy(buf+1, msg, length); - buf[length+1] = 0xF7; - msg = buf; - length += 2; - } - - MusicDeviceSysEx(au_MusicDevice, msg, length); + MusicDeviceSysEx(au_MusicDevice, msg, length); - free(buf); - } + free(buf); } MidiDriver *MidiDriver_CORE_create() { diff --git a/backends/midi/coremidi.cpp b/backends/midi/coremidi.cpp new file mode 100644 index 0000000000..f60b84cc5d --- /dev/null +++ b/backends/midi/coremidi.cpp @@ -0,0 +1,162 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2005 The ScummVM project + * + * 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; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Header$ + */ + +#ifdef MACOSX + +#include "common/stdafx.h" +#include "common/config-manager.h" +#include "common/util.h" +#include "sound/mpu401.h" + +#include <CoreMIDI/CoreMIDI.h> + + + +/* +For information on how to unify the CoreMidi and MusicDevice code: + +http://lists.apple.com/archives/Coreaudio-api/2005/Jun/msg00194.html +http://lists.apple.com/archives/coreaudio-api/2003/Mar/msg00248.html +http://lists.apple.com/archives/coreaudio-api/2003/Jul/msg00137.html + +*/ + + +/* CoreMIDI MIDI driver + * By Max Horn + */ +class MidiDriver_CoreMIDI : public MidiDriver_MPU401 { +public: + MidiDriver_CoreMIDI(); + ~MidiDriver_CoreMIDI(); + int open(); + void close(); + void send(uint32 b); + void sysEx(byte *msg, uint16 length); + +private: + MIDIClientRef mClient; + MIDIPortRef mOutPort; + MIDIEndpointRef mDest; +}; + +MidiDriver_CoreMIDI::MidiDriver_CoreMIDI() + : mClient(0), mOutPort(0), mDest(0) { + + OSStatus err; + err = MIDIClientCreate(CFSTR("ScummVM MIDI Driver for OS X"), NULL, NULL, &mClient); +} + +MidiDriver_CoreMIDI::~MidiDriver_CoreMIDI() { + if (mClient) + MIDIClientDispose(mClient); + mClient = 0; +} + +int MidiDriver_CoreMIDI::open() { + if (mDest) + return MERR_ALREADY_OPEN; + + OSStatus err = noErr; + + mOutPort = 0; + + int dests = MIDIGetNumberOfDestinations(); + if (dests > 0 && mClient) { + mDest = MIDIGetDestination(0); + err = MIDIOutputPortCreate( mClient, + CFSTR("scummvm_output_port"), + &mOutPort); + } else { + return MERR_DEVICE_NOT_AVAILABLE; + } + + if (err != noErr) + return MERR_CANNOT_CONNECT; + + return 0; +} + +void MidiDriver_CoreMIDI::close() { + MidiDriver_MPU401::close(); + + if (mOutPort && mDest) { + MIDIPortDispose(mOutPort); + mOutPort = 0; + mDest = 0; + } +} + +void MidiDriver_CoreMIDI::send(uint32 b) { + assert(mOutPort != NULL); + assert(mDest != NULL); + + byte status_byte = (b & 0x000000FF); + byte first_byte = (b & 0x0000FF00) >> 8; + byte second_byte = (b & 0x00FF0000) >> 16; + + MIDIPacketList packetList; + MIDIPacket *packet = &packetList.packet[0]; + + packetList.numPackets = 1; + + packet->timeStamp = 0; + packet->length = 3; + packet->data[0] = status_byte; + packet->data[1] = first_byte; + packet->data[2] = second_byte; + + MIDISend(mOutPort, mDest, &packetList); + +} + +void MidiDriver_CoreMIDI::sysEx(byte *msg, uint16 length) { + assert(mOutPort != NULL); + assert(mDest != NULL); + + byte buf[384]; + MIDIPacketList *packetList = (MIDIPacketList *)buf; + MIDIPacket *packet = packetList->packet; + + assert(sizeof(buf) >= sizeof(UInt32) + sizeof(MIDITimeStamp) + sizeof(UInt16) + length + 2); + + packetList->numPackets = 1; + + packet->timeStamp = 0; + + // Add SysEx frame if missing + if (*msg != 0xF0) { + packet->length = length + 2; + packet->data[0] = 0xF0; + memcpy(packet->data + 1, msg, length); + packet->data[length + 1] = 0xF7; + } else { + packet->length = length; + memcpy(packet->data, msg, length); + } + + MIDISend(mOutPort, mDest, packetList); +} + +MidiDriver *MidiDriver_CoreMIDI_create() { + return new MidiDriver_CoreMIDI(); +} + +#endif // MACOSX diff --git a/backends/module.mk b/backends/module.mk index 737f126c6a..b861404bc1 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS := \ backends/fs/amigaos4/amigaos4-fs.o \ backends/midi/alsa.o \ backends/midi/coreaudio.o \ + backends/midi/coremidi.o \ backends/midi/morphos.o \ backends/midi/null.o \ backends/midi/quicktime.o \ |