mirror of
https://github.com/zydeco/minivmac4ios.git
synced 2024-11-26 00:49:20 +00:00
229 lines
4.9 KiB
C
Executable File
229 lines
4.9 KiB
C
Executable File
/*
|
|
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 blnr audio_started;
|
|
|
|
#if 4 == kLn2SoundSampSz
|
|
LOCALPROC ConvertSoundBlockToNative(tpSoundSamp p)
|
|
{
|
|
int i;
|
|
|
|
for (i = kOneBuffLen; --i >= 0; ) {
|
|
*p++ -= 0x8000;
|
|
}
|
|
}
|
|
#else
|
|
#define ConvertSoundBlockToNative(p)
|
|
#endif
|
|
|
|
LOCALPROC MySound_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;
|
|
ui4b PlayNowSize = 0;
|
|
ui4b MaskedFillOffset = ThePlayOffset & kOneBuffMask;
|
|
ui4b PrivateBuffUsed = TheFillOffset - ThePlayOffset;
|
|
int used = (info.fragstotal * info.fragsize) - info.bytes;
|
|
|
|
if (audio_started) {
|
|
ui4b TotPendBuffs = used >> kLnOneBuffSz;
|
|
|
|
if (TotPendBuffs < MinFilledSoundBuffs) {
|
|
MinFilledSoundBuffs = TotPendBuffs;
|
|
}
|
|
/* fprintf(stderr, "buffer used %d\n", (int)used); */
|
|
} else {
|
|
if (PrivateBuffUsed >= kAllBuffLen - kOneBuffLen) {
|
|
audio_started = trueblnr;
|
|
} 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 MySound_Start(void)
|
|
{
|
|
if (audio_fd >= 0) {
|
|
MySound_Start0();
|
|
audio_started = falseblnr;
|
|
}
|
|
}
|
|
|
|
LOCALPROC MySound_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 MyDesiredFormat AFMT_S16_NE
|
|
#else
|
|
#define MyDesiredFormat AFMT_U8
|
|
#endif
|
|
|
|
LOCALFUNC blnr MySound_Init(void)
|
|
{
|
|
blnr IsOk = falseblnr;
|
|
|
|
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 = MyDesiredFormat;
|
|
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 != MyDesiredFormat))
|
|
{
|
|
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 = trueblnr;
|
|
}
|
|
|
|
if (! IsOk) {
|
|
(void) close(audio_fd);
|
|
audio_fd = -1;
|
|
}
|
|
}
|
|
|
|
return trueblnr; /* keep going, even if no sound */
|
|
}
|
|
|
|
LOCALPROC MySound_UnInit(void)
|
|
{
|
|
if (audio_fd >= 0) {
|
|
if (close(audio_fd) != 0) {
|
|
fprintf(stderr, "close /dev/dsp fails\n");
|
|
}
|
|
audio_fd = -1;
|
|
}
|
|
}
|
|
|
|
GLOBALOSGLUPROC MySound_EndWrite(ui4r actL)
|
|
{
|
|
if (MySound_EndWrite0(actL)) {
|
|
ConvertSoundBlockToNative(TheSoundBuffer
|
|
+ ((TheFillOffset - kOneBuffLen) & kAllBuffMask));
|
|
if (audio_fd >= 0) {
|
|
MySound_WriteOut();
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCALPROC MySound_SecondNotify(void)
|
|
{
|
|
if (audio_fd >= 0) {
|
|
MySound_SecondNotify0();
|
|
}
|
|
}
|