native_midi_macosx.c
上传用户:nini_0081
上传日期:2022-07-21
资源大小:2628k
文件大小:8k
源码类别:

多媒体编程

开发平台:

DOS

  1. /*
  2.     native_midi_macosx:  Native Midi support on Mac OS X for the SDL_mixer library
  3.     Copyright (C) 2009  Ryan C. Gordon
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Ryan C. Gordon
  16.     icculus@icculus.org
  17. */
  18. /* This is Mac OS X only, using Core MIDI.
  19.    Mac OS 9 support via QuickTime is in native_midi_mac.c */
  20. #include "SDL_config.h"
  21. #if __MACOSX__
  22. #include <Carbon/Carbon.h>
  23. #include <AudioToolbox/AudioToolbox.h>
  24. #include <AvailabilityMacros.h>
  25. #include "../SDL_mixer.h"
  26. #include "SDL_endian.h"
  27. #include "native_midi.h"
  28. /* Native Midi song */
  29. struct _NativeMidiSong
  30. {
  31.     MusicPlayer player;
  32.     MusicSequence sequence;
  33.     MusicTimeStamp endTime;
  34.     AudioUnit audiounit;
  35. };
  36. static NativeMidiSong *currentsong = NULL;
  37. static int latched_volume = MIX_MAX_VOLUME;
  38. static OSStatus
  39. GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
  40. {
  41.     // http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
  42.     // figure out sequence length
  43.     UInt32 ntracks, i;
  44.     MusicTimeStamp sequenceLength = 0;
  45.     OSStatus err;
  46.     err = MusicSequenceGetTrackCount(sequence, &ntracks);
  47.     if (err != noErr)
  48.         return err;
  49.     for (i = 0; i < ntracks; ++i)
  50.     {
  51.         MusicTrack track;
  52.         MusicTimeStamp tracklen = 0;
  53.         UInt32 tracklenlen = sizeof (tracklen);
  54.         err = MusicSequenceGetIndTrack(sequence, i, &track);
  55.         if (err != noErr)
  56.             return err;
  57.         err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
  58.                                     &tracklen, &tracklenlen);
  59.         if (err != noErr)
  60.             return err;
  61.         if (sequenceLength < tracklen)
  62.             sequenceLength = tracklen;
  63.     }
  64.     *_sequenceLength = sequenceLength;
  65.     return noErr;
  66. }
  67. /* we're looking for the sequence output audiounit. */
  68. static OSStatus
  69. GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit)
  70. {
  71.     AUGraph graph;
  72.     UInt32 nodecount, i;
  73.     OSStatus err;
  74.     err = MusicSequenceGetAUGraph(sequence, &graph);
  75.     if (err != noErr)
  76.         return err;
  77.     err = AUGraphGetNodeCount(graph, &nodecount);
  78.     if (err != noErr)
  79.         return err;
  80.     for (i = 0; i < nodecount; i++) {
  81.         AUNode node;
  82.         if (AUGraphGetIndNode(graph, i, &node) != noErr)
  83.             continue;  /* better luck next time. */
  84. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */
  85.         {
  86.             struct ComponentDescription desc;
  87.             UInt32 classdatasize = 0;
  88.             void *classdata = NULL;
  89.             err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize,
  90.                                      &classdata, aunit);
  91.             if (err != noErr)
  92.                 continue;
  93.             else if (desc.componentType != kAudioUnitType_Output)
  94.                 continue;
  95.             else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
  96.                 continue;
  97.         }
  98.         #else  /* not deprecated, but requires 10.5 or later */
  99.         {
  100.             AudioComponentDescription desc;
  101.             if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr)
  102.                 continue;
  103.             else if (desc.componentType != kAudioUnitType_Output)
  104.                 continue;
  105.             else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
  106.                 continue;
  107.         }
  108.         #endif
  109.         return noErr;  /* found it! */
  110.     }
  111.     return kAUGraphErr_NodeNotFound;
  112. }
  113. int native_midi_detect()
  114. {
  115.     return 1;  /* always available. */
  116. }
  117. NativeMidiSong *native_midi_loadsong(const char *midifile)
  118. {
  119.     NativeMidiSong *retval = NULL;
  120.     SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
  121.     if (rw != NULL) {
  122.         retval = native_midi_loadsong_RW(rw);
  123.         SDL_RWclose(rw);
  124.     }
  125.     return retval;
  126. }
  127. NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
  128. {
  129.     NativeMidiSong *retval = NULL;
  130.     void *buf = NULL;
  131.     int len = 0;
  132.     CFDataRef data = NULL;
  133.     if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
  134.         goto fail;
  135.     len = SDL_RWtell(rw);
  136.     if (len < 0)
  137.         goto fail;
  138.     if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
  139.         goto fail;
  140.     buf = malloc(len);
  141.     if (buf == NULL)
  142.         goto fail;
  143.     if (SDL_RWread(rw, buf, len, 1) != 1)
  144.         goto fail;
  145.     retval = malloc(sizeof(NativeMidiSong));
  146.     if (retval == NULL)
  147.         goto fail;
  148.     memset(retval, '', sizeof (*retval));
  149.     if (NewMusicPlayer(&retval->player) != noErr)
  150.         goto fail;
  151.     if (NewMusicSequence(&retval->sequence) != noErr)
  152.         goto fail;
  153.     data = CFDataCreate(NULL, (const UInt8 *) buf, len);
  154.     if (data == NULL)
  155.         goto fail;
  156.     free(buf);
  157.     buf = NULL;
  158.     #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 /* this is deprecated, but works back to 10.3 */
  159.     if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
  160.         goto fail;
  161.     #else  /* not deprecated, but requires 10.5 or later */
  162.     if (MusicSequenceFileLoadData(retval->sequence, data, 0, 0) != noErr)
  163.         goto fail;
  164.     #endif
  165.     CFRelease(data);
  166.     data = NULL;
  167.     if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
  168.         goto fail;
  169.     if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
  170.         goto fail;
  171.     return retval;
  172. fail:
  173.     if (retval) {
  174.         if (retval->sequence)
  175.             DisposeMusicSequence(retval->sequence);
  176.         if (retval->player)
  177.             DisposeMusicPlayer(retval->player);
  178.         free(retval);
  179.     }
  180.     if (data)
  181.         CFRelease(data);
  182.     if (buf)
  183.         free(buf);
  184.     return NULL;
  185. }
  186. void native_midi_freesong(NativeMidiSong *song)
  187. {
  188.     if (song != NULL) {
  189.         if (currentsong == song)
  190.             currentsong = NULL;
  191.         MusicPlayerStop(song->player);
  192.         DisposeMusicSequence(song->sequence);
  193.         DisposeMusicPlayer(song->player);
  194.         free(song);
  195.     }
  196. }
  197. void native_midi_start(NativeMidiSong *song)
  198. {
  199.     int vol;
  200.     if (song == NULL)
  201.         return;
  202.     SDL_PauseAudio(1);
  203.     SDL_UnlockAudio();
  204.     if (currentsong)
  205.         MusicPlayerStop(currentsong->player);
  206.     currentsong = song;
  207.     MusicPlayerStart(song->player);
  208.     GetSequenceAudioUnit(song->sequence, &song->audiounit);
  209.     vol = latched_volume;
  210.     latched_volume++;  /* just make this not match. */
  211.     native_midi_setvolume(vol);
  212.     SDL_LockAudio();
  213.     SDL_PauseAudio(0);
  214. }
  215. void native_midi_stop()
  216. {
  217.     if (currentsong) {
  218.         SDL_PauseAudio(1);
  219.         SDL_UnlockAudio();
  220.         MusicPlayerStop(currentsong->player);
  221.         currentsong = NULL;
  222.         SDL_LockAudio();
  223.         SDL_PauseAudio(0);
  224.     }
  225. }
  226. int native_midi_active()
  227. {
  228.     MusicTimeStamp currentTime = 0;
  229.     if (currentsong == NULL)
  230.         return 0;
  231.     MusicPlayerGetTime(currentsong->player, &currentTime);
  232.     return ((currentTime < currentsong->endTime) ||
  233.             (currentTime >= kMusicTimeStamp_EndOfTrack));
  234. }
  235. void native_midi_setvolume(int volume)
  236. {
  237.     if (latched_volume == volume)
  238.         return;
  239.     latched_volume = volume;
  240.     if ((currentsong) && (currentsong->audiounit)) {
  241.         const float floatvol = ((float) volume) / ((float) MIX_MAX_VOLUME);
  242.         AudioUnitSetParameter(currentsong->audiounit, kHALOutputParam_Volume,
  243.                               kAudioUnitScope_Global, 0, floatvol, 0);
  244.     }
  245. }
  246. const char *native_midi_error(void)
  247. {
  248.     return "";  /* !!! FIXME */
  249. }
  250. #endif /* Mac OS X native MIDI support */