Question and source... long post...
Question and source... long post...
- Subject: Question and source... long post...
- From: "Michael A. Thompson" <email@hidden>
- Date: Tue, 27 Nov 2001 02:12:06 -0600
Hello,
Sorry for posting such a long email... its mostly source...
I have been messing around with coreaudio. I have a few questions.
First Question: Is it correct to have separate AudioDeviceIOProc for
every type of audio signal like found in the Apple CASoundLab2?
for example:
a. SineIOProc
b. SquareIOProc
c. TriangleIOProc
d. AdditiveSynthIOProc
e. SoundfileIOProc etc...
I have had good luck so far with this approach (and its very easy...) I
am just wondering what kind of issues I might run across down the road.
Second Question: On retro-fitting an old app to coreaudio...
I started messing around with the patch to the enlightenment sound
daemon to see how they were adding coreaudio support. I abstracted it
into an example of building a buffer that is passed to an
AudioDeviceIOProc. It uses p_threads as well... it runs but the audio
not clear. wondering if I am doing something wrong.
#include <stdio.h>
#include <stdlib.h>
#include <CoreAudio/CoreAudio.h>
#include <machine/limits.h>
#include <math.h>
#include <pthread.h>
#define BUF_SIZE (4 * 1024)
#define RATE 44100
static AudioDeviceID gOutputDeviceID;
static float OutputDataBuf[BUF_SIZE];
static int OutputWroteSamples = 0;
static pthread_mutex_t mutexOutput;
static pthread_cond_t condOutput;
static int audioPlaybackStarted = 0;
static int coreaudio_has_output_device = 0;
static int coreaudio_init = 0;
OSStatus PlaybackIOProc(AudioDeviceID inDevice, const AudioTimeStamp
*inNow, const AudioBufferList *inInputData, const AudioTimeStamp
*inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp
*inOutputTime, void *inClientData)
{
float *bufPtr = outOutputData->mBuffers[0].mData;
int i;
pthread_mutex_lock(&mutexOutput);
for (i = 0; i < OutputWroteSamples; i++)
bufPtr[i] = OutputDataBuf[i];
for ( ; i < BUF_SIZE; i++)
bufPtr[i] = 0;
OutputWroteSamples = 0;
pthread_mutex_unlock(&mutexOutput);
pthread_cond_signal(&condOutput);
return (kAudioHardwareNoError);
}
int audio_open()
{
#define LEN_DEVICE_NAME 64
OSStatus status;
UInt32 propertySize, bufferByteCount;
char deviceName[LEN_DEVICE_NAME];
struct AudioStreamBasicDescription streamDesc;
int rval;
/*
* We only need to do this once, the rest are taken cared by
* disable/enable calback.
*/
if (coreaudio_init)
{
return (0);
}
/********************** playback section ***************************/
/* get default output device */
propertySize = sizeof(gOutputDeviceID);
status =
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
&propertySize, &gOutputDeviceID);
if (status)
{
fprintf(stderr, "get default output device failed, status = %d\n",
(int)status);
return (-2);
}
if (gOutputDeviceID != kAudioDeviceUnknown)
{
/* got default output device */
coreaudio_has_output_device = 1;
/* get output device name */
propertySize = sizeof(char)*LEN_DEVICE_NAME;
status = AudioDeviceGetProperty(gOutputDeviceID, 1, 0,
kAudioDevicePropertyDeviceName, &propertySize, deviceName);
if (status)
{
fprintf(stderr, "get device name failed, status = %d\n",
(int)status);
return (-2);
}
/* get output format */
propertySize = sizeof(struct AudioStreamBasicDescription);
status = AudioDeviceGetProperty(gOutputDeviceID, 1, 0,
kAudioDevicePropertyStreamFormat, &propertySize, &streamDesc);
if (status)
{
fprintf(stderr, "get device property failed, status = %d\n",
(int)status);
return (-2);
}
if ((streamDesc.mSampleRate != 44100.0) || (streamDesc.mFormatID !=
kAudioFormatLinearPCM) || !(streamDesc.mFormatFlags &
kLinearPCMFormatFlagIsFloat) || (streamDesc.mChannelsPerFrame != 2))
{
fprintf (stderr, "unsupported device.\n");
return (-2);
}
/* set buffer size */
bufferByteCount = BUF_SIZE * sizeof(float);
propertySize = sizeof(bufferByteCount);
status = AudioDeviceSetProperty(gOutputDeviceID, 0, 0, 0,
kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount);
if (status)
{
fprintf(stderr, "set device property failed, status = %d\n",
(int)status);
}
fprintf(stderr, "using device %s for output:\n", deviceName);
fprintf(stderr, "\twith sample rate %f, %ld channels and %ld-bit
sample\n", streamDesc.mSampleRate, streamDesc.mChannelsPerFrame,
streamDesc.mBitsPerChannel);
rval = pthread_mutex_init(&mutexOutput, NULL);
if (rval)
{
fprintf(stderr, "mutex init failed\n");
return (-1);
}
rval = pthread_cond_init(&condOutput, NULL);
if (rval)
{
fprintf(stderr, "condition init failed\n");
return (-1);
}
/* Registers PlaybackIOProc with the device without activating it. */
status = AudioDeviceAddIOProc(gOutputDeviceID, PlaybackIOProc,
(void *)1);
}
if (!coreaudio_has_output_device)
{
fprintf(stderr, "unknown output device.\n");
return (-2);
}
/* Indicates the initialization is done */
coreaudio_init = 1;
return 0;
}
void audio_close()
{
OSStatus status;
/* deactivate both of them */
if (coreaudio_has_output_device && audioPlaybackStarted)
{
status = AudioDeviceStop(gOutputDeviceID, PlaybackIOProc);
audioPlaybackStarted = 0;
}
return;
}
int audio_write( void *buffer, int buf_size )
{
OSStatus status;
int remain_to_write = buf_size;
if (!coreaudio_has_output_device)
return -1;
if (!audioPlaybackStarted)
{
status = AudioDeviceStart(gOutputDeviceID, PlaybackIOProc);
audioPlaybackStarted = 1;
}
while (remain_to_write)
{
pthread_mutex_lock(&mutexOutput);
while(OutputWroteSamples == BUF_SIZE)
pthread_cond_wait(&condOutput, &mutexOutput);
{
float *src_data = (float *)buffer + (buf_size -
remain_to_write) / sizeof(float);
float *dst_data = OutputDataBuf + OutputWroteSamples;
int src_samples = remain_to_write / sizeof(float);
int dst_samples = BUF_SIZE - OutputWroteSamples;
int n = (dst_samples < src_samples) ? dst_samples : src_samples;
int i;
for (i = 0; i < n; i++)
dst_data[i] = src_data[i];
OutputWroteSamples += n;
remain_to_write -= n * sizeof(float);
}
pthread_mutex_unlock(&mutexOutput);
}
return (buf_size);
}
void sinetone(void *buf, int freq, int speed, int length, long offset )
{
int i;
float sample;
float phase = (float)freq * M_PI * 2.0 / (float)speed;
float amp = 0.5;
float *ss_buf = (float *)buf;
//printf( "freq=%d,\tspeed=%d,\tlen=%ld\n", freq, speed, length );
for ( i = 0 ; i < length ; i+=2 )
{
sample = sin(phase) * amp;
phase = phase + freq;
ss_buf[i] = sample;
ss_buf[i+1] = sample;
}
return;
}
int main (int argc, const char * argv[])
{
int sample_size = 0;
int buf_size_sample = 0;
int buf_size_octets = 0;
int i = 0;
int default_rate = RATE, default_buf_size = BUF_SIZE;
int j, freq = 440;
void *output_buffer = NULL;
sample_size = sizeof(float);
buf_size_sample = default_buf_size / 2;
buf_size_octets = buf_size_sample * sample_size;
/* allocate and zero out buffer */
output_buffer = (float *) malloc(buf_size_octets);
memset(output_buffer, 0, buf_size_octets);
/* open audio device */
audio_open();
/* write a few buffers of sinetone audio */
printf("Playing");
for ( freq = 55; freq < default_rate/2; freq *= 2, i++ )
{
/* repeat the freq for a few buffer lengths */
for ( j = 0; j < default_rate / 2 / buf_size_sample; j++ )
{
sinetone(output_buffer, freq, default_rate, buf_size_sample,
j * buf_size_sample);
audio_write(output_buffer, buf_size_octets);
printf(".");
}
}
printf("\nDone!\n");
audio_close();
return 0;
}