1 /*-
2 * Copyright (c) 1999 Thomas Runge (coto@core.de)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <paths.h>
38 #include <X11/X.h>
39 #include <X11/Xlib.h>
40 #include <X11/Intrinsic.h>
41 #include <Xm/XmAll.h>
42
43 #ifdef __NetBSD__
44 #include <soundcard.h>
45 #else
46 #if defined(linux) || defined(__FreeBSD__)
47 #include <sys/soundcard.h>
48 #else
49 #include <machine/soundcard.h>
50 #endif
51 #endif
52
53 #include "sample.h"
54 #include "misc.h"
55 #include "radio.h"
56 #include "analyzer.h"
57
58 #if (XmVERSION < 2)
59 enum { XmUNSET, XmSET, XmINDETERMINATE };
60 #endif
61
62 Widget sample_dialogW, sampleFormW, filename_textW;
63 Widget format_optionW, capture_optionW, stereo_optionW, rate_optionW;
64 Widget overwriteW, recordB, stopB, playbackB, dismissB, searchB;
65 extern Widget analyzerW;
66
67 static int dsp;
68 static int sampling;
69 static int playing;
70 static int resetmixer;
71 static int old_recsrc;
72 static int is_popped;
73
74 static char gbuf[BUFSIZ];
75
76 extern char *DSP_DEVICE;
77 extern XtAppContext app_con;
78 extern int mixer;
79 extern int debug;
80
81 #define DEF_FILENAME "capture.audiofile"
82 /* CYCLETIME in seconds */
83 #define CYCLETIME 0.25
84
85 void CheckSampleFormat();
86 int CheckForProgram(const char *name);
87 void ResetMixer();
88 int PrepareDSP(int flags);
89
90 typedef struct
91 {
92 char *name;
93 int id;
94 } option_menu;
95
96 typedef struct
97 {
98 char *filename;
99 int file_format;
100 int capture_format;
101 int bps;
102 int stereo;
103 int speed;
104 int sign;
105 int ask_overwrite;
106 } sample_format;
107 static sample_format sformat;
108
109 enum { RAW_FORMAT=1, AU_FORMAT, WAV_FORMAT, VOC_FORMAT, AIFF_FORMAT,
110 MP3_FORMAT };
111
112 enum { SAMP8012=8012, SAMP11025=11025, SAMP22050=22050, SAMP44100=44100 };
113
114 static option_menu format_options[] =
115 {
116 { "raw_format", RAW_FORMAT },
117 { "au_format", AU_FORMAT },
118 { "wav_format", WAV_FORMAT },
119 { "voc_format", VOC_FORMAT },
120 { "aiff_format", AIFF_FORMAT },
121 { "mp3_format", MP3_FORMAT }
122 };
123
124 /* if you add new formats, add them in CheckBPS() and CheckSign() as well. */
125 static option_menu capture_options[] =
126 {
127 { "16-bit signed (LSB) (recommended)", AFMT_S16_LE },
128 { "16-bit unsigned (LSB)", AFMT_U16_LE },
129 { "16-bit unsigned (MSB)", AFMT_U16_BE },
130 { "16-bit signed (MSB)", AFMT_S16_BE },
131 { "8-bit signed (recommended)", AFMT_S8 },
132 { "8-bit mu-law", AFMT_MU_LAW },
133 { "8-bit unsigned", AFMT_U8 }
134 };
135
136 static option_menu stereo_options[] =
137 {
138 { "stereo", 1 },
139 { "mono", 0 }
140 };
141
142 static option_menu rate_options[] =
143 {
144 { "44.100 samp/s", SAMP44100 },
145 { "22.050 samp/s", SAMP22050 },
146 { "11.025 samp/s", SAMP11025 },
147 { "8.012 samp/s", SAMP8012 }
148 };
149
closeCB(Widget widget,XtPointer clientData,XtPointer callData)150 static void closeCB(Widget widget, XtPointer clientData, XtPointer callData)
151 {
152 SampleDialogToggle();
153 }
154
stopCB(Widget widget,XtPointer clientData,XtPointer callData)155 static void stopCB(Widget widget, XtPointer clientData, XtPointer callData)
156 {
157 if(resetmixer)
158 ResetMixer();
159
160 sampling = False;
161 playing = False;
162 }
163
searchCB(Widget widget,XtPointer clientData,XtPointer callData)164 static void searchCB(Widget widget, XtPointer clientData, XtPointer callData)
165 {
166 char *filename = XtomGetFileName(sample_dialogW, "search", NULL, NULL, 0, 0);
167
168 if(filename && strlen(filename))
169 XtVaSetValues(filename_textW, XmNvalue, filename, NULL);
170
171 XtFree(filename);
172 }
173
sampleCB(Widget widget,XtPointer clientData,XtPointer callData)174 static void sampleCB(Widget widget, XtPointer clientData, XtPointer callData)
175 {
176 char *buffer;
177 ssize_t len, bufsize;
178 FILE *fp = NULL;
179 XtInputMask mask;
180 int dummy, opened;
181 char command[512];
182
183 sampling = True;
184 opened = False;
185
186 CheckSampleFormat();
187
188 if(!sformat.filename || !strlen(sformat.filename))
189 {
190 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
191 "sampling", "no filename set.");
192 return;
193 }
194
195 if((dummy = access(sformat.filename, W_OK)) == -1)
196 {
197 if(errno != ENOENT)
198 {
199 sprintf(gbuf, "cant access file %s (%s)",
200 sformat.filename, strerror(errno));
201 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
202 sampling = False;
203 }
204 }
205 else
206 {
207 if(sformat.ask_overwrite)
208 {
209 sprintf(gbuf, "overwrite file %s ?", sformat.filename);
210 dummy = XtomGetChoice(sample_dialogW, "sampling", gbuf);
211 if(!dummy)
212 return;
213 }
214 }
215
216 dsp = PrepareDSP(O_RDONLY);
217 if(dsp == -1)
218 return;
219
220 bufsize = sformat.speed * (sformat.stereo+1) * sformat.bps * CYCLETIME;
221 if(debug)
222 printf("bufsize1: %d\n", bufsize);
223 bufsize = (bufsize+3)/4*4; /* hopefully this won't optimized away */
224 if(debug)
225 printf("bufsize2: %d\n", bufsize);
226 buffer = (char*)malloc(bufsize);
227
228 switch(sformat.file_format)
229 {
230 case WAV_FORMAT:
231 // TODO -w for 16bit, -b for 8bit
232 sprintf(command, "sox -c %d -t raw -r %d -%c -w - -t wav %s",
233 sformat.stereo + 1, sformat.speed,
234 sformat.sign, sformat.filename);
235 if(!CheckForProgram("sox"))
236 {
237 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
238 "sampling", "couldn't find \"sox\" in $PATH.");
239 sampling = False;
240 }
241 else
242 if(debug)
243 printf("using %s\n", command);
244 break;
245 case AU_FORMAT:
246 sprintf(command, "sox -c %d -t raw -r %d -%c -b - -t au %s",
247 sformat.stereo + 1, sformat.speed,
248 sformat.sign, sformat.filename);
249 if(!CheckForProgram("sox"))
250 {
251 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
252 "sampling", "couldn't find \"sox\" in $PATH.");
253 sampling = False;
254 }
255 else
256 if(debug)
257 printf("using %s\n", command);
258 break;
259 case VOC_FORMAT:
260 sprintf(command, "sox -c %d -t raw -r %d -%c -b - -t voc %s",
261 sformat.stereo + 1, sformat.speed,
262 sformat.sign, sformat.filename);
263 if(!CheckForProgram("sox"))
264 {
265 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
266 "sampling", "couldn't find \"sox\" in $PATH.");
267 sampling = False;
268 }
269 else
270 if(debug)
271 printf("using %s\n", command);
272 break;
273 case AIFF_FORMAT:
274 sprintf(command, "sox -c %d -t raw -r %d -%c -b - -t aiff %s",
275 sformat.stereo + 1, sformat.speed,
276 sformat.sign, sformat.filename);
277 if(!CheckForProgram("sox"))
278 {
279 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
280 "sampling", "couldn't find \"sox\" in $PATH.");
281 sampling = False;
282 }
283 else
284 if(debug)
285 printf("using %s\n", command);
286 break;
287 case MP3_FORMAT:
288 sprintf(command, "lame -b 128 -f -r -s %.4f -m %s -S -x --tc %s - > %s",
289 sformat.speed/1000., (sformat.stereo ? "j" : "m"),
290 "\"recorded by xmradio\"", sformat.filename);
291 if(!CheckForProgram("lame"))
292 {
293 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
294 "sampling", "couldn't find \"lame\" in $PATH.");
295 sampling = False;
296 }
297 else
298 if(debug)
299 printf("using %s\n", command);
300 break;
301 case RAW_FORMAT:
302 if((fp = fopen(sformat.filename, "w")) == NULL)
303 {
304 sprintf(gbuf, "couldn't open outputfile: %s (%s)",
305 sformat.filename, strerror(errno));
306 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
307 sampling = False;
308 }
309 else
310 opened = True;
311 break;
312 default:
313 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
314 "sampling", "unknown sample format!?!");
315 sampling = False;
316 break;
317 }
318
319 if(sampling && sformat.file_format != RAW_FORMAT)
320 {
321 fp = popen(command, "w");
322 if(fp == NULL)
323 {
324 sprintf(gbuf, "failed to popen() command: %s (%s)",
325 command, strerror(errno));
326 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
327 sampling = False;
328 }
329 else
330 opened = True;
331 }
332
333 XtSetSensitive(stopB, True);
334 XtSetSensitive(recordB, False);
335 XtSetSensitive(playbackB, False);
336
337 /* okay, ready for reading from dsp device */
338 while(sampling)
339 {
340 if(debug)
341 printf("read dsp\n");
342
343 if((len = read(dsp, buffer, bufsize)) == -1)
344 {
345 sprintf(gbuf, "couldn't read all data: %s", strerror(errno));
346 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
347 sampling = False;
348 }
349
350 if(debug)
351 printf("read bytes: %d\n", len);
352
353 /* if writing raw data, just throw it out to file */
354 if((len > 0) && (fwrite(buffer, len, 1, fp) != 1))
355 {
356 sprintf(gbuf, "couldn't write to outputfile: %s (%s)",
357 sformat.filename, strerror(errno));
358 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
359 sampling = False;
360 }
361
362 while((mask = XtAppPending(app_con)) != 0)
363 {
364 XtAppProcessEvent(app_con, mask);
365 }
366 }
367 free(buffer);
368
369 if(opened)
370 {
371 if(sformat.file_format != RAW_FORMAT)
372 pclose(fp);
373 else
374 fclose(fp);
375 }
376
377 XtSetSensitive(stopB, False);
378 XtSetSensitive(recordB, True);
379 XtSetSensitive(playbackB, True);
380
381 if(close(dsp) == -1)
382 {
383 sprintf(gbuf, "couldn't close dsp: %s", strerror(errno));
384 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
385 }
386 }
387
playbackCB(Widget widget,XtPointer clientData,XtPointer callData)388 static void playbackCB(Widget widget, XtPointer clientData, XtPointer callData)
389 {
390 char *buffer;
391 size_t len, bufsize;
392 FILE *fp = NULL;
393 XtInputMask mask;
394 char command[512];
395
396 CheckSampleFormat();
397
398 if(!sformat.filename || !strlen(sformat.filename))
399 {
400 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
401 "playback", "no filename set.");
402 return;
403 }
404
405 dsp = PrepareDSP(O_WRONLY);
406 if(dsp == -1)
407 return;
408
409 bufsize = sformat.speed * (sformat.stereo+1) * sformat.bps * CYCLETIME;
410 bufsize = (bufsize+3)/4*4; /* hopefully this won't optimized away */
411 buffer = (char*)malloc(bufsize);
412
413 playing = True;
414
415 switch(sformat.file_format)
416 {
417 case WAV_FORMAT:
418 if(!CheckForProgram("sox"))
419 {
420 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
421 "playing", "couldn't find \"sox\" in $PATH.");
422 playing = False;
423 }
424 else
425 {
426 // TODO -w for 16bit, -b for 8bit
427 sprintf(command, "sox -t wav %s -c %d -t raw -r %d -%c -w -",
428 sformat.filename, sformat.stereo + 1,
429 sformat.speed, sformat.sign);
430 }
431 break;
432 case AU_FORMAT:
433 if(!CheckForProgram("sox"))
434 {
435 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
436 "playing", "couldn't find \"sox\" in $PATH.");
437 playing = False;
438 }
439 else
440 {
441 sprintf(command, "sox -t au %s -c %d -t raw -r %d -%c -b -",
442 sformat.filename, sformat.stereo + 1,
443 sformat.speed, sformat.sign);
444 }
445 break;
446 case VOC_FORMAT:
447 if(!CheckForProgram("sox"))
448 {
449 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
450 "playing", "couldn't find \"sox\" in $PATH.");
451 playing = False;
452 }
453 else
454 {
455 sprintf(command, "sox -t voc %s -c %d -t raw -r %d -%c -b -",
456 sformat.filename, sformat.stereo + 1,
457 sformat.speed, sformat.sign);
458 }
459 break;
460 case AIFF_FORMAT:
461 if(!CheckForProgram("sox"))
462 {
463 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
464 "playing", "couldn't find \"sox\" in $PATH.");
465 playing = False;
466 }
467 else
468 {
469 sprintf(command, "sox -t aiff %s -c %d -t raw -r %d -%c -b -",
470 sformat.filename, sformat.stereo + 1,
471 sformat.speed, sformat.sign);
472 }
473 break;
474 case MP3_FORMAT:
475 if(!CheckForProgram("mpg123"))
476 {
477 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
478 "playing", "couldn't find \"mpg123\" in $PATH.");
479 playing = False;
480 }
481 else
482 {
483 sprintf(command, "mpg123 -q -r %d -s %s", sformat.speed, sformat.filename);
484 }
485 /*
486 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
487 "playback", "sample format not implemented, yet.");
488 playing = False;
489 */
490 break;
491 case RAW_FORMAT:
492 if((fp = fopen(sformat.filename, "r")) == NULL)
493 {
494 sprintf(gbuf, "couldn't open inputfile: %s (%s)",
495 sformat.filename, strerror(errno));
496 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "playback", gbuf);
497 playing = False;
498 }
499 break;
500 default:
501 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "playback",
502 "unknown sample format!?!");
503 playing = False;
504 break;
505 }
506
507 if(playing && sformat.file_format != RAW_FORMAT)
508 {
509 if(debug)
510 printf("using %s\n", command);
511
512 fp = popen(command, "r");
513 if(fp == NULL)
514 {
515 sprintf(gbuf, "failed to popen() command: %s (%s)",
516 command, strerror(errno));
517 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "playback", gbuf);
518 playing = False;
519 }
520 }
521
522 XtSetSensitive(stopB, True);
523 XtSetSensitive(recordB, False);
524 XtSetSensitive(playbackB, False);
525
526 while(playing)
527 {
528 len = fread(buffer, 1, bufsize, fp);
529 if(len != bufsize)
530 {
531 if(feof(fp))
532 {
533 playing = False;
534 if(debug)
535 printf(" done reading audiofile\n");
536 }
537 else
538 {
539 sprintf(gbuf, "couldn't read from inputfile: %s", sformat.filename);
540 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "playback", gbuf);
541 playing = False;
542 break;
543 }
544 }
545
546 if(playing && write(dsp, buffer, len) == -1)
547 {
548 sprintf(gbuf, "couldn't write all data to dsp: %s", strerror(errno));
549 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "playback", gbuf);
550 playing = False;
551 }
552
553 while((mask = XtAppPending(app_con)) != 0)
554 {
555 XtAppProcessEvent(app_con, mask);
556 }
557 }
558
559 if(fp)
560 fclose(fp);
561
562 free(buffer);
563 if(close(dsp) == -1)
564 {
565 sprintf(gbuf, "couldn't close dsp: %s", strerror(errno));
566 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "sampling", gbuf);
567 }
568
569 XtSetSensitive(stopB, False);
570 XtSetSensitive(recordB, True);
571 XtSetSensitive(playbackB, True);
572 }
573
CheckBPS(int format)574 int CheckBPS(int format)
575 {
576 switch(format)
577 {
578 case AFMT_MU_LAW:
579 case AFMT_S8:
580 case AFMT_U8:
581 return 1;
582 case AFMT_S16_LE:
583 case AFMT_U16_LE:
584 case AFMT_U16_BE:
585 case AFMT_S16_BE:
586 default:
587 return 2;
588 }
589 }
590
591 /* return sox flag for format */
CheckSign(int format)592 char CheckSign(int format)
593 {
594 switch(format)
595 {
596 case AFMT_MU_LAW:
597 return 'U';
598 break;
599 case AFMT_S8:
600 case AFMT_S16_LE:
601 case AFMT_S16_BE:
602 return 's';
603 break;
604 case AFMT_U8:
605 case AFMT_U16_LE:
606 case AFMT_U16_BE:
607 default:
608 return 'u';
609 break;
610 }
611 }
612
CheckSampleFormat()613 void CheckSampleFormat()
614 {
615 Widget dummyW;
616 unsigned char ow;
617 int data;
618
619 /* filename */
620 XtVaGetValues(filename_textW, XmNvalue, &(sformat.filename), NULL);
621
622 if(debug)
623 printf("filename: %s\n", sformat.filename);
624
625 /* file format */
626 XtVaGetValues(format_optionW, XmNmenuHistory, &dummyW, NULL);
627 XtVaGetValues(dummyW, XmNuserData, &data, NULL);
628 sformat.file_format = data;
629
630 if(debug)
631 printf("file format: %d\n", data);
632
633 /* mono/stereo */
634 XtVaGetValues(stereo_optionW, XmNmenuHistory, &dummyW, NULL);
635 XtVaGetValues(dummyW, XmNuserData, &data, NULL);
636 sformat.stereo = data;
637
638 if(debug)
639 printf("stereo: %d\n", data);
640
641 /* capture format */
642 XtVaGetValues(capture_optionW, XmNmenuHistory, &dummyW, NULL);
643 XtVaGetValues(dummyW, XmNuserData, &data, NULL);
644 sformat.capture_format = data;
645
646 if(debug)
647 printf("capture format: %d\n", data);
648
649 /* bps */
650 data = CheckBPS(sformat.capture_format);
651 sformat.bps = data;
652
653 if(debug)
654 printf(" (bps: %d)\n", data);
655
656 /* sign */
657 data = CheckSign(sformat.capture_format);
658 sformat.sign = data;
659
660 if(debug)
661 printf(" (sign: %c)\n", data);
662
663 /* speed */
664 XtVaGetValues(rate_optionW, XmNmenuHistory, &dummyW, NULL);
665 XtVaGetValues(dummyW, XmNuserData, &data, NULL);
666 sformat.speed = data;
667
668 if(debug)
669 printf("speed: %d\n", data);
670
671 XtVaGetValues(overwriteW, XmNset, &ow, NULL);
672 sformat.ask_overwrite = (ow == XmSET);
673
674 if(debug)
675 printf("ask for overwrite: %s\n\n", sformat.ask_overwrite ? "yes" : "no");
676 }
677
CheckForProgram(const char * name)678 int CheckForProgram(const char *name)
679 {
680 char *p, *cur, *path, buf[MAXPATHLEN];
681
682 if(!(path = getenv("PATH")))
683 path = _PATH_DEFPATH;
684
685 cur = path = strdup(path);
686
687 while((p = strsep(&cur, ":")))
688 {
689 sprintf(buf, "%s/%s", p, name);
690
691 if(!access(buf, X_OK))
692 {
693 if(debug)
694 printf("using audio tool: %s\n", buf);
695
696 if(path)
697 free(path);
698
699 return True;
700 }
701 }
702
703 if(path)
704 free(path);
705
706 return False;
707 }
708
ResetMixer()709 void ResetMixer()
710 {
711 if(ioctl(mixer, SOUND_MIXER_WRITE_RECSRC, &old_recsrc) == -1)
712 {
713 sprintf(gbuf, "couldn't reset mixer recsrc: %s", strerror(errno));
714 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "ResetMixer", gbuf);
715 }
716 resetmixer = False;
717 }
718
PrepareDSP(int flags)719 int PrepareDSP(int flags)
720 {
721 int d, dummy;
722
723 if(flags == O_RDONLY || flags == O_RDWR)
724 {
725 if(mixer == -1)
726 {
727 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
728 "PrepareDSP", "no mixer available.");
729 return -1;
730 }
731
732 /* getting old rec mask */
733 if(ioctl(mixer, SOUND_MIXER_READ_RECSRC, &old_recsrc) == -1)
734 {
735 sprintf(gbuf, "couldn't get mixer recsrc: %s", strerror(errno));
736 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
737 return -1;
738 }
739
740 resetmixer = True;
741
742 /* setting rec mask to line channel */
743 dummy = SOUND_MASK_LINE;
744 if(ioctl(mixer, SOUND_MIXER_WRITE_RECSRC, &dummy) == -1)
745 {
746 sprintf(gbuf, "couldn't set mixer recsrc: %s", strerror(errno));
747 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
748 return -1;
749 }
750 }
751
752 /* opening dsp device */
753 if((d = open(DSP_DEVICE, flags, 0)) == -1)
754 {
755 sprintf(gbuf, "couldn't open %s: %s", DSP_DEVICE, strerror(errno));
756 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
757 goto error;
758 }
759
760 /* selecting audio format */
761 dummy = sformat.capture_format;
762 if(ioctl(d, SNDCTL_DSP_SETFMT, &dummy) == -1)
763 {
764 sprintf(gbuf, "couldn't set dsp format: %s\n", strerror(errno));
765 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
766 goto error;
767 }
768
769 if(sformat.capture_format != dummy)
770 {
771 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR,
772 "PrepareDSP", "device doesn't support the requested audio format.");
773 goto error;
774 }
775
776 /* selecting stereo/mono mode */
777 dummy = sformat.stereo;
778 if(ioctl(d, SNDCTL_DSP_STEREO, &dummy) == -1)
779 {
780 sprintf(gbuf, "couldn't set dsp to %s: %s",
781 sformat.stereo ? "stereo" : "mono", strerror(errno));
782 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
783 goto error;
784 }
785
786 if(sformat.stereo != dummy)
787 {
788 sprintf(gbuf, "device doesn't support %s mode.",
789 sformat.stereo ? "stereo" : "mono");
790 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
791 goto error;
792 }
793
794 /* selecting sampling rate */
795 dummy = sformat.speed;
796 if(ioctl(d, SNDCTL_DSP_SPEED, &dummy) == -1)
797 {
798 sprintf(gbuf, "couldn't set dsp speed: %s", strerror(errno));
799 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
800 goto error;
801 }
802
803 /* we should check if difference is just some percent... */
804 if(sformat.speed != dummy)
805 {
806 sprintf(gbuf, "device doesn't support requested speed.\nWanted %d, got %d.",
807 sformat.speed, dummy);
808 XtomShowMessage(sample_dialogW, XmDIALOG_ERROR, "PrepareDSP", gbuf);
809 }
810
811 return d;
812
813 error:
814 close(d);
815
816 /* resetting rec mask */
817 if(resetmixer)
818 ResetMixer();
819
820 return -1;
821 }
822
CreateOptionMenu(Widget parent,option_menu * menu,int n)823 static Widget CreateOptionMenu(Widget parent, option_menu *menu, int n)
824 {
825 unsigned int i;
826 Arg args[10];
827 Widget menuW, optionW;
828
829 menuW = XmCreatePulldownMenu(parent, "option_pulldown", (Arg*)NULL, 0);
830
831 for(i = 0; i < n; i++)
832 {
833 XtVaCreateManagedWidget(menu[i].name,
834 xmPushButtonWidgetClass,
835 menuW,
836 XmNuserData, menu[i].id,
837 NULL);
838 }
839
840 n = 0;
841 XtSetArg(args[n], XmNsubMenuId, menuW); n++;
842 optionW = XmCreateOptionMenu(parent, "option_menu", args, n);
843 XtManageChild(optionW);
844
845 #ifdef HAS_XPM
846 if(skin)
847 SkinToWidgets(menuW, skin);
848 #endif
849
850 return optionW;
851 }
852
MakeInterface(Widget topl)853 static void MakeInterface(Widget topl)
854 {
855 Position x, y;
856 Widget filename_labelW, format_labelW, capture_labelW;
857 Widget sampleMainRowColumnW, formW, frameW, buttonSepW;
858 Widget sampleRC1W, sampleRC2W, sampleRC3W, sampleRC4W, sampleRC5W;
859
860 extern void _XEditResCheckMessages(Widget, XtPointer, XEvent*, Boolean*);
861
862 XtVaGetValues(topl, XmNx, &x, XmNy, &y, NULL);
863 sample_dialogW = XtVaCreatePopupShell("sample_dialog",
864 transientShellWidgetClass,
865 topl,
866 XmNx, x,
867 XmNy, y,
868 XmNdeleteResponse, XmDO_NOTHING,
869 XtNiconPixmap, icon_pm,
870 XtNiconMask, icon_pm_mask,
871 NULL);
872
873 XtAddEventHandler(sample_dialogW, (EventMask)0, True, _XEditResCheckMessages,
874 NULL);
875
876 formW =
877 XtVaCreateManagedWidget("sample_main",
878 xmFormWidgetClass,
879 sample_dialogW,
880 NULL);
881
882 frameW =
883 XtVaCreateManagedWidget("sample_frame",
884 xmFrameWidgetClass,
885 formW,
886 XmNleftAttachment, XmATTACH_FORM,
887 XmNleftOffset, 3,
888 XmNrightAttachment, XmATTACH_FORM,
889 XmNrightOffset, 3,
890 XmNtopAttachment, XmATTACH_FORM,
891 XmNtopOffset, 3,
892 XmNbottomAttachment, XmATTACH_FORM,
893 XmNbottomOffset, 3,
894 NULL);
895
896
897 sampleMainRowColumnW =
898 XtVaCreateManagedWidget("sample_dialog_main",
899 xmRowColumnWidgetClass,
900 frameW,
901 XmNorientation, XmVERTICAL,
902 NULL);
903
904 sampleRC1W =
905 XtVaCreateManagedWidget("sample_rc1",
906 xmRowColumnWidgetClass,
907 sampleMainRowColumnW,
908 XmNorientation, XmHORIZONTAL,
909 NULL);
910
911 filename_labelW =
912 XtVaCreateManagedWidget("filename_label",
913 xmLabelWidgetClass,
914 sampleRC1W,
915 NULL);
916
917 filename_textW =
918 XtVaCreateManagedWidget("filename_text",
919 xmTextFieldWidgetClass,
920 sampleRC1W,
921 XmNvalue, DEF_FILENAME,
922 NULL);
923
924 searchB =
925 XtVaCreateManagedWidget("filename_search",
926 xmPushButtonWidgetClass,
927 sampleRC1W,
928 NULL);
929 XtAddCallback(searchB, XmNactivateCallback, searchCB, (XtPointer)NULL);
930
931 sampleRC2W =
932 XtVaCreateManagedWidget("sample_rc2",
933 xmRowColumnWidgetClass,
934 sampleMainRowColumnW,
935 XmNorientation, XmHORIZONTAL,
936 NULL);
937
938 format_labelW =
939 XtVaCreateManagedWidget("format_label",
940 xmLabelWidgetClass,
941 sampleRC2W,
942 NULL);
943
944 format_optionW = CreateOptionMenu(sampleRC2W,
945 format_options, XtNumber(format_options));
946
947 sampleRC3W =
948 XtVaCreateManagedWidget("sample_rc3",
949 xmRowColumnWidgetClass,
950 sampleMainRowColumnW,
951 XmNorientation, XmHORIZONTAL,
952 NULL);
953
954 capture_labelW =
955 XtVaCreateManagedWidget("capture_label",
956 xmLabelWidgetClass,
957 sampleRC3W,
958 NULL);
959
960 capture_optionW = CreateOptionMenu(sampleRC3W,
961 capture_options, XtNumber(capture_options));
962
963 sampleRC4W =
964 XtVaCreateManagedWidget("sample_rc4",
965 xmRowColumnWidgetClass,
966 sampleMainRowColumnW,
967 XmNorientation, XmHORIZONTAL,
968 NULL);
969
970 stereo_optionW = CreateOptionMenu(sampleRC4W,
971 stereo_options, XtNumber(stereo_options));
972
973 rate_optionW = CreateOptionMenu(sampleRC4W,
974 rate_options, XtNumber(rate_options));
975
976 overwriteW =
977 XtVaCreateManagedWidget("overwrite_button",
978 xmToggleButtonWidgetClass,
979 sampleMainRowColumnW,
980 XmNset, True,
981 NULL);
982
983 buttonSepW =
984 XtVaCreateManagedWidget("record_separator",
985 xmSeparatorWidgetClass,
986 sampleMainRowColumnW,
987 NULL);
988
989 sampleRC5W =
990 XtVaCreateManagedWidget("sample_rc5",
991 xmRowColumnWidgetClass,
992 sampleMainRowColumnW,
993 XmNorientation, XmHORIZONTAL,
994 XmNentryAlignment, XmALIGNMENT_CENTER,
995 NULL);
996
997 recordB =
998 XtVaCreateManagedWidget("record_button",
999 xmPushButtonWidgetClass,
1000 sampleRC5W,
1001 NULL);
1002
1003 stopB =
1004 XtVaCreateManagedWidget("stop_button",
1005 xmPushButtonWidgetClass,
1006 sampleRC5W,
1007 NULL);
1008
1009 XtSetSensitive(stopB, False);
1010
1011 XtAddCallback(stopB, XmNactivateCallback, stopCB, (XtPointer)recordB);
1012 XtAddCallback(recordB, XmNactivateCallback, sampleCB, (XtPointer)stopB);
1013
1014 playbackB =
1015 XtVaCreateManagedWidget("playback_button",
1016 xmPushButtonWidgetClass,
1017 sampleRC5W,
1018 NULL);
1019
1020 XtAddCallback(playbackB, XmNactivateCallback, playbackCB, (XtPointer)NULL);
1021
1022 dismissB =
1023 XtVaCreateManagedWidget("dismiss_button",
1024 xmPushButtonWidgetClass,
1025 sampleRC5W,
1026 NULL);
1027
1028 XtAddCallback(dismissB, XmNactivateCallback, closeCB, (XtPointer)NULL);
1029
1030 #ifdef HAS_XPM
1031 if(skin)
1032 {
1033 SkinToWidgets(format_optionW, skin);
1034 SkinToWidgets(capture_optionW, skin);
1035 SkinToWidgets(stereo_optionW, skin);
1036 SkinToWidgets(rate_optionW, skin);
1037 }
1038 #endif
1039 }
1040
SampleDialogToggle()1041 void SampleDialogToggle()
1042 {
1043 if(!sample_dialogW)
1044 {
1045 // init
1046 Atom wmDeleteAtom;
1047
1048 is_popped = False;
1049 MakeInterface(toplevel);
1050 AddTooltipsToWidgets();
1051 #ifdef HAS_XPM
1052 if(skin)
1053 SkinToWidgets(sample_dialogW, skin);
1054 #endif
1055
1056 wmDeleteAtom = XmInternAtom(dpy, "WM_DELETE_WINDOW", False);
1057 XmAddWMProtocolCallback(sample_dialogW, wmDeleteAtom, closeCB,
1058 (XtPointer)NULL);
1059 }
1060
1061 if(is_popped)
1062 {
1063 is_popped = False;
1064 XtSetSensitive(analyzerW, True);
1065 XtPopdown(sample_dialogW);
1066 }
1067 else
1068 {
1069 is_popped = True;
1070 AnalyzerQuit();
1071 XtSetSensitive(analyzerW, False);
1072 XtPopup(sample_dialogW, XtGrabNone);
1073 }
1074 }
1075
1076