diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index a0e0026bf4d..0617939154e 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -220,6 +220,7 @@ function osdmodulestargetconf() elseif _OPTIONS["targetos"]=="macosx" then links { "AudioUnit.framework", + "AudioToolbox.framework", "CoreAudio.framework", "CoreServices.framework", } diff --git a/src/osd/modules/sound/coreaudio_sound.c b/src/osd/modules/sound/coreaudio_sound.c index da27ef486fd..4733b327b3a 100644 --- a/src/osd/modules/sound/coreaudio_sound.c +++ b/src/osd/modules/sound/coreaudio_sound.c @@ -15,6 +15,7 @@ #ifdef SDLMAME_MACOSX +#include #include #include #include @@ -26,7 +27,8 @@ public: sound_coreaudio() : osd_module(OSD_SOUND_PROVIDER, "coreaudio"), sound_module(), - m_open(false), + m_graph(NULL), + m_node_count(0), m_sample_bytes(0), m_headroom(0), m_buffer_size(0), @@ -43,7 +45,7 @@ public: { } - virtual int init(const osd_options &options); + virtual int init(osd_options const &options); virtual void exit(); // sound_module @@ -52,10 +54,19 @@ public: virtual void set_mastervolume(int attenuation); private: + struct node_detail + { + node_detail() : m_node(0), m_unit(NULL) { } + + AUNode m_node; + AudioUnit m_unit; + }; + enum { LATENCY_MIN = 1, - LATENCY_MAX = 5 + LATENCY_MAX = 5, + EFFECT_COUNT_MAX = 10 }; UINT32 clamped_latency() const { return MAX(MIN(m_audio_latency, LATENCY_MAX), LATENCY_MIN); } @@ -70,6 +81,8 @@ private: *d = (*s * m_scale) >> 7; } + int create_graph(osd_options const &options); + OSStatus render( AudioUnitRenderActionFlags *action_flags, const AudioTimeStamp *timestamp, @@ -85,8 +98,10 @@ private: UInt32 number_frames, AudioBufferList *data); - bool m_open; - AudioUnit m_output; + AUGraph m_graph; + unsigned m_node_count; + node_detail m_node_details[EFFECT_COUNT_MAX + 2]; + UINT32 m_sample_bytes; UINT32 m_headroom; UINT32 m_buffer_size; @@ -108,37 +123,9 @@ int sound_coreaudio::init(const osd_options &options) if (sample_rate() == 0) return 0; - // Get the Default Output AudioUnit component and open an instance - ComponentDescription output_desc; - output_desc.componentType = kAudioUnitType_Output; - output_desc.componentSubType = kAudioUnitSubType_DefaultOutput; - output_desc.componentManufacturer = kAudioUnitManufacturer_Apple; - output_desc.componentFlags = 0; - output_desc.componentFlagsMask = 0; - Component output_comp = FindNextComponent(NULL, &output_desc); - if (!output_comp) - { - osd_printf_error("Could not find Default Output AudioUnit component\n"); + // Create the output graph + if (0 != create_graph(options)) return -1; - } - err = OpenAComponent(output_comp, &m_output); - if (noErr != err) - { - osd_printf_error("Could not open Default Output AudioUnit component (%ld)\n", (long)err); - return -1; - } - - // Set render callback - AURenderCallbackStruct renderer; - renderer.inputProc = sound_coreaudio::render_callback; - renderer.inputProcRefCon = this; - err = AudioUnitSetProperty(m_output, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderer, sizeof(renderer)); - if (noErr != err) - { - CloseComponent(m_output); - osd_printf_error("Could not set audio output render callback (%ld)\n", (long)err); - return -1; - } // Set audio stream format for two-channel native-endian 16-bit packed linear PCM AudioStreamBasicDescription format; @@ -152,12 +139,17 @@ int sound_coreaudio::init(const osd_options &options) format.mBitsPerChannel = 16; format.mBytesPerFrame = format.mChannelsPerFrame * format.mBitsPerChannel / 8; format.mBytesPerPacket = format.mFramesPerPacket * format.mBytesPerFrame; - err = AudioUnitSetProperty(m_output, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof(format)); + err = AudioUnitSetProperty( + m_node_details[m_node_count - 1].m_unit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &format, + sizeof(format)); if (noErr != err) { - CloseComponent(m_output); osd_printf_error("Could not set audio output stream format (%ld)\n", (long)err); - return -1; + goto close_graph_and_return_error; } m_sample_bytes = format.mBytesPerFrame; @@ -167,9 +159,8 @@ int sound_coreaudio::init(const osd_options &options) m_buffer = global_alloc_array_clear(INT8, m_buffer_size); if (!m_buffer) { - CloseComponent(m_output); osd_printf_error("Could not allocate stream buffer\n"); - return -1; + goto close_graph_and_return_error; } m_playpos = 0; m_writepos = m_headroom; @@ -178,40 +169,45 @@ int sound_coreaudio::init(const osd_options &options) m_overflows = m_underflows = 0; // Initialise and start - err = AudioUnitInitialize(m_output); + err = AUGraphInitialize(m_graph); if (noErr != err) { - CloseComponent(m_output); - global_free_array(m_buffer); - m_buffer = NULL; - osd_printf_error("Could not initialize audio output (%ld)\n", (long)err); - return -1; + osd_printf_error("Could not initialize AudioUnit graph (%ld)\n", (long)err); + goto free_buffer_and_return_error; } - err = AudioOutputUnitStart(m_output); + err = AUGraphStart(m_graph); if (noErr != err) { - AudioUnitUninitialize(m_output); - CloseComponent(m_output); - global_free_array(m_buffer); - m_buffer = NULL; - osd_printf_error("Could not start audio output (%ld)\n", (long)err); - return -1; + osd_printf_error("Could not start AudioUnit graph (%ld)\n", (long)err); + AUGraphUninitialize(m_graph); + goto free_buffer_and_return_error; } - m_open = true; osd_printf_verbose("Audio: End initialization\n"); return 0; + +free_buffer_and_return_error: + global_free_array(m_buffer); + m_buffer_size = 0; + m_buffer = NULL; +close_graph_and_return_error: + AUGraphClose(m_graph); + DisposeAUGraph(m_graph); + m_graph = NULL; + m_node_count = 0; + return -1; } void sound_coreaudio::exit() { - if (m_open) + if (m_graph) { - osd_printf_verbose("Closing output AudioUnit component\n"); - AudioOutputUnitStop(m_output); - AudioUnitUninitialize(m_output); - CloseComponent(m_output); - m_open = false; + osd_printf_verbose("Stopping CoreAudio output\n"); + AUGraphStop(m_graph); + AUGraphUninitialize(m_graph); + DisposeAUGraph(m_graph); + m_graph = 0; + m_node_count = 0; } if (m_buffer) { @@ -258,6 +254,136 @@ void sound_coreaudio::set_mastervolume(int attenuation) } +int sound_coreaudio::create_graph(osd_options const &options) +{ + OSStatus err; + AudioComponentDescription node_desc; + + err = NewAUGraph(&m_graph); + if (noErr != err) + { + osd_printf_error("Failed to create AudioUnit graph (%ld)\n", (long)err); + goto return_error; + } + + err = AUGraphOpen(m_graph); + if (noErr != err) + { + osd_printf_error("Failed to open AudioUnit graph (%ld)\n", (long)err); + goto dispose_graph_and_return_error; + } + + node_desc.componentType = kAudioUnitType_Output; + node_desc.componentSubType = kAudioUnitSubType_DefaultOutput; + node_desc.componentManufacturer = kAudioUnitManufacturer_Apple; + node_desc.componentFlags = 0; + node_desc.componentFlagsMask = 0; + err = AUGraphAddNode(m_graph, &node_desc, &m_node_details[m_node_count].m_node); + if (noErr != err) + { + osd_printf_error( + "Failed to add default sound output to AudioUnit graph (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + err = AUGraphNodeInfo( + m_graph, + m_node_details[m_node_count].m_node, + NULL, + &m_node_details[m_node_count].m_unit); + if (noErr != err) + { + osd_printf_error( + "Failed to obtain AudioUnit for default sound output (%ld)\n", + (long)err); + } + m_node_count++; + + for (unsigned i = EFFECT_COUNT_MAX; 0U < i; i--) + { + } + + if (1U < m_node_count) + { + node_desc.componentType = kAudioUnitType_FormatConverter; + node_desc.componentSubType = kAudioUnitSubType_AUConverter; + node_desc.componentManufacturer = kAudioUnitManufacturer_Apple; + node_desc.componentFlags = 0; + node_desc.componentFlagsMask = 0; + err = AUGraphAddNode(m_graph, &node_desc, &m_node_details[m_node_count].m_node); + if (noErr != err) + { + osd_printf_error( + "Failed to add sound format converter to AudioUnit graph (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + err = AUGraphNodeInfo( + m_graph, + m_node_details[m_node_count].m_node, + NULL, + &m_node_details[m_node_count].m_unit); + if (noErr != err) + { + osd_printf_error( + "Failed to obtain AudioUnit for sound format converter (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + err = AUGraphConnectNodeInput( + m_graph, + m_node_details[m_node_count].m_node, + 0, + m_node_details[m_node_count - 1].m_node, + 0); + if (noErr != err) + { + osd_printf_error( + "Failed to connect sound format converter in AudioUnit graph (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + m_node_count++; + } + + { + AURenderCallbackStruct const renderer = { sound_coreaudio::render_callback, this }; + err = AUGraphSetNodeInputCallback( + m_graph, + m_node_details[m_node_count - 1].m_node, + 0, + &renderer); + if (noErr != err) + { + osd_printf_error( + "Failed to set audio render callback for AudioUnit graph (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + } + + err = AUGraphUpdate(m_graph, NULL); + if (noErr != err) + { + osd_printf_error( + "Failed to update AudioUnit graph (%ld)\n", + (long)err); + goto close_graph_and_return_error; + } + + return 0; + +close_graph_and_return_error: + AUGraphClose(m_graph); +dispose_graph_and_return_error: + DisposeAUGraph(m_graph); +return_error: + m_graph = NULL; + m_node_count = 0; + return -1; +} + + OSStatus sound_coreaudio::render( AudioUnitRenderActionFlags *action_flags, const AudioTimeStamp *timestamp, diff --git a/src/osd/sdl/aueffectutil.m b/src/osd/sdl/aueffectutil.m index 322c5d3dc60..1714d71f9f8 100644 --- a/src/osd/sdl/aueffectutil.m +++ b/src/osd/sdl/aueffectutil.m @@ -1,3 +1,4 @@ +#import #import #import #import @@ -13,6 +14,18 @@ #include +#ifdef MAC_OS_X_VERSION_MAX_ALLOWED + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 + +@protocol NSWindowDelegate +@end + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060 + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED + + struct EffectInfo { Component component;