4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Command-line audio play utility */
36 #include <limits.h> /* All occurances of INT_MAX used to be ~0 (by MCA) */
39 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/ioctl.h>
45 #include <netinet/in.h>
48 #include <audio_device.h>
49 #include <audio_encode.h>
51 /* localization stuff */
52 #define MGET(s) (char *)gettext(s)
54 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
55 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
58 #define Error (void) fprintf
64 static char prog_opts
[] = "VEiv:d:?"; /* getopt() flags */
68 #define MAX_GAIN (100) /* maximum gain */
71 * This defines the tolerable sample rate error as a ratio between the
72 * sample rates of the audio data and the audio device.
74 #define SAMPLE_RATE_THRESHOLD (.01)
76 #define BUFFER_LEN 10 /* seconds - for file i/o */
77 #define ADPCM_SIZE (1000*8) /* adpcm conversion output buf size */
78 #define SWAP_SIZE (8192)
79 /* swap bytes conversion output buf size */
81 static unsigned Volume
= INT_MAX
; /* output volume */
82 static double Savevol
; /* saved volume level */
84 static int Verbose
= FALSE
; /* verbose messages */
85 static int Immediate
= FALSE
;
86 /* don't hang waiting for device */
87 static int Errdetect
= FALSE
; /* don't worry about underrun */
88 static char *Audio_dev
= "/dev/audio";
90 static int NetEndian
= TRUE
; /* endian nature of the machine */
92 static int Audio_fd
= -1;
93 /* file descriptor for audio device */
94 static int Audio_ctlfd
= -1;
95 /* file descriptor for control device */
96 static Audio_hdr Save_hdr
;
97 /* saved audio header for device */
98 static Audio_hdr Dev_hdr
; /* audio header for device */
99 static char *Ifile
; /* current filename */
100 static Audio_hdr File_hdr
; /* audio header for file */
101 static unsigned Decode
= AUDIO_ENCODING_NONE
;
102 /* decode type, if any */
104 static unsigned char *buf
= NULL
; /* dynamically alloc'd */
105 static unsigned bufsiz
= 0; /* size of output buffer */
106 static unsigned char adpcm_buf
[ADPCM_SIZE
+ 32];
107 /* for adpcm conversion */
108 static unsigned char swap_buf
[SWAP_SIZE
+ 32];
109 /* for byte swap conversion */
110 static unsigned char *inbuf
;
111 /* current input buffer pointer */
112 static unsigned insiz
; /* current input buffer size */
115 * The decode_g72x() function is capable of decoding only one channel
116 * at a time and so multichannel data must be decomposed (using demux()
117 * function below ) into its constituent channels and each passed
118 * separately to the decode_g72x() function. Encoded input channels are
119 * stored in **in_ch_data and decoded output channels in **out_ch_data.
120 * Once each channel has been decoded they are recombined (see mux()
121 * function below) before being written to the audio device. For each
122 * channel and adpcm state structure is created.
125 /* adpcm state structures */
126 static struct audio_g72x_state
*adpcm_state
= NULL
;
127 static unsigned char **in_ch_data
= NULL
; /* input channels */
128 static unsigned char **out_ch_data
= NULL
; /* output channels */
129 static int out_ch_size
; /* output channel size */
131 static char *Audio_path
= NULL
;
132 /* path to search for audio files */
134 /* Global variables */
135 extern int getopt(int, char *const *, const char *);
139 /* Local functions */
140 static void usage(void);
141 static void sigint(int sig
);
142 static void open_audio(void);
143 static int path_open(char *fname
, int flags
, mode_t mode
, char *path
);
144 static int parse_unsigned(char *str
, unsigned *dst
, char *flag
);
145 static int reconfig(void);
146 static void initmux(int unitsz
, int unitsp
);
147 static void demux(int unitsz
, int cnt
);
148 static void mux(char *);
149 static void freemux(void);
155 Error(stderr
, MGET("Play an audio file -- usage:\n"
156 "\t%s [-iV] [-v vol] [-d dev] [file ...]\n"
158 "\t-i\tDon't hang if audio device is busy\n"
159 "\t-V\tPrint verbose warning messages\n"
160 "\t-v\tSet output volume (0 - %d)\n"
161 "\t-d\tSpecify audio device (default: /dev/audio)\n"
162 "\tfile\tList of files to play\n"
163 "\t\tIf no files specified, read stdin\n"),
171 /* flush output queues before exiting */
173 (void) audio_flush_play(Audio_fd
);
175 /* restore saved parameters */
176 if (Volume
!= INT_MAX
)
177 (void) audio_set_play_gain(Audio_fd
, &Savevol
);
178 if ((Audio_ctlfd
>= 0) &&
179 (audio_cmp_hdr(&Save_hdr
, &Dev_hdr
) != 0)) {
180 (void) audio_set_play_config(Audio_fd
, &Save_hdr
);
186 /* Open the audio device and initalize it. */
193 /* Return if already open */
197 /* Try opening without waiting, first */
198 Audio_fd
= open(Audio_dev
, O_WRONLY
| O_NONBLOCK
);
199 if ((Audio_fd
< 0) && (errno
== EBUSY
)) {
201 Error(stderr
, MGET("%s: %s is busy\n"),
206 Error(stderr
, MGET("%s: waiting for %s..."),
208 (void) fflush(stderr
);
210 /* Now hang until it's open */
211 Audio_fd
= open(Audio_dev
, O_WRONLY
);
213 Error(stderr
, (Audio_fd
< 0) ? "\n" : MGET("open\n"));
216 Error(stderr
, MGET("%s: error opening "), prog
);
221 /* Clear the non-blocking flag (in System V it persists after open) */
222 (void) fcntl(Audio_fd
, F_SETFL
,
223 (fcntl(Audio_fd
, F_GETFL
, 0) & ~(O_NDELAY
| O_NONBLOCK
)));
225 /* Get the device output encoding configuration */
226 if (audio_get_play_config(Audio_fd
, &Dev_hdr
) != AUDIO_SUCCESS
) {
227 Error(stderr
, MGET("%s: %s is not an audio device\n"),
232 /* If -v flag, set the output volume now */
233 if (Volume
!= INT_MAX
) {
234 vol
= (double)Volume
/ (double)MAX_GAIN
;
235 (void) audio_get_play_gain(Audio_fd
, &Savevol
);
236 err
= audio_set_play_gain(Audio_fd
, &vol
);
237 if (err
!= AUDIO_SUCCESS
) {
239 MGET("%s: could not set output volume for %s\n"),
246 /* Play a list of audio files. */
248 main(int argc
, char **argv
) {
268 char ctldev
[MAXPATHLEN
];
270 (void) setlocale(LC_ALL
, "");
271 (void) textdomain(TEXT_DOMAIN
);
273 /* Get the program name */
274 prog
= strrchr(argv
[0], '/');
279 Stdin
= MGET("(stdin)");
281 /* Check AUDIODEV environment for audio device name */
282 if (cp
= getenv("AUDIODEV")) {
286 /* Parse the command line arguments */
288 while ((i
= getopt(argc
, argv
, prog_opts
)) != EOF
) {
291 if (parse_unsigned(optarg
, &Volume
, "-v")) {
293 } else if (Volume
> MAX_GAIN
) {
294 Error(stderr
, MGET("%s: invalid value "
319 argc
-= optind
; /* update arg pointers */
322 /* Validate and open the audio device */
323 err
= stat(Audio_dev
, &st
);
325 Error(stderr
, MGET("%s: cannot stat "), prog
);
329 if (!S_ISCHR(st
.st_mode
)) {
330 Error(stderr
, MGET("%s: %s is not an audio device\n"), prog
,
335 /* This should probably use audio_cntl instead of open_audio */
336 if ((argc
<= 0) && isatty(fileno(stdin
))) {
337 Error(stderr
, MGET("%s: No files and stdin is a tty.\n"), prog
);
341 /* Check on the -i status now. */
342 Audio_fd
= open(Audio_dev
, O_WRONLY
| O_NONBLOCK
);
343 if ((Audio_fd
< 0) && (errno
== EBUSY
)) {
345 Error(stderr
, MGET("%s: %s is busy\n"), prog
,
350 (void) close(Audio_fd
);
353 /* Try to open the control device and save the current format */
354 (void) snprintf(ctldev
, sizeof (ctldev
), "%sctl", Audio_dev
);
355 Audio_ctlfd
= open(ctldev
, O_RDWR
);
356 if (Audio_ctlfd
>= 0) {
358 * wait for the device to become available then get the
359 * controls. We want to save the format that is left when the
360 * device is in a quiescent state. So wait until then.
362 Audio_fd
= open(Audio_dev
, O_WRONLY
);
363 (void) close(Audio_fd
);
365 if (audio_get_play_config(Audio_ctlfd
, &Save_hdr
)
367 (void) close(Audio_ctlfd
);
372 /* store AUDIOPATH so we don't keep doing getenv() */
373 Audio_path
= getenv("AUDIOPATH");
375 /* Set up SIGINT handler to flush output */
376 (void) signal(SIGINT
, sigint
);
378 /* Set the endian nature of the machine. */
379 if ((ulong_t
)1 != htonl((ulong_t
)1)) {
383 /* If no filenames, read stdin */
392 /* Loop through all filenames */
394 /* Interpret "-" filename to mean stdin */
395 if (strcmp(Ifile
, "-") == 0)
398 if (Ifile
== Stdin
) {
401 MGET("%s: stdin already processed\n"),
408 if ((ifd
= path_open(Ifile
, O_RDONLY
, 0, Audio_path
))
410 Error(stderr
, MGET("%s: cannot open "), prog
);
417 /* Check to make sure this is an audio file */
418 err
= audio_read_filehdr(ifd
, &File_hdr
, &file_type
, NULL
, 0);
419 if (err
!= AUDIO_SUCCESS
) {
421 MGET("%s: %s is not a valid audio file\n"),
427 /* If G.72X adpcm, set flags for conversion */
428 if ((File_hdr
.encoding
== AUDIO_ENCODING_G721
) &&
429 (File_hdr
.samples_per_unit
== 2) &&
430 (File_hdr
.bytes_per_unit
== 1)) {
431 Decode
= AUDIO_ENCODING_G721
;
432 File_hdr
.encoding
= AUDIO_ENCODING_ULAW
;
433 File_hdr
.samples_per_unit
= 1;
434 File_hdr
.bytes_per_unit
= 1;
435 adpcm_state
= (struct audio_g72x_state
*)malloc
436 (sizeof (*adpcm_state
) * File_hdr
.channels
);
437 for (i
= 0; i
< File_hdr
.channels
; i
++) {
438 g721_init_state(&adpcm_state
[i
]);
440 } else if ((File_hdr
.encoding
== AUDIO_ENCODING_G723
) &&
441 (File_hdr
.samples_per_unit
== 8) &&
442 (File_hdr
.bytes_per_unit
== 3)) {
443 Decode
= AUDIO_ENCODING_G723
;
444 File_hdr
.encoding
= AUDIO_ENCODING_ULAW
;
445 File_hdr
.samples_per_unit
= 1;
446 File_hdr
.bytes_per_unit
= 1;
447 adpcm_state
= (struct audio_g72x_state
*)malloc
448 (sizeof (*adpcm_state
) * File_hdr
.channels
);
449 for (i
= 0; i
< File_hdr
.channels
; i
++) {
450 g723_init_state(&adpcm_state
[i
]);
453 Decode
= AUDIO_ENCODING_NONE
;
456 /* Check the device configuration */
458 if (audio_cmp_hdr(&Dev_hdr
, &File_hdr
) != 0) {
460 * The device does not match the input file.
461 * Wait for any old output to drain, then attempt
462 * to reconfigure the audio device to match the
465 if (audio_drain(Audio_fd
, FALSE
) != AUDIO_SUCCESS
) {
466 /* Flush any remaining audio */
467 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
469 Error(stderr
, MGET("%s: "), prog
);
470 perror(MGET("AUDIO_DRAIN error"));
474 /* Flush any remaining audio */
475 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
484 /* try to do the mmaping - for regular files only ... */
485 err
= fstat(ifd
, &st
);
487 Error(stderr
, MGET("%s: cannot stat "), prog
);
491 regular
= (S_ISREG(st
.st_mode
));
494 /* If regular file, map it. Else, allocate a buffer */
498 * This should compare to MAP_FAILED not -1, can't
501 if (regular
&& ((mapaddr
= mmap(NULL
, st
.st_size
, PROT_READ
,
502 MAP_SHARED
, ifd
, 0)) != MAP_FAILED
)) {
504 (void) madvise(mapaddr
, st
.st_size
, MADV_SEQUENTIAL
);
506 /* Skip the file header and set the proper size */
507 cnt
= lseek(ifd
, 0, SEEK_CUR
);
512 inbuf
= (unsigned char *) mapaddr
+ cnt
;
513 len
= cnt
= st
.st_size
- cnt
;
514 } else { /* Not a regular file, or map failed */
519 /* Allocate buffer to hold 10 seconds of data */
520 cnt
= BUFFER_LEN
* File_hdr
.sample_rate
*
521 File_hdr
.bytes_per_unit
* File_hdr
.channels
;
526 buf
= (unsigned char *) malloc(cnt
);
529 MGET("%s: couldn't allocate %dK "
530 "buf\n"), prog
, bufsiz
/ 1000);
538 /* Set buffer sizes and pointers for conversion, if any */
541 case AUDIO_ENCODING_NONE
:
543 outbuf
= (char *)buf
;
545 case AUDIO_ENCODING_G721
:
546 insiz
= ADPCM_SIZE
/ 2;
547 outbuf
= (char *)adpcm_buf
;
550 case AUDIO_ENCODING_G723
:
551 insiz
= (ADPCM_SIZE
* 3) / 8;
552 outbuf
= (char *)adpcm_buf
;
558 * 8-bit audio isn't a problem, however 16-bit audio is.
559 * If the file is an endian that is different from the machine
560 * then the bytes will need to be swapped.
562 * Note: Because the G.72X conversions produce 8bit output,
563 * they don't require a byte swap before display and so
564 * this scheme works just fine. If a conversion is added
565 * that produces a 16 bit result and therefore requires
566 * byte swapping before output, then a mechanism
567 * for chaining the two conversions will have to be built.
569 * Note: The following if() could be simplified, but then
570 * it gets to be very hard to read. So it's left as is.
573 if (File_hdr
.bytes_per_unit
== 2 &&
574 ((!NetEndian
&& file_type
== FILE_AIFF
) ||
575 (!NetEndian
&& file_type
== FILE_AU
) ||
576 (NetEndian
&& file_type
== FILE_WAV
))) {
583 /* Read in interal number of sample frames. */
584 frame
= File_hdr
.bytes_per_unit
* File_hdr
.channels
;
585 insiz
= (SWAP_SIZE
/ frame
) * frame
;
586 /* make the output buffer the swap buffer. */
587 outbuf
= (char *)swap_buf
;
591 * At this point, we're all ready to copy the data.
593 if (mapaddr
== 0) { /* Not mmapped, do it a buffer at a time. */
595 frame
= File_hdr
.bytes_per_unit
* File_hdr
.channels
;
597 while ((cnt
= read(ifd
, inbuf
+rem
, insiz
-rem
)) >= 0) {
599 * We need to ensure only an integral number of
600 * samples is ever written to the audio device.
607 * If decoding adpcm, or swapping bytes do it
610 * We treat the swapping like a separate
611 * encoding here because the G.72X encodings
612 * decode to single byte output samples. If
613 * another encoding is added and it produces
614 * multi-byte output samples this will have to
617 if (Decode
== AUDIO_ENCODING_G721
) {
619 demux(1, cnt
/ File_hdr
.channels
);
620 for (c
= 0; c
< File_hdr
.channels
; c
++) {
621 err
= g721_decode(in_ch_data
[c
],
622 cnt
/ File_hdr
.channels
,
624 (void*)out_ch_data
[c
],
627 outsiz
= outsiz
+ tsize
;
628 if (err
!= AUDIO_SUCCESS
) {
630 "%s: error decoding g721\n"),
638 } else if (Decode
== AUDIO_ENCODING_G723
) {
640 demux(3, cnt
/ File_hdr
.channels
);
641 for (c
= 0; c
< File_hdr
.channels
; c
++) {
642 err
= g723_decode(in_ch_data
[c
],
643 cnt
/ File_hdr
.channels
,
645 (void*)out_ch_data
[c
],
648 outsiz
= outsiz
+ tsize
;
649 if (err
!= AUDIO_SUCCESS
) {
651 "%s: error decoding g723\n"),
659 } else if (swapBytes
) {
660 swab((char *)inbuf
, outbuf
, cnt
);
663 /* If input EOF, write an eof marker */
664 err
= write(Audio_fd
, outbuf
, cnt
);
670 } else if (err
!= cnt
) {
672 MGET("%s: output error: "), prog
);
680 /* Move remainder to the front of the buffer */
682 (void *)memcpy(inbuf
, inbuf
+ cnt
, rem
);
687 Error(stderr
, MGET("%s: error reading "), prog
);
691 } else { /* We're mmaped */
692 if ((Decode
!= AUDIO_ENCODING_NONE
) || swapBytes
) {
694 /* Transform data if we have to. */
695 for (i
= 0; i
<= len
; i
+= cnt
) {
697 if ((i
+ cnt
) > len
) {
700 if (Decode
== AUDIO_ENCODING_G721
) {
702 demux(1, cnt
/ File_hdr
.channels
);
703 for (c
= 0; c
< File_hdr
.channels
;
707 cnt
/ File_hdr
.channels
,
709 (void*)out_ch_data
[c
],
712 outsiz
= outsiz
+ tsize
;
713 if (err
!= AUDIO_SUCCESS
) {
715 "%s: error decoding "
723 (Decode
== AUDIO_ENCODING_G723
) {
726 cnt
/ File_hdr
.channels
);
728 c
< File_hdr
.channels
;
735 (void*)out_ch_data
[c
],
738 outsiz
= outsiz
+ tsize
;
739 if (err
!= AUDIO_SUCCESS
) {
749 } else if (swapBytes
) {
750 swab((char *)inbuf
, outbuf
,
756 /* If input EOF, write an eof marker */
757 err
= write(Audio_fd
, (char *)outbuf
,
762 } else if (outsiz
== 0) {
768 /* write the whole thing at once! */
769 err
= write(Audio_fd
, inbuf
, len
);
776 MGET("%s: output error: "), prog
);
780 err
= write(Audio_fd
, inbuf
, 0);
788 /* Free memory if decoding ADPCM */
790 case AUDIO_ENCODING_G721
:
791 case AUDIO_ENCODING_G723
:
800 (void) munmap(mapaddr
, st
.st_size
);
801 (void) close(ifd
); /* close input file */
804 audio_set_play_error(Audio_fd
, (unsigned int *)&cnt
);
807 MGET("%s: output underflow in %s\n"),
813 } while ((argc
> 0) && (argc
--, (Ifile
= *argv
++) != NULL
));
816 * Though drain is implicit on close(), it's performed here
817 * to ensure that the volume is reset after all output is complete.
819 (void) audio_drain(Audio_fd
, FALSE
);
821 /* Flush any remaining audio */
822 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
824 if (Volume
!= INT_MAX
)
825 (void) audio_set_play_gain(Audio_fd
, &Savevol
);
826 if ((Audio_ctlfd
>= 0) && (audio_cmp_hdr(&Save_hdr
, &Dev_hdr
) != 0)) {
827 (void) audio_set_play_config(Audio_fd
, &Save_hdr
);
829 (void) close(Audio_fd
); /* close output */
830 return (errorStatus
);
835 * Try to reconfigure the audio device to match the file encoding.
836 * If this fails, we should attempt to make the input data match the
837 * device encoding. For now, we give up on this file.
839 * Returns TRUE if successful. Returns FALSE if not.
845 char msg
[AUDIO_MAX_ENCODE_INFO
];
848 err
= audio_set_play_config(Audio_fd
, &Dev_hdr
);
854 case AUDIO_ERR_NOEFFECT
:
856 * Couldn't change the device.
857 * Check to see if we're nearly compatible.
858 * audio_cmp_hdr() returns >0 if only sample rate difference.
860 if (audio_cmp_hdr(&Dev_hdr
, &File_hdr
) > 0) {
863 ratio
= (double)abs((int)
864 (Dev_hdr
.sample_rate
- File_hdr
.sample_rate
)) /
865 (double)File_hdr
.sample_rate
;
866 if (ratio
<= SAMPLE_RATE_THRESHOLD
) {
869 MGET("%s: WARNING: %s sampled at "
870 "%d, playing at %d\n"),
871 prog
, Ifile
, File_hdr
.sample_rate
,
872 Dev_hdr
.sample_rate
);
877 MGET("%s: %s sample rate %d not available\n"),
878 prog
, Ifile
, File_hdr
.sample_rate
);
881 (void) audio_enc_to_str(&File_hdr
, msg
);
882 Error(stderr
, MGET("%s: %s encoding not available: %s\n"),
888 MGET("%s: %s audio encoding type not available\n"),
896 /* Parse an unsigned integer */
898 parse_unsigned(char *str
, unsigned *dst
, char *flag
)
902 if (sscanf(str
, "%u%c", dst
, &x
) != 1) {
903 Error(stderr
, MGET("%s: invalid value for %s\n"), prog
, flag
);
910 * Search for fname in path and open. Ignore path not opened O_RDONLY.
911 * Note: in general path can be a list of ':' separated paths to search
915 path_open(char *fname
, int flags
, mode_t mode
, char *path
)
917 char fullpath
[MAXPATHLEN
]; /* full path of file */
918 char *buf
; /* malloc off the tmp buff */
922 if (!fname
) { /* bogus */
927 * cases where we don't bother checking path:
929 * - file not opened O_RDONLY
930 * - not a relative path (i.e. starts with /, ./, or ../).
933 if ((!path
) || (flags
!= O_RDONLY
) || (*fname
== '/') ||
934 (strncmp(fname
, "./", strlen("./")) == 0) ||
935 (strncmp(fname
, "../", strlen("../")) == 0)) {
936 return (open(fname
, flags
, mode
));
940 * Malloc off a buffer to hold the path variable.
941 * This is NOT limited to MAXPATHLEN characters as
942 * it may contain multiple paths.
944 buf
= malloc(strlen(path
) + 1);
947 * if first character is ':', but not the one following it,
948 * skip over it - or it'll be interpreted as "./". it's OK
949 * to have "::" since that does mean "./".
952 if ((path
[0] == ':') && (path
[1] != ':')) {
953 (void) strncpy(buf
, path
+1, strlen(path
));
955 (void) strncpy(buf
, path
, strlen(path
));
958 for (path
= buf
; path
&& *path
; ) {
959 if (cp
= strchr(path
, ':')) {
960 *cp
++ = '\0'; /* now pts to next path element */
963 /* the safest way to create the path string :-) */
965 (void) strncpy(fullpath
, path
, MAXPATHLEN
);
966 (void) strncat(fullpath
, "/", MAXPATHLEN
);
968 /* a NULL path element means "./" */
969 (void) strncpy(fullpath
, "./", MAXPATHLEN
);
971 (void) strncat(fullpath
, fname
, MAXPATHLEN
);
973 /* see if there's a match */
974 if (stat(fullpath
, &st
) >= 0) {
975 if (S_ISREG(st
.st_mode
)) {
979 MGET("%s: Found %s in path "
981 prog
, fname
, fullpath
);
983 return (open(fullpath
, flags
, mode
));
987 /* go on to the next one */
992 * if we fall through with no match, just do a normal file open
994 return (open(fname
, flags
, mode
));
1002 * Allocates memory for carrying out demultiplexing/multiplexing.
1005 * int unitsz Bytes per unit
1006 * int unitsp Samples per unit
1012 initmux(int unitsz
, int unitsp
)
1014 int c
; /* Channel */
1015 int in_ch_size
; /* Input channel size */
1017 /* Size of each input channel */
1018 in_ch_size
= insiz
/ File_hdr
.channels
;
1020 /* Size of each output channel */
1021 out_ch_size
= in_ch_size
* unitsp
/ unitsz
;
1023 /* Allocate pointers to input channels */
1024 in_ch_data
= malloc(sizeof (unsigned char *) * File_hdr
.channels
);
1026 if (in_ch_data
== NULL
) {
1027 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1028 prog
, sizeof (unsigned char *) * File_hdr
.channels
/ 1000);
1032 /* Allocate input channels */
1033 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1034 in_ch_data
[c
] = malloc(sizeof (unsigned char) * in_ch_size
);
1036 if (in_ch_data
[c
] == NULL
) {
1037 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1038 prog
, in_ch_size
/ 1000);
1043 /* Allocate pointers to output channels */
1044 out_ch_data
= malloc(sizeof (unsigned char *) * File_hdr
.channels
);
1046 if (out_ch_data
== NULL
) {
1047 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1048 prog
, sizeof (unsigned char *) * File_hdr
.channels
/ 1000);
1052 /* Allocate output channels */
1053 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1054 out_ch_data
[c
] = malloc(sizeof (unsigned char) * out_ch_size
);
1056 if (out_ch_data
[c
] == NULL
) {
1057 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1058 prog
, out_ch_size
/ 1000);
1068 * Split a multichannel signal into separate channels.
1071 * int unitsz Bytes per unit
1072 * int cnt Bytes to process
1078 demux(int unitsz
, int cnt
)
1080 int c
; /* Channel */
1083 int tp
; /* Pointer into current data */
1084 int dp
; /* Pointer into target data */
1087 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1088 for (s
= 0; s
< cnt
/ unitsz
; s
++) {
1090 dp
= (s
* File_hdr
.channels
+ c
) * unitsz
;
1091 for (b
= 0; b
< unitsz
; b
++) {
1092 in_ch_data
[c
][tp
+ b
] = inbuf
[dp
+ b
];
1102 * Combine separate channels to produce a multichannel signal.
1105 * char *outbuf Combined signal
1113 int c
; /* Channel */
1117 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1118 for (s
= 0; s
< out_ch_size
; s
++) {
1119 outbuf
[File_hdr
.channels
* s
+ c
] = out_ch_data
[c
][s
];
1128 * Free memory used in multiplexing/demultiplexing.
1139 int c
; /* Channel */
1142 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1143 free(in_ch_data
[c
]);
1144 free(out_ch_data
[c
]);
1145 free(&adpcm_state
[c
]);