mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-05 14:32:15 +00:00
Working audio output by Daniel Sumorok.
Not quite the way I wanted to do it but it will do for now. (on a real Mac, the real audio hardware should be able to pull/grab the data from our buffers - an extra thread with its own set of buffers is wasteful!)
This commit is contained in:
parent
7af6665619
commit
f44d37bac8
307
BasiliskII/src/MacOSX/AudioBackEnd.cpp
Normal file
307
BasiliskII/src/MacOSX/AudioBackEnd.cpp
Normal file
@ -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;
|
||||
}
|
86
BasiliskII/src/MacOSX/AudioBackEnd.h
Normal file
86
BasiliskII/src/MacOSX/AudioBackEnd.h
Normal file
@ -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<OSStatus>(err);\
|
||||
fprintf(stderr, "AudioBackEnd Error: %ld -> %s: %d\n", error,\
|
||||
__FILE__, \
|
||||
__LINE__\
|
||||
);\
|
||||
fflush(stdout);\
|
||||
}
|
||||
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <pthread.h>
|
||||
#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__
|
97
BasiliskII/src/MacOSX/AudioDevice.cpp
Normal file
97
BasiliskII/src/MacOSX/AudioDevice.cpp
Normal file
@ -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;
|
||||
}
|
72
BasiliskII/src/MacOSX/AudioDevice.h
Normal file
72
BasiliskII/src/MacOSX/AudioDevice.h
Normal file
@ -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 <CoreServices/CoreServices.h>
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
|
||||
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__
|
@ -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 <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#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 <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import <CoreAudio/CoreAudio.h>
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user