/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ # if defined(__FreeBSD__) #include # if !defined(SNDCTL_DSP_CHANNELS) # define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS # endif # else #include # endif #include #include #include #include #include #include #include "SoundIF.h" #include "Sample.h" #include "util.h" class SoundIFImpl { public: SoundIFImpl() { dspFd_ = -1; } int setupDevice(); int openDevice(); void closeDevice(); int dspFd_; // sound device }; SoundIF::SoundIF() { impl_ = new SoundIFImpl; } SoundIF::~SoundIF() { end(); delete impl_; impl_ = NULL; } // Initializes sound interface. // return: 0: OK // 1: sounde device not found // 2: cannot setup sound device int SoundIF::init() { if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 2; } impl_->closeDevice(); return 0; } // Acquires sound device for playing. // return 0: OK // 1: error occured int SoundIF::start() { if (impl_->dspFd_ >= 0) return 0; // already opened if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 1; } return 0; } // Playes given sample buffer. // return: 0: OK // 1: error occured int SoundIF::play(Sample *sbuf, long nofSamples) { if (impl_->dspFd_ < 0) return 1; swapSamples(sbuf, nofSamples); long ret; long len = nofSamples * sizeof(Sample); long nwritten = 0; char *buf = (char *)sbuf; while (len > 0) { ret = write(impl_->dspFd_, buf + nwritten, len); if (ret <= 0) return 1; nwritten += ret; len -= ret; } return 0; } unsigned long SoundIF::getDelay() { if (impl_->dspFd_ < 0) return 1; #ifdef SNDCTL_DSP_GETODELAY int delay; if (ioctl(impl_->dspFd_, SNDCTL_DSP_GETODELAY, &delay) == 0) { return delay / 4; } #endif return 0; } // Finishs playing, sound device is released. void SoundIF::end() { impl_->closeDevice(); } int SoundIFImpl::openDevice() { int flags; if (dspFd_ >= 0) return 0; // already open if ((dspFd_ = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) < 0) { message(-1, _("Cannot open \"/dev/dsp\": %s"), strerror(errno)); return 1; } if ((flags = fcntl(dspFd_, F_GETFL)) >= 0) { flags &= ~O_NONBLOCK; fcntl(dspFd_, F_SETFL, flags); } return 0; } void SoundIFImpl::closeDevice() { if (dspFd_ >= 0) { close(dspFd_); dspFd_ = -1; } } int SoundIFImpl::setupDevice() { if (dspFd_ < 0) return 1; int val = 44100; if (ioctl(dspFd_, SNDCTL_DSP_SPEED, &val) < 0) { message(-1, _("Cannot set sample rate to 44100: %s"), strerror(errno)); return 1; } val = 2; if (ioctl(dspFd_, SNDCTL_DSP_CHANNELS, &val) < 0) { message(-1, _("Cannot setup 2 channels: %s"), strerror(errno)); return 1; } val = AFMT_S16_LE; if (ioctl(dspFd_, SNDCTL_DSP_SETFMT, &val) < 0) { message(-1, _("Cannot setup sound format: %s"), strerror(errno)); return 1; } if (val != AFMT_S16_LE) { message(-1, _("Sound device does not support " "little endian signed 16 bit samples.")); return 1; } return 0; }