# 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 */