/* * 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 #include #include #include #include #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 */ };