summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/sound/coreaudio_sound.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/sound/coreaudio_sound.cpp')
-rw-r--r--src/osd/modules/sound/coreaudio_sound.cpp244
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)