00001
00002
00003
00004
00005
00006
00007
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
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
00064
00065
00066
00067
00068
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;
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
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
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
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