diff src/audio/ums/SDL_umsaudio.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children c9b51268668f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audio/ums/SDL_umsaudio.c	Thu Apr 26 16:45:43 2001 +0000
@@ -0,0 +1,555 @@
+/*
+    AIX support for the SDL - Simple DirectMedia Layer
+    Copyright (C) 2000  Carsten Griwodz
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Carsten Griwodz
+    griff@kom.tu-darmstadt.de
+
+    based on linux/SDL_dspaudio.c by Sam Lantinga
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+/* Allow access to a raw mixing buffer */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "SDL_audio.h"
+#include "SDL_error.h"
+#include "SDL_audio_c.h"
+#include "SDL_audiodev_c.h"
+#include "SDL_umsaudio.h"
+
+/* The tag name used by UMS audio */
+#define UMS_DRIVER_NAME         "ums"
+
+#define DEBUG_AUDIO 1
+
+/* Audio driver functions */
+static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void UMS_PlayAudio(_THIS);
+static Uint8 *UMS_GetAudioBuf(_THIS);
+static void UMS_CloseAudio(_THIS);
+
+static UMSAudioDevice_ReturnCode UADOpen(_THIS,  string device, string mode, long flags);
+static UMSAudioDevice_ReturnCode UADClose(_THIS);
+static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits);
+static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits);
+static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate);
+static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order);
+static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt);
+static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt);
+static UMSAudioDevice_ReturnCode UADInitialize(_THIS);
+static UMSAudioDevice_ReturnCode UADStart(_THIS);
+static UMSAudioDevice_ReturnCode UADStop(_THIS);
+static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS,  UMSAudioTypes_TimeFormat fmt );
+static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS,  long* buff_size );
+static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS,  long* buff_size );
+static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS,  long* buff_size );
+static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS,  long bytes, long* bytes_ret );
+static UMSAudioDevice_ReturnCode UADSetVolume(_THIS,  long volume );
+static UMSAudioDevice_ReturnCode UADSetBalance(_THIS,  long balance );
+static UMSAudioDevice_ReturnCode UADSetChannels(_THIS,  long channels );
+static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS,  boolean block );
+static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS,  string output, long* left_gain, long* right_gain);
+static UMSAudioDevice_ReturnCode UADWrite(_THIS,  UMSAudioTypes_Buffer* buff, long samples, long* samples_written);
+
+/* Audio driver bootstrap functions */
+static int Audio_Available(void)
+{
+    return 1;
+}
+
+static void Audio_DeleteDevice(_THIS)
+{
+    if(this->hidden->playbuf._buffer) free(this->hidden->playbuf._buffer);
+    if(this->hidden->fillbuf._buffer) free(this->hidden->fillbuf._buffer);
+    _somFree( this->hidden->umsdev );
+    free(this->hidden);
+    free(this);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+    SDL_AudioDevice *this;
+
+    /*
+     * Allocate and initialize management storage and private management
+     * storage for this SDL-using library.
+     */
+    this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
+    if ( this ) {
+        memset(this, 0, (sizeof *this));
+        this->hidden = (struct SDL_PrivateAudioData *)malloc((sizeof *this->hidden));
+    }
+    if ( (this == NULL) || (this->hidden == NULL) ) {
+        SDL_OutOfMemory();
+        if ( this ) {
+            free(this);
+        }
+        return(0);
+    }
+    memset(this->hidden, 0, (sizeof *this->hidden));
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "Creating UMS Audio device\n");
+#endif
+
+    /*
+     * Calls for UMS env initialization and audio object construction.
+     */
+    this->hidden->ev     = somGetGlobalEnvironment();
+    this->hidden->umsdev = UMSAudioDeviceNew();
+
+    /*
+     * Set the function pointers.
+     */
+    this->OpenAudio   = UMS_OpenAudio;
+    this->WaitAudio   = NULL;           /* we do blocking output */
+    this->PlayAudio   = UMS_PlayAudio;
+    this->GetAudioBuf = UMS_GetAudioBuf;
+    this->CloseAudio  = UMS_CloseAudio;
+    this->free        = Audio_DeleteDevice;
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "done\n");
+#endif
+    return this;
+}
+
+AudioBootStrap UMS_bootstrap = {
+	UMS_DRIVER_NAME, "AUX UMS audio",
+	Audio_Available, Audio_CreateDevice
+};
+
+static Uint8 *UMS_GetAudioBuf(_THIS)
+{
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "enter UMS_GetAudioBuf\n");
+#endif
+    return this->hidden->fillbuf._buffer;
+/*
+    long                      bufSize;
+    UMSAudioDevice_ReturnCode rc;
+
+    rc = UADSetTimeFormat(this, UMSAudioTypes_Bytes );
+    rc = UADWriteBuffSize(this,  bufSize );
+*/
+}
+
+static void UMS_CloseAudio(_THIS)
+{
+    UMSAudioDevice_ReturnCode rc;
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "enter UMS_CloseAudio\n");
+#endif
+    rc = UADPlayRemainingData(this, TRUE);
+    rc = UADStop(this);
+    rc = UADClose(this);
+}
+
+static void UMS_PlayAudio(_THIS)
+{
+    UMSAudioDevice_ReturnCode rc;
+    long                      samplesToWrite;
+    long                      samplesWritten;
+    UMSAudioTypes_Buffer      swpbuf;
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "enter UMS_PlayAudio\n");
+#endif
+    samplesToWrite = this->hidden->playbuf._length/this->hidden->bytesPerSample;
+    do
+    {
+        rc = UADWrite(this,  &this->hidden->playbuf,
+		       samplesToWrite,
+	               &samplesWritten );
+	samplesToWrite -= samplesWritten;
+
+	/* rc values: UMSAudioDevice_Success
+	 *            UMSAudioDevice_Failure
+	 *            UMSAudioDevice_Preempted
+	 *            UMSAudioDevice_Interrupted
+	 *            UMSAudioDevice_DeviceError
+	 */
+	if ( rc == UMSAudioDevice_DeviceError ) {
+#ifdef DEBUG_AUDIO
+	    fprintf(stderr, "Returning from PlayAudio with devices error\n");
+#endif
+	    return;
+	}
+    }
+    while(samplesToWrite>0);
+
+    SDL_LockAudio();
+    memcpy( &swpbuf,                &this->hidden->playbuf, sizeof(UMSAudioTypes_Buffer) );
+    memcpy( &this->hidden->playbuf, &this->hidden->fillbuf, sizeof(UMSAudioTypes_Buffer) );
+    memcpy( &this->hidden->fillbuf, &swpbuf,                sizeof(UMSAudioTypes_Buffer) );
+    SDL_UnlockAudio();
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "Wrote audio data and swapped buffer\n");
+#endif
+}
+
+#if 0
+// 	/* Set the DSP frequency */
+// 	value = spec->freq;
+// 	if ( ioctl(this->hidden->audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) {
+// 		SDL_SetError("Couldn't set audio frequency");
+// 		return(-1);
+// 	}
+// 	spec->freq = value;
+#endif
+
+static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+    char*  audiodev = "/dev/paud0";
+    long   lgain;
+    long   rgain;
+    long   outRate;
+    long   outBufSize;
+    long   bitsPerSample;
+    long   samplesPerSec;
+    long   success;
+    Uint16 test_format;
+    int    frag_spec;
+    UMSAudioDevice_ReturnCode rc;
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "enter UMS_OpenAudio\n");
+#endif
+    rc = UADOpen(this, audiodev,"PLAY", UMSAudioDevice_BlockingIO);
+    if ( rc != UMSAudioDevice_Success ) {
+	SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+	return -1;
+    }
+ 
+    rc = UADSetAudioFormatType(this, "PCM"); 
+
+    success = 0;
+    test_format = SDL_FirstAudioFormat(spec->format);
+    do
+    {
+#ifdef DEBUG_AUDIO
+        fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+        switch ( test_format )
+        {
+        case AUDIO_U8:
+/* from the mac code: better ? */
+/* sample_bits = spec->size / spec->samples / spec->channels * 8; */
+	    success       = 1;
+            bitsPerSample = 8;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "MSB");       /* irrelevant */
+            rc = UADSetNumberFormat(this, "UNSIGNED");
+            break;
+        case AUDIO_S8:
+	    success       = 1;
+            bitsPerSample = 8;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "MSB");       /* irrelevant */
+            rc = UADSetNumberFormat(this, "SIGNED");
+            break;
+        case AUDIO_S16LSB:
+	    success       = 1;
+            bitsPerSample = 16;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "LSB");
+            rc = UADSetNumberFormat(this, "SIGNED");
+            break;
+        case AUDIO_S16MSB:
+	    success       = 1;
+            bitsPerSample = 16;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "MSB");
+            rc = UADSetNumberFormat(this, "SIGNED");
+            break;
+        case AUDIO_U16LSB:
+	    success       = 1;
+            bitsPerSample = 16;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "LSB");
+            rc = UADSetNumberFormat(this, "UNSIGNED");
+            break;
+        case AUDIO_U16MSB:
+	    success       = 1;
+            bitsPerSample = 16;
+            rc = UADSetSampleRate(this,  spec->freq << 16, &outRate );
+            rc = UADSetByteOrder(this, "MSB");
+            rc = UADSetNumberFormat(this, "UNSIGNED");
+            break;
+        default:
+            break;
+        }
+        if ( ! success ) {
+            test_format = SDL_NextAudioFormat();
+        }
+    }
+    while ( ! success && test_format );
+
+    if ( success == 0 ) {
+        SDL_SetError("Couldn't find any hardware audio formats");
+        return -1;
+    }
+
+    spec->format = test_format;
+
+    for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
+    if ( (0x01<<frag_spec) != spec->size ) {
+        SDL_SetError("Fragment size must be a power of two");
+        return -1;
+    }
+    if ( frag_spec > 2048 ) frag_spec = 2048;
+
+    this->hidden->bytesPerSample   = (bitsPerSample / 8) * spec->channels;
+    samplesPerSec                  = this->hidden->bytesPerSample * outRate;
+
+    this->hidden->playbuf._length  = 0;
+    this->hidden->playbuf._maximum = spec->size;
+    this->hidden->playbuf._buffer  = (unsigned char*)malloc(spec->size);
+    this->hidden->fillbuf._length  = 0;
+    this->hidden->fillbuf._maximum = spec->size;
+    this->hidden->fillbuf._buffer  = (unsigned char*)malloc(spec->size);
+
+    rc = UADSetBitsPerSample(this,  bitsPerSample );
+    rc = UADSetDMABufferSize(this,  frag_spec, &outBufSize );
+    rc = UADSetChannels(this, spec->channels);      /* functions reduces to mono or stereo */
+
+    lgain = 100; /*maximum left input gain*/
+    rgain = 100; /*maimum right input gain*/
+    rc = UADEnableOutput(this, "LINE_OUT",&lgain,&rgain);
+    rc = UADInitialize(this);
+    rc = UADStart(this);
+    rc = UADSetVolume(this, 100);
+    rc = UADSetBalance(this, 0);
+
+    /* We're ready to rock and roll. :-) */
+    return 0;
+}
+
+
+static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits)
+{
+    return UMSAudioDevice_get_bits_per_sample( this->hidden->umsdev,
+					       this->hidden->ev,
+					       bits );
+}
+
+static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits)
+{
+    return UMSAudioDevice_set_bits_per_sample( this->hidden->umsdev,
+					       this->hidden->ev,
+					       bits );
+}
+
+static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate)
+{
+    /* from the mac code: sample rate = spec->freq << 16; */
+    return UMSAudioDevice_set_sample_rate( this->hidden->umsdev,
+					   this->hidden->ev,
+					   rate,
+					   set_rate );
+}
+
+static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order)
+{
+    return UMSAudioDevice_set_byte_order( this->hidden->umsdev,
+					  this->hidden->ev,
+					  byte_order );
+}
+
+static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt)
+{
+    /* possible PCM, A_LAW or MU_LAW */
+    return UMSAudioDevice_set_audio_format_type( this->hidden->umsdev,
+						 this->hidden->ev,
+						 fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt)
+{
+    /* possible SIGNED, UNSIGNED, or TWOS_COMPLEMENT */
+    return UMSAudioDevice_set_number_format( this->hidden->umsdev,
+					     this->hidden->ev,
+					     fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADInitialize(_THIS)
+{
+    return UMSAudioDevice_initialize( this->hidden->umsdev,
+				      this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADStart(_THIS)
+{
+    return UMSAudioDevice_start( this->hidden->umsdev,
+				 this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS,  UMSAudioTypes_TimeFormat fmt )
+{
+    /*
+     * Switches the time format to the new format, immediately.
+     * possible UMSAudioTypes_Msecs, UMSAudioTypes_Bytes or UMSAudioTypes_Samples
+     */
+    return UMSAudioDevice_set_time_format( this->hidden->umsdev,
+					   this->hidden->ev,
+					   fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS,  long* buff_size )
+{
+    /*
+     * returns write buffer size in the current time format
+     */
+    return UMSAudioDevice_write_buff_size( this->hidden->umsdev,
+                                           this->hidden->ev,
+					   buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS,  long* buff_size )
+{
+    /*
+     * returns amount of available space in the write buffer
+     * in the current time format
+     */
+    return UMSAudioDevice_write_buff_remain( this->hidden->umsdev,
+                                             this->hidden->ev,
+					     buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS,  long* buff_size )
+{
+    /*
+     * returns amount of filled space in the write buffer
+     * in the current time format
+     */
+    return UMSAudioDevice_write_buff_used( this->hidden->umsdev,
+                                           this->hidden->ev,
+					   buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS,  long bytes, long* bytes_ret )
+{
+    /*
+     * Request a new DMA buffer size, maximum requested size 2048.
+     * Takes effect with next initialize() call.
+     * Devices may or may not support DMA.
+     */
+    return UMSAudioDevice_set_DMA_buffer_size( this->hidden->umsdev,
+					       this->hidden->ev,
+					       bytes,
+					       bytes_ret );
+}
+
+static UMSAudioDevice_ReturnCode UADSetVolume(_THIS,  long volume )
+{
+    /*
+     * Set the volume.
+     * Takes effect immediately.
+     */
+    return UMSAudioDevice_set_volume( this->hidden->umsdev,
+				      this->hidden->ev,
+				      volume );
+}
+
+static UMSAudioDevice_ReturnCode UADSetBalance(_THIS,  long balance )
+{
+    /*
+     * Set the balance.
+     * Takes effect immediately.
+     */
+    return UMSAudioDevice_set_balance( this->hidden->umsdev,
+				       this->hidden->ev,
+				       balance );
+}
+
+static UMSAudioDevice_ReturnCode UADSetChannels(_THIS,  long channels )
+{
+    /*
+     * Set mono or stereo.
+     * Takes effect with next initialize() call.
+     */
+    if ( channels != 1 ) channels = 2;
+    return UMSAudioDevice_set_number_of_channels( this->hidden->umsdev,
+				                  this->hidden->ev,
+				                  channels );
+}
+
+static UMSAudioDevice_ReturnCode UADOpen(_THIS,  string device, string mode, long flags)
+{
+    return UMSAudioDevice_open( this->hidden->umsdev,
+				this->hidden->ev,
+				device,
+				mode,
+				flags );
+}
+
+static UMSAudioDevice_ReturnCode UADWrite(_THIS,  UMSAudioTypes_Buffer* buff,
+                                           long samples,
+					   long* samples_written)
+{
+    return UMSAudioDevice_write( this->hidden->umsdev,
+				 this->hidden->ev,
+				 buff,
+				 samples,
+				 samples_written );
+}
+
+static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS,  boolean block )
+{
+    return UMSAudioDevice_play_remaining_data( this->hidden->umsdev,
+					       this->hidden->ev,
+					       block);
+}
+
+static UMSAudioDevice_ReturnCode UADStop(_THIS)
+{
+    return UMSAudioDevice_stop( this->hidden->umsdev,
+				this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADClose(_THIS)
+{
+    return UMSAudioDevice_close( this->hidden->umsdev,
+				 this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS,  string output, long* left_gain, long* right_gain)
+{
+    return UMSAudioDevice_enable_output( this->hidden->umsdev,
+					 this->hidden->ev,
+					 output,
+					 left_gain,
+					 right_gain );
+}
+