/*--------------------------------------------------------------------------* Project: Revolution SOUNDFILE dynamic link library File: soundfile.c Copyright (C)1998-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: soundfile.c,v $ Revision 1.4 2009/03/30 07:44:45 aka Copied from SDK_3_2_DEV_BRANCH. Revision 1.3.4.1 2009/03/30 04:40:35 aka Added supporting a wav file with loop information. Revision 1.3 2007/11/30 04:19:32 iwai_yuma Related to Visual Studio 2005 Revision 1.3 2007/11/22 21:57:56 iwai Replaced unsecure function to secure one. Revision 1.2 2006/02/09 06:51:39 aka Changed copyright. *--------------------------------------------------------------------------*/ #include #include #include "Types.h" #include "soundfile.h" #include "endian.h" #include "aifffile.h" #include "Wavfile.h" #define SOUND_FILE_WAVE 0 #define SOUND_FILE_AIFF 1 /*---------------------------------------------------------------------------* Name: getAiffInfo Description: get AIFF file information. Arguments: path path of an AIFF file. soundinfo pointer of a SOUNDINFO structure. buffer pointer of a samples buffer. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open an AIFF file. *---------------------------------------------------------------------------*/ int getAiffInfo(char *path, SOUNDINFO *soundinfo, void *buffer) { FILE *file; AIFFINFO aiffinfo; errno_t err; if (( err = fopen_s( &file, path, "rb" ) ) != 0) { return SOUND_FILE_FOPEN_ERROR; } aiffReadHeader(&aiffinfo, file); soundinfo->channels = aiffGetChannels(&aiffinfo); soundinfo->bitsPerSample = aiffGetBitsPerSample(&aiffinfo); soundinfo->sampleRate = aiffGetSampleRate(&aiffinfo); soundinfo->samples = aiffGetSamples(&aiffinfo); soundinfo->loopStart = aiffGetLoopStart(&aiffinfo); soundinfo->loopEnd = aiffGetLoopEnd(&aiffinfo); soundinfo->bufferLength = 0; switch (soundinfo->bitsPerSample) { case 8: soundinfo->bufferLength = soundinfo->samples * soundinfo->channels; break; case 16: soundinfo->bufferLength = soundinfo->samples * soundinfo->channels * 2; break; } if (buffer) { fread(buffer, soundinfo->bufferLength, 1, file); if (soundinfo->bitsPerSample == 16) { reverse_buffer_16(buffer, soundinfo->bufferLength / 2); } } fclose(file); return SOUND_FILE_SUCCESS; } /*---------------------------------------------------------------------------* Name: getWaveInfo Description: get Wave file information. Arguments: path path of a Wave file. soundinfo pointer of a SOUNDINFO structure. buffer pointer of a samples buffer. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open a Wave file. *---------------------------------------------------------------------------*/ int getWaveInfo(char *path, SOUNDINFO *soundinfo, void *buffer) { FILE *file; WAVECHUNK wavechunk; LOOPINFO loopinfo; errno_t err; if (( err = fopen_s( &file, path, "rb" ) ) != 0) { return SOUND_FILE_FOPEN_ERROR; } wavReadHeader(&wavechunk, &loopinfo, file); soundinfo->channels = wavGetChannels(&wavechunk); soundinfo->bitsPerSample = wavGetBitsPerSample(&wavechunk); soundinfo->sampleRate = wavGetSampleRate(&wavechunk); soundinfo->samples = wavGetSamples(&wavechunk); soundinfo->loopStart = loopinfo.start; soundinfo->loopEnd = loopinfo.end; soundinfo->bufferLength = 0; switch (soundinfo->bitsPerSample) { case 8: soundinfo->bufferLength = soundinfo->samples * soundinfo->channels; break; case 16: soundinfo->bufferLength = soundinfo->samples * soundinfo->channels * 2; break; } if (buffer) { fread(buffer, soundinfo->bufferLength, 1, file); if (soundinfo->bitsPerSample == 8) { int i; char *p; p = buffer; for (i = 0; i < soundinfo->bufferLength; i++) { *p = *p + 0x80; p++; } } } fclose(file); return SOUND_FILE_SUCCESS; } /*---------------------------------------------------------------------------* Name: getFileType Description: check file type (AIFF or Wave) of an input file. Arguments: path path of an input file. soundinfo pointer of a SOUNDINFO structure (not used). Returns: SOUND_FILE_FORMAT_ERROR neither AIFF nor Wave. SOUND_FILE_AIFF AIFF. SOUND_FILE_WAVE Wave. SOUND_FILE_FOPEN_ERROR can't open an input file. *---------------------------------------------------------------------------*/ int getFileType(char *path, SOUNDINFO *soundinfo) { FILE *file; u32 data, result; errno_t err; if (( err = fopen_s( &file, path, "rb" ) ) != 0) { return SOUND_FILE_FOPEN_ERROR; } else { result = SOUND_FILE_FORMAT_ERROR; } fread(&data, 1, sizeof(u32), file); switch (data) { case CHUNK_FORM: fread(&data, 1, sizeof(u32), file); fread(&data, 1, sizeof(u32), file); if (data == CHUNK_AIFF) { result = SOUND_FILE_AIFF; } break; case CHUNK_RIFF: fread(&data, 1, sizeof(u32), file); fread(&data, 1, sizeof(u32), file); if (data == CHUNK_WAVE) { result = SOUND_FILE_WAVE; } break; } fclose(file); return result; } /*---------------------------------------------------------------------------* Name: getSoundInfo Description: get information of an input sound file (AIFF or Wave). Arguments: path path of an input file. soundinfo pointer of a SOUNDINFO structure. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open an AIFF file. SOUND_FILE_FORMAT_ERROR neither AIFF nor Wave. *---------------------------------------------------------------------------*/ int getSoundInfo(char *path, SOUNDINFO *soundinfo) { u32 result = getFileType(path, soundinfo); switch (result) { case SOUND_FILE_AIFF: result = getAiffInfo(path, soundinfo, NULL); break; case SOUND_FILE_WAVE: result = getWaveInfo(path, soundinfo, NULL); break; } return result; } /*---------------------------------------------------------------------------* Name: getSoundSamples Description: get information and samples of an input sound file (AIFF or Wave). Arguments: path path of an input file. soundinfo pointer of a SOUNDINFO structure. dest pointer of a samples buffer. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open an AIFF file. SOUND_FILE_FORMAT_ERROR neither AIFF nor Wave. *---------------------------------------------------------------------------*/ int getSoundSamples(char *path, SOUNDINFO *soundinfo, void *dest) { u32 result = getFileType(path, soundinfo); switch (result) { case SOUND_FILE_AIFF: result = getAiffInfo(path, soundinfo, dest); break; case SOUND_FILE_WAVE: result = getWaveInfo(path, soundinfo, dest); break; } return result; } /*---------------------------------------------------------------------------* Name: writeWaveFile Description: create a Wave file. Arguments: path path of an output file. soundinfo pointer of a SOUNDINFO structure. samples pointer of a samples buffer. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open an output file. *---------------------------------------------------------------------------*/ int writeWaveFile(char *path, SOUNDINFO *info, void *samples) { WAVECHUNK wavechunk; SMPLCHUNK smpl; SMPLLOOP loop; FILE *file; errno_t err; if (( err = fopen_s( &file, path, "wb" ) ) != 0) { return SOUND_FILE_FOPEN_ERROR; } wavCreateHeader( &wavechunk, info->channels, info->samples, info->bitsPerSample, info->sampleRate, info->loopEnd ); wavWriteHeader( &wavechunk, file ); fwrite(samples, info->bufferLength, sizeof(char), file); if (info->loopEnd) { wavCreateSmplChunk(&wavechunk, &smpl, &loop, info->loopStart, info->loopEnd); wavWriteSmplChunk(&smpl, &loop, file); } fclose(file); return SOUND_FILE_SUCCESS; } /*---------------------------------------------------------------------------* Name: writeAiffFile Description: create an AIFF file. Arguments: path path of an output file. soundinfo pointer of a SOUNDINFO structure. samples pointer of a samples buffer. Returns: SOUND_FILE_SUCCESS OK. SOUND_FILE_FOPEN_ERROR can't open an output file. *---------------------------------------------------------------------------*/ int writeAiffFile(char *path, SOUNDINFO *info, void *samples) { AIFFINFO aiffinfo; FILE *file; errno_t err; if (( err = fopen_s( &file, path, "wb" ) ) != 0) { return SOUND_FILE_FOPEN_ERROR; } aiffCreateHeader( &aiffinfo, info->channels, info->samples, info->bitsPerSample, info->sampleRate ); aiffWriteHeader( &aiffinfo, file, info->channels, info->samples, info->bitsPerSample, info->loopEnd ); if (info->bitsPerSample == 16) { reverse_buffer_16(samples, info->bufferLength / 2); } fwrite(samples, info->bufferLength, sizeof(char), file); if (info->loopEnd) { aiffCreateMark(&aiffinfo, info->loopStart, info->loopEnd); aiffWriteMark(&aiffinfo, file); } fclose(file); return SOUND_FILE_SUCCESS; }