initial commit
This commit is contained in:
commit
36ca6059c1
49 changed files with 5290 additions and 0 deletions
296
alsasnd.h
Normal file
296
alsasnd.h
Normal file
|
@ -0,0 +1,296 @@
|
|||
#ifdef SND_S32
|
||||
#define pcms_t int32_t
|
||||
#define aud_ihandle aud_handle32
|
||||
#define SND_FMT SND_PCM_FORMAT_S32_LE
|
||||
#else
|
||||
#define pcms_t int16_t
|
||||
#define aud_ihandle aud_handle16
|
||||
#define SND_FMT SND_PCM_FORMAT_S16_LE
|
||||
#endif
|
||||
|
||||
#define SND_SMPSIZE (sizeof(pcms_t))
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_t *handle;
|
||||
uint32_t samplerate;
|
||||
uint32_t blocksize;
|
||||
uint32_t channels;
|
||||
uint32_t smppos;
|
||||
pcms_t *buffer;
|
||||
uint32_t devbufsize;
|
||||
wav_handle wav;
|
||||
#ifdef SND_MSGUNDER
|
||||
uint32_t underruns;
|
||||
uint32_t lastunder;
|
||||
uint32_t pushed;
|
||||
#endif
|
||||
} aud_ihandle;
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
wav_write32
|
||||
#else
|
||||
wav_write16
|
||||
#endif
|
||||
(wav_handle *wav, pcms_t *samples, uint32_t count) {
|
||||
if(wav->fd == NULL) {
|
||||
return;
|
||||
}
|
||||
for(int c = 0; c < (count * ((uint32_t)wav->channels)); c++) {
|
||||
#ifdef SND_S32
|
||||
wav_write_uint32((wav->buffer)+(c*SND_SMPSIZE), samples[c]);
|
||||
#else
|
||||
wav_write_uint16((wav->buffer)+(c*SND_SMPSIZE), samples[c]);
|
||||
#endif
|
||||
}
|
||||
if(fwrite(wav->buffer, 1, SND_SMPSIZE * ((uint32_t)wav->channels) * count, wav->fd) != (SND_SMPSIZE * ((uint32_t)wav->channels) * count)) {
|
||||
fprintf(stderr, STR_WAV_EIO"\n", wav->filename);
|
||||
fclose(wav->fd);
|
||||
wav->fd = NULL;
|
||||
return;
|
||||
}
|
||||
wav->samples += count;
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
aud_prepare32
|
||||
#else
|
||||
aud_prepare16
|
||||
#endif
|
||||
(aud_ihandle *dev) {
|
||||
if(dev->handle == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(dev->buffer, 0, dev->blocksize * SND_SMPSIZE * dev->channels);
|
||||
dev->smppos = 0;
|
||||
int rc = 0;
|
||||
uint32_t tries = 0;
|
||||
while(rc != dev->blocksize) {
|
||||
if(tries++ >= 256) {
|
||||
mid_log(STR_AUD_PREPERR);
|
||||
return;
|
||||
}
|
||||
rc = snd_pcm_writei(dev->handle, dev->buffer, dev->blocksize);
|
||||
if(rc == -EAGAIN || (rc >= 0 && (size_t)rc < dev->blocksize)) {
|
||||
snd_pcm_wait(dev->handle, 100);
|
||||
}
|
||||
else if(rc == -EPIPE) {
|
||||
snd_pcm_prepare(dev->handle);
|
||||
}
|
||||
}
|
||||
snd_pcm_nonblock(dev->handle, 1);
|
||||
for(int z = 0; z < 16; z++) {
|
||||
rc = snd_pcm_writei(dev->handle, dev->buffer, dev->blocksize);
|
||||
if(rc == -EAGAIN || (rc >= 0 && (size_t)rc < dev->blocksize)) {
|
||||
snd_pcm_wait(dev->handle, 100);
|
||||
}
|
||||
else if(rc == -EPIPE) {
|
||||
snd_pcm_prepare(dev->handle);
|
||||
}
|
||||
}
|
||||
snd_pcm_nonblock(dev->handle, 0);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
aud_write32
|
||||
#else
|
||||
aud_write16
|
||||
#endif
|
||||
(aud_ihandle *dev, pcms_t *data, uint32_t samples) {
|
||||
int rc;
|
||||
uint32_t blocksize = dev->blocksize;
|
||||
while(samples > 0) {
|
||||
blocksize = samples < blocksize ? samples : blocksize;
|
||||
if(dev->handle) {
|
||||
rc = snd_pcm_writei(dev->handle, data, blocksize);
|
||||
}
|
||||
else if(dev->wav.buffer) {
|
||||
#ifdef SND_S32
|
||||
wav_write32(&dev->wav, data, blocksize);
|
||||
#else
|
||||
wav_write16(&dev->wav, data, blocksize);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
fwrite(data, 1, blocksize * dev->channels * SND_SMPSIZE, stdout);
|
||||
}
|
||||
data += blocksize * dev->channels;
|
||||
samples -= blocksize;
|
||||
if(dev->handle) {
|
||||
if(rc == -EAGAIN || (rc >= 0 && (size_t)rc < blocksize)) {
|
||||
snd_pcm_wait(dev->handle, 100);
|
||||
}
|
||||
else if(rc == -EPIPE) {
|
||||
#ifdef SND_MSGUNDER
|
||||
if(dev->underruns == 0) {
|
||||
dev->lastunder = dev->pushed;
|
||||
}
|
||||
dev->underruns += 1;
|
||||
#endif
|
||||
snd_pcm_prepare(dev->handle);
|
||||
}
|
||||
else if(rc < 0) {
|
||||
mid_log(STR_AUD_WRITERR, snd_strerror(rc), rc);
|
||||
}
|
||||
#ifdef SND_MSGUNDER
|
||||
else {
|
||||
dev->pushed += 1;
|
||||
}
|
||||
if((dev->underruns > 0) && ((dev->pushed - dev->lastunder) >= (dev->samplerate / dev->blocksize))) {
|
||||
mid_log(STR_AUD_UNDERR, dev->underruns);
|
||||
dev->underruns = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
#ifdef SND_S32
|
||||
aud_open_dev32
|
||||
#else
|
||||
aud_open_dev16
|
||||
#endif
|
||||
(aud_ihandle *dev, const char *devname, uint32_t samplerate, uint8_t channels, uint32_t frames, uint32_t bufsize) {
|
||||
dev->channels = channels;
|
||||
dev->samplerate = samplerate;
|
||||
dev->smppos = 0;
|
||||
#ifdef SND_MSGUNDER
|
||||
dev->underruns = 0;
|
||||
dev->lastunder = 0;
|
||||
dev->pushed = 0;
|
||||
#endif
|
||||
dev->handle = NULL;
|
||||
dev->buffer = NULL;
|
||||
dev->wav.buffer = NULL;
|
||||
if((devname[0] == '-') && (devname[1] == 0)) {
|
||||
dev->blocksize = frames;
|
||||
dev->devbufsize = 0;
|
||||
dev->buffer = (pcms_t*)malloc(dev->blocksize * SND_SMPSIZE * dev->channels);
|
||||
return 0;
|
||||
}
|
||||
else if((strlen(devname) >= 4) && (strcmp(devname+(strlen(devname)-4), ".wav") == 0)) {
|
||||
if(wav_open(&dev->wav, devname, samplerate, channels, SND_SMPSIZE) ^ 1) {
|
||||
return false;
|
||||
}
|
||||
dev->blocksize = frames;
|
||||
dev->devbufsize = 0;
|
||||
dev->buffer = (pcms_t*)malloc(dev->blocksize * SND_SMPSIZE * dev->channels);
|
||||
dev->wav.buffer = malloc(dev->blocksize * SND_SMPSIZE * dev->channels);
|
||||
return 0;
|
||||
}
|
||||
int rc;
|
||||
int subdir = 0;
|
||||
snd_pcm_hw_params_t *params = NULL;
|
||||
rc = snd_pcm_open(&dev->handle, devname, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if(rc < 0) {
|
||||
fprintf(stderr, STR_AUD_OPNERR"\n", devname, snd_strerror(rc), rc);
|
||||
return 1;
|
||||
}
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
snd_pcm_hw_params_any(dev->handle, params);
|
||||
snd_pcm_hw_params_set_access(dev->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if(snd_pcm_hw_params_set_format(dev->handle, params, SND_FMT) != 0) {
|
||||
snd_pcm_close(dev->handle);
|
||||
return 2;
|
||||
}
|
||||
snd_pcm_hw_params_set_channels(dev->handle, params, dev->channels);
|
||||
snd_pcm_hw_params_set_rate_near(dev->handle, params, &dev->samplerate, &subdir);
|
||||
snd_pcm_uframes_t framesize = frames;
|
||||
snd_pcm_hw_params_set_period_size_near(dev->handle, params, &framesize, &subdir);
|
||||
snd_pcm_uframes_t buffersize = bufsize;
|
||||
if(bufsize > 0) {
|
||||
snd_pcm_hw_params_set_buffer_size_near(dev->handle, params, &buffersize);
|
||||
}
|
||||
rc = snd_pcm_hw_params(dev->handle, params);
|
||||
if(rc < 0) {
|
||||
fprintf(stderr, STR_AUD_HWERR"\n", devname, snd_strerror(rc), rc);
|
||||
snd_pcm_close(dev->handle);
|
||||
return 1;
|
||||
}
|
||||
snd_pcm_hw_params_get_period_size(params, &framesize, &subdir);
|
||||
snd_pcm_hw_params_get_buffer_size(params, &buffersize);
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
snd_pcm_sw_params_current(dev->handle, swparams);
|
||||
// snd_pcm_sw_params_set_avail_min(dev->handle, swparams, framesize);
|
||||
// snd_pcm_sw_params_set_start_threshold(dev->handle, swparams, 0);
|
||||
// snd_pcm_sw_params_set_stop_threshold(dev->handle, swparams, buffersize);
|
||||
rc = snd_pcm_sw_params(dev->handle, swparams);
|
||||
if(rc < 0) {
|
||||
fprintf(stderr, STR_AUD_SWERR"\n", devname, snd_strerror(rc), rc);
|
||||
snd_pcm_close(dev->handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev->blocksize = framesize;
|
||||
dev->devbufsize = buffersize;
|
||||
dev->buffer = (pcms_t*)malloc(dev->blocksize * SND_SMPSIZE * dev->channels);
|
||||
snd_pcm_wait(dev->handle, -1);
|
||||
#ifdef SND_S32
|
||||
aud_prepare32(dev);
|
||||
#else
|
||||
aud_prepare16(dev);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
aud_push32
|
||||
#else
|
||||
aud_push16
|
||||
#endif
|
||||
(aud_ihandle *dev, pcms_t *data) {
|
||||
memcpy(&dev->buffer[dev->smppos*dev->channels], data, SND_SMPSIZE * dev->channels);
|
||||
dev->smppos++;
|
||||
if(dev->smppos == dev->blocksize) {
|
||||
#ifdef SND_S32
|
||||
aud_write32(dev, dev->buffer, dev->blocksize);
|
||||
#else
|
||||
aud_write16(dev, dev->buffer, dev->blocksize);
|
||||
#endif
|
||||
dev->smppos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
aud_flush32
|
||||
#else
|
||||
aud_flush16
|
||||
#endif
|
||||
(aud_ihandle *dev) {
|
||||
if(dev->smppos != 0) {
|
||||
#ifdef SND_S32
|
||||
aud_write32(dev, dev->buffer, dev->smppos);
|
||||
#else
|
||||
aud_write16(dev, dev->buffer, dev->smppos);
|
||||
#endif
|
||||
dev->smppos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef SND_S32
|
||||
aud_close32
|
||||
#else
|
||||
aud_close16
|
||||
#endif
|
||||
(aud_ihandle *dev) {
|
||||
if(dev->handle) {
|
||||
snd_pcm_drain(dev->handle);
|
||||
snd_pcm_close(dev->handle);
|
||||
}
|
||||
if(dev->wav.buffer) {
|
||||
wav_close(&dev->wav);
|
||||
free(dev->wav.buffer);
|
||||
}
|
||||
free(dev->buffer);
|
||||
}
|
||||
|
||||
#undef pcms_t
|
||||
#undef aud_ihandle
|
||||
#undef SND_FMT
|
Loading…
Add table
Add a link
Reference in a new issue