diff --git a/BasiliskII/src/MacOSX/AudioBackEnd.cpp b/BasiliskII/src/MacOSX/AudioBackEnd.cpp new file mode 100644 index 00000000..65a8cb5d --- /dev/null +++ b/BasiliskII/src/MacOSX/AudioBackEnd.cpp @@ -0,0 +1,307 @@ +/* + * + * This is based on Apple example software AudioBackEnd.cpp + * + * Copyright © 2004 Apple Computer, Inc., All Rights Reserved + * Original Apple code modified by Daniel Sumorok + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "AudioBackEnd.h" + +#pragma mark ---Public Methods--- + +AudioBackEnd::AudioBackEnd(int bitsPerSample, int numChannels, int sampleRate): + mBitsPerSample(bitsPerSample), + mSampleRate(sampleRate), + mNumChannels(numChannels), + mCallback(NULL), + mCallbackArg(NULL), + mBufferSizeFrames(0), + mFramesProcessed(0), + mAudioBuffer(NULL), + mAudioBufferWriteIndex(0), + mAudioBufferReadIndex(0), + mBytesPerFrame(0), + mAudioBufferSize(0) { + OSStatus err = noErr; + err = Init(); + if(err) { + fprintf(stderr,"AudioBackEnd ERROR: Cannot Init AudioBackEnd"); + exit(1); + } +} + +AudioBackEnd::~AudioBackEnd() { //clean up + Stop(); + + AUGraphClose(mGraph); + DisposeAUGraph(mGraph); + + if(mAudioBuffer != NULL) { + delete mAudioBuffer; + mAudioBuffer = NULL; + mAudioBufferSize = 0; + } +} + +OSStatus AudioBackEnd::Init() { + OSStatus err = noErr; + + err = SetupGraph(); + checkErr(err); + + err = SetupBuffers(); + checkErr(err); + + err = AUGraphInitialize(mGraph); + checkErr(err); + + return err; +} + +#pragma mark --- Operation--- + +OSStatus AudioBackEnd::Start() +{ + OSStatus err = noErr; + if(!IsRunning()) { + mFramesProcessed = 0; + mAudioBufferWriteIndex = 0; + mAudioBufferReadIndex = 0; + + err = AUGraphStart(mGraph); + } + return err; +} + +OSStatus AudioBackEnd::Stop() { + OSStatus err = noErr; + + if(IsRunning()) { + err = AUGraphStop(mGraph); + } + return err; +} + +Boolean AudioBackEnd::IsRunning() { + OSStatus err = noErr; + Boolean graphRunning; + + err = AUGraphIsRunning(mGraph,&graphRunning); + + return (graphRunning); +} + +#pragma mark - +#pragma mark --Private methods--- +OSStatus AudioBackEnd::SetupGraph() { + OSStatus err = noErr; + AURenderCallbackStruct output; + UInt32 size; + ComponentDescription outDesc; + AudioDeviceID out; + + //Make a New Graph + err = NewAUGraph(&mGraph); + checkErr(err); + + //Open the Graph, AudioUnits are opened but not initialized + err = AUGraphOpen(mGraph); + checkErr(err); + + outDesc.componentType = kAudioUnitType_Output; + outDesc.componentSubType = kAudioUnitSubType_DefaultOutput; + outDesc.componentManufacturer = kAudioUnitManufacturer_Apple; + outDesc.componentFlags = 0; + outDesc.componentFlagsMask = 0; + + ////////////////////////// + ///MAKE NODES + //This creates a node in the graph that is an AudioUnit, using + //the supplied ComponentDescription to find and open that unit + err = AUGraphNewNode(mGraph, &outDesc, 0, NULL, &mOutputNode); + checkErr(err); + + //Get Audio Units from AUGraph node + err = AUGraphGetNodeInfo(mGraph, mOutputNode, NULL, NULL, NULL, &mOutputUnit); + checkErr(err); + + err = AUGraphUpdate(mGraph, NULL); + checkErr(err); + + size = sizeof(AudioDeviceID); + err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + &size, &out); + checkErr(err); + mOutputDevice.Init(out, false); + + //Set the Current Device to the Default Output Unit. + err = AudioUnitSetProperty(mOutputUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &out, + sizeof(out)); + checkErr(err); + + output.inputProc = OutputProc; + output.inputProcRefCon = this; + + err = AudioUnitSetProperty(mOutputUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &output, + sizeof(output)); + checkErr(err); + return err; +} + +//Allocate Audio Buffer List(s) to hold the data from input. +OSStatus AudioBackEnd::SetupBuffers() { + OSStatus err = noErr; + UInt32 safetyOffset; + AudioStreamBasicDescription asbd; + UInt32 propertySize; + + propertySize = sizeof(mBufferSizeFrames); + err = AudioUnitGetProperty(mOutputUnit, kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, 0, &mBufferSizeFrames, + &propertySize); + + propertySize = sizeof(safetyOffset); + safetyOffset = 0; + err = AudioUnitGetProperty(mOutputUnit, kAudioDevicePropertySafetyOffset, + kAudioUnitScope_Global, 0, &safetyOffset, + &propertySize); + + + asbd.mFormatID = 0x6c70636d; // 'lpcm' + asbd.mFormatFlags = (kAudioFormatFlagIsSignedInteger | + kAudioFormatFlagIsBigEndian | + kAudioFormatFlagIsPacked); + asbd.mChannelsPerFrame = mNumChannels; + asbd.mSampleRate = mSampleRate; + + if(asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) { + asbd.mBitsPerChannel = mBitsPerSample; + } else if(asbd.mFormatFlags & kAudioFormatFlagIsFloat) { + asbd.mBitsPerChannel = 32; + } else { + asbd.mBitsPerChannel = 0; + } + + asbd.mFramesPerPacket = 1; + asbd.mBytesPerFrame = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame; + asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; + + asbd.mReserved = 0; + + mBytesPerFrame = asbd.mBytesPerFrame; + if((mBytesPerFrame & (mBytesPerFrame - 1)) != 0) { + printf("Audio buffer size must be a power of two!\n"); + return -1; + } + + propertySize = sizeof(asbd); + err = AudioUnitSetProperty(mOutputUnit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, &asbd, propertySize); + checkErr(err); + + if(mAudioBuffer != NULL) { + delete mAudioBuffer; + mAudioBufferSize = 0; + } + + mAudioBufferSize = mBytesPerFrame * mBufferSizeFrames * 2; + mAudioBuffer = new UInt8[mAudioBufferSize]; + bzero(mAudioBuffer, mAudioBufferSize); + return err; +} + +#pragma mark - +#pragma mark -- IO Procs -- +OSStatus AudioBackEnd::OutputProc(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *TimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData) { + OSStatus err = noErr; + AudioBackEnd *This = (AudioBackEnd *)inRefCon; + UInt8 *dstPtr; + UInt32 bytesToCopy; + UInt32 bytesUntilEnd; + + This->mFramesProcessed += inNumberFrames; + + dstPtr = (UInt8 *)ioData->mBuffers[0].mData; + if(This->mAudioBuffer == NULL) { + bzero(dstPtr, inNumberFrames * This->mBytesPerFrame); + return noErr; + } + + bytesToCopy = inNumberFrames * This->mBytesPerFrame; + bytesUntilEnd = This->mAudioBufferSize - This->mAudioBufferReadIndex; + if(bytesUntilEnd < bytesToCopy) { + memcpy(dstPtr, &This->mAudioBuffer[This->mAudioBufferReadIndex], + bytesUntilEnd); + memcpy(dstPtr, This->mAudioBuffer, bytesToCopy - bytesUntilEnd); + + This->mAudioBufferReadIndex = bytesToCopy - bytesUntilEnd; + } else { + memcpy(dstPtr, &This->mAudioBuffer[This->mAudioBufferReadIndex], + bytesToCopy); + This->mAudioBufferReadIndex += bytesToCopy; + } + + + while(This->mFramesProcessed >= This->mBufferSizeFrames) { + This->mFramesProcessed -= This->mBufferSizeFrames; + if(This->mCallback != NULL) { + This->mCallback(This->mCallbackArg); + } + } + + return err; +} + +void AudioBackEnd::setCallback(playthruCallback func, void *arg) { + mCallback = func; + mCallbackArg = arg; +} + +UInt32 AudioBackEnd::BufferSizeFrames() { + return mBufferSizeFrames; +} + +int AudioBackEnd::sendAudioBuffer(void *buffer, int numFrames) { + UInt8 *dstBuffer; + int totalBytes; + + mAudioBufferWriteIndex += (mAudioBufferSize / 2); + mAudioBufferWriteIndex &= (mAudioBufferSize - 1); + + dstBuffer = &mAudioBuffer[mAudioBufferWriteIndex]; + totalBytes = mBytesPerFrame * numFrames; + memcpy(dstBuffer, buffer, totalBytes); + + dstBuffer += totalBytes; + bzero(dstBuffer, (mBufferSizeFrames * mBytesPerFrame) - totalBytes); + + return numFrames; +} diff --git a/BasiliskII/src/MacOSX/AudioBackEnd.h b/BasiliskII/src/MacOSX/AudioBackEnd.h new file mode 100644 index 00000000..455d42ff --- /dev/null +++ b/BasiliskII/src/MacOSX/AudioBackEnd.h @@ -0,0 +1,86 @@ +/* + * + * This is based on Apple example software AudioBackEnd.cpp + * + * Copyright © 2004 Apple Computer, Inc., All Rights Reserved + * Original Apple code modified by Daniel Sumorok + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __AudioBackEnd_H__ +#define __AudioBackEnd_H__ + +#define checkErr( err) \ +if(err) {\ + OSStatus error = static_cast(err);\ + fprintf(stderr, "AudioBackEnd Error: %ld -> %s: %d\n", error,\ + __FILE__, \ + __LINE__\ + );\ + fflush(stdout);\ +} + +#include +#include +#include +#include +#include "AudioDevice.h" + +typedef void (*playthruCallback)(void *arg); + +class AudioBackEnd { + public: + AudioBackEnd(int bitsPerSample, int numChannels, int sampleRate); + ~AudioBackEnd(); + OSStatus Init(); + OSStatus Start(); + OSStatus Stop(); + Boolean IsRunning(); + void setCallback(playthruCallback func, void *arg); + UInt32 BufferSizeFrames(); + int sendAudioBuffer(void *buffer, int numFrames); + private: + OSStatus SetupGraph(); + OSStatus CallbackSetup(); + OSStatus SetupBuffers(); + + static OSStatus OutputProc(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList * ioData); + + AudioDevice mOutputDevice; + + AUGraph mGraph; + AUNode mOutputNode; + AudioUnit mOutputUnit; + int mBitsPerSample; + int mSampleRate; + int mNumChannels; + playthruCallback mCallback; + void *mCallbackArg; + UInt32 mBufferSizeFrames; + UInt32 mFramesProcessed; + UInt8 *mAudioBuffer; + UInt32 mAudioBufferWriteIndex; + UInt32 mAudioBufferReadIndex; + UInt32 mBytesPerFrame; + UInt32 mAudioBufferSize; +}; + +#endif //__AudioBackEnd_H__ diff --git a/BasiliskII/src/MacOSX/AudioDevice.cpp b/BasiliskII/src/MacOSX/AudioDevice.cpp new file mode 100644 index 00000000..9fe065f6 --- /dev/null +++ b/BasiliskII/src/MacOSX/AudioDevice.cpp @@ -0,0 +1,97 @@ +/* Copyright: © Copyright 2004 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + AudioDevice.cpp + +=============================================================================*/ + +#include "AudioDevice.h" + +void AudioDevice::Init(AudioDeviceID devid, bool isInput) +{ + mID = devid; + mIsInput = isInput; + if (mID == kAudioDeviceUnknown) return; + + UInt32 propsize; + + propsize = sizeof(UInt32); + verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertySafetyOffset, &propsize, &mSafetyOffset)); + + propsize = sizeof(UInt32); + verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, &propsize, &mBufferSizeFrames)); + + propsize = sizeof(AudioStreamBasicDescription); + verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyStreamFormat, &propsize, &mFormat)); + +} + +void AudioDevice::SetBufferSize(UInt32 size) +{ + UInt32 propsize = sizeof(UInt32); + verify_noerr(AudioDeviceSetProperty(mID, NULL, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, propsize, &size)); + + propsize = sizeof(UInt32); + verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, &propsize, &mBufferSizeFrames)); +} + +int AudioDevice::CountChannels() +{ + OSStatus err; + UInt32 propSize; + int result = 0; + + err = AudioDeviceGetPropertyInfo(mID, 0, mIsInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); + if (err) return 0; + + AudioBufferList *buflist = (AudioBufferList *)malloc(propSize); + err = AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist); + if (!err) { + for (UInt32 i = 0; i < buflist->mNumberBuffers; ++i) { + result += buflist->mBuffers[i].mNumberChannels; + } + } + free(buflist); + return result; +} + +char * AudioDevice::GetName(char *buf, UInt32 maxlen) +{ + verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyDeviceName, &maxlen, buf)); + return buf; +} diff --git a/BasiliskII/src/MacOSX/AudioDevice.h b/BasiliskII/src/MacOSX/AudioDevice.h new file mode 100644 index 00000000..d32be287 --- /dev/null +++ b/BasiliskII/src/MacOSX/AudioDevice.h @@ -0,0 +1,72 @@ +/* Copyright: © Copyright 2004 Apple Computer, Inc. All rights reserved. + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs + copyrights in this original Apple software (the "Apple Software"), to use, + reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions of + the Apple Software. Neither the name, trademarks, service marks or logos of + Apple Computer, Inc. may be used to endorse or promote products derived from the + Apple Software without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or implied, + are granted by Apple herein, including but not limited to any patent rights that + may be infringed by your derivative works or by other works in which the Apple + Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*============================================================================= + AudioDevice.h + +=============================================================================*/ + +#ifndef __AudioDevice_h__ +#define __AudioDevice_h__ + +#include +#include + +class AudioDevice { +public: + AudioDevice() : mID(kAudioDeviceUnknown) { } + AudioDevice(AudioDeviceID devid, bool isInput) { Init(devid, isInput); } + + void Init(AudioDeviceID devid, bool isInput); + + bool Valid() { return mID != kAudioDeviceUnknown; } + + void SetBufferSize(UInt32 size); + + int CountChannels(); + char * GetName(char *buf, UInt32 maxlen); + +public: + AudioDeviceID mID; + bool mIsInput; + UInt32 mSafetyOffset; + UInt32 mBufferSizeFrames; + AudioStreamBasicDescription mFormat; +}; + + +#endif // __AudioDevice_h__ diff --git a/BasiliskII/src/MacOSX/audio_macosx.cpp b/BasiliskII/src/MacOSX/audio_macosx.cpp index f744235d..c819e976 100644 --- a/BasiliskII/src/MacOSX/audio_macosx.cpp +++ b/BasiliskII/src/MacOSX/audio_macosx.cpp @@ -1,7 +1,6 @@ /* - * audio_MacOSX.cpp - Based on audio_dummy.cpp - * - * $Id$ + * audio_macosx.cpp - Audio support, implementation Mac OS X + * Copyright (C) 2006, Daniel Sumorok * * Basilisk II (C) 1997-2005 Christian Bauer * @@ -21,65 +20,87 @@ */ #include "sysdeps.h" + +#include +#include +#include +#include +#include + +#include "cpu_emulation.h" +#include "main.h" #include "prefs.h" +#include "user_strings.h" #include "audio.h" #include "audio_defs.h" +#include "MacOSX_sound_if.h" #define DEBUG 1 #include "debug.h" -#include "main_macosx.h" +// The currently selected audio parameters (indices in +// audio_sample_rates[] etc. vectors) +static int audio_sample_rate_index = 0; +static int audio_sample_size_index = 0; +static int audio_channel_count_index = 0; -#import - -#import - - - -AudioDeviceID device = kAudioDeviceUnknown; +// Prototypes +static OSXsoundOutput *soundOutput = NULL; +static bool main_mute = false; +static bool speaker_mute = false; /* * Initialization */ +static int audioInt(void); + +static bool open_audio(void) +{ + AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index]; + AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index]; + AudioStatus.channels = audio_channel_counts[audio_channel_count_index]; + + if (soundOutput) + delete soundOutput; + + soundOutput = new OSXsoundOutput(); + soundOutput->start(AudioStatus.sample_size, AudioStatus.channels, + AudioStatus.sample_rate >> 16); + soundOutput->setCallback(audioInt); + audio_frames_per_block = soundOutput->bufferSizeFrames(); + + audio_open = true; + return true; +} void AudioInit(void) { - int count; - - // Init audio status and feature flags - AudioStatus.sample_rate = 44100 << 16; - AudioStatus.sample_size = 16; - AudioStatus.channels = 2; - AudioStatus.mixer = 0; - AudioStatus.num_sources = 0; - audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; - - // Only one sample format is supported - audio_sample_rates.push_back(44100 << 16); - audio_sample_sizes.push_back(16); - audio_channel_counts.push_back(2); - // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; + //audio_sample_sizes.push_back(8); + audio_sample_sizes.push_back(16); - // Get default audio device + audio_channel_counts.push_back(1); + audio_channel_counts.push_back(2); + + audio_sample_rates.push_back(11025 << 16); + audio_sample_rates.push_back(22050 << 16); + audio_sample_rates.push_back(44100 << 16); - count = sizeof(device); - err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, - &count, (void *) &device); - if ( err != noErr || device == kAudioDeviceUnknown ) - { - NSLog(@"Failed to get default audio output device"); - audio_open = false; - return; - } + // Default to highest supported values + audio_sample_rate_index = audio_sample_rates.size() - 1; + audio_sample_size_index = audio_sample_sizes.size() - 1; + audio_channel_count_index = audio_channel_counts.size() - 1; + AudioStatus.mixer = 0; + AudioStatus.num_sources = 0; + audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; + audio_component_flags = 0; - // Audio not available - audio_open = false; + open_audio(); } @@ -87,8 +108,23 @@ void AudioInit(void) * Deinitialization */ +static void close_audio(void) +{ + D(bug("Closing Audio\n")); + + if (soundOutput) + { + delete soundOutput; + soundOutput = NULL; + } + + audio_open = false; +} + void AudioExit(void) { + // Close audio device + close_audio(); } @@ -98,6 +134,7 @@ void AudioExit(void) void audio_enter_stream() { + // Streaming thread is always running to avoid clicking noises } @@ -107,6 +144,7 @@ void audio_enter_stream() void audio_exit_stream() { + // Streaming thread is always running to avoid clicking noises } @@ -117,6 +155,40 @@ void audio_exit_stream() void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); + uint32 apple_stream_info; + uint32 numSamples; + int16 *p; + M68kRegisters r; + + if (!AudioStatus.mixer) + { + numSamples = 0; + soundOutput->sendAudioBuffer((void *)p, (int)numSamples); + D(bug("AudioInterrupt done\n")); + return; + } + + // Get data from apple mixer + r.a[0] = audio_data + adatStreamInfo; + r.a[1] = AudioStatus.mixer; + Execute68k(audio_data + adatGetSourceData, &r); + D(bug(" GetSourceData() returns %08lx\n", r.d[0])); + + apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); + if (apple_stream_info && (main_mute == false) && (speaker_mute == false)) + { + numSamples = ReadMacInt32(apple_stream_info + scd_sampleCount); + p = (int16 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)); + } + else + { + numSamples = 0; + p = NULL; + } + + soundOutput->sendAudioBuffer((void *)p, (int)numSamples); + + D(bug("AudioInterrupt done\n")); } @@ -128,26 +200,34 @@ void AudioInterrupt(void) bool audio_set_sample_rate(int index) { + close_audio(); + audio_sample_rate_index = index; + return open_audio(); } bool audio_set_sample_size(int index) { + close_audio(); + audio_sample_size_index = index; + return open_audio(); } bool audio_set_channels(int index) { + close_audio(); + audio_channel_count_index = index; + return open_audio(); } - /* - * Get/set volume controls (volume values received/returned have the left channel - * volume in the upper 16 bits and the right channel volume in the lower 16 bits; - * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) + * Get/set volume controls (volume values received/returned have the + * left channel volume in the upper 16 bits and the right channel + * volume in the lower 16 bits; both volumes are 8.8 fixed point + * values with 0x0100 meaning "maximum volume")) */ - bool audio_get_main_mute(void) { - return false; + return main_mute; } uint32 audio_get_main_volume(void) @@ -157,7 +237,7 @@ uint32 audio_get_main_volume(void) bool audio_get_speaker_mute(void) { - return false; + return speaker_mute; } uint32 audio_get_speaker_volume(void) @@ -167,6 +247,7 @@ uint32 audio_get_speaker_volume(void) void audio_set_main_mute(bool mute) { + main_mute = mute; } void audio_set_main_volume(uint32 vol) @@ -175,8 +256,16 @@ void audio_set_main_volume(uint32 vol) void audio_set_speaker_mute(bool mute) { + speaker_mute = mute; } void audio_set_speaker_volume(uint32 vol) { } + +static int audioInt(void) +{ + SetInterruptFlag(INTFLAG_AUDIO); + TriggerInterrupt(); + return 0; +}