#include <stdlib.h>
#include <memory.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <libintl.h>
#include <math.h>
#include <libaudio_impl.h>
#define ROUND_DBL(x) (((x) + 7) & ~7)
#define HEADER_BUFFER 100
#define _MGET_(str) (char *)dgettext(TEXT_DOMAIN, str)
static int audio_encode_aiff(Audio_hdr *, unsigned char *, unsigned int *);
static int audio_encode_au(Audio_hdr *, char *, unsigned int,
unsigned char *, unsigned int *);
static int audio_encode_wav(Audio_hdr *, unsigned char *, unsigned int *);
static double convert_from_ieee_extended(unsigned char *);
static void convert_to_ieee_extended(double, unsigned char *);
int
audio_write_filehdr(int fd, Audio_hdr *hdrp, int file_type, char *infop,
unsigned int ilen)
{
int err;
unsigned blen;
unsigned char *buf;
blen = HEADER_BUFFER + (infop ? ilen : 0) + 4;
blen = ROUND_DBL(blen);
if (!(buf = (unsigned char *)calloc(1, blen))) {
return (AUDIO_UNIXERROR);
}
switch (file_type) {
case FILE_AU:
err = audio_encode_au(hdrp, infop, ilen, buf, &blen);
break;
case FILE_WAV:
err = audio_encode_wav(hdrp, buf, &blen);
break;
case FILE_AIFF:
err = audio_encode_aiff(hdrp, buf, &blen);
break;
default:
return (AUDIO_ERR_BADFILETYPE);
}
if (err != AUDIO_SUCCESS) {
return (err);
}
err = write(fd, (char *)buf, (int)blen);
(void) free((char *)buf);
if (err != blen)
return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
return (AUDIO_SUCCESS);
}
static int
audio_rewrite_aiff_filesize(int fd, unsigned int size, unsigned int channels,
unsigned int bytes_per_sample)
{
unsigned int offset;
unsigned int tmp_uint;
unsigned int tmp_uint2;
unsigned int total_size;
total_size = size + sizeof (aiff_hdr_chunk_t) +
AUDIO_AIFF_COMM_CHUNK_SIZE + sizeof (aiff_ssnd_chunk_t);
tmp_uint = total_size - (2 * sizeof (int));
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
offset = sizeof (int);
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
return (AUDIO_ERR_NOEFFECT);
}
tmp_uint = size / channels / bytes_per_sample;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
offset = sizeof (aiff_hdr_chunk_t) + (2 * sizeof (int)) +
sizeof (short);
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
return (AUDIO_ERR_NOEFFECT);
}
tmp_uint = size + sizeof (aiff_ssnd_chunk_t) - (2 * sizeof (int));
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
offset = sizeof (aiff_hdr_chunk_t) + AUDIO_AIFF_COMM_CHUNK_SIZE +
sizeof (int);
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
if (write(fd, &tmp_uint2, sizeof (tmp_uint2)) != sizeof (tmp_uint2)) {
return (AUDIO_ERR_NOEFFECT);
}
return (AUDIO_SUCCESS);
}
static int
audio_rewrite_au_filesize(int fd, unsigned int size)
{
au_filehdr_t fhdr;
int err;
int data;
int offset;
offset = (char *)&fhdr.au_data_size - (char *)&fhdr;
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
AUDIO_AU_HOST2FILE(&size, &data);
err = write(fd, (char *)&data, sizeof (fhdr.au_data_size));
if (err != sizeof (fhdr.au_data_size))
return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
return (AUDIO_SUCCESS);
}
static int
audio_rewrite_wav_filesize(int fd, unsigned int size)
{
wav_filehdr_t fhdr;
int calc_size;
int err;
int data;
int offset;
calc_size = size + sizeof (fhdr) - sizeof (fhdr.wav_riff_ID) -
sizeof (fhdr.wav_riff_size);
AUDIO_WAV_HOST2FILE_INT(&calc_size, &data);
offset = (char *)&fhdr.wav_riff_size - (char *)&fhdr;
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
err = write(fd, (char *)&data, sizeof (fhdr.wav_riff_size));
if (err != sizeof (fhdr.wav_riff_size))
return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
AUDIO_WAV_HOST2FILE_INT(&size, &data);
offset = (char *)&fhdr.wav_data_size - (char *)&fhdr;
if (lseek(fd, offset, SEEK_SET) < 0) {
return (AUDIO_ERR_NOEFFECT);
}
err = write(fd, (char *)&data, sizeof (fhdr.wav_data_size));
if (err != sizeof (fhdr.wav_data_size))
return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
return (AUDIO_SUCCESS);
}
int
audio_rewrite_filesize(int fd, int file_type, unsigned int size,
unsigned int channels, unsigned int bytes_per_sample)
{
int fcntl_err;
fcntl_err = fcntl(fd, F_GETFL, 0);
if ((fcntl_err < 0) && ((errno == EOVERFLOW) || (errno == EINVAL))) {
perror("fcntl");
exit(1);
} else if ((lseek(fd, (off_t)0, SEEK_SET) < 0) ||
(fcntl_err & FAPPEND)) {
return (AUDIO_ERR_NOEFFECT);
}
switch (file_type) {
case FILE_AU:
return (audio_rewrite_au_filesize(fd, size));
case FILE_WAV:
return (audio_rewrite_wav_filesize(fd, size));
case FILE_AIFF:
return (audio_rewrite_aiff_filesize(fd, size, channels,
bytes_per_sample));
default:
return (AUDIO_ERR_BADFILETYPE);
}
}
int
audio_read_filehdr(int fd, Audio_hdr *hdrp, int *file_type, char *infop,
unsigned int ilen)
{
int err;
int dsize;
int isize;
unsigned resid;
unsigned char buf[HEADER_BUFFER];
struct stat st;
if ((err = audio_decode_filehdr(fd, buf, file_type, hdrp, &isize)) !=
AUDIO_SUCCESS) {
goto checkerror;
}
err = fstat(fd, &st);
if (err < 0) {
return (AUDIO_UNIXERROR);
}
if (*file_type == FILE_AU && hdrp->data_size != AUDIO_UNKNOWN_SIZE) {
if (S_ISREG(st.st_mode)) {
dsize = isize + hdrp->data_size + sizeof (au_filehdr_t);
if (st.st_size < dsize) {
(void) fprintf(stderr,
_MGET_("Warning: More audio data "
"than the file header specifies\n"));
} else if (st.st_size > dsize) {
(void) fprintf(stderr,
_MGET_("Warning: Less audio data "
"than the file header specifies\n"));
}
}
}
resid = isize;
if ((infop != NULL) && (ilen != 0)) {
if (isize > ilen)
isize = ilen;
err = read(fd, infop, (int)isize);
if (err != isize)
goto checkerror;
if (isize < ilen)
(void) memset(&infop[isize], '\0',
(int)(ilen - isize));
else
infop[ilen - 1] = '\0';
resid -= err;
}
if (resid != 0) {
if (S_ISREG(st.st_mode)) {
err = lseek(fd, (off_t)(resid - 1), SEEK_CUR);
if ((err < 0) ||
((err = read(fd, (char *)buf, 1)) != 1))
goto checkerror;
} else while (resid != 0) {
char junk[8192];
isize = (resid > sizeof (junk)) ?
sizeof (junk) : resid;
err = read(fd, junk, isize);
if (err != isize)
goto checkerror;
resid -= err;
}
}
return (AUDIO_SUCCESS);
checkerror:
if ((err < 0) && (errno == EOVERFLOW)) {
perror("read");
exit(1);
} else {
return ((err < 0) ? AUDIO_UNIXERROR : AUDIO_ERR_BADFILEHDR);
}
return (AUDIO_SUCCESS);
}
int
audio_isaudiofile(char *name)
{
int fd;
int err;
int file_type;
int isize;
Audio_hdr hdr;
unsigned char buf[sizeof (au_filehdr_t)];
fd = open(name, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
if (errno == EOVERFLOW) {
perror("open");
exit(1);
} else {
return (FALSE);
}
}
err = read(fd, (char *)buf, sizeof (buf));
if (err < 0) {
if (errno == EOVERFLOW) {
perror("open");
exit(1);
} else {
return (FALSE);
}
}
(void) close(fd);
if ((err == sizeof (buf)) &&
(audio_decode_filehdr(fd, buf, &file_type, &hdr, &isize) ==
AUDIO_SUCCESS)) {
return (hdr.encoding);
} else {
return (FALSE);
}
}
static int
audio_endian(unsigned char *buf, int *file_type)
{
unsigned int magic1;
unsigned int magic2;
(void) memcpy(&magic1, buf, sizeof (magic1));
magic2 = magic1;
SWABI(magic2);
if (magic1 == AUDIO_AU_FILE_MAGIC || magic2 == AUDIO_AU_FILE_MAGIC) {
*file_type = FILE_AU;
return (AUDIO_ENDIAN_BIG);
} else if (magic1 == AUDIO_WAV_RIFF_ID || magic2 == AUDIO_WAV_RIFF_ID) {
*file_type = FILE_WAV;
return (AUDIO_ENDIAN_SMALL);
} else if (magic1 == AUDIO_AIFF_HDR_CHUNK_ID ||
magic2 == AUDIO_AIFF_HDR_CHUNK_ID) {
*file_type = FILE_AIFF;
return (AUDIO_ENDIAN_BIG);
}
return (AUDIO_ENDIAN_UNKNOWN);
}
static int
decode_aiff(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
{
aiff_hdr_chunk_t hdr_chunk;
aiff_comm_chunk_t comm_chunk;
aiff_ssnd_chunk_t ssnd_chunk;
uint32_t ID;
uint32_t size;
uint32_t tmp;
int data_type;
int hdr_sizes;
int sr;
short bits_per_sample;
short channels;
size = sizeof (hdr_chunk) - sizeof (hdr_chunk.aiff_hdr_ID);
if (read(fd, &hdr_chunk.aiff_hdr_size, size) != size) {
return (AUDIO_UNIXERROR);
}
AUDIO_AIFF_FILE2HOST_INT(&hdr_chunk.aiff_hdr_data_type, &data_type);
if (data_type != AUDIO_AIFF_HDR_FORM_AIFF) {
return (AUDIO_ERR_BADFILEHDR);
}
hdr_sizes = sizeof (hdr_chunk);
while (read(fd, &tmp, sizeof (tmp)) == sizeof (tmp)) {
AUDIO_AIFF_FILE2HOST_INT(&tmp, &ID);
switch (ID) {
case AUDIO_AIFF_COMM_ID:
size = AUDIO_AIFF_COMM_CHUNK_SIZE -
sizeof (comm_chunk.aiff_comm_ID);
if (read(fd, &comm_chunk.aiff_comm_size, size) !=
size) {
return (AUDIO_UNIXERROR);
}
sr = convert_from_ieee_extended(
comm_chunk.aiff_comm_sample_rate);
hdr_sizes += AUDIO_AIFF_COMM_CHUNK_SIZE;
break;
case AUDIO_AIFF_SSND_ID:
size = sizeof (ssnd_chunk) -
sizeof (ssnd_chunk.aiff_ssnd_ID);
if (read(fd, &ssnd_chunk.aiff_ssnd_size, size) !=
size) {
return (AUDIO_UNIXERROR);
}
hdrp->sample_rate = sr;
AUDIO_AIFF_FILE2HOST_SHORT(
&comm_chunk.aiff_comm_channels,
&channels);
hdrp->channels = channels;
AUDIO_AIFF_FILE2HOST_SHORT(
&comm_chunk.aiff_comm_sample_size,
&bits_per_sample);
switch (bits_per_sample) {
case AUDIO_AIFF_COMM_8_BIT_SAMPLE_SIZE:
hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
break;
case AUDIO_AIFF_COMM_16_BIT_SAMPLE_SIZE:
hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
break;
default:
return (AUDIO_ERR_BADFILEHDR);
}
AUDIO_AIFF_FILE2HOST_INT(&ssnd_chunk.aiff_ssnd_size,
&size);
size -= sizeof (ssnd_chunk.aiff_ssnd_offset) +
sizeof (ssnd_chunk.aiff_ssnd_block_size);
hdrp->data_size = size;
hdr_sizes += sizeof (ssnd_chunk);
*isize = hdr_sizes - sizeof (au_filehdr_t);
return (AUDIO_SUCCESS);
default:
if (read(fd, &size, sizeof (size)) != sizeof (size)) {
return (AUDIO_UNIXERROR);
}
if (lseek(fd, size, SEEK_CUR) < 0) {
return (AUDIO_UNIXERROR);
}
break;
}
}
return (AUDIO_SUCCESS);
}
static int
decode_au(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize,
boolean_t read_info)
{
au_filehdr_t fhdr;
int offset;
int size;
if (read_info) {
size = sizeof (fhdr) - sizeof (int);
(void) lseek(fd, (off_t)4, SEEK_SET);
if (read(fd, &buf[sizeof (int)], size) != size) {
return (AUDIO_UNIXERROR);
}
}
(void) memcpy(&fhdr, buf, sizeof (fhdr));
AUDIO_AU_FILE2HOST(&fhdr.au_offset, &offset);
AUDIO_AU_FILE2HOST(&fhdr.au_data_size, &hdrp->data_size);
AUDIO_AU_FILE2HOST(&fhdr.au_encoding, &hdrp->encoding);
AUDIO_AU_FILE2HOST(&fhdr.au_sample_rate, &hdrp->sample_rate);
AUDIO_AU_FILE2HOST(&fhdr.au_channels, &hdrp->channels);
*isize = offset - sizeof (au_filehdr_t);
return (AUDIO_SUCCESS);
}
static int
decode_wav(int fd, unsigned char *buf, Audio_hdr *hdrp, int *isize)
{
wav_filehdr_t fhdr;
uint32_t ID;
uint32_t size;
short bits_per_sample;
short encoding;
size = sizeof (fhdr) - sizeof (int);
if (read(fd, &buf[sizeof (int)], size) != size) {
return (AUDIO_UNIXERROR);
}
(void) memcpy(&fhdr, buf, sizeof (fhdr));
AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_type_ID, &ID);
if (ID != AUDIO_WAV_TYPE_ID) {
return (AUDIO_ERR_BADFILEHDR);
}
AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_ID, &ID);
if (ID != AUDIO_WAV_FORMAT_ID) {
return (AUDIO_ERR_BADFILEHDR);
}
AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_encoding, &encoding);
AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_channels, &hdrp->channels);
AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_fmt_sample_rate, &hdrp->sample_rate);
AUDIO_WAV_FILE2HOST_SHORT(&fhdr.wav_fmt_bits_per_sample,
&bits_per_sample);
switch (encoding) {
case AUDIO_WAV_FMT_ENCODING_PCM:
switch (bits_per_sample) {
case AUDIO_WAV_FMT_BITS_PER_SAMPLE_8_BITS:
hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_8;
break;
case AUDIO_WAV_FMT_BITS_PER_SAMPLE_16_BITS:
hdrp->encoding = AUDIO_AU_ENCODING_LINEAR_16;
break;
default:
return (AUDIO_ERR_BADFILEHDR);
}
break;
case AUDIO_WAV_FMT_ENCODING_ALAW:
hdrp->encoding = AUDIO_AU_ENCODING_ALAW;
break;
case AUDIO_WAV_FMT_ENCODING_MULAW:
hdrp->encoding = AUDIO_AU_ENCODING_ULAW;
break;
default:
return (AUDIO_ERR_BADFILEHDR);
}
AUDIO_WAV_FILE2HOST_INT(&fhdr.wav_data_size, &hdrp->data_size);
*isize = sizeof (wav_filehdr_t) - sizeof (au_filehdr_t);
return (AUDIO_SUCCESS);
}
int
audio_decode_filehdr(int fd, unsigned char *buf, int *file_type,
Audio_hdr *hdrp, int *isize)
{
int err;
struct stat fd_stat;
boolean_t read_info;
hdrp->endian = audio_endian(buf, file_type);
if (fstat(fd, &fd_stat) < 0) {
return (AUDIO_ERR_BADFILEHDR);
}
if (S_ISFIFO(fd_stat.st_mode) && (*file_type == FILE_AU)) {
read_info = B_FALSE;
} else {
(void) lseek(fd, (off_t)0, SEEK_SET);
err = read(fd, (char *)buf, sizeof (int));
read_info = B_TRUE;
if ((hdrp->endian = audio_endian(buf, file_type)) ==
AUDIO_ENDIAN_UNKNOWN) {
return (AUDIO_ERR_BADFILEHDR);
}
}
switch (*file_type) {
case FILE_AU:
if ((err = decode_au(fd, buf, hdrp, isize, read_info)) !=
AUDIO_SUCCESS) {
return (err);
}
break;
case FILE_WAV:
if ((err = decode_wav(fd, buf, hdrp, isize)) != AUDIO_SUCCESS) {
return (err);
}
break;
case FILE_AIFF:
if ((err = decode_aiff(fd, buf, hdrp, isize)) !=
AUDIO_SUCCESS) {
return (err);
}
break;
default:
return (AUDIO_ERR_BADFILEHDR);
}
switch (hdrp->encoding) {
case AUDIO_AU_ENCODING_ULAW:
hdrp->encoding = AUDIO_ENCODING_ULAW;
hdrp->bytes_per_unit = 1;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_ALAW:
hdrp->encoding = AUDIO_ENCODING_ALAW;
hdrp->bytes_per_unit = 1;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_LINEAR_8:
if (*file_type == FILE_WAV) {
hdrp->encoding = AUDIO_ENCODING_LINEAR8;
} else {
hdrp->encoding = AUDIO_ENCODING_LINEAR;
}
hdrp->bytes_per_unit = 1;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_LINEAR_16:
hdrp->encoding = AUDIO_ENCODING_LINEAR;
hdrp->bytes_per_unit = 2;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_LINEAR_24:
hdrp->encoding = AUDIO_ENCODING_LINEAR;
hdrp->bytes_per_unit = 3;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_LINEAR_32:
hdrp->encoding = AUDIO_ENCODING_LINEAR;
hdrp->bytes_per_unit = 4;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_FLOAT:
hdrp->encoding = AUDIO_ENCODING_FLOAT;
hdrp->bytes_per_unit = 4;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_DOUBLE:
hdrp->encoding = AUDIO_ENCODING_FLOAT;
hdrp->bytes_per_unit = 8;
hdrp->samples_per_unit = 1;
break;
case AUDIO_AU_ENCODING_ADPCM_G721:
hdrp->encoding = AUDIO_ENCODING_G721;
hdrp->bytes_per_unit = 1;
hdrp->samples_per_unit = 2;
break;
case AUDIO_AU_ENCODING_ADPCM_G723_3:
hdrp->encoding = AUDIO_ENCODING_G723;
hdrp->bytes_per_unit = 3;
hdrp->samples_per_unit = 8;
break;
case AUDIO_AU_ENCODING_ADPCM_G723_5:
hdrp->encoding = AUDIO_ENCODING_G723;
hdrp->bytes_per_unit = 5;
hdrp->samples_per_unit = 8;
break;
default:
return (AUDIO_ERR_BADFILEHDR);
}
return (AUDIO_SUCCESS);
}
static int
audio_encode_aiff(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
{
aiff_comm_chunk_t comm_chunk;
aiff_hdr_chunk_t hdr_chunk;
aiff_ssnd_chunk_t ssnd_chunk;
uint32_t tmp_uint;
uint32_t tmp_uint2;
int buf_size = 0;
uint16_t tmp_ushort;
if (hdrp->encoding != AUDIO_ENCODING_LINEAR) {
return (AUDIO_ERR_ENCODING);
}
tmp_uint = AUDIO_AIFF_HDR_CHUNK_ID;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_ID);
tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_size);
tmp_uint = AUDIO_AIFF_HDR_FORM_AIFF;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &hdr_chunk.aiff_hdr_data_type);
(void) memcpy(&buf[buf_size], &hdr_chunk, sizeof (hdr_chunk));
buf_size += sizeof (hdr_chunk);
tmp_uint = AUDIO_AIFF_COMM_ID;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_ID);
tmp_uint = AUDIO_AIFF_COMM_SIZE;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &comm_chunk.aiff_comm_size);
tmp_ushort = hdrp->channels;
AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort, &comm_chunk.aiff_comm_channels);
tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &tmp_uint2);
AUDIO_AIFF_COMM_INT2FRAMES(comm_chunk.aiff_comm_frames, tmp_uint2);
tmp_ushort = hdrp->bytes_per_unit * 8;
AUDIO_AIFF_HOST2FILE_SHORT(&tmp_ushort,
&comm_chunk.aiff_comm_sample_size);
convert_to_ieee_extended((double)hdrp->sample_rate,
comm_chunk.aiff_comm_sample_rate);
(void) memcpy(&buf[buf_size], &comm_chunk, AUDIO_AIFF_COMM_CHUNK_SIZE);
buf_size += AUDIO_AIFF_COMM_CHUNK_SIZE;
tmp_uint = AUDIO_AIFF_SSND_ID;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_ID);
tmp_uint = AUDIO_AIFF_UNKNOWN_SIZE;
AUDIO_AIFF_HOST2FILE_INT(&tmp_uint, &ssnd_chunk.aiff_ssnd_size);
ssnd_chunk.aiff_ssnd_offset = 0;
ssnd_chunk.aiff_ssnd_block_size = 0;
(void) memcpy(&buf[buf_size], &ssnd_chunk, sizeof (ssnd_chunk));
buf_size += sizeof (ssnd_chunk);
*blen = buf_size;
return (AUDIO_SUCCESS);
}
static int
audio_encode_au(Audio_hdr *hdrp, char *infop, unsigned int ilen,
unsigned char *buf, unsigned int *blen)
{
au_filehdr_t fhdr;
int encoding;
int hdrsize;
int magic;
int offset;
if ((infop == NULL) || (ilen == 0)) {
infop = NULL;
ilen = 4;
}
hdrsize = sizeof (fhdr) + ilen;
offset = ROUND_DBL(hdrsize);
switch (hdrp->encoding) {
case AUDIO_ENCODING_LINEAR8:
return (AUDIO_ERR_ENCODING);
case AUDIO_ENCODING_ULAW:
if (hdrp->samples_per_unit != 1)
return (AUDIO_ERR_BADHDR);
switch (hdrp->bytes_per_unit) {
case 1:
encoding = AUDIO_AU_ENCODING_ULAW;
break;
default:
return (AUDIO_ERR_BADHDR);
}
break;
case AUDIO_ENCODING_ALAW:
if (hdrp->samples_per_unit != 1)
return (AUDIO_ERR_BADHDR);
switch (hdrp->bytes_per_unit) {
case 1:
encoding = AUDIO_AU_ENCODING_ALAW;
break;
default:
return (AUDIO_ERR_BADHDR);
}
break;
case AUDIO_ENCODING_LINEAR:
if (hdrp->samples_per_unit != 1)
return (AUDIO_ERR_BADHDR);
switch (hdrp->bytes_per_unit) {
case 1:
encoding = AUDIO_AU_ENCODING_LINEAR_8;
break;
case 2:
encoding = AUDIO_AU_ENCODING_LINEAR_16;
break;
case 3:
encoding = AUDIO_AU_ENCODING_LINEAR_24;
break;
case 4:
encoding = AUDIO_AU_ENCODING_LINEAR_32;
break;
default:
return (AUDIO_ERR_BADHDR);
}
break;
case AUDIO_ENCODING_FLOAT:
if (hdrp->samples_per_unit != 1)
return (AUDIO_ERR_BADHDR);
switch (hdrp->bytes_per_unit) {
case 4:
encoding = AUDIO_AU_ENCODING_FLOAT;
break;
case 8:
encoding = AUDIO_AU_ENCODING_DOUBLE;
break;
default:
return (AUDIO_ERR_BADHDR);
}
break;
case AUDIO_ENCODING_G721:
if (hdrp->bytes_per_unit != 1)
return (AUDIO_ERR_BADHDR);
else if (hdrp->samples_per_unit != 2)
return (AUDIO_ERR_BADHDR);
else
encoding = AUDIO_AU_ENCODING_ADPCM_G721;
break;
case AUDIO_ENCODING_G723:
if (hdrp->samples_per_unit != 8)
return (AUDIO_ERR_BADHDR);
else if (hdrp->bytes_per_unit == 3)
encoding = AUDIO_AU_ENCODING_ADPCM_G723_3;
else if (hdrp->bytes_per_unit == 5)
encoding = AUDIO_AU_ENCODING_ADPCM_G723_5;
else
return (AUDIO_ERR_BADHDR);
break;
default:
return (AUDIO_ERR_BADHDR);
}
if (*blen < offset) {
return (AUDIO_EOF);
}
*blen = (unsigned)offset;
magic = AUDIO_AU_FILE_MAGIC;
AUDIO_AU_HOST2FILE(&magic, &fhdr.au_magic);
AUDIO_AU_HOST2FILE(&offset, &fhdr.au_offset);
AUDIO_AU_HOST2FILE(&hdrp->data_size, &fhdr.au_data_size);
AUDIO_AU_HOST2FILE(&encoding, &fhdr.au_encoding);
AUDIO_AU_HOST2FILE(&hdrp->sample_rate, &fhdr.au_sample_rate);
AUDIO_AU_HOST2FILE(&hdrp->channels, &fhdr.au_channels);
(void) memcpy(buf, &fhdr, sizeof (fhdr));
if (infop != NULL) {
(void) memcpy(&buf[sizeof (fhdr)], infop, (int)ilen);
buf += ilen;
}
if (offset > hdrsize) {
(void) memset(&buf[hdrsize], '\0', (size_t)(offset - hdrsize));
}
return (AUDIO_SUCCESS);
}
static int
audio_encode_wav(Audio_hdr *hdrp, unsigned char *buf, unsigned int *blen)
{
wav_filehdr_t fhdr;
int bytes_per_second;
int bytes_per_sample;
int bits_per_sample;
int id;
int length;
int type;
short encoding;
switch (hdrp->encoding) {
case AUDIO_ENCODING_LINEAR8:
if (hdrp->bytes_per_unit != 1) {
return (AUDIO_ERR_ENCODING);
}
encoding = AUDIO_WAV_FMT_ENCODING_PCM;
break;
case AUDIO_ENCODING_ULAW:
if (hdrp->bytes_per_unit != 1) {
return (AUDIO_ERR_ENCODING);
}
encoding = AUDIO_WAV_FMT_ENCODING_MULAW;
break;
case AUDIO_ENCODING_ALAW:
if (hdrp->bytes_per_unit != 1) {
return (AUDIO_ERR_ENCODING);
}
encoding = AUDIO_WAV_FMT_ENCODING_ALAW;
break;
case AUDIO_ENCODING_LINEAR:
if (hdrp->bytes_per_unit != 2) {
return (AUDIO_ERR_ENCODING);
}
encoding = AUDIO_WAV_FMT_ENCODING_PCM;
break;
default:
return (AUDIO_ERR_ENCODING);
}
id = AUDIO_WAV_RIFF_ID;
length = AUDIO_WAV_UNKNOWN_SIZE;
AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_riff_ID);
AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_riff_size);
type = AUDIO_WAV_TYPE_ID;
AUDIO_WAV_HOST2FILE_INT(&type, &fhdr.wav_type_ID);
id = AUDIO_WAV_FORMAT_ID;
length = AUDIO_WAV_FORMAT_SIZE;
bytes_per_second = hdrp->sample_rate * hdrp->channels *
hdrp->bytes_per_unit;
bytes_per_sample = hdrp->channels * hdrp->bytes_per_unit;
bits_per_sample = hdrp->bytes_per_unit * 8;
AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_fmt_ID);
AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_fmt_size);
AUDIO_WAV_HOST2FILE_SHORT(&encoding, &fhdr.wav_fmt_encoding);
AUDIO_WAV_HOST2FILE_SHORT(&hdrp->channels, &fhdr.wav_fmt_channels);
AUDIO_WAV_HOST2FILE_INT(&hdrp->sample_rate, &fhdr.wav_fmt_sample_rate);
AUDIO_WAV_HOST2FILE_INT(&bytes_per_second,
&fhdr.wav_fmt_bytes_per_second);
AUDIO_WAV_HOST2FILE_SHORT(&bytes_per_sample,
&fhdr.wav_fmt_bytes_per_sample);
AUDIO_WAV_HOST2FILE_SHORT(&bits_per_sample,
&fhdr.wav_fmt_bits_per_sample);
id = AUDIO_WAV_DATA_ID_LC;
length = AUDIO_WAV_UNKNOWN_SIZE;
AUDIO_WAV_HOST2FILE_INT(&id, &fhdr.wav_data_ID);
AUDIO_WAV_HOST2FILE_INT(&length, &fhdr.wav_data_size);
*blen = sizeof (fhdr);
(void) memcpy(buf, &fhdr, sizeof (fhdr));
return (AUDIO_SUCCESS);
}
static double
convert_from_ieee_extended(unsigned char *data)
{
double value = 0.0;
unsigned long high_mantissa;
unsigned long low_mantissa;
int exponent;
exponent = ((data[0] & 0x7f) << 8) | data[1];
high_mantissa = ((unsigned long)data[2] << 24) |
((unsigned long)data[3] << 16) |
((unsigned long)data[4] << 8) |
(unsigned long)data[5];
low_mantissa = ((unsigned long)data[6] << 24) |
((unsigned long)data[7] << 16) |
((unsigned long)data[8] << 8) |
(unsigned long)data[9];
if (exponent == 0 && high_mantissa == 0 && low_mantissa == 0) {
value = 0.0;
} else {
if (exponent == 0x7fff) {
value = MAXFLOAT;
} else {
exponent -= 0x3fff;
exponent -= 31;
value = ldexp((double)high_mantissa, exponent);
exponent -= 32;
value += ldexp((double)low_mantissa, exponent);
}
}
return (value);
}
static void
convert_to_ieee_extended(double value, unsigned char *data)
{
double fmantissa;
int exponent;
int mantissa;
exponent = 16398;
fmantissa = value;
while (fmantissa < 44000) {
fmantissa *= 2;
exponent--;
}
mantissa = (int)fmantissa << 16;
data[0] = exponent >> 8;
data[1] = exponent;
data[2] = mantissa >> 24;
data[3] = mantissa >> 16;
data[4] = mantissa >> 8;
data[5] = mantissa;
data[6] = 0;
data[7] = 0;
data[8] = 0;
data[9] = 0;
}