cocoa_m.cpp

Go to the documentation of this file.
00001 /* $Id: cocoa_m.cpp 17710 2009-10-04 21:24:09Z michi_cc $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD 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, version 2.
00006  * OpenTTD 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.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00016 #ifdef WITH_COCOA
00017 
00018 #include "../stdafx.h"
00019 #include "../os/macosx/macos.h"
00020 #include "cocoa_m.h"
00021 #include "../debug.h"
00022 
00023 #define Rect        OTTDRect
00024 #define Point       OTTDPoint
00025 #include <CoreServices/CoreServices.h>
00026 #include <AudioUnit/AudioUnit.h>
00027 #include <AudioToolbox/AudioToolbox.h>
00028 #undef Rect
00029 #undef Point
00030 
00031 static FMusicDriver_Cocoa iFMusicDriver_Cocoa;
00032 
00033 
00034 static MusicPlayer    _player = NULL;
00035 static MusicSequence  _sequence = NULL;
00036 static MusicTimeStamp _seq_length = 0;
00037 static bool           _playing = false;
00038 static byte           _volume = 127;
00039 
00040 
00042 static void DoSetVolume()
00043 {
00044   if (_sequence == NULL) return;
00045 
00046   AUGraph graph;
00047   MusicSequenceGetAUGraph(_sequence, &graph);
00048 
00049   AudioUnit output_unit = NULL;
00050 
00051   /* Get output audio unit */
00052   UInt32 node_count = 0;
00053   AUGraphGetNodeCount(graph, &node_count);
00054   for (UInt32 i = 0; i < node_count; i++) {
00055     AUNode node;
00056     AUGraphGetIndNode(graph, i, &node);
00057 
00058     AudioUnit unit;
00059     OSType comp_type = 0;
00060 
00061 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
00062     if (MacOSVersionIsAtLeast(10, 5, 0)) {
00063       /* The 10.6 SDK has changed the function prototype of
00064        * AUGraphNodeInfo. This is a binary compatible change,
00065        * but we need to get the type declaration right or
00066        * risk compilation errors. The header AudioComponent.h
00067        * was introduced in 10.6 so use it to decide which
00068        * type definition to use. */
00069 #ifdef __AUDIOCOMPONENT_H__
00070       AudioComponentDescription desc;
00071 #else
00072       ComponentDescription desc;
00073 #endif
00074       AUGraphNodeInfo(graph, node, &desc, &unit);
00075       comp_type = desc.componentType;
00076     } else
00077 #endif
00078     {
00079 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
00080       ComponentDescription desc;
00081       AUGraphGetNodeInfo(graph, node, &desc, NULL, NULL, &unit);
00082       comp_type = desc.componentType;
00083 #endif
00084     }
00085 
00086     if (comp_type == kAudioUnitType_Output) {
00087       output_unit = unit;
00088       break;
00089     }
00090   }
00091   if (output_unit == NULL) {
00092     DEBUG(driver, 1, "cocoa_m: Failed to get output node to set volume");
00093     return;
00094   }
00095 
00096   Float32 vol = _volume / 127.0f;  // 0 - +127 -> 0.0 - 1.0
00097   AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0);
00098 }
00099 
00100 
00104 const char *MusicDriver_Cocoa::Start(const char * const *parm)
00105 {
00106   if (NewMusicPlayer(&_player) != noErr) return "failed to create music player";
00107 
00108   return NULL;
00109 }
00110 
00111 
00115 bool MusicDriver_Cocoa::IsSongPlaying()
00116 {
00117   if (!_playing) return false;
00118 
00119   MusicTimeStamp time = 0;
00120   MusicPlayerGetTime(_player, &time);
00121   return time < _seq_length;
00122 }
00123 
00124 
00128 void MusicDriver_Cocoa::Stop()
00129 {
00130   if (_player != NULL) DisposeMusicPlayer(_player);
00131   if (_sequence != NULL) DisposeMusicSequence(_sequence);
00132 }
00133 
00134 
00140 void MusicDriver_Cocoa::PlaySong(const char *filename)
00141 {
00142   DEBUG(driver, 2, "cocoa_m: trying to play '%s'", filename);
00143 
00144   this->StopSong();
00145   if (_sequence != NULL) {
00146     DisposeMusicSequence(_sequence);
00147     _sequence = NULL;
00148   }
00149 
00150   if (NewMusicSequence(&_sequence) != noErr) {
00151     DEBUG(driver, 0, "cocoa_m: Failed to create music sequence");
00152     return;
00153   }
00154 
00155   const char *os_file = OTTD2FS(filename);
00156   CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file, strlen(os_file), false);
00157 
00158 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
00159   if (MacOSVersionIsAtLeast(10, 5, 0)) {
00160     if (MusicSequenceFileLoad(_sequence, url, 0, 0) != noErr) {
00161       DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file");
00162       CFRelease(url);
00163       return;
00164     }
00165   } else
00166 #endif
00167   {
00168 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
00169     FSRef ref_file;
00170     if (!CFURLGetFSRef(url, &ref_file)) {
00171       DEBUG(driver, 0, "cocoa_m: Failed to make FSRef");
00172       CFRelease(url);
00173       return;
00174     }
00175     if (MusicSequenceLoadSMFWithFlags(_sequence, &ref_file, 0) != noErr) {
00176       DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file old style");
00177       CFRelease(url);
00178       return;
00179     }
00180 #endif
00181   }
00182   CFRelease(url);
00183 
00184   /* Construct audio graph */
00185   AUGraph graph = NULL;
00186 
00187   MusicSequenceGetAUGraph(_sequence, &graph);
00188   AUGraphOpen(graph);
00189   if (AUGraphInitialize(graph) != noErr) {
00190     DEBUG(driver, 0, "cocoa_m: Failed to initialize AU graph");
00191     return;
00192   }
00193 
00194   /* Figure out sequence length */
00195   UInt32 num_tracks;
00196   MusicSequenceGetTrackCount(_sequence, &num_tracks);
00197   _seq_length = 0;
00198   for (UInt32 i = 0; i < num_tracks; i++) {
00199     MusicTrack     track = NULL;
00200     MusicTimeStamp track_length = 0;
00201     UInt32         prop_size = sizeof(MusicTimeStamp);
00202     MusicSequenceGetIndTrack(_sequence, i, &track);
00203     MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &track_length, &prop_size);
00204     if (track_length > _seq_length) _seq_length = track_length;
00205   }
00206   /* Add 8 beats for reverb/long note release */
00207   _seq_length += 8;
00208 
00209   DoSetVolume();
00210   MusicPlayerSetSequence(_player, _sequence);
00211   MusicPlayerPreroll(_player);
00212   if (MusicPlayerStart(_player) != noErr) return;
00213   _playing = true;
00214 
00215   DEBUG(driver, 3, "cocoa_m: playing '%s'", filename);
00216 }
00217 
00218 
00222 void MusicDriver_Cocoa::StopSong()
00223 {
00224   MusicPlayerStop(_player);
00225   MusicPlayerSetSequence(_player, NULL);
00226   _playing = false;
00227 }
00228 
00229 
00235 void MusicDriver_Cocoa::SetVolume(byte vol)
00236 {
00237   _volume = vol;
00238   DoSetVolume();
00239 }
00240 
00241 #endif /* WITH_COCOA */

Generated on Thu Feb 4 17:20:24 2010 for OpenTTD by  doxygen 1.5.6