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 \ | 
