src/audio/amigaos/SDL_ahiaudio.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Dec 2001 12:30:25 +0000
changeset 249 e3d0d44f6f2e
parent 21 75a95f82bc1f
child 252 e8157fcb3114
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     5635-34 Springhouse Dr.
    21     Pleasanton, CA 94588 (USA)
    22     slouken@devolution.com
    23 */
    24 
    25 #ifdef SAVE_RCSID
    26 static char rcsid =
    27  "@(#) $Id$";
    28 #endif
    29 
    30 /* Allow access to a raw mixing buffer (for AmigaOS) */
    31 
    32 #include <stdio.h>
    33 #include <stdlib.h>
    34 #include <string.h>
    35 
    36 #include "SDL_endian.h"
    37 #include "SDL_audio.h"
    38 #include "SDL_audiomem.h"
    39 #include "SDL_audio_c.h"
    40 #include "SDL_ahiaudio.h"
    41 
    42 /* Audio driver functions */
    43 static int AHI_OpenAudio(_THIS, SDL_AudioSpec *spec);
    44 static void AHI_WaitAudio(_THIS);
    45 static void AHI_PlayAudio(_THIS);
    46 static Uint8 *AHI_GetAudioBuf(_THIS);
    47 static void AHI_CloseAudio(_THIS);
    48 
    49 #ifndef __SASC
    50 	#define mymalloc(x) AllocVec(x,MEMF_PUBLIC) 
    51 	#define myfree FreeVec
    52 #else
    53 	#define mymalloc malloc
    54 	#define myfree free
    55 #endif
    56 
    57 /* Audio driver bootstrap functions */
    58 
    59 static int Audio_Available(void)
    60 {
    61 	int ok=0;
    62 	struct MsgPort *p;
    63 	struct AHIRequest *req;
    64 
    65 	if(p=CreateMsgPort())
    66 	{
    67 		if(req=(struct AHIRequest *)CreateIORequest(p,sizeof(struct AHIRequest)))
    68 		{
    69 			req->ahir_Version=4;
    70 
    71 			if(!OpenDevice(AHINAME,0,(struct IORequest *)req,NULL))
    72 			{
    73 				D(bug("AHI available.\n"));
    74 				ok=1;
    75 				CloseDevice((struct IORequest *)req);
    76 			}
    77 			DeleteIORequest((struct IORequest *)req);
    78 		}
    79 		DeleteMsgPort(p);
    80 	}
    81 
    82 	D(if(!ok) bug("AHI not available\n"));
    83 	return ok;
    84 }
    85 
    86 static void Audio_DeleteDevice(SDL_AudioDevice *device)
    87 {
    88 	free(device->hidden);
    89 	free(device);
    90 }
    91 
    92 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
    93 {
    94 	SDL_AudioDevice *this;
    95 
    96 #ifndef NO_AMIGADEBUG
    97 	D(bug("AHI created...\n"));
    98 #endif
    99 
   100 	/* Initialize all variables that we clean on shutdown */
   101 	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
   102 	if ( this ) {
   103 		memset(this, 0, (sizeof *this));
   104 		this->hidden = (struct SDL_PrivateAudioData *)
   105 				malloc((sizeof *this->hidden));
   106 	}
   107 	if ( (this == NULL) || (this->hidden == NULL) ) {
   108 		SDL_OutOfMemory();
   109 		if ( this ) {
   110 			free(this);
   111 		}
   112 		return(0);
   113 	}
   114 	memset(this->hidden, 0, (sizeof *this->hidden));
   115 
   116 	/* Set the function pointers */
   117 	this->OpenAudio = AHI_OpenAudio;
   118 	this->WaitAudio = AHI_WaitAudio;
   119 	this->PlayAudio = AHI_PlayAudio;
   120 	this->GetAudioBuf = AHI_GetAudioBuf;
   121 	this->CloseAudio = AHI_CloseAudio;
   122 
   123 	this->free = Audio_DeleteDevice;
   124 
   125 	return this;
   126 }
   127 
   128 AudioBootStrap AHI_bootstrap = {
   129 	"AHI", Audio_Available, Audio_CreateDevice
   130 };
   131 
   132 
   133 void static AHI_WaitAudio(_THIS)
   134 {
   135 	if(!CheckIO((struct IORequest *)audio_req[current_buffer]))
   136 	{
   137 		WaitIO((struct IORequest *)audio_req[current_buffer]);
   138 //		AbortIO((struct IORequest *)audio_req[current_buffer]);
   139 	}
   140 }
   141 
   142 static void AHI_PlayAudio(_THIS)
   143 {
   144 	if(playing>1)
   145 		WaitIO((struct IORequest *)audio_req[current_buffer]);
   146 
   147 	/* Write the audio data out */
   148 	audio_req[current_buffer] -> ahir_Std. io_Message.mn_Node.ln_Pri = 60;
   149 	audio_req[current_buffer] -> ahir_Std. io_Data                = mixbuf[current_buffer];
   150 	audio_req[current_buffer] -> ahir_Std. io_Length              = this->hidden->size;
   151 	audio_req[current_buffer] -> ahir_Std. io_Offset              = 0;
   152 	audio_req[current_buffer] -> ahir_Std . io_Command            = CMD_WRITE;
   153 	audio_req[current_buffer] -> ahir_Frequency                   = this->hidden->freq;
   154 	audio_req[current_buffer] -> ahir_Volume                      = 0x10000;
   155 	audio_req[current_buffer] -> ahir_Type                        = this->hidden->type;
   156 	audio_req[current_buffer] -> ahir_Position                    = 0x8000;
   157 	audio_req[current_buffer] -> ahir_Link                        = (playing>0 ? audio_req[current_buffer^1] : NULL);
   158 
   159 	SendIO((struct IORequest *)audio_req[current_buffer]);
   160 	current_buffer^=1;
   161 
   162 	playing++;
   163 }
   164 
   165 static Uint8 *AHI_GetAudioBuf(_THIS)
   166 {
   167 	return(mixbuf[current_buffer]);
   168 }
   169 
   170 static void AHI_CloseAudio(_THIS)
   171 {
   172 	D(bug("Closing audio...\n"));
   173 
   174 	playing=0;
   175 
   176 	if(audio_req[0])
   177 	{
   178 		if(audio_req[1])
   179 		{
   180 			D(bug("Break req[1]...\n"));
   181 
   182 			AbortIO((struct IORequest *)audio_req[1]);
   183 			WaitIO((struct IORequest *)audio_req[1]);
   184 		}
   185 
   186 		D(bug("Break req[0]...\n"));
   187 
   188 		AbortIO((struct IORequest *)audio_req[0]);
   189 		WaitIO((struct IORequest *)audio_req[0]);
   190 
   191 		if(audio_req[1])
   192 		{
   193 			D(bug("Break AGAIN req[1]...\n"));
   194 			AbortIO((struct IORequest *)audio_req[1]);
   195 			WaitIO((struct IORequest *)audio_req[1]);
   196 		}
   197 // Double abort to be sure to break the dbuffering process.
   198 
   199 		SDL_Delay(200);
   200 
   201 		D(bug("Reqs breaked, closing device...\n"));
   202 		CloseDevice((struct IORequest *)audio_req[0]);
   203 		D(bug("Device closed, freeing memory...\n"));
   204 		myfree(audio_req[1]);
   205 		D(bug("Memory freed, deleting IOReq...\n")); 
   206 		DeleteIORequest((struct IORequest *)audio_req[0]);
   207 		audio_req[0]=audio_req[1]=NULL;
   208 	}
   209 
   210 	D(bug("Freeing mixbuf[0]...\n"));
   211 	if ( mixbuf[0] != NULL ) {
   212 		myfree(mixbuf[0]);
   213 //		SDL_FreeAudioMem(mixbuf[0]);
   214 		mixbuf[0] = NULL;
   215 	}
   216 
   217 	D(bug("Freeing mixbuf[1]...\n"));
   218 	if ( mixbuf[1] != NULL ) {
   219 		myfree(mixbuf[1]);
   220 //		SDL_FreeAudioMem(mixbuf[1]);
   221 		mixbuf[1] = NULL;
   222 	}
   223 
   224 	D(bug("Freeing audio_port...\n"));
   225 
   226 	if ( audio_port != NULL ) {
   227 		DeleteMsgPort(audio_port);
   228 		audio_port = NULL;
   229 	}
   230 	D(bug("...done!\n"));
   231 }
   232 
   233 static int AHI_OpenAudio(_THIS, SDL_AudioSpec *spec)
   234 {	
   235 //	int width;
   236 
   237 	D(bug("AHI opening...\n"));
   238 
   239 	/* Determine the audio parameters from the AudioSpec */
   240 	switch ( spec->format & 0xFF ) {
   241 
   242 		case 8: { /* Signed 8 bit audio data */
   243 			D(bug("Samples a 8 bit...\n"));
   244 			spec->format = AUDIO_S8;
   245 			this->hidden->bytespersample=1;
   246 			if(spec->channels<2)
   247 				this->hidden->type = AHIST_M8S;
   248 			else
   249 				this->hidden->type = AHIST_S8S;
   250 		}
   251 		break;
   252 
   253 		case 16: { /* Signed 16 bit audio data */
   254 			D(bug("Samples a 16 bit...\n"));
   255 			spec->format = AUDIO_S16MSB;
   256 			this->hidden->bytespersample=2;
   257 			if(spec->channels<2)
   258 				this->hidden->type = AHIST_M16S;
   259 			else
   260 				this->hidden->type = AHIST_S16S;
   261 		}
   262 		break;
   263 
   264 		default: {
   265 			SDL_SetError("Unsupported audio format");
   266 			return(-1);
   267 		}
   268 	}
   269 
   270 	if(spec->channels!=1 && spec->channels!=2)
   271 	{
   272 		D(bug("Wrong channel number!\n"));
   273 		SDL_SetError("Channel number non supported");
   274 		return -1;
   275 	}
   276 
   277 	D(bug("Before CalculateAudioSpec\n"));
   278 	/* Update the fragment size as size in bytes */
   279 	SDL_CalculateAudioSpec(spec);
   280 
   281 	D(bug("Before CreateMsgPort\n"));
   282 
   283 	if(!(audio_port=CreateMsgPort()))
   284 	{
   285 		SDL_SetError("Unable to create a MsgPort");
   286 		return -1;
   287 	}
   288 
   289 	D(bug("Before CreateIORequest\n"));
   290 
   291 	if(!(audio_req[0]=(struct AHIRequest *)CreateIORequest(audio_port,sizeof(struct AHIRequest))))
   292 	{
   293 		SDL_SetError("Unable to create an AHIRequest");
   294 		DeleteMsgPort(audio_port);
   295 		return -1;
   296 	}
   297 
   298 	audio_req[0]->ahir_Version = 4;
   299 
   300 	if(OpenDevice(AHINAME,0,(struct IORequest *)audio_req[0],NULL))
   301 	{
   302 		SDL_SetError("Unable to open AHI device!\n");
   303 		DeleteIORequest((struct IORequest *)audio_req[0]);
   304 		DeleteMsgPort(audio_port);
   305 		return -1;
   306 	}
   307 	
   308 	D(bug("AFTER opendevice\n"));
   309 
   310 	/* Set output frequency and size */
   311 	this->hidden->freq = spec->freq;
   312 	this->hidden->size = spec->size;
   313 
   314 	D(bug("Before buffer allocation\n"));
   315 
   316 	/* Allocate mixing buffer */
   317 	mixbuf[0] = (Uint8 *)mymalloc(spec->size);
   318 	mixbuf[1] = (Uint8 *)mymalloc(spec->size);
   319 
   320 	D(bug("Before audio_req allocation\n"));
   321 
   322 	if(!(audio_req[1]=mymalloc(sizeof(struct AHIRequest))))
   323 	{
   324 		SDL_OutOfMemory();
   325 		return(-1);
   326 	}
   327 	
   328 	D(bug("Before audio_req memcpy\n"));
   329 
   330 	memcpy(audio_req[1],audio_req[0],sizeof(struct AHIRequest));
   331 
   332 	if ( mixbuf[0] == NULL || mixbuf[1] == NULL ) {
   333 		SDL_OutOfMemory();
   334 		return(-1);
   335 	}
   336 
   337 	D(bug("Before mixbuf memset\n"));
   338 
   339 	memset(mixbuf[0], spec->silence, spec->size);
   340 	memset(mixbuf[1], spec->silence, spec->size);
   341 
   342 	current_buffer=0;
   343 	playing=0;
   344 
   345 	D(bug("AHI opened: freq:%ld mixbuf:%lx/%lx buflen:%ld bits:%ld channels:%ld\n",spec->freq,mixbuf[0],mixbuf[1],spec->size,this->hidden->bytespersample*8,spec->channels));
   346 
   347 	/* We're ready to rock and roll. :-) */
   348 	return(0);
   349 }