1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
/*
* This file has been modified for the cdrkit suite.
*
* The behaviour and appearence of the program code below can differ to a major
* extent from the version distributed by the original author(s).
*
* For details, see Changelog file distributed with the cdrkit package. If you
* received this file from another source then ask the distributing person for
* a log of modifications.
*
*/
/* @(#)aiff.c 1.5 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */
/***
* CopyPolicy: GNU Public License 2 applies
* Copyright (C) by Heiko Eissfeldt
*
*
* ---------------------------------------------------------------------
* definitions for aiff pcm output
* ---------------------------------------------------------------------
*/
#include "config.h"
#include <stdio.h>
#include <unixstd.h>
#include <strdefs.h>
#include <standard.h>
#include <schily.h>
#include "mytype.h"
#include "byteorder.h"
#include "sndfile.h"
typedef UINT4 FOURCC; /* a four character code */
typedef struct CHUNKHDR {
FOURCC ckid; /* chunk ID */
UINT4 dwSize; /* chunk size */
} CHUNKHDR;
#define mmioFOURCC(ch0, ch1, ch2, ch3) \
((UINT4)(unsigned char)(ch3) | ((UINT4)(unsigned char)(ch2) << 8) | \
((UINT4)(unsigned char)(ch1) << 16) | ((UINT4)(unsigned char)(ch0) << 24))
#define FOURCC_FORM mmioFOURCC ('F', 'O', 'R', 'M')
#define FOURCC_AIFF mmioFOURCC ('A', 'I', 'F', 'F')
#define FOURCC_COMM mmioFOURCC ('C', 'O', 'M', 'M')
#define FOURCC_SSND mmioFOURCC ('S', 'S', 'N', 'D')
typedef struct AIFFHDR {
CHUNKHDR formChk;
FOURCC formType;
CHUNKHDR commChk; /* Common chunk */
/* from now on, alignment prevents us from using the original types :-(( */
unsigned char numChannels[2]; /* Audio Channels */
unsigned char numSampleFrames[4]; /* # of samples */
unsigned char samplesize[2]; /* bits per sample */
unsigned char sample_rate[10]; /* sample rate in extended float */
unsigned char ssndChkid[4]; /* Sound data chunk */
unsigned char dwSize[4]; /* size of chunk */
unsigned char offset[4]; /* start of 1st sample */
unsigned char blocksize[4]; /* aligned sound data block size */
} AIFFHDR;
static AIFFHDR AiffHdr;
/* Prototypes */
static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]);
static int InitSound(int audio, long channels, unsigned long rate,
long nBitsPerSample, unsigned long expected_bytes);
static int ExitSound(int audio, unsigned long nBytesDone);
static unsigned long GetHdrSize(void);
static unsigned long InSizeToOutSize(unsigned long BytesToDo);
/* format the sample rate into an
bigendian 10-byte IEEE-754 floating point number
*/
static int Format_samplerate(unsigned long rate, unsigned char the_rate[10])
{
int i;
/* normalize rate */
for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
if ((rate & 0x8000) != 0) {
break;
}
}
/* set exponent and sign */
the_rate[1] = 14-i;
the_rate[0] = 0x40; /* LSB = sign */
/* 16-bit part of mantisse for sample rate */
the_rate[3] = rate & 0xff;
the_rate[2] = (rate >> 8) & 0xff;
/* initialize lower digits of mantisse */
the_rate[4] = the_rate[5] = the_rate[6] =
the_rate[7] = the_rate[8] = the_rate[9] = 0;
return 0;
}
static int InitSound(int audio, long channels, unsigned long rate,
long nBitsPerSample, unsigned long expected_bytes)
{
UINT4 tmp;
fillbytes(&AiffHdr, sizeof(AiffHdr), '\0');
AiffHdr.formChk.ckid = cpu_to_be32(FOURCC_FORM);
AiffHdr.formChk.dwSize= cpu_to_be32(expected_bytes +
offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize)
- offsetof(AIFFHDR,formType));
AiffHdr.formType = cpu_to_be32(FOURCC_AIFF);
AiffHdr.commChk.ckid = cpu_to_be32(FOURCC_COMM);
AiffHdr.commChk.dwSize= cpu_to_be32(offset_of(AIFFHDR,ssndChkid)
- offset_of(AIFFHDR,numChannels));
AiffHdr.numChannels[1]= channels;
tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8)));
AiffHdr.numSampleFrames[0] = tmp >> 24;
AiffHdr.numSampleFrames[1] = tmp >> 16;
AiffHdr.numSampleFrames[2] = tmp >> 8;
AiffHdr.numSampleFrames[3] = tmp >> 0;
AiffHdr.samplesize[1] = nBitsPerSample;
Format_samplerate(rate, AiffHdr.sample_rate);
memcpy(AiffHdr.ssndChkid, "SSND", 4);
tmp = cpu_to_be32(expected_bytes + offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize) - offset_of(AIFFHDR, offset));
AiffHdr.dwSize[0] = tmp >> 24;
AiffHdr.dwSize[1] = tmp >> 16;
AiffHdr.dwSize[2] = tmp >> 8;
AiffHdr.dwSize[3] = tmp >> 0;
return write (audio, &AiffHdr, sizeof (AiffHdr));
}
static int ExitSound(int audio, unsigned long nBytesDone )
{
UINT4 tmp;
AiffHdr.formChk.dwSize= cpu_to_be32(nBytesDone + sizeof(AIFFHDR)
- offsetof(AIFFHDR,commChk));
tmp = cpu_to_be32(nBytesDone/(
AiffHdr.numChannels[1] * AiffHdr.samplesize[1]/ULONG_C(8)));
AiffHdr.numSampleFrames[0] = tmp >> 24;
AiffHdr.numSampleFrames[1] = tmp >> 16;
AiffHdr.numSampleFrames[2] = tmp >> 8;
AiffHdr.numSampleFrames[3] = tmp >> 0;
/* If an odd number of bytes has been written,
extend the chunk with one dummy byte. This is a requirement for AIFF. */
if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) {
return 0;
}
/* goto beginning */
if (lseek(audio, 0L, SEEK_SET) == -1) {
return 0;
}
return write (audio, &AiffHdr, sizeof (AiffHdr));
}
static unsigned long GetHdrSize()
{
return sizeof( AiffHdr );
}
static unsigned long InSizeToOutSize(unsigned long BytesToDo)
{
return BytesToDo;
}
struct soundfile aiffsound =
{
InitSound, /* init header method */
ExitSound, /* exit header method */
GetHdrSize, /* report header size method */
/* get sound samples out */
(int (*)(int audio, unsigned char *buf, unsigned long BytesToDo))write,
InSizeToOutSize, /* compressed? output file size */
1 /* needs big endian samples */
};
|