mirror of
https://git.code.sf.net/p/quake/quake2forge
synced 2024-11-10 07:12:01 +00:00
A lot of work to snd_alsa.c. It's not correct yet, but it's a lot closer.
Perhaps someone else will poke at it now.
This commit is contained in:
parent
712be75e22
commit
740dc42df5
1 changed files with 222 additions and 161 deletions
383
src/snd_alsa.c
383
src/snd_alsa.c
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
*(at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
|
@ -25,166 +25,227 @@
|
|||
#include "client.h"
|
||||
#include "snd_loc.h"
|
||||
|
||||
static int snd_inited;
|
||||
static snd_pcm_t *pcm_handle;
|
||||
static snd_pcm_hw_params_t *hw_params;
|
||||
|
||||
static snd_pcm_t * pcm_handle;
|
||||
static snd_pcm_hw_params_t * hw_params;
|
||||
static snd_pcm_uframes_t period_size;
|
||||
static snd_pcm_uframes_t buffer_size;
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
static int periods;
|
||||
|
||||
int tryrates[] = { 44100, 22051, 11025, 8000 };
|
||||
static int period_bytes;
|
||||
static int buffer_bytes;
|
||||
|
||||
/* sound info */
|
||||
static struct sndinfo * si;
|
||||
|
||||
qboolean SNDDMA_Init(struct sndinfo * s) {
|
||||
int i;
|
||||
int err;
|
||||
/*
|
||||
* The sample rates which will be attempted.
|
||||
*/
|
||||
static int RATES[] = {
|
||||
44100, 22050, 11025, 8000
|
||||
};
|
||||
|
||||
if (snd_inited)
|
||||
return 1;
|
||||
|
||||
snd_inited = 0;
|
||||
|
||||
si = s;
|
||||
|
||||
si->dma->samples = 1024;
|
||||
|
||||
if ((err = snd_pcm_open(&pcm_handle, si->device->string,
|
||||
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot open device %s (%s)\n",
|
||||
si->device->string,
|
||||
snd_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot allocate hw params (%s)\n",
|
||||
snd_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot init hw params (%s)\n",
|
||||
snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_access(pcm_handle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot set access (%s)\n",
|
||||
snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
si->dma->samplebits = si->bits->value;
|
||||
if (si->dma->samplebits == 16 || si->dma->samplebits != 8) {
|
||||
if ((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
|
||||
SND_PCM_FORMAT_S16_LE)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, 16 bit sound not supported, trying 8\n");
|
||||
si->dma->samplebits = 8;
|
||||
/*
|
||||
* Initialize ALSA pcm device, and bind it to sndinfo.
|
||||
*/
|
||||
qboolean SNDDMA_Init(struct sndinfo *s){
|
||||
int i, r, err, dir;
|
||||
|
||||
si = s;
|
||||
|
||||
if(!strcmp(si->device->string, "/dev/dsp")) //silly oss default
|
||||
si->device->string = "default";
|
||||
|
||||
if((err = snd_pcm_open(&pcm_handle, si->device->string,
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0){
|
||||
si->Com_Printf("ALSA: cannot open device %s(%s)\n",
|
||||
si->device->string, snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (si->dma->samplebits == 8) {
|
||||
if ((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
|
||||
SND_PCM_FORMAT_U8)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot set sample format (%s)\n",
|
||||
snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
|
||||
if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0){
|
||||
si->Com_Printf("ALSA: cannot allocate hw params(%s)\n",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
si->dma->speed = (int)si->speed->value;
|
||||
if (!si->dma->speed) {
|
||||
for (i = 0; i < sizeof(tryrates); i++) {
|
||||
int dir = 0;
|
||||
int test = tryrates[i];
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params,
|
||||
&test, &dir)) < 0) {
|
||||
si->Com_Printf("ALSA snd error, cannot set sample rate %d (%s)\n",
|
||||
tryrates[i], snd_strerror(err));
|
||||
} else {
|
||||
si->dma->speed = test;
|
||||
if (dir != 0) {
|
||||
si->Com_Printf("alsa: The rate %d Hz is not supported by your hardware, using %d Hz instead.\n", test, err);
|
||||
|
||||
if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){
|
||||
si->Com_Printf("ALSA: cannot init hw params(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = snd_pcm_hw_params_set_access(pcm_handle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
|
||||
si->Com_Printf("ALSA: cannot set access(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
si->dma->samplebits = si->bits->value;
|
||||
if(si->dma->samplebits != 8){ //try 16 by default
|
||||
|
||||
si->dma->samplebits = 16; //ensure this is set for other calculations
|
||||
|
||||
if((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
|
||||
SND_PCM_FORMAT_S16)) < 0){
|
||||
si->Com_Printf("ALSA: 16 bit not supported, trying 8\n");
|
||||
si->dma->samplebits = 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!si->dma->speed) {
|
||||
si->Com_Printf("ALSA snd error couldn't set rate.\n");
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
}
|
||||
if(si->dma->samplebits == 8){ //or 8 if specifically asked to
|
||||
if((err = snd_pcm_hw_params_set_format(pcm_handle, hw_params,
|
||||
SND_PCM_FORMAT_U8)) < 0){
|
||||
si->Com_Printf("ALSA: cannot set format(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
si->dma->speed =(int)si->speed->value;
|
||||
if(si->dma->speed){ //try specified rate
|
||||
|
||||
r = si->dma->speed;
|
||||
|
||||
if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &r, &dir)) < 0)
|
||||
si->Com_Printf("ALSA: cannot set rate %d(%s)\n", r, snd_strerror(err));
|
||||
else { //rate succeeded, but is perhaps slightly different
|
||||
if(dir != 0) si->Com_Printf("ALSA: rate %d not supported, using %d\n", si->dma->speed, r);
|
||||
si->dma->speed = r;
|
||||
}
|
||||
}
|
||||
if(!si->dma->speed){ //or all available ones
|
||||
|
||||
for(i = 0; i < sizeof(RATES); i++){
|
||||
|
||||
r = RATES[i];
|
||||
dir = 0;
|
||||
|
||||
if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &r, &dir)) < 0)
|
||||
si->Com_Printf("ALSA: cannot set rate %d(%s)\n", r, snd_strerror(err));
|
||||
else { //rate succeeded, but is perhaps slightly different
|
||||
si->dma->speed = r;
|
||||
if(dir != 0) si->Com_Printf("ALSA: rate %d not supported, using %d\n", RATES[i], r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!si->dma->speed){ //failed
|
||||
si->Com_Printf("ALSA: cannot set rate\n");
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
si->dma->channels = (int)si->channels->value;
|
||||
|
||||
if(si->dma->channels < 1 || si->dma->channels > 2)
|
||||
si->dma->channels = 2; //ensure either stereo or mono
|
||||
|
||||
if((err = snd_pcm_hw_params_set_channels(pcm_handle, hw_params,
|
||||
si->dma->channels)) < 0){
|
||||
si->Com_Printf("ALSA: cannot set channels %d(%s)\n",
|
||||
si->dma->channels, snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = snd_pcm_hw_params(pcm_handle, hw_params)) < 0){ //set params
|
||||
si->Com_Printf("ALSA: cannot set params(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, 0)) < 0){
|
||||
si->Com_Printf("ALSA: cannot get period size(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
si->dma->channels = (int)si->channels->value;
|
||||
if (si->dma->channels < 1 || si->dma->channels > 2)
|
||||
si->dma->channels = 2;
|
||||
if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hw_params, si->dma->channels)) < 0) {
|
||||
si->Com_Printf("ALSA snd error couldn't set channels %d (%s).\n",
|
||||
si->dma->channels, snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params(pcm_handle, hw_params)) < 0) {
|
||||
si->Com_Printf("ALSA snd error couldn't set params (%s).\n",snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
si->dma->buffer = malloc(BUFFER_SIZE);
|
||||
memset(si->dma->buffer, 0, BUFFER_SIZE);
|
||||
|
||||
si->dma->samplepos = 0;
|
||||
si->dma->samples = BUFFER_SIZE / (si->dma->samplebits / 8);
|
||||
si->dma->submission_chunk = 1;
|
||||
|
||||
si->Com_Printf("alsa: buffer size is %d, %d samples\n", BUFFER_SIZE, si->dma->samples);
|
||||
|
||||
snd_inited = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SNDDMA_GetDMAPos(void) {
|
||||
if (snd_inited)
|
||||
return si->dma->samplepos;
|
||||
else
|
||||
si->Com_Printf("Sound not inizialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SNDDMA_Shutdown(void) {
|
||||
if (snd_inited) {
|
||||
snd_pcm_drop(pcm_handle);
|
||||
snd_pcm_close(pcm_handle);
|
||||
snd_inited = 0;
|
||||
}
|
||||
free(si->dma->buffer);
|
||||
si->dma->buffer = NULL;
|
||||
}
|
||||
|
||||
/* SNDDMA_Submit
|
||||
* Send sound to device if buffer isn't really the dma buffer
|
||||
*/
|
||||
void SNDDMA_Submit(void) {
|
||||
int written;
|
||||
|
||||
if(!snd_inited)
|
||||
return;
|
||||
|
||||
if ((written = snd_pcm_writei(pcm_handle, si->dma->buffer, si->dma->samples * (si->dma->samplebits / 8))) < 0) {
|
||||
if((err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size)) < 0){
|
||||
si->Com_Printf("ALSA snd error, cannot get buffer size(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = snd_pcm_hw_params_get_periods(hw_params, &periods, 0)) < 0){
|
||||
si->Com_Printf("ALSA: cannot get periods(%s)\n", snd_strerror(err));
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
return false;
|
||||
}
|
||||
|
||||
period_bytes = period_size * si->dma->channels * si->dma->samplebits / 8;
|
||||
buffer_bytes = buffer_size * si->dma->channels * si->dma->samplebits / 8;
|
||||
|
||||
si->dma->buffer = malloc(buffer_bytes); //allocate pcm frame buffer
|
||||
memset(si->dma->buffer, 0, buffer_bytes);
|
||||
|
||||
si->dma->samplepos = 0;
|
||||
|
||||
si->dma->samples = buffer_size * si->dma->channels;
|
||||
si->dma->submission_chunk = period_size * si->dma->channels;
|
||||
|
||||
si->Com_Printf("period size is %d (%d bytes)\n"
|
||||
"buffer size is %d (%d bytes)\n%d periods\n", (int)period_size,
|
||||
period_bytes, (int)buffer_size, buffer_bytes, periods
|
||||
);
|
||||
|
||||
snd_pcm_prepare(pcm_handle);
|
||||
si->Com_Printf("alsa: buffer underrun\n");
|
||||
}
|
||||
si->dma->samplepos += written / (si->dma->samplebits / 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SNDDMA_BeginPainting(void) {
|
||||
/*
|
||||
* Returns the current sample position, if sound is running.
|
||||
*/
|
||||
int SNDDMA_GetDMAPos(void){
|
||||
|
||||
if(si->dma->buffer)
|
||||
return si->dma->samplepos;
|
||||
|
||||
si->Com_Printf("Sound not inizialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the ALSA pcm device and frees the dma buffer.
|
||||
*/
|
||||
void SNDDMA_Shutdown(void){
|
||||
|
||||
if(si->dma->buffer){
|
||||
snd_pcm_drop(pcm_handle);
|
||||
snd_pcm_close(pcm_handle);
|
||||
}
|
||||
|
||||
free(si->dma->buffer);
|
||||
si->dma->buffer = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes the dma buffer to the ALSA pcm device.
|
||||
*/
|
||||
void SNDDMA_Submit(void){
|
||||
int w;
|
||||
void *start;
|
||||
|
||||
if(!si->dma->buffer)
|
||||
return;
|
||||
|
||||
start = (void *)&si->dma->buffer[si->dma->samplepos];
|
||||
|
||||
if((w = snd_pcm_writei(pcm_handle, start, period_size)) < 0){ //xrun
|
||||
//si->Com_Printf("ALSA: buffer underrun(%s)\n", snd_strerror(w));
|
||||
snd_pcm_prepare(pcm_handle);
|
||||
}
|
||||
else { //mark progress
|
||||
//si->Com_Printf("wrote %d frames\n", w);
|
||||
si->dma->samplepos += w * si->dma->channels;
|
||||
|
||||
if(si->dma->samplepos >= si->dma->samples)
|
||||
si->dma->samplepos = 0; //wrap
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No clue :)
|
||||
*/
|
||||
void SNDDMA_BeginPainting(void){}
|
||||
|
|
Loading…
Reference in a new issue