diff options
Diffstat (limited to 'icedax/sndconfig.c')
-rw-r--r-- | icedax/sndconfig.c | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/icedax/sndconfig.c b/icedax/sndconfig.c new file mode 100644 index 0000000..ac446fc --- /dev/null +++ b/icedax/sndconfig.c @@ -0,0 +1,607 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sndconfig.c 1.17 04/08/03 Copyright 1998-2004 Heiko Eissfeldt */ +/* os dependent functions */ +#include "config.h" +#include <stdio.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <fctldefs.h> +#include <unixstd.h> +#include <sys/ioctl.h> + +#if !defined __CYGWIN32__ +# include <timedefs.h> +#endif +#include <schily.h> + + +/* soundcard setup */ +#if defined (HAVE_SOUNDCARD_H) || defined (HAVE_LINUX_SOUNDCARD_H) || defined (HAVE_SYS_SOUNDCARD_H) || defined (HAVE_MACHINE_SOUNDCARD_H) +# if defined (HAVE_SOUNDCARD_H) +# include <soundcard.h> +# else +# if defined (HAVE_MACHINE_SOUNDCARD_H) +# include <machine/soundcard.h> +# else +# if defined (HAVE_SYS_SOUNDCARD_H) +# include <sys/soundcard.h> +# else +# if defined (HAVE_LINUX_SOUNDCARD_H) +# include <linux/soundcard.h> +# endif +# endif +# endif +# endif +#endif + +#include "mytype.h" +#include "byteorder.h" +#include "lowlevel.h" +#include "global.h" +#include "sndconfig.h" + +#ifdef ECHO_TO_SOUNDCARD +# if defined(__CYGWIN32__) +# include <windows.h> +# include "mmsystem.h" +# endif + +# if defined(__EMX__) +# define INCL_DOS +# define INCL_OS2MM +# include <os2.h> +# define PPFN _PPFN +# include <os2me.h> +# undef PPFN +static unsigned long DeviceID; + +# define FRAGMENTS 2 +/* playlist-structure */ +typedef struct { + ULONG ulCommand; + ULONG ulOperand1, ulOperand2, ulOperand3; +} PLAYLISTSTRUCTURE; + +static PLAYLISTSTRUCTURE PlayList[FRAGMENTS + 1]; +static unsigned BufferInd; +# endif /* defined __EMX__ */ + +static char snd_device[200] = SOUND_DEV; + +int set_snd_device(const char *devicename) +{ + strncpy(snd_device, devicename, sizeof(snd_device)); + return 0; +} + +# if defined __CYGWIN32__ +static HWAVEOUT DeviceID; +# define WAVEHDRS 3 +static WAVEHDR wavehdr[WAVEHDRS]; +static unsigned lastwav = 0; + +static int check_winsound_caps(int bits, double rate, int channels); + +static int check_winsound_caps(int bits, double rate, int channels) +{ + int result = 0; + + WAVEOUTCAPS caps; + + /* get caps */ + if (waveOutGetDevCaps(0, &caps, sizeof(caps))) { + fprintf(stderr, "cannot get soundcard capabilities!\n"); + return 1; + } + + /* check caps */ + if ((bits == 8 && !(caps.dwFormats & 0x333)) || + (bits == 16 && !(caps.dwFormats & 0xccc))) { + fprintf(stderr, "%d bits sound are not supported\n", bits); + result = 2; + } + + if ((channels == 1 && !(caps.dwFormats & 0x555)) || + (channels == 2 && !(caps.dwFormats & 0xaaa))) { + fprintf(stderr, "%d sound channels are not supported\n", channels); + result = 3; + } + + if ((rate == 44100.0 && !(caps.dwFormats & 0xf00)) || + (rate == 22050.0 && !(caps.dwFormats & 0xf0)) || + (rate == 11025.0 && !(caps.dwFormats & 0xf))) { + fprintf(stderr, "%d sample rate is not supported\n", (int)rate); + result = 4; + } + + return result; +} +# endif /* defined CYGWIN */ +#endif /* defined ECHO_TO_SOUNDCARD */ + +#ifdef HAVE_SUN_AUDIOIO_H +# include <sun/audioio.h> +#endif +#ifdef HAVE_SYS_AUDIOIO_H +# include <sys/audioio.h> +#endif + +#ifdef HAVE_SYS_ASOUNDLIB_H +# include <sys/asoundlib.h> +snd_pcm_t *pcm_handle; +#endif + +#if defined HAVE_OSS && defined SNDCTL_DSP_GETOSPACE +audio_buf_info abinfo; +#endif + +int init_soundcard(double rate, int bits) +{ +#ifdef ECHO_TO_SOUNDCARD + if (global.echo) { +# if defined(HAVE_OSS) && HAVE_OSS == 1 + if (open_snd_device() != 0) { + errmsg("Cannot open sound device '%s'\n", snd_device); + global.echo = 0; + } else { + /* This the sound device initialisation for 4front Open sound drivers */ + + int dummy; + int garbled_rate = rate; + int stereo = (global.channels == 2); + int myformat = bits == 8 ? AFMT_U8 : + (MY_LITTLE_ENDIAN ? AFMT_S16_LE : AFMT_S16_BE); + int mask; + + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETBLKSIZE, &dummy) == -1) { + fprintf(stderr, "Cannot get blocksize for %s\n", snd_device); + global.echo = 0; + } + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SYNC, NULL) == -1) { + fprintf(stderr, "Cannot sync for %s\n", snd_device); + global.echo = 0; + } + +#if defined SNDCTL_DSP_GETOSPACE + if (ioctl(global.soundcard_fd, SNDCTL_DSP_GETOSPACE, &abinfo) == -1) { + fprintf(stderr, "Cannot get input buffersize for %s\n", snd_device); + abinfo.fragments = 0; + } +#endif + + /* check, if the sound device can do the requested format */ + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETFMTS, &mask) == -1) { + perror("fatal error:"); + return -1; + } + if ((mask & myformat) == 0) { + fprintf(stderr, "sound format (%d bits signed) is not available\n", bits); + if ((mask & AFMT_U8) != 0) { + bits = 8; + myformat = AFMT_U8; + } + } + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SETFMT, &myformat) == -1) { + fprintf(stderr, "Cannot set %d bits/sample for %s\n",bits, snd_device); + global.echo = 0; + } + + /* limited sound devices may not support stereo */ + if (stereo + && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) { + fprintf(stderr, "Cannot set stereo mode for %s\n", snd_device); + stereo = 0; + } + if (!stereo + && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) { + fprintf(stderr, "Cannot set mono mode for %s\n", snd_device); + global.echo = 0; + } + + /* set the sample rate */ + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SPEED, &garbled_rate) == -1) { + fprintf(stderr, "Cannot set rate %d.%2d Hz for %s\n", + (int)rate, (int)(rate*100)%100, snd_device); + global.echo = 0; + } + if ( abs((long)rate - garbled_rate) > rate / 20) { + fprintf(stderr, "sound device: next best sample rate is %d\n",garbled_rate); + } + } + +# else /* HAVE_OSS */ + +# if defined HAVE_SYS_AUDIOIO_H || defined HAVE_SUN_AUDIOIO_H + /* This is the SunOS / Solaris and compatibles sound initialisation */ + + if ((global.soundcard_fd = open(snd_device, O_WRONLY, 0)) == EOF) { + perror(""); + fprintf(stderr, "Cannot open %s\n",snd_device); + global.echo = 0; + } else { + + audio_info_t info; + +# if defined (AUDIO_INITINFO) && defined (AUDIO_ENCODING_LINEAR) + AUDIO_INITINFO(&info); + info.play.sample_rate = rate; + info.play.channels = global.channels; + info.play.precision = bits; + info.play.encoding = AUDIO_ENCODING_LINEAR; + info.play.pause = 0; + info.record.pause = 0; + info.monitor_gain = 0; + if (ioctl(global.soundcard_fd, AUDIO_SETINFO, &info) < 0) { + fprintf(stderr, "Cannot init %s (sun)\n", snd_device); + global.echo = 0; + } +# else + fprintf(stderr, "Cannot init sound device with 44.1 KHz sample rate on %s (sun compatible)\n", snd_device); + global.echo = 0; +# endif + } +# else /* SUN audio */ +# if defined(__CYGWIN32__) + /* Windows sound info */ + + MMRESULT mmres; + WAVEFORMATEX wavform; + + if (waveOutGetNumDevs() < 1) { + fprintf( stderr, "no sound devices available!\n"); + global.echo = 0; + return 1; + } + + /* check capabilities */ + if (check_winsound_caps(bits, rate, global.channels) != 0) { + fprintf( stderr, "soundcard capabilities are not sufficient!\n"); + global.echo = 0; + return 1; + } + + wavform.wFormatTag = WAVE_FORMAT_PCM; + wavform.nChannels = global.channels; + wavform.nSamplesPerSec = (int)rate; + wavform.wBitsPerSample = bits; + wavform.cbSize = sizeof(wavform); + wavform.nAvgBytesPerSec = (int)rate * global.channels * + (wavform.wBitsPerSample / 8); + wavform.nBlockAlign = global.channels * (wavform.wBitsPerSample / 8); + + DeviceID = 0; + mmres = waveOutOpen(&DeviceID, WAVE_MAPPER, &wavform, (unsigned long)WIN_CallBack, 0, CALLBACK_FUNCTION); + if (mmres) { + char erstr[329]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard open error: %s!\n", erstr); + global.echo = 0; + return 1; + } + + global.soundcard_fd = 0; + + /* init all wavehdrs */ + { int i; + for (i=0; i < WAVEHDRS; i++) { + wavehdr[i].dwBufferLength = (global.channels*(bits/ 8)*(int)rate* + global.nsectors)/75; + wavehdr[i].lpData = malloc(wavehdr[i].dwBufferLength); + if (wavehdr[i].lpData == NULL) { + fprintf(stderr, "no memory for sound buffers available\n"); + waveOutReset(0); + waveOutClose(DeviceID); + return 1; + } + + mmres = waveOutPrepareHeader(DeviceID, &wavehdr[i], sizeof(WAVEHDR)); + if (mmres) { + char erstr[129]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard prepare error: %s!\n", erstr); + return 1; + } + + wavehdr[i].dwLoops = 0; + wavehdr[i].dwFlags = WHDR_DONE; + wavehdr[i].dwBufferLength = 0; + } + } + +# else +# if defined(__EMX__) +# if defined (HAVE_MMPM) + /* OS/2 MMPM/2 MCI sound info */ + + MCI_OPEN_PARMS mciOpenParms; + int i; + + /* create playlist */ + for (i = 0; i < FRAGMENTS; i++) { + PlayList[i].ulCommand = DATA_OPERATION; /* play data */ + PlayList[i].ulOperand1 = 0; /* address */ + PlayList[i].ulOperand2 = 0; /* size */ + PlayList[i].ulOperand3 = 0; /* offset */ + } + PlayList[FRAGMENTS].ulCommand = BRANCH_OPERATION; /* jump */ + PlayList[FRAGMENTS].ulOperand1 = 0; + PlayList[FRAGMENTS].ulOperand2 = 0; /* destination */ + PlayList[FRAGMENTS].ulOperand3 = 0; + + memset(&mciOpenParms, 0, sizeof(mciOpenParms)); + mciOpenParms.pszDeviceType = (PSZ) (((unsigned long) MCI_DEVTYPE_WAVEFORM_AUDIO << 16) | (unsigned short) DeviceIndex); + mciOpenParms.pszElementName = (PSZ) & PlayList; + + /* try to open the sound device */ + if (mciSendCommand(0, MCI_OPEN, + MCI_WAIT | MCI_OPEN_SHAREABLE | MCIOPEN_Type_ID, &mciOpenParms, 0) + != MCIERR_SUCCESS) { + /* no sound */ + fprintf( stderr, "no sound devices available!\n"); + global.echo = 0; + return 1; + } + /* try to set the parameters */ + DeviceID = mciOpenParms.usDeviceID; + + { + MCI_WAVE_SET_PARMS mciWaveSetParms; + + memset(&mciWaveSetParms, 0, sizeof(mciWaveSetParms)); + mciWaveSetParms.ulSamplesPerSec = rate; + mciWaveSetParms.usBitsPerSample = bits; + mciWaveSetParms.usChannels = global.channels; + mciWaveSetParms.ulAudio = MCI_SET_AUDIO_ALL; + + /* set play-parameters */ + if (mciSendCommand(DeviceID, MCI_SET, + MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC | + MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_CHANNELS, + (PVOID) & mciWaveSetParms, 0)) { + MCI_GENERIC_PARMS mciGenericParms; + fprintf( stderr, "soundcard capabilities are not sufficient!\n"); + global.echo = 0; + /* close */ + mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0); + return 1; + } + } + +# endif /* EMX MMPM OS2 sound */ +# else +# if defined(__QNX__) + + int card = -1; + int dev = 0; + int rtn; + snd_pcm_channel_info_t pi; + snd_pcm_channel_params_t pp; + + if (card == -1) { + rtn = snd_pcm_open_preferred(&pcm_handle, + &card, &dev, SND_PCM_OPEN_PLAYBACK); + if (rtn < 0) { + perror("sound device open"); + return 1; + } + } else { + rtn = snd_pcm_open(&pcm_handle, + card, dev, SND_PCM_OPEN_PLAYBACK); + if (rtn < 0) { + perror("sound device open"); + return 1; + } + } + + memset(&pi, 0, sizeof(pi)); + pi.channel = SND_PCM_CHANNEL_PLAYBACK; + rtn = snd_pcm_plugin_info(pcm_handle, &pi); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror(rtn)); + return 1; + } + + memset(&pp, 0, sizeof(pp)); + pp.mode = SND_PCM_MODE_BLOCK; + pp.channel = SND_PCM_CHANNEL_PLAYBACK; + pp.start_mode = SND_PCM_START_FULL; + pp.stop_mode = SND_PCM_STOP_STOP; + + pp.buf.block.frag_size = pi.max_fragment_size; + pp.buf.block.frags_max = 1; + pp.buf.block.frags_min = 1; + + pp.format.interleave = 1; + pp.format.rate = rate; + pp.format.voices = global.channels; + if (bits == 8) { + pp.format.format = SND_PCM_SFMT_U8; + } else { + pp.format.format = SND_PCM_SFMT_S16_LE; + } + + rtn = snd_pcm_plugin_params(pcm_handle, &pp); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_params failed: %s\n", snd_strerror(rtn)); + return 1; + } + + rtn = snd_pcm_plugin_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rtn)); + return 1; + } + + global.soundcard_fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + +# endif /* QNX sound */ +# endif /* EMX OS2 sound */ +# endif /* CYGWIN Windows sound */ +# endif /* else SUN audio */ +# endif /* else HAVE_OSS */ + } +#endif /* ifdef ECHO_TO_SOUNDCARD */ + return 0; +} + +int open_snd_device() +{ +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + int fl; +#endif + +#if defined ECHO_TO_SOUNDCARD && !defined __CYGWIN32__ && !defined __EMX__ + global.soundcard_fd = open(snd_device, O_WRONLY +#ifdef linux + /* Linux BUG: the sound driver open() blocks, if the device is in use. */ + | O_NONBLOCK +#endif + , 0); + +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + fl = fcntl(global.soundcard_fd, F_GETFL, 0); + fl &= ~O_NONBLOCK; + fcntl(global.soundcard_fd, F_SETFL, fl); +#endif + + return (global.soundcard_fd < 0); +#else + return 0; +#endif +} + +int close_snd_device () +{ +#if !defined ECHO_TO_SOUNDCARD + return 0; +#else + +# if defined __CYGWIN32__ + waveOutReset(0); + return waveOutClose(DeviceID); +# else /* !Cygwin32 */ + +# if defined __EMX__ +# if defined HAVE_MMPM + /* close the sound device */ + MCI_GENERIC_PARMS mciGenericParms; + mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0); +# else /* HAVE_MMPM */ + return 0; +# endif /* HAVE_MMPM */ +# else /* !EMX */ +# if defined __QNX__ + snd_pcm_plugin_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + return snd_pcm_close(pcm_handle); +# else /* !QNX */ + return close(global.soundcard_fd); +# endif /* !QNX */ +# endif /* !EMX */ +# endif /* !Cygwin32 */ +#endif /* ifdef ECHO_TO_SOUNDCARD */ +} + +int write_snd_device(char *buffer, unsigned todo) +{ + int result = 0; +#ifdef ECHO_TO_SOUNDCARD +#if defined __CYGWIN32__ + MMRESULT mmres; + + wavehdr[lastwav].dwBufferLength = todo; + memcpy(wavehdr[lastwav].lpData, buffer, todo); + + mmres = waveOutWrite(DeviceID, &wavehdr[lastwav], sizeof(WAVEHDR)); + if (mmres) { + char erstr[129]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard write error: %s!\n", erstr); + return 1; + } + if (++lastwav >= WAVEHDRS) + lastwav -= WAVEHDRS; + result = mmres; +#else +#if defined __EMX__ + Playlist[BufferInd].ulOperand1 = buffer; + Playlist[BufferInd].ulOperand2 = todo; + Playlist[BufferInd].ulOperand3 = 0; + if (++BufferInd >= FRAGMENTS) + BufferInd -= FRAGMENTS; + + /* no MCI_WAIT here, because application program has to continue */ + memset(&mciPlayParms, 0, sizeof(mciPlayParms)); + if (mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM, &mciPlayParms, 0)) { + fprintf( stderr, "soundcard write error: %s!\n", erstr); + return 1; + } + result = 0; +#else + int retval2; + int towrite; + +#if defined HAVE_OSS && defined SNDCTL_DSP_GETOSPACE + towrite = abinfo.fragments * abinfo.fragsize; + if (towrite == 0) +#endif + towrite = todo; + do { + fd_set writefds[1]; + struct timeval timeout2; + int wrote; + + timeout2.tv_sec = 0; + timeout2.tv_usec = 4*120000; + + FD_ZERO(writefds); + FD_SET(global.soundcard_fd, writefds); + retval2 = select(global.soundcard_fd + 1, + NULL, writefds, NULL, &timeout2); + switch (retval2) { + default: + case -1: perror ("select failed"); + /* fall through */ + case 0: /* timeout */ + result = 2; + goto outside_loop; + case 1: break; + } + if (towrite > todo) { + towrite = todo; + } +#if defined __QNX__ && defined HAVE_SYS_ASOUNDLIB_H + wrote = snd_pcm_plugin_write(pcm_handle, buffer, towrite); +#else + wrote = write(global.soundcard_fd, buffer, towrite); +#endif + if (wrote <= 0) { + perror( "cant write audio"); + result = 1; + goto outside_loop; + } else { + todo -= wrote; + buffer += wrote; + } + } while (todo > 0); +outside_loop: + ; +#endif /* !defined __EMX__ */ +#endif /* !defined __CYGWIN32__ */ +#endif /* ECHO_TO_SOUNDCARD */ + return result; +} + |