Rewrote native Mac OS X MIDI support to be 10.6 and 64-bit clean.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 18 Oct 2009 09:49:51 +0000
changeset 458c42a228f3d90
parent 457 ad0be8fb4cf9
child 459 9ba6fd6fe73e
Rewrote native Mac OS X MIDI support to be 10.6 and 64-bit clean.

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.
configure.in
native_midi/native_midi_mac.c
native_midi/native_midi_macosx.c
     1.1 --- a/configure.in	Sun Oct 18 06:08:22 2009 +0000
     1.2 +++ b/configure.in	Sun Oct 18 09:49:51 2009 +0000
     1.3 @@ -283,10 +283,8 @@
     1.4                  EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lwinmm"
     1.5                  ;;
     1.6              *-*-darwin*)
     1.7 -                # This doesn't work on Mac OS X 10.5+
     1.8 -                # Max Horn (the original author) recommends disabling it for now.
     1.9 -                #use_music_native_midi=yes
    1.10 -                #EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuickTime -Wl,-framework,CoreServices"
    1.11 +                use_music_native_midi=yes
    1.12 +                EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,CoreServices"
    1.13                  ;;
    1.14          esac
    1.15          if test x$use_music_native_midi = xyes; then
     2.1 --- a/native_midi/native_midi_mac.c	Sun Oct 18 06:08:22 2009 +0000
     2.2 +++ b/native_midi/native_midi_mac.c	Sun Oct 18 09:49:51 2009 +0000
     2.3 @@ -22,7 +22,7 @@
     2.4  #include "SDL_config.h"
     2.5  #include "SDL_endian.h"
     2.6  
     2.7 -#if __MACOS__ || __MACOSX__
     2.8 +#if __MACOS__ /*|| __MACOSX__ */
     2.9  
    2.10  #include "native_midi.h"
    2.11  #include "native_midi_common.h"
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/native_midi/native_midi_macosx.c	Sun Oct 18 09:49:51 2009 +0000
     3.3 @@ -0,0 +1,242 @@
     3.4 +/*
     3.5 +    native_midi_macosx:  Native Midi support on Mac OS X for the SDL_mixer library
     3.6 +    Copyright (C) 2009  Ryan C. Gordon
     3.7 +
     3.8 +    This library is free software; you can redistribute it and/or
     3.9 +    modify it under the terms of the GNU Library General Public
    3.10 +    License as published by the Free Software Foundation; either
    3.11 +    version 2 of the License, or (at your option) any later version.
    3.12 +
    3.13 +    This library is distributed in the hope that it will be useful,
    3.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    3.16 +    Library General Public License for more details.
    3.17 +
    3.18 +    You should have received a copy of the GNU Library General Public
    3.19 +    License along with this library; if not, write to the Free
    3.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    3.21 +
    3.22 +    Ryan C. Gordon
    3.23 +    icculus@icculus.org
    3.24 +*/
    3.25 +
    3.26 +/* This is Mac OS X only, using Core MIDI.
    3.27 +   Mac OS 9 support via QuickTime is in native_midi_mac.c */
    3.28 +
    3.29 +#include "SDL_config.h"
    3.30 +
    3.31 +#if __MACOSX__
    3.32 +
    3.33 +#include <AudioToolbox/AudioToolbox.h>
    3.34 +
    3.35 +#include "SDL_endian.h"
    3.36 +#include "native_midi.h"
    3.37 +
    3.38 +/* Native Midi song */
    3.39 +struct _NativeMidiSong
    3.40 +{
    3.41 +    MusicPlayer player;
    3.42 +    MusicSequence sequence;
    3.43 +    MusicTimeStamp endTime;
    3.44 +};
    3.45 +
    3.46 +static NativeMidiSong *currentsong = NULL;
    3.47 +
    3.48 +static OSStatus
    3.49 +GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
    3.50 +{
    3.51 +    // http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
    3.52 +    // figure out sequence length
    3.53 +    UInt32 ntracks, i;
    3.54 +    MusicTimeStamp sequenceLength = 0;
    3.55 +    OSStatus err;
    3.56 +
    3.57 +    err = MusicSequenceGetTrackCount(sequence, &ntracks);
    3.58 +    if (err != noErr)
    3.59 +        return err;
    3.60 +
    3.61 +    for (i = 0; i < ntracks; ++i)
    3.62 +    {
    3.63 +        MusicTrack track;
    3.64 +        MusicTimeStamp tracklen = 0;
    3.65 +        UInt32 tracklenlen = sizeof (tracklen);
    3.66 +
    3.67 +        err = MusicSequenceGetIndTrack(sequence, i, &track);
    3.68 +        if (err != noErr)
    3.69 +            return err;
    3.70 +
    3.71 +        err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
    3.72 +                                    &tracklen, &tracklenlen);
    3.73 +        if (err != noErr)
    3.74 +            return err;
    3.75 +
    3.76 +        if (sequenceLength < tracklen)
    3.77 +            sequenceLength = tracklen;
    3.78 +    }
    3.79 +
    3.80 +    *_sequenceLength = sequenceLength;
    3.81 +
    3.82 +    return noErr;
    3.83 +}
    3.84 +
    3.85 +
    3.86 +int native_midi_detect()
    3.87 +{
    3.88 +    return 1;  /* always available. */
    3.89 +}
    3.90 +
    3.91 +NativeMidiSong *native_midi_loadsong(const char *midifile)
    3.92 +{
    3.93 +    NativeMidiSong *retval = NULL;
    3.94 +    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
    3.95 +    if (rw != NULL) {
    3.96 +        retval = native_midi_loadsong_RW(rw);
    3.97 +        SDL_RWclose(rw);
    3.98 +    }
    3.99 +
   3.100 +    return retval;
   3.101 +}
   3.102 +
   3.103 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
   3.104 +{
   3.105 +    NativeMidiSong *retval = NULL;
   3.106 +    void *buf = NULL;
   3.107 +    int len = 0;
   3.108 +    CFDataRef data = NULL;
   3.109 +
   3.110 +    if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
   3.111 +        goto fail;
   3.112 +    len = SDL_RWtell(rw);
   3.113 +    if (len < 0)
   3.114 +        goto fail;
   3.115 +    if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
   3.116 +        goto fail;
   3.117 +
   3.118 +    buf = malloc(len);
   3.119 +    if (buf == NULL)
   3.120 +        goto fail;
   3.121 +
   3.122 +    if (SDL_RWread(rw, buf, len, 1) != 1)
   3.123 +        goto fail;
   3.124 +
   3.125 +    retval = malloc(sizeof(NativeMidiSong));
   3.126 +    if (retval == NULL)
   3.127 +        goto fail;
   3.128 +
   3.129 +    memset(retval, '\0', sizeof (*retval));
   3.130 +
   3.131 +    if (NewMusicPlayer(&retval->player) != noErr)
   3.132 +        goto fail;
   3.133 +    if (NewMusicSequence(&retval->sequence) != noErr)
   3.134 +        goto fail;
   3.135 +
   3.136 +    data = CFDataCreate(NULL, (const UInt8 *) buf, len);
   3.137 +    if (data == NULL)
   3.138 +        goto fail;
   3.139 +
   3.140 +    free(buf);
   3.141 +    buf = NULL;
   3.142 +
   3.143 +    #if 1 /* this is deprecated, but works back to 10.3 */
   3.144 +    if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
   3.145 +        goto fail;
   3.146 +    #else  /* not deprecated, but requires 10.5 or later */
   3.147 +    if (MusicSequenceLoadData(retval->sequence, data, 0, 0) != noErr)
   3.148 +        goto fail;
   3.149 +    #endif
   3.150 +
   3.151 +    CFRelease(data);
   3.152 +    data = NULL;
   3.153 +
   3.154 +    if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
   3.155 +        goto fail;
   3.156 +
   3.157 +    if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
   3.158 +        goto fail;
   3.159 +
   3.160 +    return retval;
   3.161 +
   3.162 +fail:
   3.163 +    if (retval) {
   3.164 +        if (retval->sequence)
   3.165 +            DisposeMusicSequence(retval->sequence);
   3.166 +        if (retval->player)
   3.167 +            DisposeMusicPlayer(retval->player);
   3.168 +        free(retval);
   3.169 +    }
   3.170 +
   3.171 +    if (data)
   3.172 +        CFRelease(data);
   3.173 +
   3.174 +    if (buf)
   3.175 +        free(buf);
   3.176 +
   3.177 +    return NULL;
   3.178 +}
   3.179 +
   3.180 +void native_midi_freesong(NativeMidiSong *song)
   3.181 +{
   3.182 +    if (song != NULL) {
   3.183 +        if (currentsong == song)
   3.184 +            currentsong = NULL;
   3.185 +        MusicPlayerStop(song->player);
   3.186 +        DisposeMusicSequence(song->sequence);
   3.187 +        DisposeMusicPlayer(song->player);
   3.188 +        free(song);
   3.189 +    }
   3.190 +}
   3.191 +
   3.192 +void native_midi_start(NativeMidiSong *song)
   3.193 +{
   3.194 +    if (song == NULL)
   3.195 +        return;
   3.196 +
   3.197 +	SDL_PauseAudio(1);
   3.198 +	SDL_UnlockAudio();
   3.199 +
   3.200 +    if (currentsong)
   3.201 +        MusicPlayerStop(currentsong->player);
   3.202 +
   3.203 +    currentsong = song;
   3.204 +    MusicPlayerStart(song->player);
   3.205 +
   3.206 +	SDL_LockAudio();
   3.207 +	SDL_PauseAudio(0);
   3.208 +}
   3.209 +
   3.210 +void native_midi_stop()
   3.211 +{
   3.212 +    if (currentsong) {
   3.213 +    	SDL_PauseAudio(1);
   3.214 +	    SDL_UnlockAudio();
   3.215 +        MusicPlayerStop(currentsong->player);
   3.216 +        currentsong = NULL;
   3.217 +    	SDL_LockAudio();
   3.218 +	    SDL_PauseAudio(0);
   3.219 +    }
   3.220 +}
   3.221 +
   3.222 +int native_midi_active()
   3.223 +{
   3.224 +    MusicTimeStamp currentTime = 0;
   3.225 +    if (currentsong == NULL)
   3.226 +        return 0;
   3.227 +
   3.228 +    MusicPlayerGetTime(currentsong->player, &currentTime);
   3.229 +    return ((currentTime < currentsong->endTime) ||
   3.230 +            (currentTime >= kMusicTimeStamp_EndOfTrack));
   3.231 +}
   3.232 +
   3.233 +void native_midi_setvolume(int volume)
   3.234 +{
   3.235 +    /* !!! FIXME: call MusicSequenceGetAUGraph(), figure out where the output
   3.236 +       !!! FIXME:  audio unit is, and change its gain */
   3.237 +}
   3.238 +
   3.239 +const char *native_midi_error(void)
   3.240 +{
   3.241 +    return "";  /* !!! FIXME */
   3.242 +}
   3.243 +
   3.244 +#endif /* Mac OS X native MIDI support */
   3.245 +