/*--------------------------------------------------------------------------* Project: Revolution SOUNDFILE dynamic link library File: aifffile.c Copyright (C)2001-2009 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: aifffile.c,v $ Revision 1.3 2009/03/30 07:44:45 aka Copied from SDK_3_2_DEV_BRANCH. Revision 1.2.40.1 2009/03/30 04:39:49 aka Cleaned up. Revision 1.2 2006/02/09 06:51:39 aka Changed copyright. *--------------------------------------------------------------------------*/ #include #include #include #include "aifffile.h" #include "endian.h" u32 * str_form = (u32 *)"FORM"; u32 * str_aiff = (u32 *)"AIFF"; u32 * str_aifc = (u32 *)"AIFC"; u32 * str_fver = (u32 *)"FVER"; u32 * str_comm = (u32 *)"COMM"; u32 * str_ssnd = (u32 *)"SSND"; u32 * str_mark = (u32 *)"MARK"; u32 * str_comt = (u32 *)"COMT"; u32 * str_inst = (u32 *)"INST"; u32 * str_midi = (u32 *)"MIDI"; u32 * str_aesd = (u32 *)"AESD"; u32 * str_appl = (u32 *)"APPL"; u32 * str_name = (u32 *)"NAME"; u32 * str_auth = (u32 *)"AUTH"; u32 * str_copy = (u32 *)"(c) "; u32 * str_anno = (u32 *)"ANNO"; /*---------------------------------------------------------------------------* Name: aiffCreateHeader Description: create an Aiff file header. Arguments: aiffinfo pointer of an AIFFINFO structure. channels num of channels. samples num of samples. bitPerSample bit width per a sample. sampleRate sampling frequency. Returns: none. *---------------------------------------------------------------------------*/ void aiffCreateHeader ( AIFFINFO *aiffinfo, int channels, int samples, int bitsPerSample, int sampleRate ) { aiffinfo->comm.chunk[0] = 'C'; aiffinfo->comm.chunk[1] = 'O'; aiffinfo->comm.chunk[2] = 'M'; aiffinfo->comm.chunk[3] = 'M'; aiffinfo->comm.bytes[0] = 0; aiffinfo->comm.bytes[1] = 0; aiffinfo->comm.bytes[2] = 0; aiffinfo->comm.bytes[3] = 18; aiffinfo->comm.channels[0] = (u8)(0xFF & (channels >> 8)); aiffinfo->comm.channels[1] = (u8)(0xFF & channels); aiffinfo->comm.samples[0] = (u8)(0xFF & (samples >> 24)); aiffinfo->comm.samples[1] = (u8)(0xFF & (samples >> 16)); aiffinfo->comm.samples[2] = (u8)(0xFF & (samples >> 8)); aiffinfo->comm.samples[3] = (u8)(0xFF & samples); aiffinfo->comm.bitsPerSample[0] = (u8)(0xFF & (bitsPerSample >> 8)); aiffinfo->comm.bitsPerSample[1] = (u8)(0xFF & bitsPerSample); aiffinfo->comm.samplesPerSec[0] = 0x40; aiffinfo->comm.samplesPerSec[1] = 0x1E; aiffinfo->comm.samplesPerSec[2] = (u8)(0x7F & sampleRate >> 24); aiffinfo->comm.samplesPerSec[3] = (u8)(0xFF & sampleRate >> 16); aiffinfo->comm.samplesPerSec[4] = (u8)(0xFF & sampleRate >> 8); aiffinfo->comm.samplesPerSec[5] = (u8)(0xFF & sampleRate); aiffinfo->comm.samplesPerSec[6] = 0x00; aiffinfo->comm.samplesPerSec[7] = 0x00; aiffinfo->comm.samplesPerSec[8] = 0x00; aiffinfo->comm.samplesPerSec[9] = 0x00; } /*---------------------------------------------------------------------------* Name: aiffWriteHeader Description: output an Aiff file header. Arguments: aiffinfo pointer of an AIFFINFO structure. outfile pointer of a FILE object. channels num of channels. samples num of samples. bitPerSample bit width per a sample. loopEnd position of loop end Returns: none. *---------------------------------------------------------------------------*/ void aiffWriteHeader ( AIFFINFO *aiffinfo, FILE *outfile, int channels, int samples, int bitsPerSample, int loopEnd ) { u32 size; u32 data; size = sizeof(AIFFCOMM); // common chunk size += 12; // sound data chunk (header only) switch (bitsPerSample) { case 8: data = (samples * channels) + 8; // first 8 bytes are 0 break; case 16: data = (samples * channels * 2) + 8; // first 8 bytes are 0 break; } size += data; // Sound Data Chunk (data part) if (loopEnd) { size += sizeof(AIFFMARK); // marker chunk size += sizeof(AIFFINST); // instrument chunk } size = reverse_endian_32(size); fwrite("FORM", sizeof(char), 4, outfile); fwrite(&size, sizeof(char), 4, outfile); fwrite("AIFF", sizeof(char), 4, outfile); fwrite(&aiffinfo->comm, sizeof(AIFFCOMM), 1, outfile); fwrite("SSND", sizeof(char), 4, outfile); size = reverse_endian_32(data); fwrite(&size, sizeof(char), 4, outfile); size = 0; fwrite(&size, sizeof(char), 4, outfile); fwrite(&size, sizeof(char), 4, outfile); } /*---------------------------------------------------------------------------* Name: aiffCreateMark Description: create an instrument chunk and a marker chunk. Arguments: aiffinfo pointer of an AIFFINFO structure. looopStart position of loop start loopEnd position of loop end Returns: none. *---------------------------------------------------------------------------*/ void aiffCreateMark(AIFFINFO *aiffinfo, u32 loopStart, u32 loopEnd) { aiffinfo->inst.chunk[0] = 'I'; aiffinfo->inst.chunk[1] = 'N'; aiffinfo->inst.chunk[2] = 'S'; aiffinfo->inst.chunk[3] = 'T'; aiffinfo->inst.bytes[0] = 0; aiffinfo->inst.bytes[1] = 0; aiffinfo->inst.bytes[2] = 0; aiffinfo->inst.bytes[3] = 20; aiffinfo->inst.normalKey = 64; aiffinfo->inst.detune = 0; aiffinfo->inst.lowKey = 0; aiffinfo->inst.hiKey = 127; aiffinfo->inst.loVel = 0; aiffinfo->inst.hiVel = 127; aiffinfo->inst.gain[0] = 0; aiffinfo->inst.gain[1] = 0; aiffinfo->inst.playMode0[0] = 0; aiffinfo->inst.playMode0[1] = 1; aiffinfo->inst.begLoop0[0] = 0; aiffinfo->inst.begLoop0[1] = 0; aiffinfo->inst.endLoop0[0] = 0; aiffinfo->inst.endLoop0[1] = 1; aiffinfo->inst.playMode1[0] = 0; aiffinfo->inst.playMode1[1] = 0; aiffinfo->inst.begLoop1[0] = 0; aiffinfo->inst.begLoop1[1] = 0; aiffinfo->inst.endLoop1[0] = 0; aiffinfo->inst.endLoop1[1] = 0; aiffinfo->mark.chunk[0] = 'M'; aiffinfo->mark.chunk[1] = 'A'; aiffinfo->mark.chunk[2] = 'R'; aiffinfo->mark.chunk[3] = 'K'; aiffinfo->mark.bytes[0] = 0; aiffinfo->mark.bytes[1] = 0; aiffinfo->mark.bytes[2] = 0; aiffinfo->mark.bytes[3] = 34; aiffinfo->mark.count[0] = 0; aiffinfo->mark.count[1] = 2; aiffinfo->mark.id0[0] = 0; aiffinfo->mark.id0[1] = 0; aiffinfo->mark.position0[0] = (u8)(0xFF & (loopStart >> 24)); aiffinfo->mark.position0[1] = (u8)(0xFF & (loopStart >> 16)); aiffinfo->mark.position0[2] = (u8)(0xFF & (loopStart >> 8)); aiffinfo->mark.position0[3] = (u8)(0xFF & (loopStart)); aiffinfo->mark.ch0[0] = 0x08; aiffinfo->mark.ch0[1] = 'b'; aiffinfo->mark.ch0[2] = 'e'; aiffinfo->mark.ch0[3] = 'g'; aiffinfo->mark.ch0[4] = ' '; aiffinfo->mark.ch0[5] = 'l'; aiffinfo->mark.ch0[6] = 'o'; aiffinfo->mark.ch0[7] = 'o'; aiffinfo->mark.ch0[8] = 'p'; aiffinfo->mark.ch0[9] = 0; aiffinfo->mark.id1[0] = 0; aiffinfo->mark.id1[1] = 1; aiffinfo->mark.position1[0] = (u8)(0xFF & (loopEnd >> 24)); aiffinfo->mark.position1[1] = (u8)(0xFF & (loopEnd >> 16)); aiffinfo->mark.position1[2] = (u8)(0xFF & (loopEnd >> 8)); aiffinfo->mark.position1[3] = (u8)(0xFF & (loopEnd)); aiffinfo->mark.ch1[0] = 0x08; aiffinfo->mark.ch1[1] = 'e'; aiffinfo->mark.ch1[2] = 'n'; aiffinfo->mark.ch1[3] = 'd'; aiffinfo->mark.ch1[4] = ' '; aiffinfo->mark.ch1[5] = 'l'; aiffinfo->mark.ch1[6] = 'o'; aiffinfo->mark.ch1[7] = 'o'; aiffinfo->mark.ch1[8] = 'p'; aiffinfo->mark.ch1[9] = 0; } /*---------------------------------------------------------------------------* Name: aiffWriteMark Description: output an instrument chunk and a marker chunk. Arguments: aiffinfo pointer of an AIFFINFO structure. outfile pointer of a FILE object. Returns: none. *---------------------------------------------------------------------------*/ void aiffWriteMark(AIFFINFO *aiffinfo, FILE *outfile) { fwrite(&aiffinfo->inst, sizeof(AIFFINST), 1, outfile); fwrite(&aiffinfo->mark, sizeof(AIFFMARK), 1, outfile); } /*---------------------------------------------------------------------------* Name: aiffReadHeader Description: get & parse an Aiff file header. Arguments: aiffinfo pointer of an AIFFINFO structure. infile pointer of a FILE object. Returns: none. *---------------------------------------------------------------------------*/ int aiffReadHeader ( AIFFINFO *aiffinfo, FILE *infile ) { u32 chunk, length, sample_position; if (0 != fseek(infile, 0, SEEK_SET)) { return FALSE; } fread(&chunk, 1, sizeof(u32), infile); if (chunk != *str_form) { return FALSE; } fread(&length, 1, sizeof(u32), infile); fread(&chunk, 1, sizeof(u32), infile); if (chunk != *str_aiff) { return FALSE; } fread(&chunk, 1, sizeof(u32), infile); if (chunk != *str_comm) { return FALSE; } fread(&length, 1, sizeof(u32), infile); fread(&aiffinfo->comm.channels, 1, sizeof(u16), infile); fread(&aiffinfo->comm.samples, 1, sizeof(u32), infile); fread(&aiffinfo->comm.bitsPerSample, 1, sizeof(u16), infile); fread(&aiffinfo->comm.samplesPerSec[0], 10, sizeof(u8), infile); length = reverse_endian_32(length); length = 18 - length; if (length) { fseek(infile, length, SEEK_CUR); } // initialize loop markers to 0 aiffinfo->mark.position0[0] = aiffinfo->mark.position0[1] = aiffinfo->mark.position0[2] = aiffinfo->mark.position0[3] = aiffinfo->mark.position1[0] = aiffinfo->mark.position1[1] = aiffinfo->mark.position1[2] = aiffinfo->mark.position1[3] = 0; // get the read position up to the sample data, that's what the // caller is expecting.. I know... while (fread(&chunk, 1, sizeof(u32), infile) == 4) { u16 count; u32 i; // length of chunk fread(&length, 1, sizeof(u32), infile); length = reverse_endian_32(length); if (feof(infile)) { break; } switch (chunk) { case CHUNK_SSND: // first 8 bytes of samples are garbage fread(&chunk, 1, sizeof(u32), infile); fread(&chunk, 1, sizeof(u32), infile); // save the position because we are going to go look for a loop markers sample_position = ftell(infile); fseek(infile, length - 8, SEEK_CUR); break; case CHUNK_MARK: fread(&count, 1, sizeof(u16), infile); // count, n markers count = reverse_endian_16(count); length -= 2; i = 0; while (count) { u16 id; u32 position; u8 ch; fread(&id, 1, sizeof(u16), infile); fread(&position, 1, sizeof(u32), infile); id = reverse_endian_16(id); position = reverse_endian_32(position); switch (i) { case 0: aiffinfo->mark.position0[0] = (u8)(0xFF & (position >> 24)); aiffinfo->mark.position0[1] = (u8)(0xFF & (position >> 16)); aiffinfo->mark.position0[2] = (u8)(0xFF & (position >> 8)); aiffinfo->mark.position0[3] = (u8)(0xFF & position); break; case 1: aiffinfo->mark.position1[0] = (u8)(0xFF & (position >> 24)); aiffinfo->mark.position1[1] = (u8)(0xFF & (position >> 16)); aiffinfo->mark.position1[2] = (u8)(0xFF & (position >> 8)); aiffinfo->mark.position1[3] = (u8)(0xFF & position); break; } // skip pstring fread(&ch, 1, sizeof(u8), infile); fseek(infile, ch, SEEK_CUR); if (ftell(infile) & 1) { fread(&ch, 1, sizeof(u8), infile); } count--; i++; } break; case CHUNK_INST: { u16 playmode; // skip some stuff we don't care about fseek(infile, 8, SEEK_CUR); fread(&playmode, 1, sizeof(u16), infile); playmode = reverse_endian_16(playmode); if (playmode != 1) { aiffinfo->mark.position0[0] = 0; aiffinfo->mark.position0[1] = 0; aiffinfo->mark.position0[2] = 0; aiffinfo->mark.position0[3] = 0; aiffinfo->mark.position1[0] = 0; aiffinfo->mark.position1[1] = 0; aiffinfo->mark.position1[2] = 0; aiffinfo->mark.position1[3] = 0; } fseek(infile, 10, SEEK_CUR); } break; default: fseek(infile, length, SEEK_CUR); break; } } // put the read position back to where the samples are fseek(infile, sample_position, SEEK_SET); return TRUE; } /*---------------------------------------------------------------------------* Name: aiffGetChannels Description: return num of channels. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: num of channels. *---------------------------------------------------------------------------*/ int aiffGetChannels(AIFFINFO *aiffinfo) { return ((aiffinfo->comm.channels[0] << 8) | (aiffinfo->comm.channels[1])); } /*---------------------------------------------------------------------------* Name: aiffGetSampleRate Description: return num of samples per 1 sec. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: num of samples per sec. *---------------------------------------------------------------------------*/ int aiffGetSampleRate(AIFFINFO *aiffinfo) { unsigned long ieeeExponent; unsigned long ieeeMantissaHi; // FIXED: sign must be removed from exponent, NOT mantissa. ieeeExponent = ((aiffinfo->comm.samplesPerSec[0] << 8) | (aiffinfo->comm.samplesPerSec[1])); ieeeMantissaHi = ((aiffinfo->comm.samplesPerSec[2] << 24) | (aiffinfo->comm.samplesPerSec[3] << 16) | (aiffinfo->comm.samplesPerSec[4] << 8) | (aiffinfo->comm.samplesPerSec[5])); ieeeExponent &= 0x7FFF; // remove sign bit return (ieeeMantissaHi >> (16414 - ieeeExponent)); } /*---------------------------------------------------------------------------* Name: aiffGetSamples Description: return num of samples. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: num of samples. *---------------------------------------------------------------------------*/ int aiffGetSamples(AIFFINFO *aiffinfo) { return ((aiffinfo->comm.samples[0] << 24) | (aiffinfo->comm.samples[1] << 16) | (aiffinfo->comm.samples[2] << 8) | (aiffinfo->comm.samples[3])); } /*---------------------------------------------------------------------------* Name: aiffGetBitsPerSample Description: return bit width per a sample. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: bit width per a sample. *---------------------------------------------------------------------------*/ int aiffGetBitsPerSample(AIFFINFO *aiffinfo) { return ((aiffinfo->comm.bitsPerSample[0] << 8) | (aiffinfo->comm.bitsPerSample[1])); } /*---------------------------------------------------------------------------* Name: aiffGetLoopStart Description: return a position of loop start. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: position of loop start. *---------------------------------------------------------------------------*/ int aiffGetLoopStart(AIFFINFO *aiffinfo) { return ((aiffinfo->mark.position0[0] << 24) | (aiffinfo->mark.position0[1] << 16) | (aiffinfo->mark.position0[2] << 8) | (aiffinfo->mark.position0[3])); } /*---------------------------------------------------------------------------* Name: aiffGetLoopEnd Description: return a position of loop end. Arguments: aiffinfo pointer of an AIFFINFO structure. Returns: position of loop end. *---------------------------------------------------------------------------*/ int aiffGetLoopEnd(AIFFINFO *aiffinfo) { return ((aiffinfo->mark.position1[0] << 24) | (aiffinfo->mark.position1[1] << 16) | (aiffinfo->mark.position1[2] << 8) | (aiffinfo->mark.position1[3])); }