Bochs/bochs/iodev/soundosx.cc
Stanislav Shwartsman 5873b26a82 Speed up compilation process.
bochs.h already not include iodev.h which reduces compilation dependences for almost all cpu and fpu files, now cpu files will not be recompiled if iodev includes was changed
2004-06-19 15:20:15 +00:00

395 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id: soundosx.cc,v 1.4 2004-06-19 15:20:14 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
// This file (SOUNDOSX.CC) written and donated by Brian Huffman
#ifdef PARANOID
#include <MacTypes.h>
#else
#define Float32 KLUDGE_Float32
#define Float64 KLUDGE_Float64
#endif
#include "iodev.h"
#undef Float32
#undef Float64
#if defined(macintosh) && BX_SUPPORT_SB16
#define LOG_THIS bx_sb16.
#if BX_WITH_MACOS
#include <QuickTimeMusic.h>
#else
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/DefaultAudioOutput.h>
#include <AudioToolbox/AudioConverter.h>
#include <AudioToolbox/AUGraph.h>
#include <QuickTime/QuickTimeMusic.h>
#endif
#include <string.h>
#ifdef BX_SOUND_OSX_use_converter
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData);
OSStatus MyACInputProc (AudioConverterRef inAudioConverter, UInt32* outDataSize,
void** outData, void* inUserData);
#endif
// Global variables
#ifdef BX_SOUND_OSX_use_converter
AUGraph MidiGraph;
AudioUnit synthUnit;
#endif
#ifdef BX_SOUND_OSX_use_quicktime
SndChannelPtr WaveChannel;
ExtSoundHeader WaveInfo;
ExtSoundHeader WaveHeader[BX_SOUND_OSX_NBUF];
#endif
#ifdef BX_SOUND_OSX_use_converter
AudioUnit WaveOutputUnit = NULL;
AudioConverterRef WaveConverter = NULL;
#endif
bx_sound_osx_c::bx_sound_osx_c(bx_sb16_c *sb16)
:bx_sound_output_c(sb16)
{
this->sb16 = sb16;
MidiOpen = 0;
WaveOpen = 0;
head = 0;
tail = 0;
for (int i=0; i<BX_SOUND_OSX_NBUF; i++)
WaveLength[i] = 0;
}
bx_sound_osx_c::~bx_sound_osx_c()
{
// nothing for now
}
int bx_sound_osx_c::midiready()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::openmidioutput(char *device)
{
#ifdef BX_SOUND_OSX_use_converter
ComponentDescription description;
AUNode synthNode, outputNode;
// Create the graph
NewAUGraph (&MidiGraph);
// Open the DLS Synth
description.componentType = kAudioUnitComponentType;
description.componentSubType = kAudioUnitSubType_MusicDevice;
description.componentManufacturer = kAudioUnitID_DLSSynth;
description.componentFlags = 0;
description.componentFlagsMask = 0;
AUGraphNewNode (MidiGraph, &description, 0, NULL, &synthNode);
// Open the output device
description.componentType = kAudioUnitComponentType;
description.componentSubType = kAudioUnitSubType_Output;
description.componentManufacturer = kAudioUnitID_DefaultOutput;
description.componentFlags = 0;
description.componentFlagsMask = 0;
AUGraphNewNode (MidiGraph, &description, 0, NULL, &outputNode);
// Connect the devices up
AUGraphConnectNodeInput (MidiGraph, synthNode, 1, outputNode, 0);
AUGraphUpdate (MidiGraph, NULL);
// Open and initialize the audio units
AUGraphOpen (MidiGraph);
AUGraphInitialize (MidiGraph);
// Turn off the reverb on the synth
AUGraphGetNodeInfo (MidiGraph, synthNode, NULL, NULL, NULL, &synthUnit);
UInt32 usesReverb = 0;
AudioUnitSetProperty (synthUnit, kMusicDeviceProperty_UsesInternalReverb,
kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb));
// Start playing
AUGraphStart (MidiGraph);
#endif
WRITELOG( WAVELOG(4), "openmidioutput(%s)", device);
MidiOpen = 1;
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
{
WRITELOG( WAVELOG(5), "sendmidicommand(%i,%02x,%i)", delta, command, length);
if (!MidiOpen) return BX_SOUND_OUTPUT_ERR;
#ifdef BX_SOUND_OSX_use_converter
if (length <= 2) {
Bit8u arg1 = (length >=1) ? data[0] : 0;
Bit8u arg2 = (length >=2) ? data[1] : 0;
MusicDeviceMIDIEvent (synthUnit, command, arg1, arg2, delta);
}
else {
MusicDeviceSysEx (synthUnit, data, length);
}
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::closemidioutput()
{
WRITELOG( WAVELOG(4), "closemidioutput()");
MidiOpen = 0;
#ifdef BX_SOUND_OSX_use_converter
AUGraphStop (MidiGraph);
AUGraphClose (MidiGraph);
#endif
return BX_SOUND_OUTPUT_OK;
}
#ifdef BX_SOUND_OSX_use_quicktime
#if BX_WITH_MACOS
pascal
#endif
void WaveCallbackProc (SndChannelPtr chan, SndCommand *cmd)
{
// a new buffer is available, so increment tail pointer
int *tail = (int *) (cmd->param2);
(*tail)++;
}
#endif
int bx_sound_osx_c::openwaveoutput(char *device)
{
OSStatus err;
WRITELOG( WAVELOG(4), "openwaveoutput(%s)", device);
// open the default output unit
#ifdef BX_SOUND_OSX_use_quicktime
err = SndNewChannel (&WaveChannel, sampledSynth, 0, NewSndCallBackUPP(WaveCallbackProc));
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
#endif
#ifdef BX_SOUND_OSX_use_converter
err = OpenDefaultAudioOutput (&WaveOutputUnit);
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
AudioUnitInitialize (WaveOutputUnit);
// Set up a callback function to generate output to the output unit
AudioUnitInputCallback input;
input.inputProc = MyRenderer;
input.inputProcRefCon = (void *) this;
AudioUnitSetProperty (WaveOutputUnit, kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Global, 0, &input, sizeof(input));
#endif
WaveOpen = 1;
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::startwaveplayback(int frequency, int bits, int stereo, int format)
{
#ifdef BX_SOUND_OSX_use_converter
static int oldfreq, oldbits, oldstereo, oldformat;
AudioStreamBasicDescription srcFormat, dstFormat;
UInt32 formatSize = sizeof(AudioStreamBasicDescription);
#endif
WRITELOG( WAVELOG(4), "startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format);
#ifdef BX_SOUND_OSX_use_quicktime
WaveInfo.samplePtr = NULL;
WaveInfo.numChannels = stereo ? 2 : 1;
WaveInfo.sampleRate = frequency << 16; // sampleRate is a 16.16 fixed-point value
WaveInfo.loopStart = 0;
WaveInfo.loopEnd = 0;
WaveInfo.encode = extSH; // WaveInfo has type ExtSoundHeader
WaveInfo.baseFrequency = 1; // not sure what means. It's only a Uint8.
WaveInfo.numFrames = 0;
//WaveInfo.AIFFSampleRate = frequency; // frequency as float80
WaveInfo.markerChunk = NULL;
WaveInfo.instrumentChunks = NULL;
WaveInfo.AESRecording = NULL;
WaveInfo.sampleSize = bits * WaveInfo.numChannels;
#endif
#ifdef BX_SOUND_OSX_use_converter
if ( (frequency == oldfreq) &&
(bits == oldbits) &&
(stereo == oldstereo) &&
(format == oldformat) )
return BX_SOUND_OUTPUT_OK; // nothing to do
oldfreq = frequency;
oldbits = bits;
oldstereo = stereo;
oldformat = format;
// update the source audio format
UInt32 bytes = bits / 8;
UInt32 channels = stereo ? 2 : 1;
srcFormat.mSampleRate = (Float64) frequency;
srcFormat.mFormatID = kAudioFormatLinearPCM;
srcFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
if (format & 1) srcFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
srcFormat.mBytesPerPacket = channels * bytes;
srcFormat.mFramesPerPacket = 1;
srcFormat.mBytesPerFrame = channels * bytes;
srcFormat.mChannelsPerFrame = channels;
srcFormat.mBitsPerChannel = bytes * 8;
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
if (WaveConverter) AudioConverterDispose (WaveConverter);
AudioUnitGetProperty (WaveOutputUnit, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0, &dstFormat, &formatSize);
AudioConverterNew (&srcFormat, &dstFormat, &WaveConverter);
if (srcFormat.mChannelsPerFrame == 1 && dstFormat.mChannelsPerFrame == 2) {
// map single-channel input to both output channels
SInt32 map[2] = {0,0};
AudioConverterSetProperty (WaveConverter, kAudioConverterChannelMap,
sizeof(map), (void*) map);
}
if (WavePlaying) AudioOutputUnitStart (WaveOutputUnit);
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::waveready()
{
// HACK: the -4 is to keep from overwriting buffers that
// have been sent, but possibly not yet played. There
// should be a better way of doing this.
if (WaveOpen && (head - tail < BX_SOUND_OSX_NBUF-4)) {
return BX_SOUND_OUTPUT_OK;
}
else {
#ifdef BX_SOUND_OSX_use_converter
// If buffer is full, make sure sound is playing
if (WaveOutputUnit && !WavePlaying) {
AudioOutputUnitStart (WaveOutputUnit);
WavePlaying = 1;
}
#endif
return BX_SOUND_OUTPUT_ERR;
}
}
int bx_sound_osx_c::sendwavepacket(int length, Bit8u data[])
{
#ifdef BX_SOUND_OSX_use_quicktime
SndCommand mySndCommand;
#endif
WRITELOG( WAVELOG(4), "sendwavepacket(%d, %p), head=%u", length, data, head);
// sanity check
if ((!WaveOpen) || (head - tail >= BX_SOUND_OSX_NBUF))
return BX_SOUND_OUTPUT_ERR;
// find next available buffer
int n = head++ % BX_SOUND_OSX_NBUF;
// put data in buffer
memcpy(WaveData[n], data, length);
WaveLength[n] = length;
#ifdef BX_SOUND_OSX_use_quicktime
memcpy(&WaveHeader[n], &WaveInfo, sizeof(WaveInfo));
WaveHeader[n].samplePtr = (char *) (WaveData[n]);
WaveHeader[n].numFrames = length * 8 / WaveInfo.sampleSize;
#endif
#ifdef BX_SOUND_OSX_use_converter
// make sure that the sound is playing
if (!WavePlaying) {
AudioOutputUnitStart (WaveOutputUnit);
WavePlaying = 1;
}
#endif
#ifdef BX_SOUND_OSX_use_quicktime
// queue buffer to play
mySndCommand.cmd = bufferCmd;
mySndCommand.param1 = 0;
mySndCommand.param2 = (long)(&WaveHeader[n]);
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
// queue callback for when buffer finishes
mySndCommand.cmd = callBackCmd;
mySndCommand.param1 = 0;
mySndCommand.param2 = (long)(&tail);
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::stopwaveplayback()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::closewaveoutput()
{
#ifdef BX_SOUND_OSX_use_converter
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
if (WaveConverter) AudioConverterDispose (WaveConverter);
if (WaveOutputUnit) CloseComponent (WaveOutputUnit);
WavePlaying = 0;
WaveOpen = 0;
WaveConverter = NULL;
WaveOutputUnit = NULL;
#endif
return BX_SOUND_OUTPUT_OK;
}
#ifdef BX_SOUND_OSX_use_converter
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
{
UInt32 size = ioData->mDataByteSize;
AudioConverterFillBuffer (WaveConverter, MyACInputProc, inRefCon, &size, ioData->mData);
return noErr;
}
OSStatus MyACInputProc (AudioConverterRef inAudioConverter,
UInt32* outDataSize, void** outData, void* inUserData)
{
bx_sound_osx_c *self = (bx_sound_osx_c*) inUserData;
self->nextbuffer ((int*) outDataSize, outData);
return noErr;
}
void bx_sound_osx_c::nextbuffer (int *outDataSize, void **outData)
{
WRITELOG( WAVELOG(4), "nextbuffer(), tail=%u", tail);
if (head - tail <= 0) {
*outData = NULL;
*outDataSize = 0;
// We are getting behind, so stop the output for now
AudioOutputUnitStop (WaveOutputUnit);
WavePlaying = 0;
}
else {
int n = tail % BX_SOUND_OSX_NBUF;
*outData = (void *) (WaveData[n]);
*outDataSize = WaveLength[n];
tail++;
}
}
#endif
#endif // defined(macintosh)