2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "audio/wav_sound_file.hpp"
23 #include "audio/sound_error.hpp"
24 #include "util/log.hpp"
26 static inline uint32_t read32LE(PHYSFS_file* file)
29 if(PHYSFS_readULE32(file, &result) == 0)
30 throw SoundError("file too short");
35 static inline uint16_t read16LE(PHYSFS_file* file)
38 if(PHYSFS_readULE16(file, &result) == 0)
39 throw SoundError("file too short");
44 WavSoundFile::WavSoundFile(PHYSFS_file* file_) :
50 if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
51 throw SoundError("Couldn't read file magic (not a wave file)");
52 if(strncmp(magic, "RIFF", 4) != 0) {
53 log_debug << "MAGIC: " << magic << std::endl;
54 throw SoundError("file is not a RIFF wav file");
57 uint32_t wavelen = read32LE(file);
60 if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
61 throw SoundError("Couldn't read chunk header (not a wav file?)");
62 if(strncmp(magic, "WAVE", 4) != 0)
63 throw SoundError("file is not a valid RIFF/WAVE file");
68 // search audio data format chunk
70 if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
71 throw SoundError("EOF while searching format chunk");
72 chunklen = read32LE(file);
74 if(strncmp(chunkmagic, "fmt ", 4) == 0)
77 if(strncmp(chunkmagic, "fact", 4) == 0
78 || strncmp(chunkmagic, "LIST", 4) == 0) {
80 if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
81 throw SoundError("EOF while searching fmt chunk");
83 throw SoundError("complex WAVE files not supported");
88 throw SoundError("Format chunk too short");
91 uint16_t encoding = read16LE(file);
93 throw SoundError("only PCM encoding supported");
94 channels = read16LE(file);
95 rate = read32LE(file);
96 uint32_t byterate = read32LE(file);
98 uint16_t blockalign = read16LE(file);
100 bits_per_sample = read16LE(file);
103 if(PHYSFS_seek(file, PHYSFS_tell(file) + (chunklen-16)) == 0)
104 throw SoundError("EOF while reading rest of format chunk");
107 // set file offset to DATA chunk data
109 if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
110 throw SoundError("EOF while searching data chunk");
111 chunklen = read32LE(file);
113 if(strncmp(chunkmagic, "data", 4) == 0)
117 if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
118 throw SoundError("EOF while searching fmt chunk");
121 datastart = PHYSFS_tell(file);
122 size = static_cast<size_t> (chunklen);
125 WavSoundFile::~WavSoundFile()
131 WavSoundFile::reset()
133 if(PHYSFS_seek(file, datastart) == 0)
134 throw SoundError("Couldn't seek to data start");
138 WavSoundFile::read(void* buffer, size_t buffer_size)
140 PHYSFS_sint64 end = datastart + size;
141 PHYSFS_sint64 cur = PHYSFS_tell(file);
145 size_t readsize = std::min(static_cast<size_t> (end - cur), buffer_size);
146 if(PHYSFS_read(file, buffer, readsize, 1) != 1)
147 throw SoundError("read error while reading samples");
149 #ifdef WORDS_BIGENDIAN
150 if (bits_per_sample != 16)
152 char *tmp = (char*)buffer;
156 for (i = 0; i < readsize / 2; i++)
159 tmp[2*i] = tmp[2*i+1];