/* Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons * to whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Except as contained in this notice, the name of a copyright holder * shall not be used in advertising or otherwise to promote the sale, use * or other dealings in this Software without prior written authorization * of the copyright holder. */ #ifdef HAVE_XORG_CONFIG_H #include #endif #include #include #include #include #include #include "xf86.h" #include "xf86Priv.h" #include "xf86_OSlib.h" #define BELL_RATE 48000 /* Samples per second */ #define BELL_HZ 50 /* Fraction of a second i.e. 1/x */ #define BELL_MS (1000/BELL_HZ) /* MS */ #define BELL_SAMPLES (BELL_RATE / BELL_HZ) #define BELL_MIN 3 /* Min # of repeats */ #define AUDIO_DEVICE "/dev/audio" void xf86OSRingBell(int loudness, int pitch, int duration) { static short samples[BELL_SAMPLES]; static short silence[BELL_SAMPLES]; /* "The Sound of Silence" */ static int lastFreq; int cnt; int i; int written; int repeats; int freq; audio_info_t audioInfo; struct iovec iov[IOV_MAX]; int iovcnt; double ampl, cyclen, phase; int audioFD; if ((loudness <= 0) || (pitch <= 0) || (duration <= 0)) { return; } lastFreq = 0; bzero(silence, sizeof(silence)); audioFD = open(AUDIO_DEVICE, O_WRONLY | O_NONBLOCK); if (audioFD == -1) { xf86Msg(X_ERROR, "Bell: cannot open audio device \"%s\": %s\n", AUDIO_DEVICE, strerror(errno)); return; } freq = pitch; freq = min(freq, (BELL_RATE / 2) - 1); freq = max(freq, 2 * BELL_HZ); /* * Ensure full waves per buffer */ freq -= freq % BELL_HZ; if (freq != lastFreq) { lastFreq = freq; ampl = 16384.0; cyclen = (double) freq / (double) BELL_RATE; phase = 0.0; for (i = 0; i < BELL_SAMPLES; i++) { samples[i] = (short) (ampl * sin(2.0 * M_PI * phase)); phase += cyclen; if (phase >= 1.0) phase -= 1.0; } } repeats = (duration + (BELL_MS / 2)) / BELL_MS; repeats = max(repeats, BELL_MIN); loudness = max(0, loudness); loudness = min(loudness, 100); #ifdef DEBUG ErrorF("BELL : freq %d volume %d duration %d repeats %d\n", freq, loudness, duration, repeats); #endif AUDIO_INITINFO(&audioInfo); audioInfo.play.encoding = AUDIO_ENCODING_LINEAR; audioInfo.play.sample_rate = BELL_RATE; audioInfo.play.channels = 2; audioInfo.play.precision = 16; audioInfo.play.gain = min(AUDIO_MAX_GAIN, AUDIO_MAX_GAIN * loudness / 100); if (ioctl(audioFD, AUDIO_SETINFO, &audioInfo) < 0){ xf86Msg(X_ERROR, "Bell: AUDIO_SETINFO failed on audio device \"%s\": %s\n", AUDIO_DEVICE, strerror(errno)); close(audioFD); return; } iovcnt = 0; for (cnt = 0; cnt <= repeats; cnt++) { iov[iovcnt].iov_base = (char *) samples; iov[iovcnt++].iov_len = sizeof(samples); if (cnt == repeats) { /* Insert a bit of silence so that multiple beeps are distinct and * not compressed into a single tone. */ iov[iovcnt].iov_base = (char *) silence; iov[iovcnt++].iov_len = sizeof(silence); } if ((iovcnt >= IOV_MAX) || (cnt == repeats)) { written = writev(audioFD, iov, iovcnt); if ((written < ((int)(sizeof(samples) * iovcnt)))) { /* audio buffer was full! */ int naptime; if (written == -1) { if (errno != EAGAIN) { xf86Msg(X_ERROR, "Bell: writev failed on audio device \"%s\": %s\n", AUDIO_DEVICE, strerror(errno)); close(audioFD); return; } i = iovcnt; } else { i = ((sizeof(samples) * iovcnt) - written) / sizeof(samples); } cnt -= i; /* sleep a little to allow audio buffer to drain */ naptime = BELL_MS * i; poll(NULL, 0, naptime); i = ((sizeof(samples) * iovcnt) - written) % sizeof(samples); iovcnt = 0; if ((written != -1) && (i > 0)) { iov[iovcnt].iov_base = ((char *) samples) + i; iov[iovcnt++].iov_len = sizeof(samples) - i; } } else { iovcnt = 0; } } } close(audioFD); return; }