Navigation Menu

Skip to content

Commit

Permalink
Rewrote native Mac OS X MIDI support to be 10.6 and 64-bit clean.
Browse files Browse the repository at this point in the history
This uses Core MIDI now, instead of QuickTime, so it's Snow Leopard and 64-bit
 compatible. There's one deprecated API used (still available in 10.6 and
 64-bit, though), that is cool for 10.3 to 10.5...you can flip an #if to get
 the 10.5-and-later, undeprecated API.

This is initial, first shot stuff, but it works with playmus. Please test!

Only updated configure script; Xcode project needs updating still.
  • Loading branch information
icculus committed Oct 18, 2009
1 parent a844b90 commit 57a4967
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 5 deletions.
6 changes: 2 additions & 4 deletions configure.in
Expand Up @@ -283,10 +283,8 @@ AC_HELP_STRING([--enable-music-native-midi], [enable native MIDI music output [[
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lwinmm"
;;
*-*-darwin*)
# This doesn't work on Mac OS X 10.5+
# Max Horn (the original author) recommends disabling it for now.
#use_music_native_midi=yes
#EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuickTime -Wl,-framework,CoreServices"
use_music_native_midi=yes
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,CoreServices"
;;
esac
if test x$use_music_native_midi = xyes; then
Expand Down
2 changes: 1 addition & 1 deletion native_midi/native_midi_mac.c
Expand Up @@ -22,7 +22,7 @@
#include "SDL_config.h"
#include "SDL_endian.h"

#if __MACOS__ || __MACOSX__
#if __MACOS__ /*|| __MACOSX__ */

#include "native_midi.h"
#include "native_midi_common.h"
Expand Down
242 changes: 242 additions & 0 deletions native_midi/native_midi_macosx.c
@@ -0,0 +1,242 @@
/*
native_midi_macosx: Native Midi support on Mac OS X for the SDL_mixer library
Copyright (C) 2009 Ryan C. Gordon
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Ryan C. Gordon
icculus@icculus.org
*/

/* This is Mac OS X only, using Core MIDI.
Mac OS 9 support via QuickTime is in native_midi_mac.c */

#include "SDL_config.h"

#if __MACOSX__

#include <AudioToolbox/AudioToolbox.h>

#include "SDL_endian.h"
#include "native_midi.h"

/* Native Midi song */
struct _NativeMidiSong
{
MusicPlayer player;
MusicSequence sequence;
MusicTimeStamp endTime;
};

static NativeMidiSong *currentsong = NULL;

static OSStatus
GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
{
// http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
// figure out sequence length
UInt32 ntracks, i;
MusicTimeStamp sequenceLength = 0;
OSStatus err;

err = MusicSequenceGetTrackCount(sequence, &ntracks);
if (err != noErr)
return err;

for (i = 0; i < ntracks; ++i)
{
MusicTrack track;
MusicTimeStamp tracklen = 0;
UInt32 tracklenlen = sizeof (tracklen);

err = MusicSequenceGetIndTrack(sequence, i, &track);
if (err != noErr)
return err;

err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
&tracklen, &tracklenlen);
if (err != noErr)
return err;

if (sequenceLength < tracklen)
sequenceLength = tracklen;
}

*_sequenceLength = sequenceLength;

return noErr;
}


int native_midi_detect()
{
return 1; /* always available. */
}

NativeMidiSong *native_midi_loadsong(const char *midifile)
{
NativeMidiSong *retval = NULL;
SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
if (rw != NULL) {
retval = native_midi_loadsong_RW(rw);
SDL_RWclose(rw);
}

return retval;
}

NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
{
NativeMidiSong *retval = NULL;
void *buf = NULL;
int len = 0;
CFDataRef data = NULL;

if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
goto fail;
len = SDL_RWtell(rw);
if (len < 0)
goto fail;
if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
goto fail;

buf = malloc(len);
if (buf == NULL)
goto fail;

if (SDL_RWread(rw, buf, len, 1) != 1)
goto fail;

retval = malloc(sizeof(NativeMidiSong));
if (retval == NULL)
goto fail;

memset(retval, '\0', sizeof (*retval));

if (NewMusicPlayer(&retval->player) != noErr)
goto fail;
if (NewMusicSequence(&retval->sequence) != noErr)
goto fail;

data = CFDataCreate(NULL, (const UInt8 *) buf, len);
if (data == NULL)
goto fail;

free(buf);
buf = NULL;

#if 1 /* this is deprecated, but works back to 10.3 */
if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
goto fail;
#else /* not deprecated, but requires 10.5 or later */
if (MusicSequenceLoadData(retval->sequence, data, 0, 0) != noErr)
goto fail;
#endif

CFRelease(data);
data = NULL;

if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
goto fail;

if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
goto fail;

return retval;

fail:
if (retval) {
if (retval->sequence)
DisposeMusicSequence(retval->sequence);
if (retval->player)
DisposeMusicPlayer(retval->player);
free(retval);
}

if (data)
CFRelease(data);

if (buf)
free(buf);

return NULL;
}

void native_midi_freesong(NativeMidiSong *song)
{
if (song != NULL) {
if (currentsong == song)
currentsong = NULL;
MusicPlayerStop(song->player);
DisposeMusicSequence(song->sequence);
DisposeMusicPlayer(song->player);
free(song);
}
}

void native_midi_start(NativeMidiSong *song)
{
if (song == NULL)
return;

SDL_PauseAudio(1);
SDL_UnlockAudio();

if (currentsong)
MusicPlayerStop(currentsong->player);

currentsong = song;
MusicPlayerStart(song->player);

SDL_LockAudio();
SDL_PauseAudio(0);
}

void native_midi_stop()
{
if (currentsong) {
SDL_PauseAudio(1);
SDL_UnlockAudio();
MusicPlayerStop(currentsong->player);
currentsong = NULL;
SDL_LockAudio();
SDL_PauseAudio(0);
}
}

int native_midi_active()
{
MusicTimeStamp currentTime = 0;
if (currentsong == NULL)
return 0;

MusicPlayerGetTime(currentsong->player, &currentTime);
return ((currentTime < currentsong->endTime) ||
(currentTime >= kMusicTimeStamp_EndOfTrack));
}

void native_midi_setvolume(int volume)
{
/* !!! FIXME: call MusicSequenceGetAUGraph(), figure out where the output
!!! FIXME: audio unit is, and change its gain */
}

const char *native_midi_error(void)
{
return ""; /* !!! FIXME */
}

#endif /* Mac OS X native MIDI support */

0 comments on commit 57a4967

Please sign in to comment.