1 /* Sysdep Irix_al sound dsp driver
2 
3    Copyright 2001 by Brandon Corey
4 
5    This file and the acompanying files in this directory are free software;
6    you can redistribute them and/or modify them under the terms of the GNU
7    Library General Public License as published by the Free Software Foundation;
8    either version 2 of the License, or (at your option) any later version.
9 
10    These files are distributed in the hope that they 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 these files; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19 
20    Addendum: This file may also be used under the terms of the MAME license, by
21    permission of Brandon Corey.  (For the text of the license, see
22    http://www.mame.net/readme.html.)
23 */
24 /* Changelog
25 Version 0.1, April 15, 2001
26 - initial release
27 Version 0.2, April 15, 2001
28 - added sample frequency code so that a sample frequency other than the
29 	system default is usable
30 */
31 
32 /* Notes/Future
33 1) I've only compiled this with MIPSPro, although it should work with gcc.
34 	If someone could test that and email me, I'd appreciate it.
35 2) Will add mixer support for the next version
36 3) Use IRIX_DEBUG and IRIX_DEBUG_VERBOSE for Extra Info
37 4) Use FORCEMONO to force MONO output
38 5) Use FORCE8BIT to force 8 Bit output
39 
40 Email: brandon@blackboxcentral.com
41 */
42 
43 /* #define IRIX_DEBUG */
44 /* #define IRIX_DEBUG_VERBOSE */
45 /* #define FORCEMONO */
46 /* #define FORCE8BIT */
47 /* #define SYSDEP_DSP_IRIX */
48 
49 #ifdef SYSDEP_DSP_IRIX
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <sys/ioctl.h>
53 #include <dmedia/audio.h>
54 #include "sysdep/sysdep_dsp.h"
55 #include "sysdep/sysdep_dsp_priv.h"
56 #include "sysdep/plugin_manager.h"
57 
58 /* our per instance private data struct */
59 struct irix_dsp_priv_data {
60 	ALport devAudio;
61 	ALconfig devAudioConfig;
62 	unsigned int buffer_samples;
63 	int sampwidth;
64 	int sampchan;
65 	int port_status;
66 };
67 
68 /* public methods prototypes (static but exported through the sysdep_dsp or
69    plugin struct) */
70 static void *irix_dsp_create(const void *flags);
71 static void irix_dsp_destroy(struct sysdep_dsp_struct *dsp);
72 static int irix_dsp_get_freespace(struct sysdep_dsp_struct *dsp);
73 static int irix_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data,
74    int count);
75 
76 /* public variables */
77 const struct plugin_struct sysdep_dsp_irix = {
78    "irix_al",
79    "sysdep_dsp",
80    "IrixAL DSP plugin",
81    NULL, /* no options */
82    NULL, /* no init */
83    NULL, /* no exit */
84    irix_dsp_create,
85    3     /* high priority as direct device access */
86 };
87 
88 
89 /* public methods (static but exported through the sysdep_dsp or plugin
90    struct) */
irix_dsp_create(const void * flags)91 static void *irix_dsp_create(const void *flags)
92 {
93 	ALpv pvs[4];
94 	long tempbits, tempchan;
95 	long oldrate;
96 	long ratechange = 0;
97 	struct irix_dsp_priv_data *priv = NULL;
98 	struct sysdep_dsp_struct *dsp = NULL;
99 	const struct sysdep_dsp_create_params *params = flags;
100 
101    /* allocate the dsp struct */
102    if (!(dsp = calloc(1, sizeof(struct sysdep_dsp_struct))))
103    {
104       fprintf(stderr, "Error: malloc failed for struct sysdep_dsp_struct.\n");
105       return NULL;
106    }
107 
108    /* alloc private data */
109    if(!(priv = calloc(1, sizeof(struct irix_dsp_priv_data))))
110    {
111       fprintf(stderr, "Error: malloc failed for struct irix_dsp_priv_data.\n");
112       irix_dsp_destroy(dsp);
113       return NULL;
114    }
115 
116 	/* fill in the functions and some data */
117 	priv->port_status = -1;
118    	dsp->_priv = priv;
119 	dsp->get_freespace = irix_dsp_get_freespace;
120    	dsp->write = irix_dsp_write;
121    	dsp->destroy = irix_dsp_destroy;
122    	dsp->hw_info.type = params->type;
123    	dsp->hw_info.samplerate = params->samplerate;
124 
125    	/* open the sound device */
126 	pvs[0].param = AL_MAX_PORTS;
127 	pvs[1].param = AL_UNUSED_PORTS;
128 	if (alGetParams(AL_SYSTEM,pvs,2) < 0) {
129 		fprintf(stderr, "alGetParams failed: %s\n", alGetErrorString(oserror()));
130 		irix_dsp_destroy(dsp);
131 		return NULL;
132 	}
133 
134 	if (pvs[1].value.i < 1) {
135 		fprintf(stderr, "No available audio ports.\n");
136 		irix_dsp_destroy(dsp);
137 		return NULL;
138 	}
139 
140 	pvs[0].param = AL_RATE;
141 	if (alGetParams(AL_DEFAULT_OUTPUT,pvs,1) < 0) {
142 		fprintf(stderr, "alGetParams failed: %s\n", alGetErrorString(oserror()));
143 		irix_dsp_destroy(dsp);
144 		return NULL;
145 	}
146 
147     /* If samplerate is different than systems, override */
148 	oldrate = pvs[0].value.i;
149 	if (pvs[0].value.i != dsp->hw_info.samplerate)
150 	{
151 		ratechange = 1;
152 		fprintf(stderr, "System sample rate was %dHz, forcing %dHz instead.\n",
153 			pvs[0].value.i, dsp->hw_info.samplerate);
154 	}
155 
156 	/* create a clean config descriptor */
157 	if ( (priv->devAudioConfig = alNewConfig() ) == (ALconfig) NULL ) {
158 		fprintf(stderr, "Cannot get a Descriptor. Exiting..\n");
159 		irix_dsp_destroy(dsp);
160 		return NULL;
161 	}
162 
163 #ifdef FORCE8BIT
164 	dsp->hw_info.type &= ~SYSDEP_DSP_16BIT;
165 #endif
166 #ifdef FORCEMONO
167 	dsp->hw_info.type &= ~SYSDEP_DSP_STEREO;
168 #endif
169 
170 	priv->buffer_samples = dsp->hw_info.samplerate * params->bufsize;
171 
172 	tempchan = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? 2:1;
173 	tempbits = (dsp->hw_info.type & SYSDEP_DSP_16BIT)? 2:1;
174 
175 	priv->buffer_samples = priv->buffer_samples * tempchan;
176 
177 	priv->sampwidth = tempbits;
178 	priv->sampchan = tempchan;
179 
180 #ifdef IRIX_DEBUG
181 	fprintf(stderr, "Sample Rate Requested: %d\n", dsp->hw_info.samplerate);
182 	fprintf(stderr, "Buffer Size Requested: %d\n", priv->buffer_samples);
183 #endif
184 
185 	fprintf(stderr, "Setting sound to %dHz, %d bit, %s\n",dsp->hw_info.samplerate,
186 		tempbits * 8, (tempchan == 2) ? "stereo" : "mono");
187 
188 	/* channel specific audio parameters */
189 	alSetChannels(priv->devAudioConfig, tempchan);						/* channels */
190 	alSetQueueSize(priv->devAudioConfig,(long) priv->buffer_samples);	/* buffer size */
191 	alSetSampFmt(priv->devAudioConfig, AL_SAMPFMT_TWOSCOMP);			/* BTC */
192 	alSetWidth(priv->devAudioConfig, tempbits);							/* bitrate */
193 
194 	/* global audio parameters */
195 	pvs[0].param = AL_MASTER_CLOCK;
196 	pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
197 	pvs[1].param = AL_RATE;
198 	pvs[1].value.i = dsp->hw_info.samplerate;
199 	if (alSetParams(AL_DEFAULT_OUTPUT,pvs,2) < 0) {
200 		fprintf(stderr, "Error: Cannot configure the sound system.\n");
201 		irix_dsp_destroy(dsp);
202 		return(NULL);
203 	}
204 
205 	/* Get new sample rate */
206 	pvs[0].param = AL_RATE;
207 	if (alGetParams(AL_DEFAULT_OUTPUT,pvs,1) < 0) {
208 		fprintf(stderr, "failed\n");
209 		irix_dsp_destroy(dsp);
210 		return NULL;
211 	}
212 
213     /* Verify rate was changed */
214 	if ((ratechange == 1) && (oldrate == pvs[0].value.i))
215 	  fprintf(stderr, "Error changing sample rate, using default of: %dHz.\n",
216 		pvs[0].value.i);
217 
218 	/* Open the audio port with the parameters we setup */
219 	if ( (priv->devAudio=alOpenPort("audio_fd","w",priv->devAudioConfig) ) == (ALport) NULL ) {
220 		fprintf(stderr, "Error: Cannot get an audio channel descriptor.\n");
221 		irix_dsp_destroy(dsp);
222 		return NULL;
223 	}
224 
225 	/* since we don't have FD's with DMEDIA, we use this to inform us of success */
226 	priv->port_status = 0;
227 
228    return dsp;
229 }
230 
irix_dsp_destroy(struct sysdep_dsp_struct * dsp)231 static void irix_dsp_destroy(struct sysdep_dsp_struct *dsp)
232 {
233    struct irix_dsp_priv_data *priv = dsp->_priv;
234 
235 #ifdef IRIX_DEBUG
236 	fprintf(stderr, "Destroying sound channel.\n");
237 #endif
238 
239    if(priv)
240    {
241 	  if(priv->port_status >= 0) alClosePort(priv->devAudio);
242 	  alFreeConfig(priv->devAudioConfig);
243 
244       free(priv);
245    }
246    free(dsp);
247 }
248 
249 
irix_dsp_get_freespace(struct sysdep_dsp_struct * dsp)250 static int irix_dsp_get_freespace(struct sysdep_dsp_struct *dsp)
251 {
252 	struct irix_dsp_priv_data *priv = dsp->_priv;
253 
254 	return alGetFillable(priv->devAudio);
255 }
256 
257 
irix_dsp_write(struct sysdep_dsp_struct * dsp,unsigned char * data,int count)258 static int irix_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data,
259    int count)
260 {
261 	unsigned char *outbuf=data;
262    int result;
263    struct irix_dsp_priv_data *priv = dsp->_priv;
264 	int playcnt;
265 	int maxsize;
266 
267 	maxsize = alGetFillable(priv->devAudio);
268 
269 /*	count = count * priv->sampchan; */
270 
271 	if (count <= maxsize) playcnt = count;
272 		else playcnt = maxsize;
273 
274 	outbuf += (priv->sampwidth - 1);
275 
276 	for (;outbuf<(data+count);outbuf+=priv->sampwidth) *outbuf ^= 0x80;
277 
278 	result = alWriteFrames(priv->devAudio, (void *)data, playcnt);
279 
280 	if (result < 0) {
281 		fprintf(stderr, "Error %d: failure writing to irix stream\n",oserror());
282 		return -1;
283 	}
284 
285 
286 #ifdef IRIX_DEBUG_VERBOSE
287 	fprintf(stderr, "Wrote %d samples OK.\n",playcnt);
288 #endif
289 
290 /*	return playcnt / priv->sampchan; */
291 	return playcnt;
292 }
293 
294 #endif /* ifdef SYSDEP_DSP_IRIX */
295 
296