1 /**
2 * Copyright 1993 Network Computing Devices, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name Network Computing Devices, Inc. not be
9 * used in advertising or publicity pertaining to distribution of this
10 * software without specific, written prior permission.
11 *
12 * THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC.,
13 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
14 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15 * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
16 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
17 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
18 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
19 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author: Greg Renda <greg@ncd.com>
23 * Network Computing Devices, Inc.
24 * 350 North Bernardo Ave.
25 * Mountain View, CA 94043
26 *
27 * $NCDId: @(#)audemo.c,v 1.60 1995/12/06 01:08:33 greg Exp $
28 */
29 #include "config.h"
30
31 #include <inttypes.h>
32 #include <stdio.h>
33
34 #if defined(HAVE_STDLIB_H)
35 # include <stdlib.h>
36 #endif
37
38 #if defined(HAVE_MALLOC_H)
39 # include <malloc.h>
40 #endif
41
42 #include <signal.h>
43 #if !defined(SYSV) || defined(WIN32)
44 #include <audio/Aos.h> /* for string and other os stuff */
45 #endif
46 #include <audio/Afuncs.h> /* for bcopy et. al. */
47 #include <audio/audiolib.h>
48 #include <audio/soundlib.h>
49
50 #if defined(SYSV) && !defined(WIN32)
51 #include <sys/time.h> /* for timeval */
52
53 /* not defined in <stdio.h> when -Xc used */
54 extern FILE *
55 popen(
56 #if NeedFunctionPrototypes
57 const char *, const char *
58 #endif
59 );
60 #endif /* SVR4 */
61
62 #ifdef WIN32
63 #include <winsock.h>
64 #endif /* WIN32 */
65
66 #define AddToLinkedList(head, item) \
67 { \
68 (item)->prev = NULL; \
69 (item)->next = head; \
70 if (head) \
71 (head)->prev = item; \
72 head = item; \
73 }
74
75 #define RemoveFromLinkedList(head, item) \
76 { \
77 if ((item)->next) \
78 (item)->next->prev = (item)->prev; \
79 \
80 if ((item)->prev) \
81 (item)->prev->next = (item)->next; \
82 else \
83 head = (item)->next; \
84 }
85
86 #define XT
87
88 #ifdef XT
89 #include <X11/Intrinsic.h>
90 #include <X11/StringDefs.h>
91 #include <X11/Shell.h>
92 #include <X11/Xaw/Cardinals.h>
93 #include <audio/Xtutil.h>
94
95 /* widgets */
96 #include <X11/Xaw/Command.h>
97 #include <X11/Xaw/Form.h>
98 #include <X11/Xaw/List.h>
99 #include <X11/Xaw/Viewport.h>
100 #include <X11/Xaw/AsciiText.h>
101 #include <X11/Xaw/Scrollbar.h>
102 #include <X11/Xaw/Label.h>
103 #include <X11/Xaw/SimpleMenu.h>
104 #include <X11/Xaw/MenuButton.h>
105 #include <X11/Xaw/SmeBSB.h>
106 #include <X11/Xaw/Toggle.h>
107 #endif /* XT */
108
109 #define APP_INSTANCE "audemo"
110 #define APP_CLASS "Audemo"
111 #define VOLUME_FORMAT "Volume: %3d%%"
112 #define GAIN_FORMAT "Gain: %3d%%"
113 #define DEFAULT_VOLUME 100
114 #define BUF_SIZE 200
115 #define MAX_VOLUME 200
116 #define MIN_VOLUME 1
117 #define MAX_GAIN 100
118 #define MIN_GAIN 1
119 #define DOUBLE_CLICK_TIME 500000 /* in microseconds */
120
121 #define VOL AuFixedPointFromFraction(globals->volume, 100)
122 #define GAIN AuFixedPointFromSum(globals->rec.gain, 0)
123
124 #define BUCKET_HEADER_FORMAT \
125 "%-20s %5.2f %2d %5d Hz %c %s"
126
127 #define MakePopup(_w, _parent, _type, _name) \
128 { \
129 (_w) = \
130 XtCreatePopupShell(_name, _type, _parent, NULL, 0); \
131 }
132
133 #define MakeWidget(_w, _parent, _type, _callback, _name) \
134 { \
135 (_w) = XtCreateManagedWidget(_name, _type, _parent, NULL, 0); \
136 \
137 if ((void *) (_callback) != NULL) \
138 XtAddCallback(_w, XtNcallback, _callback, g); \
139 }
140
141 #define MakeButton(_w, _parent, _callback, _name) \
142 MakeWidget(_w, _parent, commandWidgetClass, _callback, _name)
143
144 #define MakeLabel(_w, _parent, _name) \
145 MakeWidget(_w, _parent, labelWidgetClass, NULL, _name)
146
147 #define MakeMenuItem(_parent, _label) \
148 XtCreateManagedWidget(_label, smeBSBObjectClass, _parent, NULL, 0)
149
150 static String defaultResources[] =
151 {
152 #include "resources.h"
153 NULL
154 };
155
156 static char **makeFileList(char **fileNames, int nfiles);
157 static int getFileNames(char *dir, char ***fileNames, char *template);
158 static void fatalError(const char *message, const char *arg),
159 bucketQueryCB(Widget w, XtPointer globalsp, XtPointer call_data),
160 bucketRecordDismissCB(Widget w, XtPointer globalsp, XtPointer call_data),
161 meterCB();
162
163 #ifdef XT
164 #define Invert(w) \
165 { \
166 Pixel fg, bg; \
167 \
168 XtVaGetValues(w, XtNforeground, &fg, XtNbackground, &bg, NULL); \
169 XtVaSetValues(w, XtNforeground, bg, XtNbackground, fg, NULL); \
170 }
171
172 typedef struct
173 {
174 Widget popShell,
175 file,
176 fileFormatMenuButton,
177 form;
178 } SaveDialogDataRec, *SaveDialogDataPtr;
179
180 typedef struct
181 {
182 Widget popShell,
183 form,
184 record,
185 dismiss,
186 file,
187 fileFormatMenuButton,
188 dataFormatMenuButton,
189 rate,
190 monitor,
191 comment,
192 duration,
193 new,
194 readOnly,
195 mode,
196 gainLabel,
197 gainBar;
198 unsigned int gain;
199 } RecordDialogDataRec, *RecordDialogDataPtr;
200
201 typedef struct
202 {
203 Widget popShell,
204 form,
205 dismiss,
206 viewport,
207 bucketList,
208 query,
209 play,
210 record,
211 load,
212 delete,
213 save,
214 formatMenu,
215 formatMenuButton,
216 accessMenu,
217 accessMenuButton;
218 int numBuckets;
219 AuBucketAttributes *list;
220 char **bucketText;
221 } BucketDialogDataRec, *BucketDialogDataPtr;
222
223 typedef struct
224 {
225 Widget topLevel,
226 meter,
227 quit,
228 form,
229 play,
230 samples,
231 info,
232 viewport,
233 volumeBar,
234 volumeLabel,
235 leftMeter,
236 rightMeter,
237 record,
238 buckets,
239 directory,
240 template,
241 rescan;
242 int volume,
243 numFiles,
244 inputDeviceNum,
245 sourceIndex;
246 AuServer *aud;
247 char **fileNames;
248 Display *dpy;
249 RecordDialogDataRec rec;
250 BucketDialogDataRec buf;
251 SaveDialogDataRec save;
252 AuDeviceID inputDeviceId;
253 } GlobalDataRec, *GlobalDataPtr;
254
255 typedef struct _ElementList
256 {
257 AuFlowID flow;
258 int volumeElement,
259 monitorElement;
260 struct _ElementList *prev,
261 *next;
262 } ElementListRec, *ElementListPtr;
263
264 typedef ElementListPtr ElementListId;
265
266 static ElementListPtr ElementList;
267 static int ElementCount,
268 MonitorCount;
269
270 #if !defined(sun) && !defined(linux) && !defined(__GNU__) && !defined(__GLIBC__) /* who else doesn't have
271 * this? */
272 #define strdup ncd_strdup /* To avoid conflicting with
273 * headers on hosts that *do*
274 * have strdup... */
275 char *
strdup(char * s)276 strdup(char *s)
277 {
278 char *t;
279
280 if (!s)
281 return s;
282 t = (char *) malloc(strlen(s) + 1);
283 strcpy(t, s);
284 return t;
285 }
286 #endif
287
288 static void
RemoveFromElementList(GlobalDataPtr globals,ElementListPtr p)289 RemoveFromElementList(GlobalDataPtr globals, ElementListPtr p)
290 {
291 RemoveFromLinkedList(ElementList, p);
292 ElementCount--;
293
294 if (p->monitorElement != -1)
295 {
296 MonitorCount--;
297
298 if (!MonitorCount)
299 meterCB(globals->aud, NULL, NULL, globals);
300 }
301
302 free(p);
303 }
304
305 static ElementListId
AddToElementList(AuFlowID flow,int volumeElement,int monitorElement)306 AddToElementList(AuFlowID flow, int volumeElement, int monitorElement)
307 {
308 ElementListPtr p;
309
310 if (!(p = (ElementListPtr) malloc(sizeof(ElementListRec))))
311 fatalError("malloc error in AddToElementList", NULL);
312
313 p->flow = flow;
314 p->volumeElement = volumeElement;
315 p->monitorElement = monitorElement;
316
317 AddToLinkedList(ElementList, p);
318 ElementCount++;
319
320 if (monitorElement != -1)
321 MonitorCount++;
322
323 return (ElementListId) p;
324 }
325
326 static void
queryInputAttributes(GlobalDataPtr globals)327 queryInputAttributes(GlobalDataPtr globals)
328 {
329 Boolean mode;
330 AuDeviceAttributes *attr;
331 char buf[50];
332
333 attr = AuGetDeviceAttributes(globals->aud, globals->inputDeviceId, NULL);
334 globals->rec.gain = AuFixedPointRoundUp(AuDeviceGain(attr));
335 sprintf(buf, GAIN_FORMAT, globals->rec.gain);
336 XtVaSetValues(globals->rec.gainLabel, XtNlabel, buf, NULL);
337 XawScrollbarSetThumb(globals->rec.gainBar,
338 (float) globals->rec.gain / MAX_GAIN, -1.0);
339
340 mode = AuDeviceLineMode(attr) == AuDeviceLineModeHigh;
341 XtVaSetValues(globals->rec.mode, XtNstate, mode, NULL);
342
343 AuFreeDeviceAttributes(globals->aud, 1, attr);
344 }
345
346 static void
meterToggleCB(Widget w,XtPointer globalsp,XtPointer call_data)347 meterToggleCB(Widget w, XtPointer globalsp, XtPointer call_data)
348 {
349 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
350 Boolean meter;
351 AuElementState *states,
352 *s;
353 ElementListPtr p;
354 int state;
355
356 XtVaGetValues(globals->meter, XtNstate, &meter, NULL);
357
358 state = meter ? AuStateStart : AuStateStop;
359
360 if (MonitorCount)
361 {
362 if (!(states = (AuElementState *) malloc(sizeof(AuElementState) *
363 MonitorCount)))
364 return;
365
366 p = ElementList;
367 s = states;
368
369 while (p)
370 {
371 if (p->monitorElement != -1)
372 {
373 AuMakeElementState(s, p->flow, p->monitorElement, state);
374 s++;
375 }
376
377 p = p->next;
378 }
379
380 AuSetElementStates(globals->aud, MonitorCount, states, NULL);
381 free(states);
382 meterCB(globals->aud, NULL, NULL, globals);
383 }
384 }
385
386 #define MonitorNotifyEventMin(e, i) ((short *) &(e)->data)[i * (e)->num_fields]
387 #define MonitorNotifyEventMax(e, i) \
388 ((short *) &(e)->data)[i * (e)->num_fields + 1]
389
meterCB(AuServer * aud,AuEventHandlerRec * handler,AuEvent * ev,GlobalDataPtr globals)390 static void meterCB(AuServer *aud, AuEventHandlerRec *handler, AuEvent *ev,
391 GlobalDataPtr globals)
392 {
393 AuMonitorNotifyEvent *e = (AuMonitorNotifyEvent *) ev;
394 static int count;
395 static float left,
396 right;
397 float l;
398 Boolean meter;
399
400
401 if (!ev)
402 {
403 XawScrollbarSetThumb(globals->leftMeter, -1.0, 0);
404 XawScrollbarSetThumb(globals->rightMeter, -1.0, 0);
405 count = left = right = 0;
406 return;
407 }
408
409 XtVaGetValues(globals->meter, XtNstate, &meter, NULL);
410
411 if (!meter)
412 return;
413
414 l = (float) (MonitorNotifyEventMax(e, 0) -
415 MonitorNotifyEventMin(e, 0)) / 65535;
416
417 left += l;
418
419 if (e->num_tracks == 1)
420 right += l;
421 else
422 right += (float) (MonitorNotifyEventMax(e, 1) -
423 MonitorNotifyEventMin(e, 1)) / 65535;
424
425 count++;
426
427 if (count >= MonitorCount)
428 {
429 left /= MonitorCount;
430 right /= MonitorCount;
431
432 XawScrollbarSetThumb(globals->leftMeter, -1.0, left);
433 XawScrollbarSetThumb(globals->rightMeter, -1.0, right);
434 count = left = right = 0;
435 }
436 }
437
438 typedef struct
439 {
440 GlobalDataPtr globals;
441 void (*callback) ();
442 } DonePrivRec, *DonePrivPtr;
443
444 static void
doneCB(AuServer * aud,AuEventHandlerRec * handler,AuEvent * ev,AuPointer datap)445 doneCB(AuServer *aud, AuEventHandlerRec *handler, AuEvent *ev, AuPointer datap)
446 {
447 DonePrivPtr data = (DonePrivPtr) datap;
448
449 if (ev->type == AuEventTypeMonitorNotify)
450 meterCB(aud, handler, ev, data->globals);
451 else
452 (*data->callback) (NULL, data->globals, data);
453 }
454
455 static void
modeCB(Widget w,XtPointer globalsp,XtPointer call_data)456 modeCB(Widget w, XtPointer globalsp, XtPointer call_data)
457 {
458 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
459 Boolean mode;
460 AuDeviceAttributes a;
461
462 XtVaGetValues(globals->rec.mode, XtNstate, &mode, NULL);
463 AuDeviceValueMask(&a) = AuCompDeviceLineModeMask;
464 AuDeviceLineMode(&a) = mode ? AuDeviceLineModeHigh : AuDeviceLineModeLow;
465 AuSetDeviceAttributes(globals->aud, globals->inputDeviceId,
466 AuCompDeviceLineModeMask, &a, NULL);
467 }
468
469 static void
newBucketCB(Widget w,XtPointer globalsp,XtPointer call_data)470 newBucketCB(Widget w, XtPointer globalsp, XtPointer call_data)
471 {
472 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
473 String s;
474 unsigned int rate,
475 format;
476 Boolean readOnly;
477 AuString desc;
478 float maxDuration;
479
480 XtVaGetValues(globals->rec.rate, XtNstring, &s, NULL);
481 rate = atoi(s);
482 XtVaGetValues(globals->rec.duration, XtNstring, &s, NULL);
483 sscanf(s, "%f", &maxDuration);
484 XtVaGetValues(globals->rec.readOnly, XtNstate, &readOnly, NULL);
485 XtVaGetValues(globals->rec.dataFormatMenuButton, XtNlabel, &s, NULL);
486 format = AuStringToFormat(s);
487 XtVaGetValues(globals->rec.comment, XtNstring, &s, NULL);
488
489 desc.type = AuStringLatin1;
490 desc.len = strlen(s);
491 desc.data = s;
492
493 AuCreateBucket(globals->aud, format, 1,
494 readOnly ? AuAccessImportMask | AuAccessListMask :
495 AuAccessAllMasks, rate,
496 (AuUint32) (maxDuration * rate), &desc, NULL);
497
498 bucketQueryCB(globals->buf.query, globals, NULL);
499 }
500
501 static void
rescanCB(Widget w,XtPointer globalsp,XtPointer call_data)502 rescanCB(Widget w, XtPointer globalsp, XtPointer call_data)
503 {
504 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
505 static char *noFilesString = "No files found";
506 char *dir,
507 *template;
508 int i;
509
510 if (globals->numFiles)
511 {
512 for (i = 0; i < globals->numFiles; i++)
513 free(globals->fileNames[i]);
514
515 free(globals->fileNames);
516 }
517
518 XtVaGetValues(globals->directory, XtNstring, &dir, NULL);
519 XtVaGetValues(globals->template, XtNstring, &template, NULL);
520 globals->numFiles = getFileNames(dir, &globals->fileNames, template);
521
522 if (globals->numFiles)
523 {
524 XawListChange(globals->samples,
525 makeFileList(globals->fileNames, globals->numFiles),
526 globals->numFiles, -1, True);
527 XtSetSensitive(globals->samples, True);
528 }
529 else
530 {
531 XawListChange(globals->samples, &noFilesString, 1, -1, True);
532 XtSetSensitive(globals->samples, False);
533 }
534 }
535
536 static void
bucketPlayCB(Widget w,XtPointer globalsp,XtPointer call_data)537 bucketPlayCB(Widget w, XtPointer globalsp, XtPointer call_data)
538 {
539 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
540 static Boolean playing;
541 static AuFlowID flow;
542 static int multiplier;
543 static DonePrivRec priv;
544 static ElementListId listid;
545 XawListReturnStruct *sel;
546 BucketDialogDataPtr buf = &globals->buf;
547 Boolean meter;
548 int ind,
549 monitor = -1;
550
551 if (playing)
552 {
553 if (w)
554 /* user requested stop */
555 AuStopFlow(globals->aud, flow, NULL);
556 else
557 {
558 /* got a done callback */
559 RemoveFromElementList(globals, listid);
560 playing = False;
561 Invert(globals->buf.play);
562 }
563
564 return;
565 }
566 else if (w != globals->buf.play)
567 return;
568
569 sel = XawListShowCurrent(buf->bucketList);
570
571 if ((ind = sel->list_index) == -1)
572 return;
573
574 priv.globals = globals;
575 priv.callback = bucketPlayCB;
576
577 XtVaGetValues(globals->meter, XtNstate, &meter, NULL);
578
579 if (AuSoundPlayFromBucket(globals->aud,
580 AuBucketIdentifier(&buf->list[ind]), AuNone,
581 VOL, doneCB, &priv, 1, &flow, &multiplier,
582 meter ? &monitor : NULL, NULL))
583 {
584 listid = AddToElementList(flow, multiplier, monitor);
585 playing = True;
586 Invert(globals->buf.play);
587 }
588 }
589
590 #define COMMENT_LEN 20
591
592 static void
bucketQueryCB(Widget w,XtPointer globalsp,XtPointer call_data)593 bucketQueryCB(Widget w, XtPointer globalsp, XtPointer call_data)
594 {
595 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
596 BucketDialogDataPtr buf = &globals->buf;
597 char tmp[200],
598 access[4],
599 desc[COMMENT_LEN];
600 int i;
601 static char *noBucketString = "No buckets";
602
603 if (buf->numBuckets)
604 {
605 AuFreeBucketAttributes(globals->aud, buf->numBuckets, buf->list);
606
607 for (i = 0; i < buf->numBuckets; i++)
608 free(buf->bucketText[i]);
609
610 free(buf->bucketText);
611 }
612
613 buf->list = AuListBuckets(globals->aud, 0, NULL, &buf->numBuckets, NULL);
614
615 if (buf->numBuckets &&
616 !(buf->bucketText = (char **) malloc(sizeof(char *) * buf->numBuckets)))
617 fatalError("malloc error in bucketQueryCB", NULL);
618
619 for (i = 0; i < buf->numBuckets; i++)
620 {
621 AuBucketAttributes *p;
622 int j;
623 char format;
624
625 p = &buf->list[i];
626 *desc = 0;
627 *access = 0;
628
629 if (AuBucketValueMask(p) & AuCompCommonDescriptionMask)
630 {
631 strncpy(desc, AuBucketDescription(p)->data, COMMENT_LEN - 1);
632 desc[COMMENT_LEN - 1] = 0;
633 }
634
635 if (AuBucketAccess(p) & AuAccessImportMask)
636 strcat(access, "I");
637 if (AuBucketAccess(p) & AuAccessExportMask)
638 strcat(access, "E");
639 if (AuBucketAccess(p) & AuAccessDestroyMask)
640 strcat(access, "D");
641
642 for (j = 0, format = 'A'; j < AuServerNumFormats(globals->aud);
643 j++, format++)
644 if (AuBucketFormat(p) == AuServerFormat(globals->aud, j))
645 break;
646
647 sprintf(tmp, BUCKET_HEADER_FORMAT,
648 desc, (float) AuBucketNumSamples(p) / AuBucketSampleRate(p),
649 AuBucketNumTracks(p), AuBucketSampleRate(p), format, access);
650
651 buf->bucketText[i] = strdup(tmp);
652 }
653
654 if (buf->numBuckets)
655 {
656 XawListChange(buf->bucketList, buf->bucketText, buf->numBuckets, -1,
657 True);
658 XtSetSensitive(buf->bucketList, True);
659 }
660 else
661 {
662 XawListChange(buf->bucketList, &noBucketString, 1, -1, True);
663 XtSetSensitive(buf->bucketList, False);
664 }
665 }
666
667 static void
bucketDeleteCB(Widget w,XtPointer globalsp,XtPointer call_data)668 bucketDeleteCB(Widget w, XtPointer globalsp, XtPointer call_data)
669 {
670 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
671 XawListReturnStruct *sel;
672 BucketDialogDataPtr buf = &globals->buf;
673 int ind;
674
675 sel = XawListShowCurrent(buf->bucketList);
676
677 if ((ind = sel->list_index) == -1)
678 return;
679
680 AuDestroyBucket(globals->aud, AuBucketIdentifier(&buf->list[ind]), NULL);
681 bucketQueryCB(buf->query, globals, NULL);
682 }
683
684 static void
bucketLoadCB(Widget w,XtPointer globalsp,XtPointer call_data)685 bucketLoadCB(Widget w, XtPointer globalsp, XtPointer call_data)
686 {
687 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
688 XawListReturnStruct *sel;
689 int ind;
690
691 sel = XawListShowCurrent(globals->samples);
692
693 if ((ind = sel->list_index) == -1)
694 return;
695
696 AuSoundCreateBucketFromFile(globals->aud, globals->fileNames[ind],
697 AuAccessAllMasks, NULL, NULL);
698 bucketQueryCB(globals->buf.query, globals, NULL);
699 }
700
701 static void
bucketsCB(Widget w,XtPointer globalsp,XtPointer call_data)702 bucketsCB(Widget w, XtPointer globalsp, XtPointer call_data)
703 {
704 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
705
706 bucketQueryCB(globals->buf.query, globals, 0);
707 XtSetSensitive(w, False);
708 XtPopup(globals->buf.popShell, XtGrabNone);
709 }
710
711 static void
bucketRecordStartCB(Widget w,XtPointer globalsp,XtPointer call_data)712 bucketRecordStartCB(Widget w, XtPointer globalsp, XtPointer call_data)
713 {
714 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
715 static Boolean recording;
716 static DonePrivRec priv;
717 static AuFlowID flow;
718 Boolean mode;
719 XawListReturnStruct *sel;
720 BucketDialogDataPtr buf = &globals->buf;
721 int ind;
722
723 if (recording)
724 {
725 if (w)
726 /* user requested stop */
727 AuStopFlow(globals->aud, flow, NULL);
728 else
729 {
730 /* got a done callback */
731 recording = False;
732 Invert(globals->rec.record);
733 }
734
735 return;
736 }
737 else if (w != globals->rec.record)
738 return;
739
740 sel = XawListShowCurrent(buf->bucketList);
741
742 if ((ind = sel->list_index) == -1)
743 return;
744
745 priv.globals = globals;
746 priv.callback = bucketRecordStartCB;
747
748 XtVaGetValues(globals->rec.mode, XtNstate, &mode, NULL);
749
750 if (AuSoundRecordToBucket(globals->aud,
751 AuBucketIdentifier(&buf->list[ind]),
752 globals->inputDeviceId, GAIN, doneCB, &priv,
753 mode ? AuDeviceLineModeHigh : AuDeviceLineModeLow,
754 &flow, NULL, NULL))
755 {
756 Invert(globals->rec.record);
757 recording = True;
758 }
759 }
760
761 static void
recordStartCB(Widget w,XtPointer globalsp,XtPointer call_data)762 recordStartCB(Widget w, XtPointer globalsp, XtPointer call_data)
763 {
764 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
765 static Boolean recording;
766 static DonePrivRec priv;
767 static AuFlowID flow;
768 String s,
769 comment;
770 AuUint32 rate,
771 dataFormat,
772 fileFormat;
773 Boolean mode;
774
775 if (recording)
776 {
777 if (w)
778 /* user requested stop */
779 AuStopFlow(globals->aud, flow, NULL);
780 else
781 {
782 /* got a done callback */
783 recording = False;
784 Invert(globals->rec.record);
785 rescanCB(globals->rescan, globals, 0);
786 }
787
788 return;
789 }
790 else if (w != globals->rec.record)
791 return;
792
793 priv.globals = globals;
794 priv.callback = recordStartCB;
795
796 XtVaGetValues(globals->rec.fileFormatMenuButton, XtNlabel, &s, NULL);
797 fileFormat = SoundStringToFileFormat(s);
798
799 XtVaGetValues(globals->rec.dataFormatMenuButton, XtNlabel, &s, NULL);
800 dataFormat = AuStringToFormat(s);
801
802 XtVaGetValues(globals->rec.rate, XtNstring, &s, NULL);
803 rate = atoi(s);
804
805 XtVaGetValues(globals->rec.mode, XtNstate, &mode, NULL);
806 XtVaGetValues(globals->rec.comment, XtNstring, &comment, NULL);
807 XtVaGetValues(globals->rec.file, XtNstring, &s, NULL);
808
809 if (strlen(s) &&
810 AuSoundRecordToFile(globals->aud, s, globals->inputDeviceId, GAIN,
811 doneCB, &priv,
812 mode ? AuDeviceLineModeHigh :
813 AuDeviceLineModeLow,
814 fileFormat, comment, rate, dataFormat,
815 &flow, NULL, NULL))
816 {
817 Invert(globals->rec.record);
818 recording = True;
819 }
820 }
821
822 static void
monitorCB(Widget w,XtPointer globalsp,XtPointer call_data)823 monitorCB(Widget w, XtPointer globalsp, XtPointer call_data)
824 {
825 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
826 static Boolean monitoring;
827 static AuFlowID flow;
828 static int multiplier;
829 static DonePrivRec priv;
830 static ElementListId listid;
831 String s;
832 Boolean meter;
833 int rate,
834 monitor = -1;
835
836 if (monitoring)
837 {
838 if (w)
839 /* user requested stop */
840 AuStopFlow(globals->aud, flow, NULL);
841 else
842 {
843 /* got a done callback */
844 RemoveFromElementList(globals, listid);
845 monitoring = False;
846 Invert(globals->rec.monitor);
847 }
848
849 return;
850 }
851 else if (w != globals->rec.monitor)
852 return;
853
854 XtVaGetValues(globals->rec.rate, XtNstring, &s, NULL);
855 rate = atoi(s);
856
857 priv.globals = globals;
858 priv.callback = monitorCB;
859
860 XtVaGetValues(globals->meter, XtNstate, &meter, NULL);
861
862 if (AuMonitorDevice(globals->aud, rate, globals->inputDeviceId, AuNone, VOL,
863 doneCB, &priv, &flow, &multiplier,
864 meter ? &monitor : NULL, NULL))
865 {
866 listid = AddToElementList(flow, multiplier, monitor);
867 monitoring = True;
868 Invert(globals->rec.monitor);
869 }
870 }
871
872 static void
saveCancel(Widget w,XtPointer globalsp,XtPointer call_data)873 saveCancel(Widget w, XtPointer globalsp, XtPointer call_data)
874 {
875 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
876
877 XtPopdown(globals->save.popShell);
878 XtSetSensitive(globals->buf.save, True);
879 }
880
881 static void
saveOk(Widget w,XtPointer globalsp,XtPointer call_data)882 saveOk(Widget w, XtPointer globalsp, XtPointer call_data)
883 {
884 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
885 String s;
886 XawListReturnStruct *sel;
887 BucketDialogDataPtr buf = &globals->buf;
888 int ind,
889 fileFormat;
890
891 sel = XawListShowCurrent(buf->bucketList);
892
893 if ((ind = sel->list_index) == -1)
894 return;
895
896 XtVaGetValues(globals->save.fileFormatMenuButton, XtNlabel, &s, NULL);
897 fileFormat = SoundStringToFileFormat(s);
898
899 XtVaGetValues(globals->save.file, XtNstring, &s, NULL);
900
901 if (strlen(s) &&
902 AuSoundCreateFileFromBucket(globals->aud, s, fileFormat,
903 AuBucketIdentifier(&buf->list[ind]),
904 NULL))
905 {
906 saveCancel(w, globals, call_data);
907 rescanCB(globals->rescan, globals, 0);
908 }
909 }
910
911 static void
okAction(Widget w,XEvent * event,String * params,Cardinal * num_params)912 okAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
913 {
914 GlobalDataPtr globals;
915
916 /* retrieve the address of the globals from the first parameter */
917 globals = (GlobalDataPtr)(uintptr_t)strtoull(params[0], NULL, 0);
918 saveOk(w, globals, 0);
919 }
920
921 static void
bucketSaveCB(Widget w,XtPointer globalsp,XtPointer call_data)922 bucketSaveCB(Widget w, XtPointer globalsp, XtPointer call_data)
923 {
924 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
925 XawListReturnStruct *sel;
926
927 sel = XawListShowCurrent(globals->buf.bucketList);
928
929 if (sel->list_index == -1)
930 return;
931
932 XtSetSensitive(w, False);
933 XtPopup(globals->save.popShell, XtGrabNonexclusive);
934 }
935
936 static void
bucketDismissCB(Widget w,XtPointer globalsp,XtPointer call_data)937 bucketDismissCB(Widget w, XtPointer globalsp, XtPointer call_data)
938 {
939 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
940
941 if (globals->inputDeviceId)
942 bucketRecordDismissCB(globals->rec.dismiss, globals, NULL);
943
944 bucketPlayCB(NULL, globals, NULL);
945
946 XtPopdown(globals->buf.popShell);
947 XtSetSensitive(globals->buckets, True);
948 }
949
950 static void
recordDismissCB(Widget w,XtPointer globalsp,XtPointer call_data)951 recordDismissCB(Widget w, XtPointer globalsp, XtPointer call_data)
952 {
953 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
954
955 monitorCB(w, globals, NULL);
956 recordStartCB(w, globals, NULL);
957
958 XtPopdown(globals->rec.popShell);
959 XtSetSensitive(globals->record, True);
960 XtSetSensitive(globals->buf.record, True);
961 }
962
963 static void
bucketRecordDismissCB(Widget w,XtPointer globalsp,XtPointer call_data)964 bucketRecordDismissCB(Widget w, XtPointer globalsp, XtPointer call_data)
965 {
966 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
967
968 monitorCB(w, globals, NULL);
969 bucketRecordStartCB(w, globals, NULL);
970
971 if (globals->inputDeviceId)
972 {
973 XtPopdown(globals->rec.popShell);
974 XtSetSensitive(globals->record, True);
975 XtSetSensitive(globals->buf.record, True);
976 }
977 }
978
979 #define ReplaceCallback(w, cb) \
980 { \
981 XtRemoveAllCallbacks(w, XtNcallback); \
982 XtAddCallback(w, XtNcallback, cb, globals); \
983 }
984
985 static void
recordSensitives(GlobalDataPtr globals,Boolean state)986 recordSensitives(GlobalDataPtr globals, Boolean state)
987 {
988 XtSetSensitive(globals->rec.file, state);
989 }
990
991 static void
bucketRecordSensitives(GlobalDataPtr globals,Boolean state)992 bucketRecordSensitives(GlobalDataPtr globals, Boolean state)
993 {
994 XtSetSensitive(globals->rec.duration, state);
995 XtSetSensitive(globals->rec.readOnly, state);
996 XtSetSensitive(globals->rec.new, state);
997 }
998
999 static void
recordCB(Widget w,XtPointer globalsp,XtPointer call_data)1000 recordCB(Widget w, XtPointer globalsp, XtPointer call_data)
1001 {
1002 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1003
1004 ReplaceCallback(globals->rec.record, recordStartCB);
1005 ReplaceCallback(globals->rec.dismiss, recordDismissCB);
1006
1007 recordSensitives(globals, True);
1008 bucketRecordSensitives(globals, False);
1009 XtSetSensitive(globals->buf.record, False);
1010
1011 queryInputAttributes(globals);
1012
1013 XtSetSensitive(w, False);
1014 XtPopup(globals->rec.popShell, XtGrabNone);
1015 }
1016
1017 static void
bucketRecordCB(Widget w,XtPointer globalsp,XtPointer call_data)1018 bucketRecordCB(Widget w, XtPointer globalsp, XtPointer call_data)
1019 {
1020 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1021
1022 ReplaceCallback(globals->rec.record, bucketRecordStartCB);
1023 ReplaceCallback(globals->rec.dismiss, bucketRecordDismissCB);
1024
1025 recordSensitives(globals, False);
1026 bucketRecordSensitives(globals, True);
1027 XtSetSensitive(globals->record, False);
1028
1029 queryInputAttributes(globals);
1030
1031 XtSetSensitive(w, False);
1032 XtPopup(globals->rec.popShell, XtGrabNone);
1033 }
1034
1035 static void
playCB(Widget w,XtPointer globalsp,XtPointer datap)1036 playCB(Widget w, XtPointer globalsp, XtPointer datap)
1037 {
1038 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1039 static Boolean playing;
1040 static AuFlowID flow;
1041 static int multiplier;
1042 static DonePrivRec priv;
1043 static ElementListId listid;
1044 XawListReturnStruct *sel;
1045 Boolean meter;
1046 int ind,
1047 monitor = -1;
1048
1049 if (playing)
1050 {
1051 if (w)
1052 /* user requested stop */
1053 AuStopFlow(globals->aud, flow, NULL);
1054 else
1055 {
1056 /* got a done callback */
1057 RemoveFromElementList(globals, listid);
1058 playing = False;
1059 Invert(globals->play);
1060 }
1061
1062 return;
1063 }
1064
1065 sel = XawListShowCurrent(globals->samples);
1066
1067 if ((ind = sel->list_index) == -1)
1068 return;
1069
1070 priv.globals = globals;
1071 priv.callback = playCB;
1072
1073 XtVaGetValues(globals->meter, XtNstate, &meter, NULL);
1074
1075 if (AuSoundPlayFromFile(globals->aud, globals->fileNames[ind], AuNone,
1076 VOL, doneCB, &priv, &flow, &multiplier,
1077 meter ? &monitor : NULL, NULL))
1078 {
1079 listid = AddToElementList(flow, multiplier, monitor);
1080 playing = True;
1081 Invert(globals->play);
1082 }
1083 }
1084
1085 static void
bucketListCB(Widget w,XtPointer globalsp,XtPointer listInfop)1086 bucketListCB(Widget w, XtPointer globalsp, XtPointer listInfop)
1087 {
1088 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1089 XawListReturnStruct *listInfo = (XawListReturnStruct *) listInfop;
1090 struct timeval tp;
1091 AuUint32 currentTime;
1092 static AuInt32 lastTime;
1093 static int lastSelection;
1094
1095 gettimeofday(&tp, NULL);
1096 currentTime = tp.tv_sec * 1000000 + tp.tv_usec;
1097
1098 if (listInfo->list_index == lastSelection &&
1099 currentTime - lastTime < DOUBLE_CLICK_TIME)
1100 bucketPlayCB(globals->buf.play, globals, NULL);
1101
1102 lastTime = currentTime;
1103 lastSelection = listInfo->list_index;
1104 }
1105
1106 static void
samplesCB(Widget w,XtPointer globalsp,XtPointer listInfop)1107 samplesCB(Widget w, XtPointer globalsp, XtPointer listInfop)
1108 {
1109 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1110 XawListReturnStruct *listInfo = (XawListReturnStruct *) listInfop;
1111 struct timeval tp;
1112 AuInt32 currentTime;
1113 static AuInt32 lastTime;
1114 static int lastSelection = -1;
1115
1116 gettimeofday(&tp, NULL);
1117 currentTime = tp.tv_sec * 1000000 + tp.tv_usec;
1118
1119 if (listInfo->list_index == lastSelection &&
1120 currentTime - lastTime < DOUBLE_CLICK_TIME)
1121 playCB(globals->play, globals, (XtPointer) 0);
1122 else if (lastSelection != listInfo->list_index)
1123 {
1124 Sound s;
1125
1126 lastSelection = listInfo->list_index;
1127
1128 if ((s = SoundOpenFileForReading(globals->fileNames[lastSelection])))
1129 {
1130 char *buf,
1131 *p;
1132
1133 #define PRINT(p, f, a) \
1134 { \
1135 sprintf(p, f, a); \
1136 p += strlen(p); \
1137 }
1138
1139 if (!(p = buf = (char *) malloc(2000 + strlen(SoundComment(s)))))
1140 fatalError("Can't malloc text in samplesCB", NULL);
1141
1142 PRINT(p, " Filename: %s\n", globals->fileNames[lastSelection]);
1143 PRINT(p, "File Format: %s\n", SoundFileFormatString(s));
1144 PRINT(p, "Data Format: %s\n", SoundDataFormatString(s));
1145 PRINT(p, " Tracks: %d\n", SoundNumTracks(s));
1146 PRINT(p, " Frequency: %d Hz\n", SoundSampleRate(s));
1147 PRINT(p, " Duration: %.2f seconds\n",
1148 (float) SoundNumSamples(s) / SoundSampleRate(s));
1149
1150 PRINT(p, "\n%s", SoundComment(s));
1151
1152 XtVaSetValues(globals->info, XtNstring, buf, NULL);
1153
1154 free(buf);
1155 SoundCloseFile(s);
1156 }
1157 }
1158
1159 gettimeofday(&tp, NULL);
1160 lastTime = tp.tv_sec * 1000000 + tp.tv_usec;
1161 }
1162
1163 static void
quitCB(Widget w,XtPointer globalsp,XtPointer call_data)1164 quitCB(Widget w, XtPointer globalsp, XtPointer call_data)
1165 {
1166 exit(0);
1167 }
1168
1169 static void
adjustVolume(GlobalDataPtr globals)1170 adjustVolume(GlobalDataPtr globals)
1171 {
1172 AuElementParameters *parms;
1173 ElementListPtr p = ElementList;
1174 int i = 0;
1175
1176 if (!ElementCount)
1177 return;
1178
1179 if (!(parms = (AuElementParameters *)
1180 malloc(sizeof(AuElementParameters) * ElementCount)))
1181 fatalError("malloc error in adjustVolume", NULL);
1182
1183 while (p)
1184 {
1185 parms[i].flow = p->flow;
1186 parms[i].element_num = p->volumeElement;
1187 parms[i].num_parameters = AuParmsMultiplyConstant;
1188 parms[i].parameters[AuParmsMultiplyConstantConstant] = VOL;
1189
1190 p = p->next;
1191 i++;
1192 }
1193
1194 AuSetElementParameters(globals->aud, ElementCount, parms, NULL);
1195 free(parms);
1196 }
1197
1198 static void
scrollProcCB(Widget w,XtPointer globalsp,XtPointer positionp)1199 scrollProcCB(Widget w, XtPointer globalsp, XtPointer positionp)
1200 {
1201 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1202 intptr_t position = (intptr_t) positionp;
1203 int newVolume;
1204 char buf[50];
1205
1206 newVolume = globals->volume + (position > 0 ? -1 : 1);
1207
1208 if (newVolume < MIN_VOLUME)
1209 newVolume = MIN_VOLUME;
1210 else if (newVolume > MAX_VOLUME)
1211 newVolume = MAX_VOLUME;
1212
1213 if (newVolume != globals->volume)
1214 {
1215 globals->volume = newVolume;
1216 sprintf(buf, VOLUME_FORMAT, globals->volume);
1217 XtVaSetValues(globals->volumeLabel, XtNlabel, buf, NULL);
1218
1219 XawScrollbarSetThumb(globals->volumeBar,
1220 (float) globals->volume / MAX_VOLUME, -1.0);
1221 adjustVolume(globals);
1222 }
1223 }
1224
1225 static void
jumpProcCB(Widget w,XtPointer globalsp,XtPointer percentp)1226 jumpProcCB(Widget w, XtPointer globalsp, XtPointer percentp)
1227 {
1228 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1229 float *percent = (float *) percentp;
1230 int newVolume;
1231 char buf[50];
1232
1233 newVolume = *percent * MAX_VOLUME;
1234
1235 if (newVolume < MIN_VOLUME)
1236 newVolume = MIN_VOLUME;
1237
1238 if (newVolume != globals->volume)
1239 {
1240 globals->volume = newVolume;
1241 sprintf(buf, VOLUME_FORMAT, globals->volume);
1242 XtVaSetValues(globals->volumeLabel, XtNlabel, buf, NULL);
1243 adjustVolume(globals);
1244 }
1245 }
1246
1247 static void
adjustGain(GlobalDataPtr globals)1248 adjustGain(GlobalDataPtr globals)
1249 {
1250 AuDeviceAttributes a;
1251
1252 AuDeviceValueMask(&a) = AuCompDeviceGainMask;
1253 AuDeviceGain(&a) = GAIN;
1254 AuSetDeviceAttributes(globals->aud, globals->inputDeviceId,
1255 AuCompDeviceGainMask, &a, NULL);
1256 }
1257
1258 static void
gainScrollCB(Widget w,XtPointer globalsp,XtPointer positionp)1259 gainScrollCB(Widget w, XtPointer globalsp, XtPointer positionp)
1260 {
1261 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1262 intptr_t position = (intptr_t) positionp;
1263 int newGain;
1264 char buf[50];
1265
1266 newGain = globals->rec.gain + (position > 0 ? -1 : 1);
1267
1268 if (newGain < MIN_GAIN)
1269 newGain = MIN_GAIN;
1270 else if (newGain > MAX_GAIN)
1271 newGain = MAX_GAIN;
1272
1273 if (newGain != globals->rec.gain)
1274 {
1275 globals->rec.gain = newGain;
1276 sprintf(buf, GAIN_FORMAT, globals->rec.gain);
1277 XtVaSetValues(globals->rec.gainLabel, XtNlabel, buf, NULL);
1278
1279 XawScrollbarSetThumb(globals->rec.gainBar,
1280 (float) globals->rec.gain / MAX_GAIN, -1.0);
1281 adjustGain(globals);
1282 }
1283 }
1284
1285 static void
gainJumpCB(Widget w,XtPointer globalsp,XtPointer percentp)1286 gainJumpCB(Widget w, XtPointer globalsp, XtPointer percentp)
1287 {
1288 GlobalDataPtr globals = (GlobalDataPtr) globalsp;
1289 float *percent = (float *) percentp;
1290 int newGain;
1291 char buf[50];
1292
1293 newGain = *percent * MAX_GAIN;
1294
1295 if (newGain < MIN_GAIN)
1296 newGain = MIN_GAIN;
1297
1298 if (newGain != globals->rec.gain)
1299 {
1300 globals->rec.gain = newGain;
1301 sprintf(buf, GAIN_FORMAT, globals->rec.gain);
1302 XtVaSetValues(globals->rec.gainLabel, XtNlabel, buf, NULL);
1303 adjustGain(globals);
1304 }
1305 }
1306
1307 static void
setFileFormatMenuButton(Widget w,XtPointer globalsp,XtPointer call_data)1308 setFileFormatMenuButton(Widget w, XtPointer globalsp, XtPointer call_data)
1309 {
1310 GlobalDataPtr g = (GlobalDataPtr) globalsp;
1311 String string;
1312
1313 XtVaGetValues(w, XtNlabel, &string, NULL);
1314 XtVaSetValues(g->save.fileFormatMenuButton, XtNlabel, string, NULL);
1315
1316 if (g->inputDeviceId)
1317 XtVaSetValues(g->rec.fileFormatMenuButton, XtNlabel, string, NULL);
1318 }
1319
1320 static void
setDataFormatMenuButton(Widget w,XtPointer globalsp,XtPointer call_data)1321 setDataFormatMenuButton(Widget w, XtPointer globalsp, XtPointer call_data)
1322 {
1323 GlobalDataPtr g = (GlobalDataPtr) globalsp;
1324 String string;
1325
1326 XtVaGetValues(w, XtNlabel, &string, NULL);
1327 XtVaSetValues(g->rec.dataFormatMenuButton, XtNlabel, string, NULL);
1328 }
1329
1330 static void
makeSaveDialog(GlobalDataPtr g)1331 makeSaveDialog(GlobalDataPtr g)
1332 {
1333 SaveDialogDataPtr s = &g->save;
1334 Widget w;
1335 char tmp[50];
1336
1337 MakePopup(s->popShell, g->topLevel, transientShellWidgetClass,
1338 "savePop");
1339 MakeWidget(s->form, s->popShell, formWidgetClass, NULL, "saveWin");
1340
1341 /* filename */
1342 MakeLabel(w, s->form, "filenameLabel");
1343 MakeWidget(s->file, s->form, asciiTextWidgetClass, NULL, "filename");
1344
1345 /* pass the address of the globals as an argument to the action */
1346 sprintf(tmp, "<Key>Return: ok(%p)", g);
1347 XtOverrideTranslations(s->file, XtParseTranslationTable(tmp));
1348
1349 /* file format */
1350 MakeLabel(w, s->form, "fileFormatLabel");
1351 MakeWidget(s->fileFormatMenuButton, s->form, menuButtonWidgetClass, NULL,
1352 "fileFormatMenuButton");
1353 XtVaSetValues(s->fileFormatMenuButton, XtNlabel, SoundFileFormatToString(0),
1354 NULL);
1355
1356 MakeButton(w, s->form, saveOk, "ok");
1357 MakeButton(w, s->form, saveCancel, "cancel");
1358 }
1359
1360 static void
makeBucketDialog(GlobalDataPtr g)1361 makeBucketDialog(GlobalDataPtr g)
1362 {
1363 Widget w;
1364 int i;
1365 BucketDialogDataPtr b = &g->buf;
1366 char tmp[100];
1367
1368 makeSaveDialog(g);
1369
1370 b->numBuckets = 0;
1371 MakePopup(b->popShell, g->topLevel, transientShellWidgetClass,
1372 "bucketPop");
1373 MakeWidget(b->form, b->popShell, formWidgetClass, NULL, "bucketWin");
1374
1375 /* command buttons */
1376 MakeButton(b->query, b->form, bucketQueryCB, "query");
1377 MakeButton(b->play, b->form, bucketPlayCB, "play");
1378 MakeButton(b->record, b->form, bucketRecordCB, "record");
1379 MakeButton(b->load, b->form, bucketLoadCB, "load");
1380 MakeButton(b->save, b->form, bucketSaveCB, "save");
1381 MakeButton(b->delete, b->form, bucketDeleteCB, "delete");
1382 MakeButton(b->dismiss, b->form, bucketDismissCB, "dismiss");
1383
1384 /* format menu */
1385 MakePopup(b->formatMenu, b->form, simpleMenuWidgetClass, "formatMenu");
1386 for (i = 0; i < AuServerNumFormats(g->aud); i++)
1387 {
1388 sprintf(tmp, "%c - %s", 'A' + i,
1389 AuFormatToString(AuServerFormat(g->aud, i)));
1390 MakeMenuItem(b->formatMenu, tmp);
1391 }
1392 MakeWidget(b->formatMenuButton, b->form, menuButtonWidgetClass, NULL,
1393 "format");
1394
1395 /* access menu */
1396 MakePopup(b->accessMenu, b->form, simpleMenuWidgetClass, "accessMenu");
1397 MakeMenuItem(b->accessMenu, "I - Importable");
1398 MakeMenuItem(b->accessMenu, "E - Exportable");
1399 MakeMenuItem(b->accessMenu, "D - Destroyable");
1400 MakeWidget(b->accessMenuButton, b->form, menuButtonWidgetClass, NULL,
1401 "access");
1402
1403 MakeLabel(w, b->form, "header");
1404 MakeWidget(b->viewport, b->form, viewportWidgetClass, NULL, "viewport");
1405
1406 MakeWidget(b->bucketList, b->viewport, listWidgetClass, bucketListCB,
1407 "list");
1408 }
1409
1410 static void
makeRecordDialog(GlobalDataPtr g)1411 makeRecordDialog(GlobalDataPtr g)
1412 {
1413 Widget w;
1414 RecordDialogDataPtr r = &g->rec;
1415
1416 MakePopup(r->popShell, g->topLevel, transientShellWidgetClass, "recordPop");
1417 MakeWidget(r->form, r->popShell, formWidgetClass, NULL, "recordWin");
1418
1419 /* filename */
1420 MakeLabel(w, r->form, "filenameLabel");
1421 MakeWidget(r->file, r->form, asciiTextWidgetClass, NULL, "filename");
1422
1423 /* file format */
1424 MakeLabel(w, r->form, "fileFormatLabel");
1425 MakeWidget(r->fileFormatMenuButton, r->form, menuButtonWidgetClass, NULL,
1426 "fileFormatMenuButton");
1427 XtVaSetValues(r->fileFormatMenuButton, XtNlabel, SoundFileFormatToString(0),
1428 NULL);
1429
1430 /* data format */
1431 MakeLabel(w, r->form, "dataFormatLabel");
1432 MakeWidget(r->dataFormatMenuButton, r->form, menuButtonWidgetClass, NULL,
1433 "dataFormatMenuButton");
1434 XtVaSetValues(r->dataFormatMenuButton, XtNlabel,
1435 AuFormatToString(AuServerFormat(g->aud, 0)), NULL);
1436
1437 /* max duration */
1438 MakeLabel(w, r->form, "durationLabel");
1439 MakeWidget(r->duration, r->form, asciiTextWidgetClass, NULL, "duration");
1440
1441 /* read only toggle */
1442 MakeWidget(r->readOnly, r->form, toggleWidgetClass, NULL, "readOnly");
1443
1444 /* frequency */
1445 MakeLabel(w, r->form, "frequencyLabel");
1446 MakeWidget(r->rate, r->form, asciiTextWidgetClass, NULL, "frequency");
1447
1448 /* mode toggle */
1449 MakeWidget(r->mode, r->form, toggleWidgetClass, modeCB, "lineMode");
1450
1451 /* comment */
1452 MakeLabel(w, r->form, "commentLabel");
1453 MakeWidget(r->comment, r->form, asciiTextWidgetClass, NULL, "comment");
1454
1455 /* gain */
1456 MakeLabel(r->gainLabel, r->form, "gainLabel");
1457 MakeWidget(r->gainBar, r->form, scrollbarWidgetClass, NULL, "gain");
1458 XtAddCallback(r->gainBar, XtNscrollProc, gainScrollCB, g);
1459 XtAddCallback(r->gainBar, XtNjumpProc, gainJumpCB, g);
1460
1461 /* command buttons */
1462 MakeButton(r->record, r->form, recordStartCB, "record");
1463 MakeButton(r->monitor, r->form, monitorCB, "monitor");
1464 MakeButton(r->new, r->form, newBucketCB, "new");
1465 MakeButton(r->dismiss, r->form, NULL, "dismiss");
1466 }
1467
1468 static void
createWidgets(GlobalDataPtr g,char * dir)1469 createWidgets(GlobalDataPtr g, char *dir)
1470 {
1471 Widget w,
1472 ww;
1473 int i;
1474 char buf[20];
1475
1476 MakeWidget(g->form, g->topLevel, formWidgetClass, NULL, "mainWin");
1477
1478 /* command buttons */
1479 MakeButton(g->play, g->form, playCB, "play");
1480 MakeButton(g->record, g->form, recordCB, "record");
1481 MakeButton(g->buckets, g->form, bucketsCB, "buckets");
1482 MakeWidget(g->meter, g->form, toggleWidgetClass, meterToggleCB,
1483 "meterToggle");
1484 MakeButton(g->rescan, g->form, rescanCB, "rescan");
1485 MakeButton(g->quit, g->form, quitCB, "quit");
1486
1487 /* version label */
1488 MakeLabel(w, g->form, "version");
1489 sprintf(buf, "NAS %d.%d", AuServerProtocolMajorVersion(g->aud),
1490 AuServerProtocolMinorVersion(g->aud));
1491 XtVaSetValues(w, XtNlabel, buf, NULL);
1492
1493 /* left meter */
1494 MakeLabel(w, g->form, "leftMeterLabel");
1495 MakeWidget(g->leftMeter, g->form, scrollbarWidgetClass, NULL, "leftMeter");
1496
1497 /* right meter */
1498 MakeLabel(w, g->form, "rightMeterLabel");
1499 MakeWidget(g->rightMeter, g->form, scrollbarWidgetClass, NULL,
1500 "rightMeter");
1501
1502 /* volume label */
1503 MakeLabel(g->volumeLabel, g->form, "volumeLabel");
1504 sprintf(buf, VOLUME_FORMAT, g->volume);
1505 XtVaSetValues(g->volumeLabel, XtNlabel, buf, NULL);
1506
1507 /* volume slider */
1508 MakeWidget(g->volumeBar, g->form, scrollbarWidgetClass, NULL, "volume");
1509 XawScrollbarSetThumb(g->volumeBar,
1510 ((float) DEFAULT_VOLUME) / MAX_VOLUME, -1.0);
1511 XtAddCallback(g->volumeBar, XtNscrollProc, scrollProcCB, g);
1512 XtAddCallback(g->volumeBar, XtNjumpProc, jumpProcCB, g);
1513
1514 /* info window */
1515 MakeWidget(g->info, g->form, asciiTextWidgetClass, NULL, "info");
1516
1517 /* directory */
1518 MakeLabel(w, g->form, "directoryLabel");
1519 MakeWidget(g->directory, g->form, asciiTextWidgetClass, NULL, "directory");
1520 XtVaSetValues(g->directory, XtNstring, dir, NULL);
1521
1522 /* template */
1523 MakeLabel(w, g->form, "templateLabel");
1524 MakeWidget(g->template, g->form, asciiTextWidgetClass, NULL, "template");
1525
1526 /* samples window */
1527 MakeWidget(g->viewport, g->form, viewportWidgetClass, NULL, "viewport");
1528 MakeWidget(g->samples, g->viewport, listWidgetClass, samplesCB, "list");
1529
1530 /* file format menu */
1531 MakePopup(w, g->topLevel, simpleMenuWidgetClass, "fileFormatMenu");
1532
1533 for (i = 0; i < SoundNumFileFormats; i++)
1534 MakeWidget(ww, w, smeBSBObjectClass, setFileFormatMenuButton,
1535 SoundFileFormatToString(i));
1536
1537 /* data format menu */
1538 MakePopup(w, g->topLevel, simpleMenuWidgetClass, "dataFormatMenu");
1539
1540 for (i = 0; i < AuServerNumFormats(g->aud); i++)
1541 MakeWidget(ww, w, smeBSBObjectClass, setDataFormatMenuButton,
1542 AuFormatToString(AuServerFormat(g->aud, i)));
1543
1544 makeBucketDialog(g);
1545
1546 if (g->inputDeviceId)
1547 {
1548 makeRecordDialog(g);
1549
1550 if (!(AuDeviceChangableMask(AuServerDevice(g->aud, g->inputDeviceNum)) &
1551 AuCompDeviceLineModeMask))
1552 XtVaSetValues(g->rec.mode, XtNsensitive, False, NULL);
1553 }
1554 else
1555 {
1556 g->rec.popShell = (Widget) 0;
1557 XtVaSetValues(g->record, XtNsensitive, False, NULL);
1558 XtVaSetValues(g->buf.record, XtNsensitive, False, NULL);
1559 }
1560
1561 }
1562
1563 #define SET_WIDTH(_w) \
1564 { \
1565 XtVaGetValues(_w, XtNx, &x, NULL); \
1566 XtVaSetValues(_w, XtNwidth, maxX - x, NULL); \
1567 }
1568
1569 static void
alignWidgets(GlobalDataPtr g)1570 alignWidgets(GlobalDataPtr g)
1571 {
1572 Position maxX,
1573 x;
1574 Dimension width;
1575 BucketDialogDataPtr b = &g->buf;
1576 RecordDialogDataPtr r = &g->rec;
1577 SaveDialogDataPtr s = &g->save;
1578
1579 /* main window */
1580 XtRealizeWidget(g->topLevel);
1581 XtVaGetValues(XtNameToWidget(g->form, "version"),
1582 XtNx, &x, XtNwidth, &width, NULL);
1583 maxX = x + width - 2; /* the -2 is a hack since
1584 * "version" has no border */
1585
1586 SET_WIDTH(g->leftMeter);
1587 SET_WIDTH(g->rightMeter);
1588 SET_WIDTH(g->volumeBar);
1589 SET_WIDTH(g->info);
1590 SET_WIDTH(g->directory);
1591 SET_WIDTH(g->template);
1592 SET_WIDTH(g->viewport);
1593
1594 /* buckets window */
1595 XtRealizeWidget(b->popShell);
1596 XtVaGetValues(b->accessMenuButton, XtNx, &x, XtNwidth, &width, NULL);
1597 maxX = x + width;
1598
1599 SET_WIDTH(b->viewport);
1600
1601 if (r->popShell)
1602 {
1603 /* record window */
1604 XtRealizeWidget(r->popShell);
1605 XtVaGetValues(r->readOnly, XtNx, &x, XtNwidth, &width, NULL);
1606 maxX = x + width;
1607
1608 SET_WIDTH(r->file);
1609 SET_WIDTH(r->comment);
1610 SET_WIDTH(r->fileFormatMenuButton);
1611 SET_WIDTH(r->dataFormatMenuButton);
1612 SET_WIDTH(r->gainBar);
1613
1614 XtVaSetValues(r->fileFormatMenuButton, XtNresizable, False, NULL);
1615 XtVaSetValues(r->dataFormatMenuButton, XtNresizable, False, NULL);
1616 }
1617
1618 XtRealizeWidget(s->popShell);
1619 XtVaGetValues(s->file, XtNx, &x, XtNwidth, &width, NULL);
1620 maxX = x + width;
1621 SET_WIDTH(s->fileFormatMenuButton);
1622 XtVaSetValues(s->fileFormatMenuButton, XtNresizable, False, NULL);
1623
1624 XtVaSetValues(g->viewport, XtNresizable, False, NULL);
1625 XtVaSetValues(b->viewport, XtNresizable, False, NULL);
1626 }
1627
1628 int
main(int argc,char ** argv)1629 main(int argc, char **argv)
1630 {
1631 int i,
1632 endian = 1;
1633 char *audioServerString = NULL,
1634 *dir = NULL;
1635 GlobalDataRec globalData,
1636 *globals;
1637 XtAppContext appContext;
1638 extern int AuMonitorFormat;
1639 static XtActionsRec Actions[] = {{"ok", okAction}};
1640
1641 globals = &globalData;
1642
1643 globals->topLevel = XtVaAppInitialize(&appContext, APP_CLASS, NULL, ZERO,
1644 &argc, argv, defaultResources,
1645 NULL, NULL);
1646
1647 globals->volume = DEFAULT_VOLUME;
1648 globals->numFiles = 0;
1649 globals->dpy = XtDisplay(globals->topLevel);
1650
1651 while (argc > 1)
1652 {
1653 argv++;
1654 argc--;
1655
1656 if (!strcmp("-a", *argv) || !strcmp("-audio", *argv))
1657 {
1658 audioServerString = argv[1];
1659 argv++;
1660 argc--;
1661 if (!argc)
1662 {
1663 printf("usage: audemo [ -toolkitoption ...] [-audio AUDIOSERVER] [directory]\n");
1664 exit(1);
1665 }
1666 }
1667 else
1668 dir = *argv;
1669 }
1670
1671 if (!dir)
1672 dir = (char *) getcwd(NULL, 256);
1673
1674 if (!(globals->aud =
1675 AuOpenServer(audioServerString, 0, NULL, 0, NULL, NULL)))
1676 fatalError("Can't connect to audio server", NULL);
1677
1678 globals->inputDeviceId = (AuDeviceID) 0;
1679
1680 for (i = 0; i < AuServerNumDevices(globals->aud); i++)
1681 if ((AuDeviceKind(AuServerDevice(globals->aud, i)) ==
1682 AuComponentKindPhysicalInput))
1683 {
1684 globals->inputDeviceId =
1685 AuDeviceIdentifier(AuServerDevice(globals->aud, i));
1686 globals->inputDeviceNum = i;
1687 break;
1688 }
1689
1690 XtAppAddActions(appContext, Actions, XtNumber(Actions));
1691
1692 createWidgets(globals, dir);
1693 rescanCB(NULL, globals, NULL);
1694 alignWidgets(globals);
1695
1696 AuMonitorFormat = *(char *) &endian ? AuFormatLinearSigned16LSB :
1697 AuFormatLinearSigned16MSB;
1698
1699 AuXtAppAddAudioHandler(appContext, globals->aud);
1700 XtAppMainLoop(appContext);
1701 return 0;
1702 }
1703
1704 #endif /* XT */
1705
1706 static void
fatalError(const char * message,const char * arg)1707 fatalError(const char *message, const char *arg)
1708 {
1709 fprintf(stderr, message, arg);
1710 fprintf(stderr, "\n");
1711 exit(1);
1712 }
1713
1714 static int
sortRoutine(const void * ap,const void * bp)1715 sortRoutine(const void *ap, const void *bp)
1716 {
1717 const char **a = (const char **)ap;
1718 const char **b = (const char **)bp;
1719
1720 return strcmp(strrchr(*a, '/') + 1, strrchr(*b, '/') + 1);
1721 }
1722
1723 static char **
makeFileList(char ** fileNames,int nfiles)1724 makeFileList(char **fileNames, int nfiles)
1725 {
1726 char **fileList,
1727 *p;
1728 int i;
1729
1730 qsort(fileNames, nfiles, sizeof(char *), sortRoutine);
1731
1732 if (!(fileList = (char **) malloc(sizeof(char *) * nfiles)))
1733 fatalError("Can't malloc file list in makeFileList", NULL);
1734
1735 for (i = 0; i < nfiles; i++)
1736 {
1737 if (p = strrchr(fileNames[i], '/'))
1738 p++;
1739 else
1740 p = fileNames[i];
1741
1742 fileList[i] = (char *) strdup(p);
1743
1744 if ((p = strrchr(fileList[i], '.')))
1745 *p = 0;
1746
1747 fileList[i] = (char *) realloc(fileList[i], strlen(fileList[i]) + 1);
1748
1749 if (!fileList[i])
1750 fatalError("Can't realloc file list in makeFileList", NULL);
1751 }
1752
1753 return fileList;
1754 }
1755
1756 #ifndef WIN32
1757 static FILE *
startFind(char * dir,char * template)1758 startFind(char *dir, char *template)
1759 {
1760 char *cmd,
1761 *p;
1762 FILE *fp;
1763 int first = 1;
1764
1765 cmd = (char *) malloc(2000);
1766
1767 sprintf(cmd, "find %s -type f -a \\( ", dir);
1768
1769 p = strtok(template, " ");
1770
1771 while (p)
1772 {
1773 if (!first)
1774 strcat(cmd, " -o -name '");
1775 else
1776 {
1777 strcat(cmd, " -name '");
1778 first = 0;
1779 }
1780
1781 strcat(cmd, p);
1782 strcat(cmd, "'");
1783
1784 p = strtok(NULL, " ");
1785 }
1786
1787 strcat(cmd, " \\) -print");
1788
1789 fp = popen(cmd, "r");
1790 free(cmd);
1791 return fp;
1792 }
1793 #endif /* !WIN32 */
1794
1795 static int
getFileNames(char * dir,char *** fileNames,char * template)1796 getFileNames(char *dir, char ***fileNames, char *template)
1797 {
1798 #ifndef WIN32
1799 int files;
1800 FILE *fp;
1801 char line[BUF_SIZE];
1802
1803 /* prime the realloc pump */
1804 *fileNames = (char **) malloc(1);
1805
1806 if (!fileNames)
1807 fatalError("Can't malloc file names in getFileNames", NULL);
1808
1809 if (!(fp = startFind(dir, template)))
1810 {
1811 free(*fileNames);
1812 return 0;
1813 }
1814
1815 files = 0;
1816
1817 while (fgets(line, BUF_SIZE, fp))
1818 {
1819 *fileNames =
1820 (char **) realloc(*fileNames, sizeof(char *) * (files + 1));
1821
1822 if (!*fileNames)
1823 fatalError("Can't realloc file names in getFileNames", NULL);
1824
1825 line[strlen(line) - 1] = 0; /* zap the trailing newline */
1826 (*fileNames)[files++] = (char *) strdup(line);
1827 }
1828
1829 pclose(fp);
1830
1831 if (!files)
1832 free(*fileNames);
1833
1834 return files;
1835 #else /* WIN32 */
1836 WIN32_FIND_DATA fileInfo;
1837 char *d;
1838 int files = 0;
1839 HANDLE h;
1840
1841 *fileNames = NULL;
1842 if (!(d = (char *) malloc(strlen(dir) + 5)))
1843 return 0;
1844
1845 strcpy(d, dir);
1846 strcat(d, "/*.*");
1847 h = FindFirstFile(d, &fileInfo);
1848 free(d);
1849
1850 if (!h)
1851 return 0;
1852
1853 do
1854 {
1855 if (!(fileInfo.dwFileAttributes &
1856 (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM)))
1857 {
1858 char *p = NULL;
1859
1860 if (p = (char *) malloc(strlen(dir) + strlen(fileInfo.cFileName) +
1861 2))
1862 {
1863 *fileNames = (char **) realloc(*fileNames, sizeof(char *) *
1864 (files + 1));
1865 strcpy(p, dir);
1866 strcat(p, "/");
1867 strcat(p, fileInfo.cFileName);
1868
1869 (*fileNames)[files++] = p;
1870 }
1871 }
1872 } while(FindNextFile(h, &fileInfo));
1873
1874 FindClose(h);
1875 return files;
1876 #endif /* WIN32 */
1877 }
1878
1879 #ifdef WIN32
1880 #include <sys/timeb.h>
1881
1882 int
gettimeofday(struct timeval * tv,void * dummy)1883 gettimeofday(struct timeval *tv, void *dummy)
1884 {
1885 struct _timeb tm;
1886 _ftime(&tm);
1887 tv->tv_sec = tm.time;
1888 tv->tv_usec = tm.millitm;
1889 return 0;
1890 }
1891 #endif /* WIN32 */
1892