Example #1
0
long audiofile_header_extractor(FILE *inputfile, float *SR, unsigned int *nbchan, unsigned int *depth, unsigned char *isfloat, unsigned char *isbigendian, unsigned int *frames)
{
    unsigned char FileHead[12], WavTemp[8], *aChunk, AIFCflag;
    unsigned int n;
    long index = -1;
    
    // checks the file is a legit AIFF or WAV by importing the header
    fread(FileHead, 1, 12, inputfile);
    
    //selects aiff or aifc
    if (strncmp((char *)FileHead, "FORM", 4) == 0)
    {
        //check if 'only' an AIFF
        if (strncmp((char *)FileHead+8, "AIFF", 4) == 0)
            AIFCflag = 0;
        else if (strncmp((char *)FileHead+8, "AIFC", 4) == 0)
            AIFCflag = 1;
        else
        {
            //            printf("this is an unknown AIFx\r");
            return -1;
        }
        
        //check for the different headers and size
        while(fread(WavTemp, 1, 8, inputfile))
        {
            n = (unsigned int)WavTemp[4]<<24 | (unsigned int)WavTemp[5]<<16 | (unsigned int)WavTemp[6]<<8 | (unsigned int)WavTemp[7];
            //the version header
            if (strncmp((char *)WavTemp, "FVER", 4) == 0)
            {
                aChunk = malloc(n);
                fread(aChunk, 1, n, inputfile);
                n = (unsigned int)aChunk[0]<<24 | (unsigned int)aChunk[1]<<16 | (unsigned int)aChunk[2]<<8 | (unsigned int)aChunk[3];
                if (n != 0xA2805140)
                {
                    //                   printf("wrong version of AIFC\r");
                    free(aChunk);
                    return -2;
                }
                free(aChunk);
            }
            // the common header
            else if (strncmp((char *)WavTemp, "COMM", 4) == 0)
            {
                aChunk = malloc(n);
                fread(aChunk, 1, n, inputfile);
                
                *nbchan = (unsigned int)aChunk[0]<<8 | (unsigned int)aChunk[1];
                *depth = ((unsigned int)aChunk[6]<<8 | (unsigned int)aChunk[7]) / 8;
                *isfloat = 0; // in case of AIFF
                *isbigendian = 1; // in case of AIFF
                
                *frames = (unsigned int)aChunk[2]<<24 | (unsigned int)aChunk[3]<<16 | (unsigned int)aChunk[4]<<8 | (unsigned int)aChunk[5];
                //type of compression accepted (none or float32)
                // if aifc it can be float
                if (AIFCflag)
                {
                    if (strncmp((char *)aChunk+18, "NONE", 4) == 0)
                        *isfloat = 0;//could do nothing here but gotta keep the place neet.
                    else if (strncmp((char *)aChunk+18, "sowt", 4) == 0)
                        *isbigendian = 0;//the few little endian cases
                    else if (strncmp((char *)aChunk+18, "fl32", 4) == 0 || strncmp((char *)aChunk+18, "FL32", 4) == 0)
                        *isfloat = 1;
                    else
                    {
                        //                       printf("neither PCM-int or FL32 AIFC\r");
                        free(aChunk);
                        return -3;
                    }
                }
                
                // converts the sampling rate 80bit to double
                // tried with http://blogs.perl.org/users/rurban/2012/09/reading-binary-floating-point-numbers-numbers-part2.html but was not working. Found the old apple conversion routine
                *SR = _af_convert_from_ieee_extended((unsigned char *)aChunk+8);
                
                free(aChunk);
            }
            else if (strncmp((char *)WavTemp, "SSND", 4) == 0)
            {
                index = ftell(inputfile) + 8;// pass the index where the audio frames start (offset of 8 because of unused (unsigned long)offset + blockSize)
                fseek(inputfile, n, SEEK_CUR);
            }
            else
                // jumps the chunk
                fseek(inputfile, n, SEEK_CUR);
        }
        if (!frames)
        {
            //           printf("no data\r");
            return -4;
        }
    }
    // OR checks the file is a legit WAV and process
    else if (strncmp((char *)FileHead, "RIF", 3) == 0)
    {
        if (FileHead[3] == 'F')
            *isbigendian = 0;
        else if (FileHead[3] == 'X')
            *isbigendian = 1;//the very rare RIFX files
        else
        {
            //            printf("NoWAVE-at-all\r");
            return -5;
        }
        
        if (strncmp((char *)FileHead+8, "WAVE", 4))
        {
            //            printf("NoWAVE\r");
            return -6;
        }
        
        // check the different parameters
        // imports the first chunk + the header of the 2nd
        fread(WavTemp, 1, 8, inputfile);
        
        //check proper header
        if (strncmp((char *)WavTemp, "fmt ", 4))
        {
            //            printf("NoFMT\r");
            return -7;
        }
        
        n = (unsigned int)WavTemp[7]<<24 | (unsigned int)WavTemp[6]<<16 | (unsigned int)WavTemp[5]<<8 | (unsigned int)WavTemp[4];
        
        // import the rest of the format chunk
        aChunk= malloc(n);
        fread(aChunk, 1, n, inputfile);
        
        //check if PCM or float
        if (aChunk[1]== 0)
        {
            //safety check the datachunk
            //transfer useful data from the chunk
            *nbchan = (unsigned int)aChunk[3]<<8 | (unsigned int)aChunk[2];
            *SR = (double)((unsigned int)aChunk[7]<<24 | (unsigned int)aChunk[6]<<16 | (unsigned int)aChunk[5]<<8 | (unsigned int)aChunk[4]);
            *depth = ((unsigned int)aChunk[15]<<8 | (unsigned int)aChunk[14]) / 8;
            free(aChunk);
            
            // IF PCM or FLOAT
            if (aChunk[0] == 1)
                *isfloat = 0;
            // IF FLOAT
            else if (aChunk[0] == 3)
                *isfloat = 1;
            else
            {
                //                printf("NoINTofFLOAT\r");
                return -8;
            }
            
            while(fread(WavTemp, 1, 8, inputfile))
            {
                n = (unsigned int)WavTemp[7]<<24 | (unsigned int)WavTemp[6]<<16 | (unsigned int)WavTemp[5]<<8 | (unsigned int)WavTemp[4];
                //looking for the data header
                if (strncmp((char *)WavTemp, "data", 4) == 0)
                {
                    *frames = ((unsigned int)WavTemp[7]<<24 | (unsigned int)WavTemp[6]<<16 | (unsigned int)WavTemp[5]<<8 | (unsigned int)WavTemp[4]) / *depth / *nbchan;
                    index = ftell(inputfile);// sets the index where the sound frames start
                    fseek(inputfile, n, SEEK_CUR);
                }
                else
                    fseek(inputfile, n, SEEK_CUR);
            }
            
            if (!frames)
            {
                //                printf("no data\r");
                return -9;
            }
            
        }
        else
        {
            //            printf("NoPCM\r");
            free(aChunk);
            return -8;
        }
    }
    else
    {
        // OR discarts
        //        printf("Not a supported filetype\r");
        return -10;
    }
    return index;
}
Example #2
0
/*
	Parse common data chunks, which contain information regarding the
	sampling rate, the number of sample frames, and the number of
	sound channels.
*/
static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
	size_t size)
{
	_Track		*track;
	u_int16_t	numChannels;
	u_int32_t	numSampleFrames;
	u_int16_t	sampleSize;
	unsigned char	sampleRate[10];

	assert(!memcmp(&type, "COMM", 4));

	track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);

	af_fread(&numChannels, sizeof (u_int16_t), 1, fh);
	track->f.channelCount = BENDIAN_TO_HOST_INT16(numChannels);

	af_fread(&numSampleFrames, sizeof (u_int32_t), 1, fh);
	track->totalfframes = BENDIAN_TO_HOST_INT32(numSampleFrames);

	af_fread(&sampleSize, sizeof (u_int16_t), 1, fh);
	track->f.sampleWidth = BENDIAN_TO_HOST_INT16(sampleSize);

	af_fread(sampleRate, 10, 1, fh);
	track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate);

	track->f.compressionType = AF_COMPRESSION_NONE;
	track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
	track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;

	if (file->fileFormat == AF_FILE_AIFFC)
	{
		u_int8_t	compressionID[4];
		/* Pascal strings are at most 255 bytes long. */
		unsigned char	compressionName[256];
		unsigned char	compressionNameLength;

		af_fread(compressionID, 4, 1, fh);

		/* Read the Pascal-style string containing the name. */
		af_fread(&compressionNameLength, 1, 1, fh);
		af_fread(compressionName, compressionNameLength, 1, fh);
		compressionName[compressionNameLength] = '\0';

		if (!memcmp(compressionID, "NONE", 4))
			track->f.compressionType = AF_COMPRESSION_NONE;
		else if (!memcmp(compressionID, "ACE2", 4) ||
			!memcmp(compressionID, "ACE8", 4) ||
			!memcmp(compressionID, "MAC3", 4) ||
			!memcmp(compressionID, "MAC6", 4))
		{
			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName);
			return AF_FAIL;
		}
		else if (!memcmp(compressionID, "ulaw", 4) ||
			!memcmp(compressionID, "ULAW", 4))
		{
			track->f.compressionType = AF_COMPRESSION_G711_ULAW;
		}
		else if (!memcmp(compressionID, "alaw", 4) ||
			!memcmp(compressionID, "ALAW", 4))
		{
			track->f.compressionType = AF_COMPRESSION_G711_ALAW;
		}
		else if (!memcmp(compressionID, "fl32", 4) ||
			!memcmp(compressionID, "FL32", 4))
		{
			track->f.sampleFormat = AF_SAMPFMT_FLOAT;
			track->f.sampleWidth = 32;
			track->f.compressionType = AF_COMPRESSION_NONE;
		}
		else if (!memcmp(compressionID, "fl64", 4) ||
			!memcmp(compressionID, "FL64", 4))
		{
			track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
			track->f.sampleWidth = 64;
			track->f.compressionType = AF_COMPRESSION_NONE;
		}
		else if (!memcmp(compressionID, "sowt", 4))
		{
			track->f.compressionType = AF_COMPRESSION_NONE;
			track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
		}
		else
		{
			_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%c%c%c%c' not currently supported",
				compressionID[0],
				compressionID[1],
				compressionID[2],
				compressionID[3]);
			return AF_FAIL;
		}
	}

	_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);

	return AF_SUCCEED;
}