1 /* -*- Mode: C++-C -*-
2 *
3 * Copyright 1994 Christopher B. Liebman
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without fee,
7 * provided that the above copyright notice appear in all copies and that
8 * both that copyright notice and this permission notice appear in
9 * supporting documentation, and that the name Christopher B. Liebman not
10 * be used in advertising or publicity pertaining to distribution of this
11 * software without specific, written prior permission.
12 *
13 * THIS SOFTWARE IS PROVIDED `AS-IS'. CHRISTOPHER B. LIEBMAN, DISCLAIMS
14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
15 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL CHRISTOPHER
17 * B. LIEBMAN, BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING SPECIAL,
18 * INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, OR
19 * PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
20 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author : Chris Liebman
24 * Created On : Tue Jan 11 14:11:30 1994
25 * Last Modified By: Chris Liebman
26 * Last Modified On: Sat Feb 12 23:11:34 1994
27 * Update Count : 40
28 * Status : Released
29 *
30 * HISTORY
31 * 31-Jan-1994 Chris Liebman
32 * Last Modified: Sat Jan 29 23:56:11 1994 #35 (Chris Liebman)
33 * Major changes for new search stuff.
34 *
35 * 24-Jan-1994 Chris Liebman
36 * Last Modified: Sun Jan 23 16:03:49 1994 #19 (Chris Liebman)
37 * Added path support and moved all sound checking here.
38 *
39 * 14-Jan-1994 Chris Liebman
40 * Last Modified: Wed Jan 12 11:58:51 1994 #4 (Chris Liebman)
41 * added #if to use XtDatabase() for versions of Xt less than 5
42 *
43 *
44 * PURPOSE
45 * Sound support using NetAudio.
46 */
47
48 #ifndef lint
49 static char *RCSid = "$Id: face_sound.c,v 1.17 1994/03/07 20:27:46 liebman Exp $";
50 #endif
51
52 #include "faces.h"
53 #include <audio/audiolib.h>
54 #include <audio/Xtutil.h>
55 #include <audio/soundlib.h>
56 #include "face_sound.h"
57 #include "face_search.h"
58 #include <sys/stat.h>
59
60 static AuServer* audio = NULL;
61
62 /*
63 * Here is the play list.
64 */
65
66 typedef struct play_list
67 {
68 FaceSound* sound;
69 struct play_list* next;
70 } PlayList;
71
72 static PlayList* PlayListHead;
73 static PlayList* PlayListTail;
74
75 /*
76 * Here we store a complete list of sounds.
77 */
78
79 static FaceSound *TheSounds = NULL;
80
81 /*
82 * Create face sound data for face.
83 */
84
85 FaceSound *
FaceSoundCreate(file)86 FaceSoundCreate(file)
87 char *file;
88 {
89 struct stat buf;
90 FaceSound *fs;
91
92 /*
93 * First see if we already have this sound.
94 */
95
96 for (fs = TheSounds; fs != NULL; fs = fs->next)
97 {
98 if (strcmp(fs->file, file) == 0)
99 {
100 /*
101 * Yep!
102 */
103
104 fs->refs += 1;
105
106 return(fs);
107 }
108 }
109
110 if (!audio)
111 {
112 return NULL;
113 }
114
115 /*
116 * Fail if file is a directory or does not exist.
117 */
118
119 if ((stat(file, &buf) == -1) || (buf.st_mode & S_IFDIR))
120 {
121 return NULL;
122 }
123
124 /*
125 * Ok, create a face sound struct.
126 */
127
128 fs = (FaceSound *)XtCalloc(1, sizeof(FaceSound));
129 fs->file = XtNewString(file);
130 #ifdef USE_BUCKETS
131 fs->bucket = AuSoundCreateBucketFromFile(audio, file, (AuAccessImportMask |
132 AuAccessExportMask |
133 AuAccessListMask),
134 NULL, NULL);
135
136 if (fs->bucket == AuNone)
137 {
138 XtFree((char *)fs);
139 return NULL;
140 }
141 #else
142 fs->sound = SoundOpenFileForReading(file);
143 if (!fs->sound)
144 {
145 XtFree((void*)fs);
146 return NULL;
147 }
148 #endif /* USE_BUCKETS */
149
150 fs->refs = 1;
151
152 /*
153 * Put the new sound on the list.
154 */
155
156 fs->next = TheSounds;
157 fs->prev = NULL;
158
159 if (fs->next != NULL)
160 {
161 fs->next->prev = fs;
162 }
163
164 TheSounds = fs;
165
166 /*
167 * and return it.
168 */
169
170 return(fs);
171 }
172
173 /*
174 * Free an sound.
175 */
176
177 void
FaceSoundFree(fs)178 FaceSoundFree(fs)
179 FaceSound *fs;
180 {
181 if (!fs)
182 {
183 return;
184 }
185
186 /*
187 * First remove one reference. If there are still more refs just
188 * return.
189 */
190
191 fs->refs -= 1;
192 if (fs->refs != 0)
193 {
194 return;
195 }
196
197 /*
198 * Destroy the attacked sound.
199 */
200
201 if (audio)
202 {
203 #ifdef USE_BUCKETS
204 AuDestroyBucket(audio, fs->bucket, NULL);
205 #else
206 SoundCloseFile(fs->sound);
207 #endif /* USE_BUCKETS */
208 }
209
210 /*
211 * The previous sound is now previous to the next sound.
212 */
213
214 if (fs->next != NULL)
215 {
216 fs->next->prev = fs->prev;
217 }
218
219 /*
220 * The next face is now next from the previous face.
221 */
222
223 if (fs->prev != NULL)
224 {
225 fs->prev->next = fs->next;
226 }
227
228 /*
229 * If this was the first sound then the next sound is
230 * first.
231 */
232
233 if (fs == TheSounds)
234 {
235 TheSounds = fs->next;
236 }
237
238 /*
239 * Ok, free the name.
240 */
241
242 XtFree(fs->file);
243
244 /*
245 * Free the struct.
246 */
247
248 XtFree((void *)fs);
249 }
250
251 static int
FaceSoundLoadWork(file,path,item)252 FaceSoundLoadWork(file, path, item)
253 char* file;
254 char* path;
255 MailItem* item;
256 {
257 FaceSound* fs;
258 char** p;
259 int length;
260 static char *filename = NULL;
261 static int filename_length;
262 static char *extensions[] =
263 {
264 ".au", ".snd", ".voc", ".wav", ".wave", 0
265 };
266
267 /*
268 * First try the file as given.
269 */
270
271 if ((fs = FaceSoundCreate(file)) != NULL)
272 {
273 item->sound = fs;
274 return 1;
275 }
276
277 /*
278 * Make a buffer to try various names in.
279 */
280
281 length = strlen(file) + 20;
282
283 if (filename_length < length)
284 {
285 filename_length = length;
286
287 if (filename)
288 {
289 XtFree(filename);
290 }
291
292 filename = XtMalloc(filename_length);
293 }
294
295 for(p = extensions; *p; ++p)
296 {
297 sprintf(filename, "%s%s", file, *p);
298 if ((fs = FaceSoundCreate(filename)) != NULL)
299 {
300 item->sound = fs;
301 return 1;
302 }
303 }
304
305 return 0;
306 }
307
308 int
FaceSoundLoad(file,item,data)309 FaceSoundLoad(file, item, data)
310 char* file;
311 MailItem* item;
312 FaceSearchData* data;
313 {
314 int found = 0;
315 char** paths = TheFacesResources.sound_paths;
316
317 if (data != NULL)
318 {
319 /*
320 * Fixup paths.
321 */
322
323 if (data->paths != NULL)
324 {
325 paths = data->paths;
326 }
327 }
328
329 /*
330 * enumerate thru paths if needed.
331 */
332
333 if ((*file != '/') &&
334 strncmp(file, "./", 2) &&
335 strncmp(file, "../", 3))
336 {
337 found = PathEnumerate(file, paths, FaceSoundLoadWork, item);
338 }
339 else
340 {
341 found = FaceSoundLoadWork(file, ".", item);
342 }
343
344 return found;
345 }
346
347 /*
348 * Shamlessly coppied from net audio and modified to play from bucket
349 * instead of file.
350 */
351
352 #define VOL(volume) ((1 << 16) * (volume) / 100)
353
354 /* ARGSUSED */
355 static void
play_cb(aud,handler,ev,data)356 play_cb(aud, handler, ev, data)
357 AuServer *aud;
358 AuEventHandlerRec *handler;
359 AuEvent *ev;
360 AuPointer data;
361 {
362 AuStatus ret;
363 PlayList *this;
364
365 /*
366 * Ok, one item finished, remove it from the list and start the next.
367 */
368
369
370 this = PlayListHead;
371 PlayListHead = this->next;
372 XtFree((char *)this);
373
374 /*
375 * If there is another sound to play then start it, else that was the
376 * last sound so NULL the tail pointer.
377 */
378
379 if (PlayListHead != NULL)
380 {
381 #ifdef USE_BUCKETS
382 AuSoundPlayFromBucket(audio, PlayListHead->sound->bucket, AuNone,
383 VOL(TheFacesResources.volume),
384 play_cb, NULL, 1,
385 NULL, NULL, NULL,
386 &ret);
387 #else
388 AuSoundPlayFromFile(audio, PlayListHead->sound->file, AuNone,
389 VOL(TheFacesResources.volume),
390 play_cb, NULL,
391 NULL, NULL, NULL,
392 &ret);
393 #endif
394 }
395 else
396 {
397 PlayListTail = NULL;
398 }
399 }
400
401 /*
402 * Play a sound.
403 */
404
405 void
FaceSoundPlay(fs)406 FaceSoundPlay(fs)
407 FaceSound *fs;
408 {
409 PlayList *this;
410 AuStatus ret;
411
412 /*
413 * No audio device!
414 */
415
416 if (!audio)
417 {
418 return;
419 }
420
421 /*
422 * No sound!
423 */
424
425 if (!fs)
426 {
427 return;
428 }
429
430 /*
431 * make a play list for this guy.
432 */
433
434 this = (PlayList*)XtMalloc(sizeof(PlayList));
435 this->sound = fs;
436 this->next = NULL;
437
438 /*
439 * First item on play list starts the playing.
440 */
441
442 if (!PlayListHead)
443 {
444 PlayListHead = PlayListTail = this;
445 #ifdef USE_BUCKETS
446 AuSoundPlayFromBucket(audio, PlayListHead->sound->bucket, AuNone,
447 VOL(TheFacesResources.volume),
448 play_cb, NULL, 1,
449 NULL, NULL, NULL,
450 &ret);
451 #else
452 AuSoundPlayFromFile(audio, PlayListHead->sound->file, AuNone,
453 VOL(TheFacesResources.volume),
454 play_cb, NULL,
455 NULL, NULL, NULL,
456 &ret);
457 #endif
458 return;
459 }
460
461 /*
462 * Just add this item to the tail of the list.
463 */
464
465 PlayListTail->next = this;
466 PlayListTail = this;
467 }
468
469 void
FaceSoundFind(item)470 FaceSoundFind(item)
471 MailItem* item;
472 {
473 if (TheFacesResources.use_sound)
474 {
475 FaceSearch(item, TheFacesResources.sound_search);
476 }
477 }
478
479
480 void
FaceSoundInit()481 FaceSoundInit()
482 {
483 static int init = 0;
484
485 if (!init)
486 {
487 String dpy_name = DisplayString(XtDisplay(TheTopLevel));
488 audio = AuOpenServer(dpy_name, 0, NULL, 0, NULL, NULL);
489
490 if (audio)
491 {
492 AuXtAppAddAudioHandler(XtWidgetToApplicationContext(TheTopLevel),
493 audio);
494 }
495
496 init = 1;
497 }
498 }
499