uvmac/src/SGLUDDSP.h

229 lines
4.9 KiB
C

/*
SGLUDDSP.h
Copyright (C) 2012 Paul C. Pratt
You can redistribute this file and/or modify it under the terms
of version 2 of the GNU General Public License as published by
the Free Software Foundation. You should have received a copy
of the license along with this file; see the file COPYING.
This file 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
license for more details.
*/
/*
Sound GLUe for "/Dev/DSP"
OSS and related, accessed through "/dev/dsp"
*/
LOCALVAR int audio_fd = -1;
LOCALVAR bool audio_started;
#if 4 == kLn2SoundSampSz
LOCALPROC ConvertSoundBlockToNative(tpSoundSamp p)
{
int i;
for (i = kOneBuffLen; --i >= 0; ) {
*p++ -= 0x8000;
}
}
#else
#define ConvertSoundBlockToNative(p)
#endif
LOCALPROC Sound_WriteOut(void)
{
int retry_count = 32;
label_retry:
if (--retry_count > 0) {
int err;
struct audio_buf_info info;
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) != 0) {
fprintf(stderr, "SNDCTL_DSP_GETOSPACE fails\n");
} else {
tpSoundSamp NextPlayPtr;
uint16_t PlayNowSize = 0;
uint16_t MaskedFillOffset = ThePlayOffset & kOneBuffMask;
uint16_t PrivateBuffUsed = TheFillOffset - ThePlayOffset;
int used = (info.fragstotal * info.fragsize) - info.bytes;
if (audio_started) {
uint16_t TotPendBuffs = used >> kLnOneBuffSz;
if (TotPendBuffs < MinFilledSoundBuffs) {
MinFilledSoundBuffs = TotPendBuffs;
}
/* fprintf(stderr, "buffer used %d\n", (int)used); */
} else {
if (PrivateBuffUsed >= kAllBuffLen - kOneBuffLen) {
audio_started = true;
} else {
info.bytes = 0;
}
}
if (MaskedFillOffset != 0) {
/* take care of left overs */
PlayNowSize = kOneBuffLen - MaskedFillOffset;
NextPlayPtr =
TheSoundBuffer + (ThePlayOffset & kAllBuffMask);
} else if (0 !=
((TheFillOffset - ThePlayOffset) >> kLnOneBuffLen))
{
PlayNowSize = kOneBuffLen;
NextPlayPtr =
TheSoundBuffer + (ThePlayOffset & kAllBuffMask);
} else {
/* nothing to play now */
}
#if 4 == kLn2SoundSampSz
PlayNowSize <<= 1;
#endif
if (PlayNowSize > info.bytes) {
PlayNowSize = info.bytes;
}
if (0 != PlayNowSize) {
err = write(
audio_fd, NextPlayPtr, PlayNowSize);
if (err < 0) {
if (- EAGAIN == err) {
/* buffer full, try again later */
fprintf(stderr, "pcm write: EAGAIN\n");
} else if (- EPIPE == err) {
/* buffer seems to have emptied */
fprintf(stderr, "pcm write emptied\n");
goto label_retry;
} else {
fprintf(stderr, "audio_fd write error: %d\n",
err);
}
} else {
ThePlayOffset += err
#if 4 == kLn2SoundSampSz
>> 1
#endif
;
goto label_retry;
}
}
}
}
}
LOCALPROC Sound_Start(void)
{
if (audio_fd >= 0) {
Sound_Start0();
audio_started = false;
}
}
LOCALPROC Sound_Stop(void)
{
if (audio_fd >= 0) {
if (0 !=
ioctl(audio_fd, SNDCTL_DSP_RESET /* SNDCTL_DSP_HALT */,
NULL))
{
fprintf(stderr, "SNDCTL_DSP_RESET fails\n");
}
}
}
#if 4 == kLn2SoundSampSz
#define DesiredFormat AFMT_S16_NE
#else
#define DesiredFormat AFMT_U8
#endif
LOCALFUNC bool Sound_Init(void)
{
bool IsOk = false;
audio_fd = open(AudioDevPath, O_WRONLY, 0);
if (audio_fd < 0) {
fprintf(stderr, "open /dev/dsp fails: %d\n", audio_fd);
} else {
int fragment_value = (16 /* 16 fragments */ << 16)
#if 4 == kLn2SoundSampSz
| 10 /* of 1024 bytes */
#else
| 9 /* of 512 bytes */
#endif
;
int channels_value = 1;
int fmt_value = DesiredFormat;
int speed_value = SOUND_SAMPLERATE;
/* fprintf(stderr, "open /dev/dsp works\n"); */
if (0 !=
ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_value))
{
fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT fails\n");
} else if ((0 !=
ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels_value))
|| (channels_value != 1))
{
fprintf(stderr, "SNDCTL_DSP_CHANNELS fails\n");
} else if ((0 !=
ioctl(audio_fd, SNDCTL_DSP_SETFMT, &fmt_value))
|| (fmt_value != DesiredFormat))
{
fprintf(stderr, "SNDCTL_DSP_SETFMT fails\n");
} else if ((0 !=
ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed_value))
|| (speed_value != SOUND_SAMPLERATE))
{
fprintf(stderr, "SNDCTL_DSP_SPEED fails\n");
} else
{
IsOk = true;
}
if (! IsOk) {
(void) close(audio_fd);
audio_fd = -1;
}
}
return true; /* keep going, even if no sound */
}
LOCALPROC Sound_UnInit(void)
{
if (audio_fd >= 0) {
if (close(audio_fd) != 0) {
fprintf(stderr, "close /dev/dsp fails\n");
}
audio_fd = -1;
}
}
GLOBALOSGLUPROC Sound_EndWrite(uint16_t actL)
{
if (Sound_EndWrite0(actL)) {
ConvertSoundBlockToNative(TheSoundBuffer
+ ((TheFillOffset - kOneBuffLen) & kAllBuffMask));
if (audio_fd >= 0) {
Sound_WriteOut();
}
}
}
LOCALPROC Sound_SecondNotify(void)
{
if (audio_fd >= 0) {
Sound_SecondNotify0();
}
}