Fixed compilation error
[bochs-mirror.git] / iodev / soundosx.cc
blob47211bfbbecbbfaad497858af9a3480b165dfd59
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: soundosx.cc,v 1.10 2008/07/26 08:02:27 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // This file (SOUNDOSX.CC) written and donated by Brian Huffman
7 #ifdef PARANOID
8 #include <MacTypes.h>
9 #else
10 #define Float32 KLUDGE_Float32
11 #define Float64 KLUDGE_Float64
12 #endif
14 #define NO_DEVICE_INCLUDES
15 #include "iodev.h"
16 #define BX_SOUNDLOW
17 #include "sb16.h"
18 #undef Float32
19 #undef Float64
21 #if defined(macintosh) && BX_SUPPORT_SB16
23 #define LOG_THIS sb16->
25 #include "soundosx.h"
27 #if BX_WITH_MACOS
28 #include <QuickTimeMusic.h>
29 #else
30 #include <CoreAudio/CoreAudio.h>
31 #include <AudioUnit/AudioUnit.h>
32 #include <AudioToolbox/DefaultAudioOutput.h>
33 #include <AudioToolbox/AudioConverter.h>
34 #include <AudioToolbox/AUGraph.h>
35 #include <QuickTime/QuickTimeMusic.h>
36 #endif
37 #include <string.h>
39 #ifdef BX_SOUND_OSX_use_converter
40 OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
41 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData);
42 OSStatus MyACInputProc (AudioConverterRef inAudioConverter, UInt32* outDataSize,
43 void** outData, void* inUserData);
44 #endif
46 // Global variables
47 #ifdef BX_SOUND_OSX_use_converter
48 AUGraph MidiGraph;
49 AudioUnit synthUnit;
50 #endif
52 #ifdef BX_SOUND_OSX_use_quicktime
53 SndChannelPtr WaveChannel;
54 ExtSoundHeader WaveInfo;
55 ExtSoundHeader WaveHeader[BX_SOUND_OSX_NBUF];
56 #endif
58 #ifdef BX_SOUND_OSX_use_converter
59 AudioUnit WaveOutputUnit = NULL;
60 AudioConverterRef WaveConverter = NULL;
61 #endif
63 bx_sound_osx_c::bx_sound_osx_c(bx_sb16_c *sb16)
64 :bx_sound_output_c(sb16)
66 this->sb16 = sb16;
68 MidiOpen = 0;
69 WaveOpen = 0;
70 head = 0;
71 tail = 0;
72 for (int i=0; i<BX_SOUND_OSX_NBUF; i++)
73 WaveLength[i] = 0;
76 bx_sound_osx_c::~bx_sound_osx_c()
78 // nothing for now
82 int bx_sound_osx_c::midiready()
84 return BX_SOUND_OUTPUT_OK;
87 int bx_sound_osx_c::openmidioutput(char *device)
89 #ifdef BX_SOUND_OSX_use_converter
90 ComponentDescription description;
91 AUNode synthNode, outputNode;
93 // Create the graph
94 NewAUGraph (&MidiGraph);
96 // Open the DLS Synth
97 description.componentType = kAudioUnitComponentType;
98 description.componentSubType = kAudioUnitSubType_MusicDevice;
99 description.componentManufacturer = kAudioUnitID_DLSSynth;
100 description.componentFlags = 0;
101 description.componentFlagsMask = 0;
102 AUGraphNewNode (MidiGraph, &description, 0, NULL, &synthNode);
104 // Open the output device
105 description.componentType = kAudioUnitComponentType;
106 description.componentSubType = kAudioUnitSubType_Output;
107 description.componentManufacturer = kAudioUnitID_DefaultOutput;
108 description.componentFlags = 0;
109 description.componentFlagsMask = 0;
110 AUGraphNewNode (MidiGraph, &description, 0, NULL, &outputNode);
112 // Connect the devices up
113 AUGraphConnectNodeInput (MidiGraph, synthNode, 1, outputNode, 0);
114 AUGraphUpdate (MidiGraph, NULL);
116 // Open and initialize the audio units
117 AUGraphOpen (MidiGraph);
118 AUGraphInitialize (MidiGraph);
120 // Turn off the reverb on the synth
121 AUGraphGetNodeInfo (MidiGraph, synthNode, NULL, NULL, NULL, &synthUnit);
122 UInt32 usesReverb = 0;
123 AudioUnitSetProperty (synthUnit, kMusicDeviceProperty_UsesInternalReverb,
124 kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb));
126 // Start playing
127 AUGraphStart (MidiGraph);
128 #endif
129 WRITELOG(WAVELOG(4), "openmidioutput(%s)", device);
130 MidiOpen = 1;
131 return BX_SOUND_OUTPUT_OK;
134 int bx_sound_osx_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
136 WRITELOG(WAVELOG(5), "sendmidicommand(%i,%02x,%i)", delta, command, length);
137 if (!MidiOpen) return BX_SOUND_OUTPUT_ERR;
139 #ifdef BX_SOUND_OSX_use_converter
140 if (length <= 2) {
141 Bit8u arg1 = (length >=1) ? data[0] : 0;
142 Bit8u arg2 = (length >=2) ? data[1] : 0;
143 MusicDeviceMIDIEvent (synthUnit, command, arg1, arg2, delta);
145 else {
146 MusicDeviceSysEx (synthUnit, data, length);
148 #endif
149 return BX_SOUND_OUTPUT_OK;
152 int bx_sound_osx_c::closemidioutput()
154 WRITELOG(WAVELOG(4), "closemidioutput()");
155 MidiOpen = 0;
156 #ifdef BX_SOUND_OSX_use_converter
157 AUGraphStop (MidiGraph);
158 AUGraphClose (MidiGraph);
159 #endif
160 return BX_SOUND_OUTPUT_OK;
163 #ifdef BX_SOUND_OSX_use_quicktime
164 #if BX_WITH_MACOS
165 pascal
166 #endif
167 void WaveCallbackProc (SndChannelPtr chan, SndCommand *cmd)
169 // a new buffer is available, so increment tail pointer
170 int *tail = (int *) (cmd->param2);
171 (*tail)++;
173 #endif
175 int bx_sound_osx_c::openwaveoutput(char *device)
177 OSStatus err;
179 WRITELOG(WAVELOG(4), "openwaveoutput(%s)", device);
181 // open the default output unit
182 #ifdef BX_SOUND_OSX_use_quicktime
183 err = SndNewChannel (&WaveChannel, sampledSynth, 0, NewSndCallBackUPP(WaveCallbackProc));
184 if (err != noErr) return BX_SOUND_OUTPUT_ERR;
185 #endif
186 #ifdef BX_SOUND_OSX_use_converter
187 err = OpenDefaultAudioOutput (&WaveOutputUnit);
188 if (err != noErr) return BX_SOUND_OUTPUT_ERR;
189 AudioUnitInitialize (WaveOutputUnit);
191 // Set up a callback function to generate output to the output unit
192 AudioUnitInputCallback input;
193 input.inputProc = MyRenderer;
194 input.inputProcRefCon = (void *) this;
195 AudioUnitSetProperty (WaveOutputUnit, kAudioUnitProperty_SetInputCallback,
196 kAudioUnitScope_Global, 0, &input, sizeof(input));
197 #endif
199 WaveOpen = 1;
200 return BX_SOUND_OUTPUT_OK;
203 int bx_sound_osx_c::startwaveplayback(int frequency, int bits, int stereo, int format)
205 #ifdef BX_SOUND_OSX_use_converter
206 static int oldfreq, oldbits, oldstereo, oldformat;
207 AudioStreamBasicDescription srcFormat, dstFormat;
208 UInt32 formatSize = sizeof(AudioStreamBasicDescription);
209 #endif
211 WRITELOG(WAVELOG(4), "startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format);
213 #ifdef BX_SOUND_OSX_use_quicktime
214 WaveInfo.samplePtr = NULL;
215 WaveInfo.numChannels = stereo ? 2 : 1;
216 WaveInfo.sampleRate = frequency << 16; // sampleRate is a 16.16 fixed-point value
217 WaveInfo.loopStart = 0;
218 WaveInfo.loopEnd = 0;
219 WaveInfo.encode = extSH; // WaveInfo has type ExtSoundHeader
220 WaveInfo.baseFrequency = 1; // not sure what means. It's only a Uint8.
221 WaveInfo.numFrames = 0;
222 //WaveInfo.AIFFSampleRate = frequency; // frequency as float80
223 WaveInfo.markerChunk = NULL;
225 WaveInfo.instrumentChunks = NULL;
226 WaveInfo.AESRecording = NULL;
227 WaveInfo.sampleSize = bits * WaveInfo.numChannels;
228 #endif
230 #ifdef BX_SOUND_OSX_use_converter
231 if ((frequency == oldfreq) &&
232 (bits == oldbits) &&
233 (stereo == oldstereo) &&
234 (format == oldformat))
235 return BX_SOUND_OUTPUT_OK; // nothing to do
237 oldfreq = frequency;
238 oldbits = bits;
239 oldstereo = stereo;
240 oldformat = format;
242 // update the source audio format
243 UInt32 bytes = bits / 8;
244 UInt32 channels = stereo ? 2 : 1;
245 srcFormat.mSampleRate = (Float64) frequency;
246 srcFormat.mFormatID = kAudioFormatLinearPCM;
247 srcFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
248 if (format & 1) srcFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
249 srcFormat.mBytesPerPacket = channels * bytes;
250 srcFormat.mFramesPerPacket = 1;
251 srcFormat.mBytesPerFrame = channels * bytes;
252 srcFormat.mChannelsPerFrame = channels;
253 srcFormat.mBitsPerChannel = bytes * 8;
255 if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
256 if (WaveConverter) AudioConverterDispose (WaveConverter);
258 AudioUnitGetProperty (WaveOutputUnit, kAudioUnitProperty_StreamFormat,
259 kAudioUnitScope_Output, 0, &dstFormat, &formatSize);
261 AudioConverterNew (&srcFormat, &dstFormat, &WaveConverter);
263 if (srcFormat.mChannelsPerFrame == 1 && dstFormat.mChannelsPerFrame == 2) {
264 // map single-channel input to both output channels
265 SInt32 map[2] = {0,0};
266 AudioConverterSetProperty (WaveConverter, kAudioConverterChannelMap,
267 sizeof(map), (void*) map);
270 if (WavePlaying) AudioOutputUnitStart (WaveOutputUnit);
271 #endif
273 return BX_SOUND_OUTPUT_OK;
276 int bx_sound_osx_c::waveready()
278 // HACK: the -4 is to keep from overwriting buffers that
279 // have been sent, but possibly not yet played. There
280 // should be a better way of doing this.
281 if (WaveOpen && (head - tail < BX_SOUND_OSX_NBUF-4)) {
282 return BX_SOUND_OUTPUT_OK;
284 else {
285 #ifdef BX_SOUND_OSX_use_converter
286 // If buffer is full, make sure sound is playing
287 if (WaveOutputUnit && !WavePlaying) {
288 AudioOutputUnitStart (WaveOutputUnit);
289 WavePlaying = 1;
291 #endif
292 return BX_SOUND_OUTPUT_ERR;
296 int bx_sound_osx_c::sendwavepacket(int length, Bit8u data[])
298 #ifdef BX_SOUND_OSX_use_quicktime
299 SndCommand mySndCommand;
300 #endif
302 WRITELOG(WAVELOG(4), "sendwavepacket(%d, %p), head=%u", length, data, head);
304 // sanity check
305 if ((!WaveOpen) || (head - tail >= BX_SOUND_OSX_NBUF))
306 return BX_SOUND_OUTPUT_ERR;
308 // find next available buffer
309 int n = head++ % BX_SOUND_OSX_NBUF;
311 // put data in buffer
312 memcpy(WaveData[n], data, length);
313 WaveLength[n] = length;
315 #ifdef BX_SOUND_OSX_use_quicktime
316 memcpy(&WaveHeader[n], &WaveInfo, sizeof(WaveInfo));
317 WaveHeader[n].samplePtr = (char *) (WaveData[n]);
318 WaveHeader[n].numFrames = length * 8 / WaveInfo.sampleSize;
319 #endif
320 #ifdef BX_SOUND_OSX_use_converter
321 // make sure that the sound is playing
322 if (!WavePlaying) {
323 AudioOutputUnitStart (WaveOutputUnit);
324 WavePlaying = 1;
326 #endif
328 #ifdef BX_SOUND_OSX_use_quicktime
329 // queue buffer to play
330 mySndCommand.cmd = bufferCmd;
331 mySndCommand.param1 = 0;
332 mySndCommand.param2 = (long)(&WaveHeader[n]);
333 SndDoCommand(WaveChannel, &mySndCommand, TRUE);
335 // queue callback for when buffer finishes
336 mySndCommand.cmd = callBackCmd;
337 mySndCommand.param1 = 0;
338 mySndCommand.param2 = (long)(&tail);
339 SndDoCommand(WaveChannel, &mySndCommand, TRUE);
340 #endif
342 return BX_SOUND_OUTPUT_OK;
345 int bx_sound_osx_c::stopwaveplayback()
347 return BX_SOUND_OUTPUT_OK;
350 int bx_sound_osx_c::closewaveoutput()
352 #ifdef BX_SOUND_OSX_use_converter
353 if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
354 if (WaveConverter) AudioConverterDispose (WaveConverter);
355 if (WaveOutputUnit) CloseComponent (WaveOutputUnit);
356 WavePlaying = 0;
357 WaveOpen = 0;
358 WaveConverter = NULL;
359 WaveOutputUnit = NULL;
360 #endif
361 return BX_SOUND_OUTPUT_OK;
364 #ifdef BX_SOUND_OSX_use_converter
365 OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
366 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
368 UInt32 size = ioData->mDataByteSize;
369 AudioConverterFillBuffer (WaveConverter, MyACInputProc, inRefCon, &size, ioData->mData);
370 return noErr;
373 OSStatus MyACInputProc (AudioConverterRef inAudioConverter,
374 UInt32* outDataSize, void** outData, void* inUserData)
376 bx_sound_osx_c *self = (bx_sound_osx_c*) inUserData;
377 self->nextbuffer ((int*) outDataSize, outData);
378 return noErr;
381 void bx_sound_osx_c::nextbuffer (int *outDataSize, void **outData)
383 WRITELOG(WAVELOG(4), "nextbuffer(), tail=%u", tail);
384 if (head - tail <= 0) {
385 *outData = NULL;
386 *outDataSize = 0;
388 // We are getting behind, so stop the output for now
389 AudioOutputUnitStop (WaveOutputUnit);
390 WavePlaying = 0;
392 else {
393 int n = tail % BX_SOUND_OSX_NBUF;
394 *outData = (void *) (WaveData[n]);
395 *outDataSize = WaveLength[n];
396 tail++;
399 #endif
401 #endif // defined(macintosh)