Remove trailing whitespace.
[dockapps.git] / wmnotify / src / sound.c
blob10dc8e4192fc0b62bba4bedd50aeb7f336033e5b
1 /*
2 * sound.c -- Plays sound from file.
4 * Copyright (C) 2003 Hugo Villeneuve <hugo@hugovil.com>
5 * Based on the 'sndfile-play' demo program from 'libsndfile'
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 #if HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #if defined(HAVE_SNDFILE)
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
33 #if defined(__linux__)
34 # include <fcntl.h>
35 # include <sys/ioctl.h>
36 # include <sys/soundcard.h>
37 #elif( defined(sun) && defined(unix) )
38 # include <fcntl.h>
39 # include <sys/ioctl.h>
40 # include <sys/audioio.h>
41 #endif
43 #include <sndfile.h>
45 #include "common.h"
46 #include "wmnotify.h"
47 #include "sound.h"
50 #define BUFFER_LEN ((sf_count_t) 2048)
53 static int
54 OpenDspDevice( int channels, int srate )
56 int fd, status;
57 #if defined (__linux__)
58 int stereo, temp;
59 const char audio_device[] = "/dev/dsp";
60 #elif( defined(sun) && defined(unix) )
61 audio_info_t audio_info;
62 const char audio_device[] = "/dev/audio";
63 #endif
65 #if defined (__linux__)
66 fd = open( audio_device, O_WRONLY, 0 );
67 #elif( defined(sun) && defined(unix) )
68 /* Open the audio device - write only, non-blocking */
69 fd = open( audio_device, O_WRONLY | O_NONBLOCK );
70 #endif
72 if( fd < 0 ) {
73 fprintf( stderr, "%s: open() failed trying to open device '%s':\n", PACKAGE,
74 audio_device );
75 fprintf( stderr, " %s\n", strerror( errno ) );
76 fprintf( stderr,
77 " Check if device file exists and has correct write permissions.\n" );
78 ErrorLocation( __FILE__, __LINE__ );
79 return -1;
82 #if defined (__linux__)
83 stereo = 0;
84 status = ioctl( fd, SNDCTL_DSP_STEREO, &stereo );
85 if( status == -1 ) {
86 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
87 ErrorLocation( __FILE__, __LINE__ );
88 exit( EXIT_FAILURE );
91 status = ioctl( fd, SNDCTL_DSP_RESET, 0 );
92 if( status > 0 ) {
93 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
94 ErrorLocation( __FILE__, __LINE__ );
95 exit( EXIT_FAILURE );
98 temp = 16;
99 status = ioctl( fd, SOUND_PCM_WRITE_BITS, &temp );
100 if( status != 0 ) {
101 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
102 ErrorLocation( __FILE__, __LINE__ );
103 exit( EXIT_FAILURE );
106 status = ioctl( fd, SOUND_PCM_WRITE_CHANNELS, &channels );
107 if( status != 0 ) {
108 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
109 ErrorLocation( __FILE__, __LINE__ );
110 exit( EXIT_FAILURE );
113 status = ioctl( fd, SOUND_PCM_WRITE_RATE, &srate );
114 if( status != 0 ) {
115 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
116 ErrorLocation( __FILE__, __LINE__ );
117 exit( EXIT_FAILURE );
120 status = ioctl( fd, SNDCTL_DSP_SYNC, 0 );
121 if( status != 0 ) {
122 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
123 ErrorLocation( __FILE__, __LINE__ );
124 exit( EXIT_FAILURE );
127 #elif( defined(sun) && defined(unix) )
128 /* Retrieve standard values. */
129 AUDIO_INITINFO( &audio_info );
131 audio_info.play.sample_rate = sfinfo.samplerate;
132 audio_info.play.channels = sfinfo.channels;
133 audio_info.play.precision = 16;
134 audio_info.play.encoding = AUDIO_ENCODING_LINEAR;
135 audio_info.play.gain = AUDIO_MAX_GAIN;
136 audio_info.play.balance = AUDIO_MID_BALANCE;
138 status = ioctl( audio_fd, AUDIO_SETINFO, &audio_info );
139 if( status > 0 ) {
140 fprintf( stderr, "%s: ioctl() failed: %s\n", PACKAGE, strerror( errno ) );
141 ErrorLocation( __FILE__, __LINE__ );
142 exit( EXIT_FAILURE );
144 #endif
146 return fd;
150 void
151 PlayAudioFile( char *filename, int volume )
153 static short buffer[BUFFER_LEN];
154 SNDFILE *sndfile;
155 SF_INFO sfinfo;
156 int audio_fd;
157 int readcount;
158 int status;
159 #if defined (__linux__)
160 int subformat;
161 int m;
162 #elif( defined(sun) && defined(unix) )
163 unsigned long delay_time;
164 long start_count, output_count, write_count;
165 bool done;
166 #endif
168 if( wmnotify_infos.debug ) {
169 printf( "%s: PlayAudioFile() Entry\n", PACKAGE );
172 if( filename == NULL ) {
173 fprintf( stderr, "%s: No audio file specified.\n", PACKAGE );
174 ErrorLocation( __FILE__, __LINE__ );
175 exit( EXIT_FAILURE );
178 sndfile = sf_open( filename, SFM_READ, &sfinfo );
180 if( sndfile == NULL ) {
181 fprintf( stderr, "%s: sf_open() failed trying to open '%s':\n", PACKAGE, filename );
182 fprintf( stderr, " %s\n", sf_strerror(NULL) );
183 fprintf( stderr, " Check if file exists and has correct read permissions.\n" );
184 ErrorLocation( __FILE__, __LINE__ );
185 return;
188 if( sfinfo.channels < 1 || sfinfo.channels > 2 ) {
189 fprintf( stderr, "%s: Audio file has %d channel(s), but ", PACKAGE, sfinfo.channels );
190 fprintf( stderr, "we support only 1 or 2 channels.\n" );
191 ErrorLocation( __FILE__, __LINE__ );
192 exit( EXIT_FAILURE );
195 audio_fd = OpenDspDevice( sfinfo.channels, sfinfo.samplerate );
196 if( audio_fd < 0 ) {
197 goto play_audio_file_close_file;
200 #if( defined(sun) && defined(unix) )
201 /* Delay time equal to 1/4 of a buffer in microseconds. */
202 delay_time = (BUFFER_LEN * 1000000) / (sfinfo.samplerate * 4);
203 #endif
205 subformat = sfinfo.format & SF_FORMAT_SUBMASK;
207 if( subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE ) {
208 static float flt_buffer[BUFFER_LEN];
209 double scale;
211 status = sf_command( sndfile, SFC_CALC_SIGNAL_MAX, &scale, (int) sizeof(scale) );
212 if( status == 0 ) {
213 fprintf( stderr, "%s: Warning, sf_command() failed.\n", PACKAGE );
214 ErrorLocation( __FILE__, __LINE__ );
215 goto play_audio_file_close_audio;
218 if (scale < 1e-10) {
219 scale = 1.0;
221 else {
222 scale = 32700.0 / scale;
225 while( ( readcount = (int) sf_read_float( sndfile, flt_buffer, BUFFER_LEN ) ) != 0 ) {
226 /* Linux/OSS -- FLOAT samples */
227 #if defined (__linux__)
228 for( m = 0 ; m < readcount ; m++ ) {
229 /* Float to integer conversion. */
230 buffer[m] = (short) ( scale * flt_buffer[m] );
231 /* Changing volume */
232 buffer[m] = buffer[m] * volume / 100;
234 status = (int) write( audio_fd, buffer, readcount * sizeof(short) );
235 if( status == -1 ) {
236 perror( PACKAGE );
237 ErrorLocation( __FILE__, __LINE__ );
238 goto play_audio_file_close_audio;
241 /* Solaris -- FLOAT samples */
242 #elif( defined(sun) && defined(unix) )
243 start_count = 0;
244 output_count = read_count * sizeof(short);
246 while( output_count > 0 ) {
247 /* Write as much data as possible */
248 for( m = 0 ; m < readcount ; m++ ) {
249 /* Float to integer conversion. */
250 buffer[m] = (short) ( scale * flt_buffer[m] );
251 /* Changing volume */
252 buffer[m] = buffer[m] * volume / 100;
255 write_count = write( audio_fd, &(buffer[start_count]), output_count );
256 if( write_count > 0 ) {
257 output_count -= write_count;
258 start_count += write_count;
260 else {
261 /* Give the audio output time to catch up. */
262 usleep( delay_time );
264 } /* while( output_count > 0 ) */
265 #endif
266 } /* while( ( readcount... ) */
268 else {
269 while( ( readcount = (int) sf_read_short( sndfile, buffer, BUFFER_LEN ) ) != 0 ) {
270 /* Linux/OSS -- INTEGER samples */
271 #if defined (__linux__)
272 /* Changing volume... */
273 for( m = 0 ; m < readcount ; m++ ) {
274 buffer[m] = ( buffer[m] * volume ) / 100;
277 status = (int) write( audio_fd, buffer, readcount * sizeof(short) );
278 if( status == -1 ) {
279 perror( PACKAGE );
280 ErrorLocation( __FILE__, __LINE__ );
281 goto play_audio_file_close_audio;
284 /* Solaris -- INTEGER samples */
285 #elif( defined(sun) && defined(unix) )
286 start_count = 0;
287 output_count = read_count * sizeof(short);
289 while( output_count > 0 ) {
290 /* Write as much data as possible */
292 /* Changing volume. */
293 for( m = 0 ; m < read_count ; m++ ) {
294 buffer[m] = ( buffer[m] * volume ) / 100;
297 write_count = write( audio_fd, &(buffer[start_count]), output_count );
298 if( write_count > 0 ) {
299 output_count -= write_count;
300 start_count += write_count;
302 else {
303 /* Give the audio output time to catch up. */
304 usleep( delay_time );
306 } /* while( output_count > 0 ) */
307 #endif
308 } /* while( ( readcount... ) */
309 } /* else */
311 play_audio_file_close_audio:
313 status = close( audio_fd );
314 if( status != 0 ) {
315 fprintf( stderr, "%s: Error, close() failed.\n", PACKAGE );
316 ErrorLocation( __FILE__, __LINE__ );
317 exit( EXIT_FAILURE );
320 play_audio_file_close_file:
322 status = sf_close( sndfile );
323 if( status != 0 ) {
324 fprintf( stderr, "%s: Error, sf_close() failed.\n", PACKAGE );
325 ErrorLocation( __FILE__, __LINE__ );
326 exit( EXIT_FAILURE );
329 if( wmnotify_infos.debug ) {
330 printf( "%s: PlayAudioFile() Exit\n", PACKAGE );
333 return;
336 #endif /* HAVE_SNDFILE */