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
,
420 if (err
!= AUDIO_SUCCESS
) {
422 MGET("%s: %s is not a valid audio file\n"),
428 /* If G.72X adpcm, set flags for conversion */
429 if ((File_hdr
.encoding
== AUDIO_ENCODING_G721
) &&
430 (File_hdr
.samples_per_unit
== 2) &&
431 (File_hdr
.bytes_per_unit
== 1)) {
432 Decode
= AUDIO_ENCODING_G721
;
433 File_hdr
.encoding
= AUDIO_ENCODING_ULAW
;
434 File_hdr
.samples_per_unit
= 1;
435 File_hdr
.bytes_per_unit
= 1;
436 adpcm_state
= (struct audio_g72x_state
*)malloc
437 (sizeof (*adpcm_state
) * File_hdr
.channels
);
438 for (i
= 0; i
< File_hdr
.channels
; i
++) {
439 g721_init_state(&adpcm_state
[i
]);
441 } else if ((File_hdr
.encoding
== AUDIO_ENCODING_G723
) &&
442 (File_hdr
.samples_per_unit
== 8) &&
443 (File_hdr
.bytes_per_unit
== 3)) {
444 Decode
= AUDIO_ENCODING_G723
;
445 File_hdr
.encoding
= AUDIO_ENCODING_ULAW
;
446 File_hdr
.samples_per_unit
= 1;
447 File_hdr
.bytes_per_unit
= 1;
448 adpcm_state
= (struct audio_g72x_state
*)malloc
449 (sizeof (*adpcm_state
) * File_hdr
.channels
);
450 for (i
= 0; i
< File_hdr
.channels
; i
++) {
451 g723_init_state(&adpcm_state
[i
]);
454 Decode
= AUDIO_ENCODING_NONE
;
457 /* Check the device configuration */
459 if (audio_cmp_hdr(&Dev_hdr
, &File_hdr
) != 0) {
461 * The device does not match the input file.
462 * Wait for any old output to drain, then attempt
463 * to reconfigure the audio device to match the
466 if (audio_drain(Audio_fd
, FALSE
) != AUDIO_SUCCESS
) {
467 /* Flush any remaining audio */
468 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
470 Error(stderr
, MGET("%s: "), prog
);
471 perror(MGET("AUDIO_DRAIN error"));
475 /* Flush any remaining audio */
476 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
485 /* try to do the mmaping - for regular files only ... */
486 err
= fstat(ifd
, &st
);
488 Error(stderr
, MGET("%s: cannot stat "), prog
);
492 regular
= (S_ISREG(st
.st_mode
));
495 /* If regular file, map it. Else, allocate a buffer */
499 * This should compare to MAP_FAILED not -1, can't
502 if (regular
&& ((mapaddr
= mmap(0, st
.st_size
, PROT_READ
,
503 MAP_SHARED
, ifd
, 0)) != MAP_FAILED
)) {
505 (void) madvise(mapaddr
, st
.st_size
, MADV_SEQUENTIAL
);
507 /* Skip the file header and set the proper size */
508 cnt
= lseek(ifd
, 0, SEEK_CUR
);
513 inbuf
= (unsigned char *) mapaddr
+ cnt
;
514 len
= cnt
= st
.st_size
- cnt
;
515 } else { /* Not a regular file, or map failed */
520 /* Allocate buffer to hold 10 seconds of data */
521 cnt
= BUFFER_LEN
* File_hdr
.sample_rate
*
522 File_hdr
.bytes_per_unit
* File_hdr
.channels
;
527 buf
= (unsigned char *) malloc(cnt
);
530 MGET("%s: couldn't allocate %dK "
531 "buf\n"), prog
, bufsiz
/ 1000);
539 /* Set buffer sizes and pointers for conversion, if any */
542 case AUDIO_ENCODING_NONE
:
544 outbuf
= (char *)buf
;
546 case AUDIO_ENCODING_G721
:
547 insiz
= ADPCM_SIZE
/ 2;
548 outbuf
= (char *)adpcm_buf
;
551 case AUDIO_ENCODING_G723
:
552 insiz
= (ADPCM_SIZE
* 3) / 8;
553 outbuf
= (char *)adpcm_buf
;
559 * 8-bit audio isn't a problem, however 16-bit audio is.
560 * If the file is an endian that is different from the machine
561 * then the bytes will need to be swapped.
563 * Note: Because the G.72X conversions produce 8bit output,
564 * they don't require a byte swap before display and so
565 * this scheme works just fine. If a conversion is added
566 * that produces a 16 bit result and therefore requires
567 * byte swapping before output, then a mechanism
568 * for chaining the two conversions will have to be built.
570 * Note: The following if() could be simplified, but then
571 * it gets to be very hard to read. So it's left as is.
574 if (File_hdr
.bytes_per_unit
== 2 &&
575 ((!NetEndian
&& file_type
== FILE_AIFF
) ||
576 (!NetEndian
&& file_type
== FILE_AU
) ||
577 (NetEndian
&& file_type
== FILE_WAV
))) {
584 /* Read in interal number of sample frames. */
585 frame
= File_hdr
.bytes_per_unit
* File_hdr
.channels
;
586 insiz
= (SWAP_SIZE
/ frame
) * frame
;
587 /* make the output buffer the swap buffer. */
588 outbuf
= (char *)swap_buf
;
592 * At this point, we're all ready to copy the data.
594 if (mapaddr
== 0) { /* Not mmapped, do it a buffer at a time. */
596 frame
= File_hdr
.bytes_per_unit
* File_hdr
.channels
;
598 while ((cnt
= read(ifd
, inbuf
+rem
, insiz
-rem
)) >= 0) {
600 * We need to ensure only an integral number of
601 * samples is ever written to the audio device.
608 * If decoding adpcm, or swapping bytes do it
611 * We treat the swapping like a separate
612 * encoding here because the G.72X encodings
613 * decode to single byte output samples. If
614 * another encoding is added and it produces
615 * multi-byte output samples this will have to
618 if (Decode
== AUDIO_ENCODING_G721
) {
620 demux(1, cnt
/ File_hdr
.channels
);
621 for (c
= 0; c
< File_hdr
.channels
; c
++) {
622 err
= g721_decode(in_ch_data
[c
],
623 cnt
/ File_hdr
.channels
,
625 (void*)out_ch_data
[c
],
628 outsiz
= outsiz
+ tsize
;
629 if (err
!= AUDIO_SUCCESS
) {
631 "%s: error decoding g721\n"),
639 } else if (Decode
== AUDIO_ENCODING_G723
) {
641 demux(3, cnt
/ File_hdr
.channels
);
642 for (c
= 0; c
< File_hdr
.channels
; c
++) {
643 err
= g723_decode(in_ch_data
[c
],
644 cnt
/ File_hdr
.channels
,
646 (void*)out_ch_data
[c
],
649 outsiz
= outsiz
+ tsize
;
650 if (err
!= AUDIO_SUCCESS
) {
652 "%s: error decoding g723\n"),
660 } else if (swapBytes
) {
661 swab((char *)inbuf
, outbuf
, cnt
);
664 /* If input EOF, write an eof marker */
665 err
= write(Audio_fd
, outbuf
, cnt
);
671 } else if (err
!= cnt
) {
673 MGET("%s: output error: "), prog
);
681 /* Move remainder to the front of the buffer */
683 (void *)memcpy(inbuf
, inbuf
+ cnt
, rem
);
688 Error(stderr
, MGET("%s: error reading "), prog
);
692 } else { /* We're mmaped */
693 if ((Decode
!= AUDIO_ENCODING_NONE
) || swapBytes
) {
695 /* Transform data if we have to. */
696 for (i
= 0; i
<= len
; i
+= cnt
) {
698 if ((i
+ cnt
) > len
) {
701 if (Decode
== AUDIO_ENCODING_G721
) {
703 demux(1, cnt
/ File_hdr
.channels
);
704 for (c
= 0; c
< File_hdr
.channels
;
708 cnt
/ File_hdr
.channels
,
710 (void*)out_ch_data
[c
],
713 outsiz
= outsiz
+ tsize
;
714 if (err
!= AUDIO_SUCCESS
) {
716 "%s: error decoding "
724 (Decode
== AUDIO_ENCODING_G723
) {
727 cnt
/ File_hdr
.channels
);
729 c
< File_hdr
.channels
;
736 (void*)out_ch_data
[c
],
739 outsiz
= outsiz
+ tsize
;
740 if (err
!= AUDIO_SUCCESS
) {
750 } else if (swapBytes
) {
751 swab((char *)inbuf
, outbuf
,
757 /* If input EOF, write an eof marker */
758 err
= write(Audio_fd
, (char *)outbuf
,
763 } else if (outsiz
== 0) {
769 /* write the whole thing at once! */
770 err
= write(Audio_fd
, inbuf
, len
);
777 MGET("%s: output error: "), prog
);
781 err
= write(Audio_fd
, inbuf
, 0);
789 /* Free memory if decoding ADPCM */
791 case AUDIO_ENCODING_G721
:
792 case AUDIO_ENCODING_G723
:
801 (void) munmap(mapaddr
, st
.st_size
);
802 (void) close(ifd
); /* close input file */
805 audio_set_play_error(Audio_fd
, (unsigned int *)&cnt
);
808 MGET("%s: output underflow in %s\n"),
814 } while ((argc
> 0) && (argc
--, (Ifile
= *argv
++) != NULL
));
817 * Though drain is implicit on close(), it's performed here
818 * to ensure that the volume is reset after all output is complete.
820 (void) audio_drain(Audio_fd
, FALSE
);
822 /* Flush any remaining audio */
823 (void) ioctl(Audio_fd
, I_FLUSH
, FLUSHW
);
825 if (Volume
!= INT_MAX
)
826 (void) audio_set_play_gain(Audio_fd
, &Savevol
);
827 if ((Audio_ctlfd
>= 0) && (audio_cmp_hdr(&Save_hdr
, &Dev_hdr
) != 0)) {
828 (void) audio_set_play_config(Audio_fd
, &Save_hdr
);
830 (void) close(Audio_fd
); /* close output */
831 return (errorStatus
);
836 * Try to reconfigure the audio device to match the file encoding.
837 * If this fails, we should attempt to make the input data match the
838 * device encoding. For now, we give up on this file.
840 * Returns TRUE if successful. Returns FALSE if not.
846 char msg
[AUDIO_MAX_ENCODE_INFO
];
849 err
= audio_set_play_config(Audio_fd
, &Dev_hdr
);
855 case AUDIO_ERR_NOEFFECT
:
857 * Couldn't change the device.
858 * Check to see if we're nearly compatible.
859 * audio_cmp_hdr() returns >0 if only sample rate difference.
861 if (audio_cmp_hdr(&Dev_hdr
, &File_hdr
) > 0) {
864 ratio
= (double)abs((int)
865 (Dev_hdr
.sample_rate
- File_hdr
.sample_rate
)) /
866 (double)File_hdr
.sample_rate
;
867 if (ratio
<= SAMPLE_RATE_THRESHOLD
) {
870 MGET("%s: WARNING: %s sampled at "
871 "%d, playing at %d\n"),
872 prog
, Ifile
, File_hdr
.sample_rate
,
873 Dev_hdr
.sample_rate
);
878 MGET("%s: %s sample rate %d not available\n"),
879 prog
, Ifile
, File_hdr
.sample_rate
);
882 (void) audio_enc_to_str(&File_hdr
, msg
);
883 Error(stderr
, MGET("%s: %s encoding not available: %s\n"),
889 MGET("%s: %s audio encoding type not available\n"),
897 /* Parse an unsigned integer */
899 parse_unsigned(char *str
, unsigned *dst
, char *flag
)
903 if (sscanf(str
, "%u%c", dst
, &x
) != 1) {
904 Error(stderr
, MGET("%s: invalid value for %s\n"), prog
, flag
);
911 * Search for fname in path and open. Ignore path not opened O_RDONLY.
912 * Note: in general path can be a list of ':' separated paths to search
916 path_open(char *fname
, int flags
, mode_t mode
, char *path
)
918 char fullpath
[MAXPATHLEN
]; /* full path of file */
919 char *buf
; /* malloc off the tmp buff */
923 if (!fname
) { /* bogus */
928 * cases where we don't bother checking path:
930 * - file not opened O_RDONLY
931 * - not a relative path (i.e. starts with /, ./, or ../).
934 if ((!path
) || (flags
!= O_RDONLY
) || (*fname
== '/') ||
935 (strncmp(fname
, "./", strlen("./")) == 0) ||
936 (strncmp(fname
, "../", strlen("../")) == 0)) {
937 return (open(fname
, flags
, mode
));
941 * Malloc off a buffer to hold the path variable.
942 * This is NOT limited to MAXPATHLEN characters as
943 * it may contain multiple paths.
945 buf
= malloc(strlen(path
) + 1);
948 * if first character is ':', but not the one following it,
949 * skip over it - or it'll be interpreted as "./". it's OK
950 * to have "::" since that does mean "./".
953 if ((path
[0] == ':') && (path
[1] != ':')) {
954 (void) strncpy(buf
, path
+1, strlen(path
));
956 (void) strncpy(buf
, path
, strlen(path
));
959 for (path
= buf
; path
&& *path
; ) {
960 if (cp
= strchr(path
, ':')) {
961 *cp
++ = NULL
; /* now pts to next path element */
964 /* the safest way to create the path string :-) */
966 (void) strncpy(fullpath
, path
, MAXPATHLEN
);
967 (void) strncat(fullpath
, "/", MAXPATHLEN
);
969 /* a NULL path element means "./" */
970 (void) strncpy(fullpath
, "./", MAXPATHLEN
);
972 (void) strncat(fullpath
, fname
, MAXPATHLEN
);
974 /* see if there's a match */
975 if (stat(fullpath
, &st
) >= 0) {
976 if (S_ISREG(st
.st_mode
)) {
980 MGET("%s: Found %s in path "
982 prog
, fname
, fullpath
);
984 return (open(fullpath
, flags
, mode
));
988 /* go on to the next one */
993 * if we fall through with no match, just do a normal file open
995 return (open(fname
, flags
, mode
));
1003 * Allocates memory for carrying out demultiplexing/multiplexing.
1006 * int unitsz Bytes per unit
1007 * int unitsp Samples per unit
1013 initmux(int unitsz
, int unitsp
)
1015 int c
; /* Channel */
1016 int in_ch_size
; /* Input channel size */
1018 /* Size of each input channel */
1019 in_ch_size
= insiz
/ File_hdr
.channels
;
1021 /* Size of each output channel */
1022 out_ch_size
= in_ch_size
* unitsp
/ unitsz
;
1024 /* Allocate pointers to input channels */
1025 in_ch_data
= malloc(sizeof (unsigned char *) * File_hdr
.channels
);
1027 if (in_ch_data
== NULL
) {
1028 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1029 prog
, sizeof (unsigned char *) * File_hdr
.channels
/ 1000);
1033 /* Allocate input channels */
1034 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1035 in_ch_data
[c
] = malloc(sizeof (unsigned char) * in_ch_size
);
1037 if (in_ch_data
[c
] == NULL
) {
1038 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1039 prog
, in_ch_size
/ 1000);
1044 /* Allocate pointers to output channels */
1045 out_ch_data
= malloc(sizeof (unsigned char *) * File_hdr
.channels
);
1047 if (out_ch_data
== NULL
) {
1048 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1049 prog
, sizeof (unsigned char *) * File_hdr
.channels
/ 1000);
1053 /* Allocate output channels */
1054 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1055 out_ch_data
[c
] = malloc(sizeof (unsigned char) * out_ch_size
);
1057 if (out_ch_data
[c
] == NULL
) {
1058 Error(stderr
, MGET("%s: couldn't allocate %dK buf\n"),
1059 prog
, out_ch_size
/ 1000);
1069 * Split a multichannel signal into separate channels.
1072 * int unitsz Bytes per unit
1073 * int cnt Bytes to process
1079 demux(int unitsz
, int cnt
)
1081 int c
; /* Channel */
1084 int tp
; /* Pointer into current data */
1085 int dp
; /* Pointer into target data */
1088 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1089 for (s
= 0; s
< cnt
/ unitsz
; s
++) {
1091 dp
= (s
* File_hdr
.channels
+ c
) * unitsz
;
1092 for (b
= 0; b
< unitsz
; b
++) {
1093 in_ch_data
[c
][tp
+ b
] = inbuf
[dp
+ b
];
1103 * Combine separate channels to produce a multichannel signal.
1106 * char *outbuf Combined signal
1114 int c
; /* Channel */
1118 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1119 for (s
= 0; s
< out_ch_size
; s
++) {
1120 outbuf
[File_hdr
.channels
* s
+ c
] = out_ch_data
[c
][s
];
1129 * Free memory used in multiplexing/demultiplexing.
1140 int c
; /* Channel */
1143 for (c
= 0; c
< File_hdr
.channels
; c
++) {
1144 free(in_ch_data
[c
]);
1145 free(out_ch_data
[c
]);
1146 free(&adpcm_state
[c
]);