OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

cocoa_m.cpp
Go to the documentation of this file.
1 /* $Id: cocoa_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
16 #ifdef WITH_COCOA
17
18 #include "../stdafx.h"
19 #include "../os/macosx/macos.h"
20 #include "cocoa_m.h"
21 #include "../debug.h"
22
23 #define Rect OTTDRect
24 #define Point OTTDPoint
25 #include <CoreServices/CoreServices.h>
26 #include <AudioUnit/AudioUnit.h>
27 #include <AudioToolbox/AudioToolbox.h>
28 #undef Rect
29 #undef Point
30
31 #include "../safeguards.h"
32
33 static FMusicDriver_Cocoa iFMusicDriver_Cocoa;
34
35
36 static MusicPlayer _player = NULL;
37 static MusicSequence _sequence = NULL;
38 static MusicTimeStamp _seq_length = 0;
39 static bool _playing = false;
40 static byte _volume = 127;
41
42
44 static void DoSetVolume()
45 {
46 if (_sequence == NULL) return;
47
48 AUGraph graph;
49 MusicSequenceGetAUGraph(_sequence, &graph);
50
51 AudioUnit output_unit = NULL;
52
53 /* Get output audio unit */
54 UInt32 node_count = 0;
55 AUGraphGetNodeCount(graph, &node_count);
56 for (UInt32 i = 0; i < node_count; i++) {
57 AUNode node;
58 AUGraphGetIndNode(graph, i, &node);
59
60 AudioUnit unit;
61 OSType comp_type = 0;
62
63 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
64 if (MacOSVersionIsAtLeast(10, 5, 0)) {
65 /* The 10.6 SDK has changed the function prototype of
66 * AUGraphNodeInfo. This is a binary compatible change,
67 * but we need to get the type declaration right or
68 * risk compilation errors. The header AudioComponent.h
69 * was introduced in 10.6 so use it to decide which
70 * type definition to use. */
71 #ifdef __AUDIOCOMPONENT_H__
72 AudioComponentDescription desc;
73 #else
74 ComponentDescription desc;
75 #endif
76 AUGraphNodeInfo(graph, node, &desc, &unit);
77 comp_type = desc.componentType;
78 } else
79 #endif
80 {
81 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
82 ComponentDescription desc;
83 AUGraphGetNodeInfo(graph, node, &desc, NULL, NULL, &unit);
84 comp_type = desc.componentType;
85 #endif
86 }
87
88 if (comp_type == kAudioUnitType_Output) {
89 output_unit = unit;
90 break;
91 }
92 }
93 if (output_unit == NULL) {
94 DEBUG(driver, 1, "cocoa_m: Failed to get output node to set volume");
95 return;
96 }
97
98 Float32 vol = _volume / 127.0f; // 0 - +127 -> 0.0 - 1.0
99 AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0);
100 }
101
102
106 const char *MusicDriver_Cocoa::Start(const char * const *parm)
107 {
108 if (NewMusicPlayer(&_player) != noErr) return "failed to create music player";
109
110 return NULL;
111 }
112
113
117 bool MusicDriver_Cocoa::IsSongPlaying()
118 {
119 if (!_playing) return false;
120
121 MusicTimeStamp time = 0;
122 MusicPlayerGetTime(_player, &time);
123 return time < _seq_length;
124 }
125
126
130 void MusicDriver_Cocoa::Stop()
131 {
132 if (_player != NULL) DisposeMusicPlayer(_player);
133 if (_sequence != NULL) DisposeMusicSequence(_sequence);
134 }
135
136
142 void MusicDriver_Cocoa::PlaySong(const char *filename)
143 {
144 DEBUG(driver, 2, "cocoa_m: trying to play '%s'", filename);
145
146 this->StopSong();
147 if (_sequence != NULL) {
148 DisposeMusicSequence(_sequence);
149 _sequence = NULL;
150 }
151
152 if (NewMusicSequence(&_sequence) != noErr) {
153 DEBUG(driver, 0, "cocoa_m: Failed to create music sequence");
154 return;
155 }
156
157 const char *os_file = OTTD2FS(filename);
158 CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file, strlen(os_file), false);
159
160 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
161 if (MacOSVersionIsAtLeast(10, 5, 0)) {
162 if (MusicSequenceFileLoad(_sequence, url, 0, 0) != noErr) {
163 DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file");
164 CFRelease(url);
165 return;
166 }
167 } else
168 #endif
169 {
170 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
171 FSRef ref_file;
172 if (!CFURLGetFSRef(url, &ref_file)) {
173 DEBUG(driver, 0, "cocoa_m: Failed to make FSRef");
174 CFRelease(url);
175 return;
176 }
177 if (MusicSequenceLoadSMFWithFlags(_sequence, &ref_file, 0) != noErr) {
178 DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file old style");
179 CFRelease(url);
180 return;
181 }
182 #endif
183 }
184 CFRelease(url);
185
186 /* Construct audio graph */
187 AUGraph graph = NULL;
188
189 MusicSequenceGetAUGraph(_sequence, &graph);
190 AUGraphOpen(graph);
191 if (AUGraphInitialize(graph) != noErr) {
192 DEBUG(driver, 0, "cocoa_m: Failed to initialize AU graph");
193 return;
194 }
195
196 /* Figure out sequence length */
197 UInt32 num_tracks;
198 MusicSequenceGetTrackCount(_sequence, &num_tracks);
199 _seq_length = 0;
200 for (UInt32 i = 0; i < num_tracks; i++) {
201 MusicTrack track = NULL;
202 MusicTimeStamp track_length = 0;
203 UInt32 prop_size = sizeof(MusicTimeStamp);
204 MusicSequenceGetIndTrack(_sequence, i, &track);
205 MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &track_length, &prop_size);
206 if (track_length > _seq_length) _seq_length = track_length;
207 }
208 /* Add 8 beats for reverb/long note release */
209 _seq_length += 8;
210
211 DoSetVolume();
212 MusicPlayerSetSequence(_player, _sequence);
213 MusicPlayerPreroll(_player);
214 if (MusicPlayerStart(_player) != noErr) return;
215 _playing = true;
216
217 DEBUG(driver, 3, "cocoa_m: playing '%s'", filename);
218 }
219
220
224 void MusicDriver_Cocoa::StopSong()
225 {
226 MusicPlayerStop(_player);
227 MusicPlayerSetSequence(_player, NULL);
228 _playing = false;
229 }
230
231
237 void MusicDriver_Cocoa::SetVolume(byte vol)
238 {
239 _volume = vol;
240 DoSetVolume();
241 }
242
243 #endif /* WITH_COCOA */