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.
26 #if defined(HAVE_SNDFILE)
33 #if defined(__linux__)
35 # include <sys/ioctl.h>
36 # include <sys/soundcard.h>
37 #elif( defined(sun) && defined(unix) )
39 # include <sys/ioctl.h>
40 # include <sys/audioio.h>
50 #define BUFFER_LEN ((sf_count_t) 2048)
54 OpenDspDevice( int channels
, int srate
)
57 #if defined (__linux__)
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";
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
);
73 fprintf( stderr
, "%s: open() failed trying to open device '%s':\n", PACKAGE
,
75 fprintf( stderr
, " %s\n", strerror( errno
) );
77 " Check if device file exists and has correct write permissions.\n" );
78 ErrorLocation( __FILE__
, __LINE__
);
82 #if defined (__linux__)
84 status
= ioctl( fd
, SNDCTL_DSP_STEREO
, &stereo
);
86 fprintf( stderr
, "%s: ioctl() failed: %s\n", PACKAGE
, strerror( errno
) );
87 ErrorLocation( __FILE__
, __LINE__
);
91 status
= ioctl( fd
, SNDCTL_DSP_RESET
, 0 );
93 fprintf( stderr
, "%s: ioctl() failed: %s\n", PACKAGE
, strerror( errno
) );
94 ErrorLocation( __FILE__
, __LINE__
);
99 status
= ioctl( fd
, SOUND_PCM_WRITE_BITS
, &temp
);
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
);
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
);
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 );
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
);
140 fprintf( stderr
, "%s: ioctl() failed: %s\n", PACKAGE
, strerror( errno
) );
141 ErrorLocation( __FILE__
, __LINE__
);
142 exit( EXIT_FAILURE
);
151 PlayAudioFile( char *filename
, int volume
)
153 static short buffer
[BUFFER_LEN
];
159 #if defined (__linux__)
162 #elif( defined(sun) && defined(unix) )
163 unsigned long delay_time
;
164 long start_count
, output_count
, write_count
;
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__
);
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
);
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);
205 subformat
= sfinfo
.format
& SF_FORMAT_SUBMASK
;
207 if( subformat
== SF_FORMAT_FLOAT
|| subformat
== SF_FORMAT_DOUBLE
) {
208 static float flt_buffer
[BUFFER_LEN
];
211 status
= sf_command( sndfile
, SFC_CALC_SIGNAL_MAX
, &scale
, (int) sizeof(scale
) );
213 fprintf( stderr
, "%s: Warning, sf_command() failed.\n", PACKAGE
);
214 ErrorLocation( __FILE__
, __LINE__
);
215 goto play_audio_file_close_audio
;
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) );
237 ErrorLocation( __FILE__
, __LINE__
);
238 goto play_audio_file_close_audio
;
241 /* Solaris -- FLOAT samples */
242 #elif( defined(sun) && defined(unix) )
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
;
261 /* Give the audio output time to catch up. */
262 usleep( delay_time
);
264 } /* while( output_count > 0 ) */
266 } /* while( ( readcount... ) */
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) );
280 ErrorLocation( __FILE__
, __LINE__
);
281 goto play_audio_file_close_audio
;
284 /* Solaris -- INTEGER samples */
285 #elif( defined(sun) && defined(unix) )
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
;
303 /* Give the audio output time to catch up. */
304 usleep( delay_time
);
306 } /* while( output_count > 0 ) */
308 } /* while( ( readcount... ) */
311 play_audio_file_close_audio
:
313 status
= close( audio_fd
);
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
);
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
);
336 #endif /* HAVE_SNDFILE */