Previous 199869 Revisions Next

r36935 Saturday 4th April, 2015 at 14:48:35 UTC by Vasantha Crabb
Add a simple CoreAudio sound output module
It doesn't provide facilities for AU effects, although that could be
added pretty easily if someone wants to.  Advantages over SDL sound
output are simpler code and lower latency.
[/trunk]makefile
[scripts/src/osd]modules.lua
[src/osd/modules/font]font_osx.c
[src/osd/modules/lib]osdobj_common.c
[src/osd/modules/sound]coreaudio_sound.c* direct_sound.c sdl_sound.c

trunk/makefile
r245446r245447
464464   scripts/src/main.lua \
465465   scripts/src/3rdparty.lua \
466466   scripts/src/cpu.lua \
467   scripts/src/osd/modules.lua \
467468   $(wildcard scripts/src/osd/$(OSD)*.lua) \
468469   scripts/src/sound.lua \
469470   scripts/src/tools.lua \
trunk/scripts/src/osd/modules.lua
r245446r245447
2626      MAME_DIR .. "src/osd/modules/midi/none.c",
2727      MAME_DIR .. "src/osd/modules/sound/js_sound.c",
2828      MAME_DIR .. "src/osd/modules/sound/direct_sound.c",
29      MAME_DIR .. "src/osd/modules/sound/coreaudio_sound.c",
2930      MAME_DIR .. "src/osd/modules/sound/sdl_sound.c",
3031      MAME_DIR .. "src/osd/modules/sound/none.c",
3132   }
r245446r245447
181182         }
182183      elseif _OPTIONS["targetos"]=="macosx" then
183184         links {
184            "CoreAudio.framework",
185185            "CoreMIDI.framework",
186186         }
187187      end
r245446r245447
218218         "dsound",
219219         "dxguid",
220220      }
221   elseif _OPTIONS["targetos"]=="macosx" then
222      links {
223         "AudioUnit.framework",
224         "CoreAudio.framework",
225         "CoreServices.framework",
226      }
221227   end
222228
223229end
trunk/src/osd/modules/font/font_osx.c
r245446r245447
196196   }
197197
198198};
199#else /* SDLMAME_UNIX */
199#else /* SDLMAME_MACOSX */
200200   MODULE_NOT_SUPPORTED(font_osx, OSD_FONT_PROVIDER, "osx")
201201#endif
202202
trunk/src/osd/modules/lib/osdobj_common.c
r245446r245447
165165   REGISTER_MODULE(m_mod_man, SOUND_DSOUND);
166166   REGISTER_MODULE(m_mod_man, SOUND_JS);
167167   REGISTER_MODULE(m_mod_man, SOUND_SDL);
168   REGISTER_MODULE(m_mod_man, SOUND_COREAUDIO);
168169   REGISTER_MODULE(m_mod_man, SOUND_NONE);
169170
170171#ifdef SDLMAME_MACOSX
trunk/src/osd/modules/sound/coreaudio_sound.c
r0r245447
1// license:BSD-3-Clause
2// copyright-holders:Vas Crabb
3//============================================================
4//
5//  sound.c - CoreAudio implementation of MAME sound routines
6//
7//  Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team.
8//  Visit http://mamedev.org for licensing and usage restrictions.
9//
10//============================================================
11
12#include "sound_module.h"
13#include "modules/osdmodule.h"
14
15#ifdef SDLMAME_MACOSX
16
17#include <AudioUnit/AudioUnit.h>
18#include <CoreAudio/CoreAudio.h>
19#include <CoreServices/CoreServices.h>
20
21
22class sound_coreaudio : public osd_module, public sound_module
23{
24public:
25   sound_coreaudio() :
26      osd_module(OSD_SOUND_PROVIDER, "coreaudio"),
27      sound_module(),
28      m_open(false),
29      m_started(false),
30      m_attenuation(0),
31      m_scale(128),
32      m_sample_bytes(0),
33      m_headroom(0),
34      m_buffer_size(0),
35      m_buffer(NULL),
36      m_playpos(0),
37      m_writepos(0),
38      m_in_underrun(false),
39      m_overflows(0),
40      m_underflows(0)
41   {
42   }
43   virtual ~sound_coreaudio()
44   {
45   }
46
47   virtual int init();
48   virtual void exit();
49
50   // sound_module
51
52   virtual void update_audio_stream(bool is_throttled, INT16 const *buffer, int samples_this_frame);
53   virtual void set_mastervolume(int attenuation);
54
55private:
56   enum
57   {
58      LATENCY_MIN = 1,
59      LATENCY_MAX = 5
60   };
61
62   UINT32 clamped_latency() const { return MAX(MIN(m_audio_latency, LATENCY_MAX), LATENCY_MIN); }
63   UINT32 buffer_avail() const { return ((m_writepos <= m_playpos) ? m_buffer_size : 0) + m_playpos - m_writepos; }
64   UINT32 buffer_used() const { return ((m_playpos < m_writepos) ? m_buffer_size : 0) + m_writepos - m_playpos; }
65
66   void copy_scaled(void *dst, void const *src, UINT32 bytes) const
67   {
68      bytes /= sizeof(INT16);
69      INT16 const *s = (INT16 const *)src;
70      for (INT16 *d = (INT16 *)dst; bytes > 0; bytes--, s++, d++)
71         *d = (*s * m_scale) >> 7;
72   }
73
74   OSStatus render(
75         AudioUnitRenderActionFlags  *action_flags,
76         const AudioTimeStamp        *timestamp,
77         UInt32                      bus_number,
78         UInt32                      number_frames,
79         AudioBufferList             *data);
80
81   static OSStatus render_callback(
82         void                        *refcon,
83         AudioUnitRenderActionFlags  *action_flags,
84         const AudioTimeStamp        *timestamp,
85         UInt32                      bus_number,
86         UInt32                      number_frames,
87         AudioBufferList             *data);
88
89   bool        m_open;
90   bool        m_started;
91   AudioUnit   m_output;
92   int         m_attenuation;
93   UINT32      m_scale;
94   UINT32      m_sample_bytes;
95   UINT32      m_headroom;
96   UINT32      m_buffer_size;
97   INT8        *m_buffer;
98   UINT32      m_playpos;
99   UINT32      m_writepos;
100   bool        m_in_underrun;
101   unsigned    m_overflows;
102   unsigned    m_underflows;
103};
104
105
106int sound_coreaudio::init()
107{
108   OSStatus err;
109
110   // Don't bother with any of this if sound is disabled
111   if (sample_rate() == 0)
112      return 0;
113
114   // Get the Default Output AudioUnit component and open an instance
115   ComponentDescription output_desc;
116   output_desc.componentType           = kAudioUnitType_Output;
117   output_desc.componentSubType        = kAudioUnitSubType_DefaultOutput;
118   output_desc.componentManufacturer   = kAudioUnitManufacturer_Apple;
119   output_desc.componentFlags          = 0;
120   output_desc.componentFlagsMask      = 0;
121   Component output_comp = FindNextComponent(NULL, &output_desc);
122   if (!output_comp)
123   {
124      osd_printf_error("Could not find Default Output AudioUnit component\n");
125      return -1;
126   }
127   err = OpenAComponent(output_comp, &m_output);
128   if (noErr != err)
129   {
130      osd_printf_error("Could not open Default Output AudioUnit component (%ld)\n", (long)err);
131      return -1;
132   }
133
134   // Set render callback
135   AURenderCallbackStruct renderer;
136   renderer.inputProc          = sound_coreaudio::render_callback;
137   renderer.inputProcRefCon    = this;
138   err = AudioUnitSetProperty(m_output, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderer, sizeof(renderer));
139   if (noErr != err)
140   {
141      CloseComponent(m_output);
142      osd_printf_error("Could not set audio output render callback (%ld)\n", (long)err);
143      return -1;
144   }
145
146   // Set audio stream format for two-channel native-endian 16-bit packed linear PCM
147   AudioStreamBasicDescription format;
148   format.mSampleRate          = sample_rate();
149   format.mFormatID            = kAudioFormatLinearPCM;
150   format.mFormatFlags         = kAudioFormatFlagsNativeEndian
151                        | kLinearPCMFormatFlagIsSignedInteger
152                        | kLinearPCMFormatFlagIsPacked;
153   format.mFramesPerPacket     = 1;
154   format.mChannelsPerFrame    = 2;
155   format.mBitsPerChannel      = 16;
156   format.mBytesPerFrame       = format.mChannelsPerFrame * format.mBitsPerChannel / 8;
157   format.mBytesPerPacket      = format.mFramesPerPacket * format.mBytesPerFrame;
158   err = AudioUnitSetProperty(m_output, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof(format));
159   if (noErr != err)
160   {
161      CloseComponent(m_output);
162      osd_printf_error("Could not set audio output stream format (%ld)\n", (long)err);
163      return -1;
164   }
165   m_sample_bytes = format.mBytesPerFrame;
166
167   // Allocate buffer
168   m_headroom = (clamped_latency() * sample_rate() / 40) * m_sample_bytes;
169   m_buffer_size = MAX((sample_rate() * m_sample_bytes * (clamped_latency() + 2) / 20480) * 1024, m_sample_bytes * 256);
170   m_buffer = global_alloc_array_clear(INT8, m_buffer_size);
171   if (!m_buffer)
172   {
173      CloseComponent(m_output);
174      osd_printf_error("Could not allocate stream buffer\n");
175      return -1;
176   }
177   m_playpos = 0;
178   m_writepos = m_headroom;
179   m_in_underrun = false;
180   m_overflows = m_underflows = 0;
181
182   // Initialise and start
183   err = AudioUnitInitialize(m_output);
184   if (noErr != err)
185   {
186      CloseComponent(m_output);
187      global_free_array(m_buffer);
188      m_buffer = NULL;
189      osd_printf_error("Could not initialize audio output (%ld)\n", (long)err);
190      return -1;
191   }
192   err = AudioOutputUnitStart(m_output);
193   if (noErr != err)
194   {
195      AudioUnitUninitialize(m_output);
196      CloseComponent(m_output);
197      global_free_array(m_buffer);
198      m_buffer = NULL;
199      osd_printf_error("Could not start audio output (%ld)\n", (long)err);
200      return -1;
201   }
202   m_open = true;
203   m_started = true;
204   osd_printf_verbose("Audio: End initialization\n");
205   return 0;
206}
207
208
209void sound_coreaudio::exit()
210{
211   if (m_open)
212   {
213      osd_printf_verbose("Closing output AudioUnit component\n");
214      AudioOutputUnitStop(m_output);
215      AudioUnitUninitialize(m_output);
216      CloseComponent(m_output);
217      m_open = false;
218      m_started = false;
219   }
220   if (m_buffer)
221   {
222      global_free_array(m_buffer);
223      m_buffer = NULL;
224   }
225   if (m_overflows || m_underflows)
226      osd_printf_verbose("Sound buffer: overflows=%u underflows=%u\n", m_overflows, m_underflows);
227}
228
229
230void sound_coreaudio::update_audio_stream(bool is_throttled, INT16 const *buffer, int samples_this_frame)
231{
232   if ((sample_rate() == 0) || !m_buffer)
233      return;
234
235   UINT32 const bytes_this_frame = samples_this_frame * m_sample_bytes;
236   if (bytes_this_frame >= buffer_avail())
237   {
238      m_overflows++;
239      return;
240   }
241
242   UINT32 const chunk = MIN(m_buffer_size - m_writepos, bytes_this_frame);
243   memcpy(m_buffer + m_writepos, (INT8 *)buffer, chunk);
244   m_writepos += chunk;
245   if (m_writepos >= m_buffer_size)
246      m_writepos = 0;
247
248   if (chunk < bytes_this_frame)
249   {
250      assert(0U == m_writepos);
251      assert(m_playpos > (bytes_this_frame - chunk));
252      memcpy(m_buffer, (INT8 *)buffer + chunk, bytes_this_frame - chunk);
253      m_writepos += bytes_this_frame - chunk;
254   }
255}
256
257
258void sound_coreaudio::set_mastervolume(int attenuation)
259{
260   m_attenuation   = MAX(MIN(attenuation, 0), -32);
261   m_scale         = (UINT32)(pow(10.0, m_attenuation / 20.0) * 128);
262   if (m_open)
263   {
264      if (-32 == m_attenuation)
265      {
266         if (m_started)
267         {
268            if (noErr == AudioOutputUnitStop(m_output))
269               m_started = false;
270         }
271      }
272      else
273      {
274         if (!m_started)
275         {
276            if (noErr == AudioOutputUnitStart(m_output))
277               m_started = true;
278         }
279      }
280   }
281}
282
283
284OSStatus sound_coreaudio::render(
285      AudioUnitRenderActionFlags  *action_flags,
286      const AudioTimeStamp        *timestamp,
287      UInt32                      bus_number,
288      UInt32                      number_frames,
289      AudioBufferList             *data)
290{
291   UINT32 const number_bytes = number_frames * m_sample_bytes;
292   UINT32 const used = buffer_used();
293   if (m_in_underrun && (used < m_headroom))
294   {
295      memset(data->mBuffers[0].mData, 0, number_bytes);
296      return noErr;
297   }
298   m_in_underrun = false;
299   if (number_bytes > used)
300   {
301      m_in_underrun = true;
302      m_underflows++;
303      memset(data->mBuffers[0].mData, 0, number_bytes);
304      return noErr;
305   }
306
307   UINT32 const chunk = MIN(m_buffer_size - m_playpos, number_bytes);
308   copy_scaled((INT8 *)data->mBuffers[0].mData, m_buffer + m_playpos, chunk);
309   m_playpos += chunk;
310   if (m_playpos >= m_buffer_size)
311      m_playpos = 0;
312
313   if (chunk < number_bytes)
314   {
315      assert(0U == m_playpos);
316      assert(m_writepos >= (number_bytes - chunk));
317      copy_scaled((INT8 *)data->mBuffers[0].mData + chunk, m_buffer, number_bytes - chunk);
318      m_playpos += number_bytes - chunk;
319   }
320
321   return noErr;
322}
323
324
325OSStatus sound_coreaudio::render_callback(
326      void                        *refcon,
327      AudioUnitRenderActionFlags  *action_flags,
328      const AudioTimeStamp        *timestamp,
329      UInt32                      bus_number,
330      UInt32                      number_frames,
331      AudioBufferList             *data)
332{
333   return ((sound_coreaudio *)refcon)->render(action_flags, timestamp, bus_number, number_frames, data);
334}
335
336#else /* SDLMAME_MACOSX */
337   MODULE_NOT_SUPPORTED(sound_coreaudio, OSD_SOUND_PROVIDER, "coreaudio")
338#endif
339
340MODULE_DEFINITION(SOUND_COREAUDIO, sound_coreaudio)
trunk/src/osd/modules/sound/direct_sound.c
r245446r245447
275275   }
276276
277277   // set the cooperative level
278   #ifdef SDLMAME_WIN32
278#ifdef SDLMAME_WIN32
279279   SDL_SysWMinfo wminfo;
280280   SDL_VERSION(&wminfo.version);
281281#if (SDLMAME_SDL2)
r245446r245447
287287#endif
288288   #else
289289   result = IDirectSound_SetCooperativeLevel(dsound, win_window_list->m_hwnd, DSSCL_PRIORITY);
290   #endif
290#endif
291291   if (result != DS_OK)
292292   {
293293      osd_printf_error("Error setting DirectSound cooperative level: %08x\n", (UINT32)result);
trunk/src/osd/modules/sound/sdl_sound.c
r245446r245447
332332void sound_sdl::set_mastervolume(int _attenuation)
333333{
334334   // clamp the attenuation to 0-32 range
335   if (_attenuation > 0)
336      _attenuation = 0;
337   if (_attenuation < -32)
338      _attenuation = -32;
335   attenuation = MAX(MIN(_attenuation, 0), -32);
339336
340   attenuation = _attenuation;
341
342   if ((attenuation == -32) && (stream_in_initialized))
337   if (stream_in_initialized)
343338   {
344      SDL_PauseAudio(1);
339      if (attenuation == -32)
340         SDL_PauseAudio(1);
341      else
342         SDL_PauseAudio(0);
345343   }
346   else if (stream_in_initialized)
347   {
348      SDL_PauseAudio(0);
349   }
350344}
351345
352346//============================================================
r245446r245447
455449
456450      sdl_xfer_samples = obtained.samples;
457451
458      audio_latency = m_audio_latency;
459
460452      // pin audio latency
461      if (audio_latency > MAX_AUDIO_LATENCY)
462      {
463         audio_latency = MAX_AUDIO_LATENCY;
464      }
465      else if (audio_latency < 1)
466      {
467         audio_latency = 1;
468      }
453      audio_latency = MAX(MIN(m_audio_latency, MAX_AUDIO_LATENCY), 1);
469454
470455      // compute the buffer sizes
471456      stream_buffer_size = (sample_rate() * 2 * sizeof(INT16) * (2 + audio_latency)) / 30;


Previous 199869 Revisions Next


© 1997-2024 The MAME Team