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