diff options
Diffstat (limited to 'src/osd/modules/sound/coreaudio_sound.cpp')
-rw-r--r-- | src/osd/modules/sound/coreaudio_sound.cpp | 244 |
1 files changed, 109 insertions, 135 deletions
diff --git a/src/osd/modules/sound/coreaudio_sound.cpp b/src/osd/modules/sound/coreaudio_sound.cpp index d43d47a114f..7e9814af117 100644 --- a/src/osd/modules/sound/coreaudio_sound.cpp +++ b/src/osd/modules/sound/coreaudio_sound.cpp @@ -8,10 +8,11 @@ #include "sound_module.h" #include "modules/osdmodule.h" -#include "modules/lib/osdobj_common.h" #ifdef SDLMAME_MACOSX +#include "modules/lib/osdobj_common.h" + #include <AvailabilityMacros.h> #include <AudioToolbox/AudioToolbox.h> #include <AudioUnit/AudioUnit.h> @@ -19,19 +20,14 @@ #include <CoreFoundation/CoreFoundation.h> #include <CoreServices/CoreServices.h> -#include <string.h> - - -#ifdef MAC_OS_X_VERSION_MAX_ALLOWED - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 +#include <memory> +#include <new> +#include <cstring> -typedef ComponentDescription AudioComponentDescription; -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED +namespace osd { +namespace { class sound_coreaudio : public osd_module, public sound_module { @@ -41,14 +37,15 @@ public: sound_module(), m_graph(nullptr), m_node_count(0), + m_sample_rate(0), + m_audio_latency(0), m_sample_bytes(0), m_headroom(0), m_buffer_size(0), - m_buffer(nullptr), + m_buffer(), m_playpos(0), m_writepos(0), m_in_underrun(false), - m_scale(128), m_overflows(0), m_underflows(0) { @@ -57,13 +54,12 @@ public: { } - virtual int init(osd_options const &options) override; + virtual int init(osd_interface &osd, osd_options const &options) override; virtual void exit() override; // sound_module - virtual void update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) override; - virtual void set_mastervolume(int attenuation) override; + virtual void stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) override; private: struct node_detail @@ -81,18 +77,10 @@ private: EFFECT_COUNT_MAX = 10 }; - uint32_t clamped_latency() const { return unsigned(std::max(std::min(m_audio_latency, int(LATENCY_MAX)), int(LATENCY_MIN))); } + uint32_t clamped_latency() const { return unsigned(std::clamp<int>(m_audio_latency, LATENCY_MIN, LATENCY_MAX)); } uint32_t buffer_avail() const { return ((m_writepos >= m_playpos) ? m_buffer_size : 0) + m_playpos - m_writepos; } uint32_t buffer_used() const { return ((m_playpos > m_writepos) ? m_buffer_size : 0) + m_writepos - m_playpos; } - void copy_scaled(void *dst, void const *src, uint32_t bytes) const - { - bytes /= sizeof(int16_t); - int16_t const *s = (int16_t const *)src; - for (int16_t *d = (int16_t *)dst; bytes > 0; bytes--, s++, d++) - *d = (*s * m_scale) >> 7; - } - bool create_graph(osd_options const &options); bool add_output(char const *name); bool add_device_output(char const *name); @@ -125,8 +113,8 @@ private: } bool get_output_device_id(char const *name, AudioDeviceID &id) const; - char *get_device_uid(AudioDeviceID id) const; - char *get_device_name(AudioDeviceID id) const; + std::unique_ptr<char []> get_device_uid(AudioDeviceID id) const; + std::unique_ptr<char []> get_device_name(AudioDeviceID id) const; UInt32 get_output_stream_count( AudioDeviceID id, char const *uid, @@ -141,17 +129,14 @@ private: CFPropertyListRef &class_info) const; CFPropertyListRef load_property_list(char const *name) const; - char *convert_cfstring_to_utf8(CFStringRef str) const + std::unique_ptr<char []> convert_cfstring_to_utf8(CFStringRef str) const { CFIndex const len = CFStringGetMaximumSizeForEncoding( CFStringGetLength(str), kCFStringEncodingUTF8); - char *const result = global_alloc_array_clear<char>(len + 1); - if (!CFStringGetCString(str, result, len + 1, kCFStringEncodingUTF8)) - { - global_free_array(result); - return nullptr; - } + std::unique_ptr<char []> result = std::make_unique<char []>(len + 1); + if (!CFStringGetCString(str, result.get(), len + 1, kCFStringEncodingUTF8)) + result.reset(); return result; } @@ -174,25 +159,28 @@ private: unsigned m_node_count; node_detail m_node_details[EFFECT_COUNT_MAX + 2]; - uint32_t m_sample_bytes; - uint32_t m_headroom; - uint32_t m_buffer_size; - int8_t *m_buffer; - uint32_t m_playpos; - uint32_t m_writepos; + int m_sample_rate; + int m_audio_latency; + uint32_t m_sample_bytes; + uint32_t m_headroom; + uint32_t m_buffer_size; + std::unique_ptr<int8_t []> m_buffer; + uint32_t m_playpos; + uint32_t m_writepos; bool m_in_underrun; - int32_t m_scale; unsigned m_overflows; unsigned m_underflows; }; -int sound_coreaudio::init(const osd_options &options) +int sound_coreaudio::init(osd_interface &osd, const osd_options &options) { OSStatus err; // Don't bother with any of this if sound is disabled - if (sample_rate() == 0) + m_sample_rate = options.sample_rate(); + m_audio_latency = options.audio_latency(); + if (m_sample_rate == 0) return 0; // Create the output graph @@ -202,7 +190,7 @@ int sound_coreaudio::init(const osd_options &options) // Set audio stream format for two-channel native-endian 16-bit packed linear PCM AudioStreamBasicDescription format; - format.mSampleRate = sample_rate(); + format.mSampleRate = m_sample_rate; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsSignedInteger @@ -227,10 +215,13 @@ int sound_coreaudio::init(const osd_options &options) m_sample_bytes = format.mBytesPerFrame; // Allocate buffer - m_headroom = m_sample_bytes * (clamped_latency() * sample_rate() / 40); - m_buffer_size = m_sample_bytes * std::max<uint32_t>(sample_rate() * (clamped_latency() + 3) / 40, 256U); - m_buffer = global_alloc_array_clear<int8_t>(m_buffer_size); - if (!m_buffer) + m_headroom = m_sample_bytes * (clamped_latency() * m_sample_rate / 40); + m_buffer_size = m_sample_bytes * std::max<uint32_t>(m_sample_rate * (clamped_latency() + 3) / 40, 256U); + try + { + m_buffer = std::make_unique<int8_t []>(m_buffer_size); + } + catch (std::bad_alloc const &) { osd_printf_error("Could not allocate stream buffer\n"); goto close_graph_and_return_error; @@ -238,7 +229,6 @@ int sound_coreaudio::init(const osd_options &options) m_playpos = 0; m_writepos = m_headroom; m_in_underrun = false; - m_scale = 128; m_overflows = m_underflows = 0; // Initialise and start @@ -246,23 +236,21 @@ int sound_coreaudio::init(const osd_options &options) if (noErr != err) { osd_printf_error("Could not initialize AudioUnit graph (%ld)\n", (long)err); - goto free_buffer_and_return_error; + goto close_graph_and_return_error; } err = AUGraphStart(m_graph); if (noErr != err) { osd_printf_error("Could not start AudioUnit graph (%ld)\n", (long)err); AUGraphUninitialize(m_graph); - goto free_buffer_and_return_error; + goto close_graph_and_return_error; } 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 = nullptr; close_graph_and_return_error: + m_buffer_size = 0; + m_buffer.reset(); AUGraphClose(m_graph); DisposeAUGraph(m_graph); m_graph = nullptr; @@ -283,20 +271,16 @@ void sound_coreaudio::exit() m_graph = nullptr; m_node_count = 0; } - if (m_buffer) - { - global_free_array(m_buffer); - m_buffer = nullptr; - } + m_buffer.reset(); if (m_overflows || m_underflows) osd_printf_verbose("Sound buffer: overflows=%u underflows=%u\n", m_overflows, m_underflows); osd_printf_verbose("Audio: End deinitialization\n"); } -void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) +void sound_coreaudio::stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) { - if ((sample_rate() == 0) || !m_buffer) + if ((m_sample_rate == 0) || !m_buffer) return; uint32_t const bytes_this_frame = samples_this_frame * m_sample_bytes; @@ -307,7 +291,7 @@ void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buff } uint32_t const chunk = std::min(m_buffer_size - m_writepos, bytes_this_frame); - memcpy(m_buffer + m_writepos, (int8_t *)buffer, chunk); + memcpy(&m_buffer[m_writepos], (int8_t *)buffer, chunk); m_writepos += chunk; if (m_writepos >= m_buffer_size) m_writepos = 0; @@ -316,19 +300,12 @@ void sound_coreaudio::update_audio_stream(bool is_throttled, int16_t const *buff { assert(0U == m_writepos); assert(m_playpos > (bytes_this_frame - chunk)); - memcpy(m_buffer, (int8_t *)buffer + chunk, bytes_this_frame - chunk); + memcpy(&m_buffer[0], (int8_t *)buffer + chunk, bytes_this_frame - chunk); m_writepos += bytes_this_frame - chunk; } } -void sound_coreaudio::set_mastervolume(int attenuation) -{ - int const clamped_attenuation = std::max(std::min(attenuation, 0), -32); - m_scale = (-32 == clamped_attenuation) ? 0 : (int32_t)(pow(10.0, clamped_attenuation / 20.0) * 128); -} - - bool sound_coreaudio::create_graph(osd_options const &options) { OSStatus err; @@ -648,7 +625,7 @@ bool sound_coreaudio::get_output_device_id( return false; } property_size /= sizeof(AudioDeviceID); - AudioDeviceID *const devices = global_alloc_array_clear<AudioDeviceID>(property_size); + std::unique_ptr<AudioDeviceID []> const devices = std::make_unique<AudioDeviceID []>(property_size); property_size *= sizeof(AudioDeviceID); err = AudioObjectGetPropertyData( kAudioObjectSystemObject, @@ -656,20 +633,19 @@ bool sound_coreaudio::get_output_device_id( 0, nullptr, &property_size, - devices); + devices.get()); UInt32 const device_count = property_size / sizeof(AudioDeviceID); if (noErr != err) { osd_printf_error("Error getting audio device list (%ld)\n", (long)err); - global_free_array(devices); return false; } for (UInt32 i = 0; device_count > i; i++) { - char *const device_uid = get_device_uid(devices[i]); - char *const device_name = get_device_name(devices[i]); - if ((nullptr == device_uid) && (nullptr == device_name)) + std::unique_ptr<char []> const device_uid = get_device_uid(devices[i]); + std::unique_ptr<char []> const device_name = get_device_name(devices[i]); + if (!device_uid && !device_name) { osd_printf_warning( "Could not get UID or name for device %lu - skipping\n", @@ -679,52 +655,46 @@ bool sound_coreaudio::get_output_device_id( UInt32 const streams = get_output_stream_count( devices[i], - device_uid, - device_name); + device_uid.get(), + device_name.get()); if (1U > streams) { osd_printf_verbose( "No output streams found for device %s (%s) - skipping\n", - (nullptr != device_name) ? device_name : "<anonymous>", - (nullptr != device_uid) ? device_uid : "<unknown>"); - if (nullptr != device_uid) global_free_array(device_uid); - if (nullptr != device_name) global_free_array(device_name); + device_name ? device_name.get() : "<anonymous>", + device_uid ? device_uid.get() : "<unknown>"); continue; } - for (std::size_t j = strlen(device_uid); (0 < j) && (' ' == device_uid[j - 1]); j--) + for (std::size_t j = strlen(device_uid.get()); (0 < j) && (' ' == device_uid[j - 1]); j--) device_uid[j - 1] = '\0'; - for (std::size_t j = strlen(device_name); (0 < j) && (' ' == device_name[j - 1]); j--) + for (std::size_t j = strlen(device_name.get()); (0 < j) && (' ' == device_name[j - 1]); j--) device_name[j - 1] = '\0'; - bool const matched_uid = (nullptr != device_uid) && !strcmp(name, device_uid); - bool const matched_name = (nullptr != device_name) && !strcmp(name, device_name); + bool const matched_uid = device_uid && !strcmp(name, device_uid.get()); + bool const matched_name = device_name && !strcmp(name, device_name.get()); if (matched_uid || matched_name) { osd_printf_verbose( "Matched device %s (%s) with %lu output stream(s)\n", - (nullptr != device_name) ? device_name : "<anonymous>", - (nullptr != device_uid) ? device_uid : "<unknown>", + device_name ? device_name.get() : "<anonymous>", + device_uid ? device_uid.get() : "<unknown>", (unsigned long)streams); } - global_free_array(device_uid); - global_free_array(device_name); if (matched_uid || matched_name) { id = devices[i]; - global_free_array(devices); return true; } } osd_printf_verbose("No audio output devices match %s\n", name); - global_free_array(devices); return false; } -char *sound_coreaudio::get_device_uid(AudioDeviceID id) const +std::unique_ptr<char []> sound_coreaudio::get_device_uid(AudioDeviceID id) const { AudioObjectPropertyAddress const uid_addr = { kAudioDevicePropertyDeviceUID, @@ -747,9 +717,9 @@ char *sound_coreaudio::get_device_uid(AudioDeviceID id) const (long)err); return nullptr; } - char *const result = convert_cfstring_to_utf8(device_uid); + std::unique_ptr<char []> result = convert_cfstring_to_utf8(device_uid); CFRelease(device_uid); - if (nullptr == result) + if (!result) { osd_printf_warning( "Error converting UID for audio device %lu to UTF-8\n", @@ -759,7 +729,7 @@ char *sound_coreaudio::get_device_uid(AudioDeviceID id) const } -char *sound_coreaudio::get_device_name(AudioDeviceID id) const +std::unique_ptr<char []> sound_coreaudio::get_device_name(AudioDeviceID id) const { AudioObjectPropertyAddress const name_addr = { kAudioDevicePropertyDeviceNameCFString, @@ -782,9 +752,9 @@ char *sound_coreaudio::get_device_name(AudioDeviceID id) const (long)err); return nullptr; } - char *const result = convert_cfstring_to_utf8(device_name); + std::unique_ptr<char []> result = convert_cfstring_to_utf8(device_name); CFRelease(device_name); - if (nullptr == result) + if (!result) { osd_printf_warning( "Error converting name for audio device %lu to UTF-8\n", @@ -913,51 +883,48 @@ CFPropertyListRef sound_coreaudio::load_property_list(char const *name) const (UInt8 const *)name, strlen(name), false); - if (nullptr == url) - { + if (!url) return nullptr; - } - CFDataRef data = nullptr; - SInt32 err; - Boolean const status = CFURLCreateDataAndPropertiesFromResource( - nullptr, - url, - &data, - nullptr, - nullptr, - &err); + CFReadStreamRef const stream = CFReadStreamCreateWithFile(nullptr, url); CFRelease(url); - if (!status) + if (!stream) { - osd_printf_error( - "Error reading data from %s (%ld)\n", - name, - (long)err); - if (nullptr != data) CFRelease(data); + osd_printf_error("Error opening file %s\n", name); + return nullptr; + } + if (!CFReadStreamOpen(stream)) + { + CFRelease(stream); + osd_printf_error("Error opening file %s\n", name); return nullptr; } - CFStringRef msg = nullptr; - CFPropertyListRef const result = CFPropertyListCreateFromXMLData( + CFErrorRef msg = nullptr; + CFPropertyListRef const result = CFPropertyListCreateWithStream( nullptr, - data, + stream, + 0, kCFPropertyListImmutable, + nullptr, &msg); - CFRelease(data); - if ((nullptr == result) || (nullptr != msg)) - { - char *buf = (nullptr != msg) ? convert_cfstring_to_utf8(msg) : nullptr; - if (nullptr != msg) + CFReadStreamClose(stream); + CFRelease(stream); + if (!result || msg) + { + CFStringRef const desc = msg ? CFErrorCopyDescription(msg) : nullptr; + std::unique_ptr<char []> const buf = desc ? convert_cfstring_to_utf8(desc) : nullptr; + if (desc) + CFRelease(desc); + if (msg) CFRelease(msg); - if (nullptr != buf) + if (buf) { osd_printf_error( "Error creating property list from %s: %s\n", name, - buf); - global_free_array(buf); + buf.get()); } else { @@ -965,7 +932,8 @@ CFPropertyListRef sound_coreaudio::load_property_list(char const *name) const "Error creating property list from %s\n", name); } - if (nullptr != result) CFRelease(result); + if (result) + CFRelease(result); return nullptr; } @@ -997,7 +965,7 @@ OSStatus sound_coreaudio::render( } uint32_t const chunk = std::min(m_buffer_size - m_playpos, number_bytes); - copy_scaled((int8_t *)data->mBuffers[0].mData, m_buffer + m_playpos, chunk); + memcpy((int8_t *)data->mBuffers[0].mData, &m_buffer[m_playpos], chunk); m_playpos += chunk; if (m_playpos >= m_buffer_size) m_playpos = 0; @@ -1006,7 +974,7 @@ OSStatus sound_coreaudio::render( { assert(0U == m_playpos); assert(m_writepos >= (number_bytes - chunk)); - copy_scaled((int8_t *)data->mBuffers[0].mData + chunk, m_buffer, number_bytes - chunk); + memcpy((int8_t *)data->mBuffers[0].mData + chunk, &m_buffer[0], number_bytes - chunk); m_playpos += number_bytes - chunk; } @@ -1025,8 +993,14 @@ OSStatus sound_coreaudio::render_callback( return ((sound_coreaudio *)refcon)->render(action_flags, timestamp, bus_number, number_frames, data); } -#else /* SDLMAME_MACOSX */ - MODULE_NOT_SUPPORTED(sound_coreaudio, OSD_SOUND_PROVIDER, "coreaudio") -#endif +} // anonymous namespace + +} // namespace osd + +#else // SDLMAME_MACOSX + +namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_coreaudio, OSD_SOUND_PROVIDER, "coreaudio") } } + +#endif // SDLMAME_MACOSX -MODULE_DEFINITION(SOUND_COREAUDIO, sound_coreaudio) +MODULE_DEFINITION(SOUND_COREAUDIO, osd::sound_coreaudio) |