updated on Mon Jan 16 04:00:32 UTC 2012
[aur-mirror.git] / quake2 / snd_alsa.c
blob2fb7411ce68dc7daaa67376328144cf3c6378099
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 *(at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
21 #include <alsa/asoundlib.h>
23 #include "../client/client.h"
24 #include "../client/snd_loc.h"
26 #define BUFFER_SAMPLES 4096
27 #define SUBMISSION_CHUNK BUFFER_SAMPLES / 2
29 static snd_pcm_t *pcm_handle;
30 static snd_pcm_hw_params_t *hw_params;
32 static struct sndinfo * si;
34 static int sample_bytes;
35 static int buffer_bytes;
37 cvar_t *sndbits;
38 cvar_t *sndspeed;
39 cvar_t *sndchannels;
40 cvar_t *snddevice;
44 * The sample rates which will be attempted.
46 static int RATES[] = {
47 44100, 22050, 11025, 8000
51 * Initialize ALSA pcm device, and bind it to sndinfo.
53 qboolean SNDDMA_Init(void){
54 int i, err, dir;
55 unsigned int r;
56 snd_pcm_uframes_t p;
59 if (!snddevice)
61 sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE);
62 sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE);
63 sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE);
64 snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE);
67 if(!strcmp(snddevice->string, "/dev/dsp")) //silly oss default
68 snddevice->string = "default";
70 if((err = snd_pcm_open(&pcm_handle, snddevice->string,
71 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0)
73 Com_Printf("ALSA: cannot open device %s(%s)\n",
74 snddevice->string, snd_strerror(err));
75 return false;
78 if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0){
79 Com_Printf("ALSA: cannot allocate hw params(%s)\n",
80 snd_strerror(err));
81 return false;
84 if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
85 Com_Printf("ALSA: cannot init hw params(%s)\n", snd_strerror(err));
86 snd_pcm_hw_params_free(hw_params);
87 return false;
90 if((err = snd_pcm_hw_params_set_access
91 (pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
93 Com_Printf("ALSA: cannot set access(%s)\n", snd_strerror(err));
94 snd_pcm_hw_params_free(hw_params);
95 return false;
98 dma.samplebits = (int)sndbits->value;
99 if(dma.samplebits != 8){ //try 16 by default
100 dma.samplebits = 16; //ensure this is set for other calculations
102 if((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
103 SND_PCM_FORMAT_S16)) < 0){
104 Com_Printf("ALSA: 16 bit not supported, trying 8\n");
105 dma.samplebits = 8;
108 if(dma.samplebits == 8){ //or 8 if specifically asked to
109 if((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
110 SND_PCM_FORMAT_U8)) < 0){
111 Com_Printf("ALSA: cannot set format(%s)\n", snd_strerror(err));
112 snd_pcm_hw_params_free(hw_params);
113 return false;
117 dma.speed = (int)sndspeed->value;
118 if(dma.speed){ //try specified rate
119 r = dma.speed;
121 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &r, &dir)) < 0)
122 Com_Printf("ALSA: cannot set rate %d(%s)\n", r, snd_strerror(err));
123 else { //rate succeeded, but is perhaps slightly different
124 if(dir != 0)
125 Com_Printf("ALSA: rate %d not supported, using %d\n", sndspeed->value, r);
126 dma.speed = r;
129 if(!dma.speed){ //or all available ones
130 for(i = 0; i < sizeof(RATES); i++){
131 r = RATES[i];
132 dir = 0;
134 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &r, &dir)) < 0)
135 Com_Printf("ALSA: cannot set rate %d(%s)\n", r, snd_strerror(err));
136 else { //rate succeeded, but is perhaps slightly different
137 dma.speed = r;
138 if(dir != 0)
139 Com_Printf("ALSA: rate %d not supported, using %d\n", RATES[i], r);
140 break;
144 if(!dma.speed){ //failed
145 Com_Printf("ALSA: cannot set rate\n");
146 snd_pcm_hw_params_free(hw_params);
147 return false;
150 dma.channels = sndchannels->value;
151 if(dma.channels < 1 || dma.channels > 2)
152 dma.channels = 2; //ensure either stereo or mono
156 if((err = snd_pcm_hw_params_set_channels(pcm_handle, hw_params,
157 dma.channels)) < 0)
159 Com_Printf("ALSA: cannot set channels %d(%s)\n",
160 sndchannels->value, snd_strerror(err));
161 snd_pcm_hw_params_free(hw_params);
162 return false;
165 p = BUFFER_SAMPLES / dma.channels;
166 if((err = snd_pcm_hw_params_set_period_size_near(pcm_handle, hw_params,
167 &p, &dir)) < 0){
168 Com_Printf("ALSA: cannot set period size (%s)\n", snd_strerror(err));
169 snd_pcm_hw_params_free(hw_params);
170 return false;
172 else { //rate succeeded, but is perhaps slightly different
173 if(dir != 0)
174 Com_Printf("ALSA: period %d not supported, using %d\n", (BUFFER_SAMPLES/dma.channels), p);
177 if((err = snd_pcm_hw_params(pcm_handle, hw_params)) < 0){ //set params
178 Com_Printf("ALSA: cannot set params(%s)\n", snd_strerror(err));
179 snd_pcm_hw_params_free(hw_params);
180 return false;
183 sample_bytes = dma.samplebits / 8;
184 buffer_bytes = BUFFER_SAMPLES * sample_bytes;
186 dma.buffer = malloc(buffer_bytes); //allocate pcm frame buffer
187 memset(dma.buffer, 0, buffer_bytes);
189 dma.samplepos = 0;
191 dma.samples = BUFFER_SAMPLES;
192 dma.submission_chunk = SUBMISSION_CHUNK;
194 snd_pcm_prepare(pcm_handle);
196 return true;
200 * Returns the current sample position, if sound is running.
202 int SNDDMA_GetDMAPos(void){
204 if(dma.buffer)
205 return dma.samplepos;
207 Com_Printf("Sound not inizialized\n");
208 return 0;
212 * Closes the ALSA pcm device and frees the dma buffer.
214 void SNDDMA_Shutdown(void){
216 if(dma.buffer){
217 snd_pcm_drop(pcm_handle);
218 snd_pcm_close(pcm_handle);
221 free(dma.buffer);
222 dma.buffer = 0;
226 * Writes the dma buffer to the ALSA pcm device.
228 void SNDDMA_Submit(void){
229 int s, w, frames;
230 void *start;
232 if(!dma.buffer)
233 return;
235 s = dma.samplepos * sample_bytes;
236 start = (void *)&dma.buffer[s];
238 frames = dma.submission_chunk / dma.channels;
240 if((w = snd_pcm_writei(pcm_handle, start, frames)) < 0){ //write to card
241 snd_pcm_prepare(pcm_handle); //xrun occured
242 return;
245 dma.samplepos += w * dma.channels; //mark progress
247 if(dma.samplepos >= dma.samples)
248 dma.samplepos = 0; //wrap buffer
252 * Callback provided by the engine in case we need it. We don't.
254 void SNDDMA_BeginPainting(void){}