16 #include "../stdafx.h" 17 #include "../os/macosx/macos.h" 19 #include "midifile.hpp" 21 #include "../base_media_base.h" 23 #include <CoreServices/CoreServices.h> 24 #include <AudioUnit/AudioUnit.h> 25 #include <AudioToolbox/AudioToolbox.h> 27 #include "../safeguards.h" 29 #if !defined(HAVE_OSX_1011_SDK) 30 #define kMusicSequenceFile_AnyType 0 36 static MusicPlayer _player =
nullptr;
37 static MusicSequence _sequence =
nullptr;
38 static MusicTimeStamp _seq_length = 0;
39 static bool _playing =
false;
40 static byte _volume = 127;
44 static void DoSetVolume()
46 if (_sequence ==
nullptr)
return;
49 MusicSequenceGetAUGraph(_sequence, &graph);
51 AudioUnit output_unit =
nullptr;
54 UInt32 node_count = 0;
55 AUGraphGetNodeCount(graph, &node_count);
56 for (UInt32 i = 0; i < node_count; i++) {
58 AUGraphGetIndNode(graph, i, &node);
63 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 71 #if defined(__AUDIOCOMPONENT_H__) || defined(HAVE_OSX_107_SDK) 72 AudioComponentDescription desc;
74 ComponentDescription desc;
76 AUGraphNodeInfo(graph, node, &desc, &unit);
77 comp_type = desc.componentType;
81 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) 82 ComponentDescription desc;
83 AUGraphGetNodeInfo(graph, node, &desc,
nullptr,
nullptr, &unit);
84 comp_type = desc.componentType;
88 if (comp_type == kAudioUnitType_Output) {
93 if (output_unit ==
nullptr) {
94 DEBUG(driver, 1,
"cocoa_m: Failed to get output node to set volume");
98 Float32 vol = _volume / 127.0f;
99 AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0);
108 if (NewMusicPlayer(&_player) != noErr)
return "failed to create music player";
119 if (!_playing)
return false;
121 MusicTimeStamp time = 0;
122 MusicPlayerGetTime(_player, &time);
123 return time < _seq_length;
132 if (_player !=
nullptr) DisposeMusicPlayer(_player);
133 if (_sequence !=
nullptr) DisposeMusicSequence(_sequence);
146 DEBUG(driver, 2,
"cocoa_m: trying to play '%s'", filename.c_str());
149 if (_sequence !=
nullptr) {
150 DisposeMusicSequence(_sequence);
154 if (filename.empty())
return;
156 if (NewMusicSequence(&_sequence) != noErr) {
157 DEBUG(driver, 0,
"cocoa_m: Failed to create music sequence");
161 const char *os_file =
OTTD2FS(filename.c_str());
162 CFAutoRelease<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (
const UInt8*)os_file, strlen(os_file),
false));
164 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 166 if (MusicSequenceFileLoad(_sequence, url.get(), kMusicSequenceFile_AnyType, 0) != noErr) {
167 DEBUG(driver, 0,
"cocoa_m: Failed to load MIDI file");
173 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) 175 if (!CFURLGetFSRef(url.get(), &ref_file)) {
176 DEBUG(driver, 0,
"cocoa_m: Failed to make FSRef");
179 if (MusicSequenceLoadSMFWithFlags(_sequence, &ref_file, 0) != noErr) {
180 DEBUG(driver, 0,
"cocoa_m: Failed to load MIDI file old style");
187 AUGraph graph =
nullptr;
189 MusicSequenceGetAUGraph(_sequence, &graph);
191 if (AUGraphInitialize(graph) != noErr) {
192 DEBUG(driver, 0,
"cocoa_m: Failed to initialize AU graph");
198 MusicSequenceGetTrackCount(_sequence, &num_tracks);
200 for (UInt32 i = 0; i < num_tracks; i++) {
201 MusicTrack track =
nullptr;
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;
212 MusicPlayerSetSequence(_player, _sequence);
213 MusicPlayerPreroll(_player);
214 if (MusicPlayerStart(_player) != noErr)
return;
217 DEBUG(driver, 3,
"cocoa_m: playing '%s'", filename.c_str());
226 MusicPlayerStop(_player);
227 MusicPlayerSetSequence(_player,
nullptr);
Metadata about a music track.
void SetVolume(byte vol) override
Set the volume, if possible.
static bool MacOSVersionIsAtLeast(long major, long minor, long bugfix)
Check if we are at least running on the specified version of Mac OS.
void Stop() override
Stop this driver.
const char * Start(const char *const *param) override
Start this driver.
bool IsSongPlaying() override
Are we currently playing a song?
Base of music playback via CoreAudio.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
#define DEBUG(name, level,...)
Output a line of debugging information.
std::unique_ptr< typename std::remove_pointer< T >::type, CFDeleter< typename std::remove_pointer< T >::type > > CFAutoRelease
Specialisation of std::unique_ptr for CoreFoundation objects.
static std::string GetSMFFile(const MusicSongInfo &song)
Get the name of a Standard MIDI File for a given song.
void StopSong() override
Stop playing the current song.
void PlaySong(const MusicSongInfo &song) override
Play a particular song.