00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "audio/wav_sound_file.hpp"
00018
00019 #include <string.h>
00020 #include <stdint.h>
00021 #include <assert.h>
00022
00023 #include "audio/sound_error.hpp"
00024 #include "util/log.hpp"
00025
00026 static inline uint32_t read32LE(PHYSFS_file* file)
00027 {
00028 uint32_t result;
00029 if(PHYSFS_readULE32(file, &result) == 0)
00030 throw SoundError("file too short");
00031
00032 return result;
00033 }
00034
00035 static inline uint16_t read16LE(PHYSFS_file* file)
00036 {
00037 uint16_t result;
00038 if(PHYSFS_readULE16(file, &result) == 0)
00039 throw SoundError("file too short");
00040
00041 return result;
00042 }
00043
00044 WavSoundFile::WavSoundFile(PHYSFS_file* file_) :
00045 file(file_),
00046 datastart()
00047 {
00048 assert(file);
00049 char magic[4];
00050 if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
00051 throw SoundError("Couldn't read file magic (not a wave file)");
00052 if(strncmp(magic, "RIFF", 4) != 0) {
00053 log_debug << "MAGIC: " << magic << std::endl;
00054 throw SoundError("file is not a RIFF wav file");
00055 }
00056
00057 uint32_t wavelen = read32LE(file);
00058 (void) wavelen;
00059
00060 if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
00061 throw SoundError("Couldn't read chunk header (not a wav file?)");
00062 if(strncmp(magic, "WAVE", 4) != 0)
00063 throw SoundError("file is not a valid RIFF/WAVE file");
00064
00065 char chunkmagic[4];
00066 uint32_t chunklen;
00067
00068
00069 do {
00070 if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
00071 throw SoundError("EOF while searching format chunk");
00072 chunklen = read32LE(file);
00073
00074 if(strncmp(chunkmagic, "fmt ", 4) == 0)
00075 break;
00076
00077 if(strncmp(chunkmagic, "fact", 4) == 0
00078 || strncmp(chunkmagic, "LIST", 4) == 0) {
00079
00080 if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
00081 throw SoundError("EOF while searching fmt chunk");
00082 } else {
00083 throw SoundError("complex WAVE files not supported");
00084 }
00085 } while(true);
00086
00087 if(chunklen < 16)
00088 throw SoundError("Format chunk too short");
00089
00090
00091 uint16_t encoding = read16LE(file);
00092 if(encoding != 1)
00093 throw SoundError("only PCM encoding supported");
00094 channels = read16LE(file);
00095 rate = read32LE(file);
00096 uint32_t byterate = read32LE(file);
00097 (void) byterate;
00098 uint16_t blockalign = read16LE(file);
00099 (void) blockalign;
00100 bits_per_sample = read16LE(file);
00101
00102 if(chunklen > 16) {
00103 if(PHYSFS_seek(file, PHYSFS_tell(file) + (chunklen-16)) == 0)
00104 throw SoundError("EOF while reading rest of format chunk");
00105 }
00106
00107
00108 do {
00109 if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
00110 throw SoundError("EOF while searching data chunk");
00111 chunklen = read32LE(file);
00112
00113 if(strncmp(chunkmagic, "data", 4) == 0)
00114 break;
00115
00116
00117 if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
00118 throw SoundError("EOF while searching fmt chunk");
00119 } while(true);
00120
00121 datastart = PHYSFS_tell(file);
00122 size = static_cast<size_t> (chunklen);
00123 }
00124
00125 WavSoundFile::~WavSoundFile()
00126 {
00127 PHYSFS_close(file);
00128 }
00129
00130 void
00131 WavSoundFile::reset()
00132 {
00133 if(PHYSFS_seek(file, datastart) == 0)
00134 throw SoundError("Couldn't seek to data start");
00135 }
00136
00137 size_t
00138 WavSoundFile::read(void* buffer, size_t buffer_size)
00139 {
00140 PHYSFS_sint64 end = datastart + size;
00141 PHYSFS_sint64 cur = PHYSFS_tell(file);
00142 if(cur >= end)
00143 return 0;
00144
00145 size_t readsize = std::min(static_cast<size_t> (end - cur), buffer_size);
00146 if(PHYSFS_read(file, buffer, readsize, 1) != 1)
00147 throw SoundError("read error while reading samples");
00148
00149 #ifdef WORDS_BIGENDIAN
00150 if (bits_per_sample != 16)
00151 return readsize;
00152 char *tmp = (char*)buffer;
00153
00154 size_t i;
00155 char c;
00156 for (i = 0; i < readsize / 2; i++)
00157 {
00158 c = tmp[2*i];
00159 tmp[2*i] = tmp[2*i+1];
00160 tmp[2*i+1] = c;
00161 }
00162
00163 buffer = tmp;
00164 #endif
00165
00166 return readsize;
00167 }
00168
00169