00001 #include <string.h>
00002 #include "debug.h"
00003 #include "input_wav.h"
00004 #include "utility.h"
00005
00006
00007 namespace audiere {
00008
00009 static inline bool IsValidSampleSize(u32 size) {
00010 return (size == 8 || size == 16);
00011 }
00012
00013
00014 WAVInputStream::WAVInputStream() {
00015 m_file = 0;
00016
00017 m_channel_count = 0;
00018 m_sample_rate = 0;
00019 m_sample_format = SF_U8;
00020
00021 m_data_chunk_location = 0;
00022 m_data_chunk_length = 0;
00023
00024 m_frames_left_in_chunk = 0;
00025 }
00026
00027
00029 bool
00030 WAVInputStream::initialize(FilePtr file) {
00031 m_file = file;
00032
00033
00034 char riff_id[4];
00035 u8 riff_length_buffer[4];
00036 char riff_datatype[4];
00037
00038 u32 size = 0;
00039 size += file->read(riff_id, 4);
00040 size += file->read(riff_length_buffer, 4);
00041 size += file->read(riff_datatype, 4);
00042
00043 int riff_length = read32_le(riff_length_buffer);
00044
00045 if (size != 12 ||
00046 memcmp(riff_id, "RIFF", 4) != 0 ||
00047 riff_length == 0 ||
00048 memcmp(riff_datatype, "WAVE", 4) != 0) {
00049
00050 ADR_LOG("Couldn't read RIFF header");
00051
00052
00053 m_file = 0;
00054 return false;
00055 }
00056
00057 if (findFormatChunk() && findDataChunk()) {
00058 return true;
00059 } else {
00060 m_file = 0;
00061 return false;
00062 }
00063 }
00064
00065
00066 void
00067 WAVInputStream::getFormat(
00068 int& channel_count,
00069 int& sample_rate,
00070 SampleFormat& sample_format)
00071 {
00072 channel_count = m_channel_count;
00073 sample_rate = m_sample_rate;
00074 sample_format = m_sample_format;
00075 }
00076
00077
00078 int
00079 WAVInputStream::doRead(int frame_count, void* buffer) {
00080 if (m_frames_left_in_chunk == 0) {
00081 return 0;
00082 }
00083
00084 const int frames_to_read = std::min(frame_count, m_frames_left_in_chunk);
00085 const int frame_size = m_channel_count * GetSampleSize(m_sample_format);
00086 const int bytes_to_read = frames_to_read * frame_size;
00087
00088 const int read = m_file->read(buffer, bytes_to_read);
00089 const int frames_read = read / frame_size;
00090
00091 #if WORDS_BIGENDIAN
00092 if (m_sample_format == SF_S16) {
00093
00094 u8* out = (u8*)buffer;
00095 for (int i = 0; i < frames_read * m_channel_count; ++i) {
00096 std::swap(out[0], out[1]);
00097 out += 2;
00098 }
00099 }
00100 #endif
00101
00102
00103 if (read != bytes_to_read) {
00104 m_frames_left_in_chunk = 0;
00105 return frames_read;
00106 }
00107
00108 m_frames_left_in_chunk -= frames_read;
00109 return frames_read;
00110 }
00111
00112
00113 void
00114 WAVInputStream::reset() {
00115
00116 m_frames_left_in_chunk = m_data_chunk_length;
00117 m_file->seek(m_data_chunk_location, File::BEGIN);
00118 }
00119
00120
00121 bool
00122 WAVInputStream::isSeekable() {
00123 return true;
00124 }
00125
00126
00127 int
00128 WAVInputStream::getLength() {
00129 return m_data_chunk_length;
00130 }
00131
00132
00133 void
00134 WAVInputStream::setPosition(int position) {
00135 int frame_size = m_channel_count * GetSampleSize(m_sample_format);
00136 m_frames_left_in_chunk = m_data_chunk_length - position;
00137 m_file->seek(m_data_chunk_location + position * frame_size, File::BEGIN);
00138 }
00139
00140
00141 int
00142 WAVInputStream::getPosition() {
00143 return m_data_chunk_length - m_frames_left_in_chunk;
00144 }
00145
00146
00147 bool
00148 WAVInputStream::findFormatChunk() {
00149 ADR_GUARD("WAVInputStream::findFormatChunk");
00150
00151
00152 m_file->seek(12, File::BEGIN);
00153
00154
00155 for (;;) {
00156 char chunk_id[4];
00157 u8 chunk_length_buffer[4];
00158
00159 int size = m_file->read(chunk_id, 4);
00160 size += m_file->read(chunk_length_buffer, 4);
00161 u32 chunk_length = read32_le(chunk_length_buffer);
00162
00163
00164 if (size != 8) {
00165 return false;
00166 }
00167
00168
00169 if (memcmp(chunk_id, "fmt ", 4) == 0 && chunk_length >= 16) {
00170
00171 ADR_LOG("Found format chunk");
00172
00173
00174 u8 chunk[16];
00175 size = m_file->read(chunk, 16);
00176
00177
00178 if (size < 16) {
00179 return false;
00180 }
00181
00182 chunk_length -= size;
00183
00184
00185 u16 format_tag = read16_le(chunk + 0);
00186 u16 channel_count = read16_le(chunk + 2);
00187 u32 samples_per_second = read32_le(chunk + 4);
00188
00189
00190 u16 bits_per_sample = read16_le(chunk + 14);
00191
00192
00193
00194 if (format_tag != 1 ||
00195 channel_count > 2 ||
00196 !IsValidSampleSize(bits_per_sample)) {
00197 ADR_LOG("Invalid WAV");
00198 return false;
00199 }
00200
00201
00202 if (!skipBytes(chunk_length)) {
00203
00204 return false;
00205 }
00206
00207
00208 if (bits_per_sample == 8) {
00209 m_sample_format = SF_U8;
00210 } else if (bits_per_sample == 16) {
00211 m_sample_format = SF_S16;
00212 } else {
00213 return false;
00214 }
00215
00216
00217 m_channel_count = channel_count;
00218 m_sample_rate = samples_per_second;
00219 return true;
00220
00221 } else {
00222
00223
00224 if (!skipBytes(chunk_length)) {
00225
00226 return false;
00227 }
00228
00229 }
00230 }
00231 }
00232
00233
00234 bool
00235 WAVInputStream::findDataChunk() {
00236 ADR_GUARD("WAVInputStream::findDataChunk");
00237
00238
00239 m_file->seek(12, File::BEGIN);
00240
00241
00242 while (true) {
00243 char chunk_id[4];
00244 u8 chunk_length_buffer[4];
00245
00246 int size = m_file->read(chunk_id, 4);
00247 size += m_file->read(chunk_length_buffer, 4);
00248 u32 chunk_length = read32_le(chunk_length_buffer);
00249
00250
00251 if (size != 8) {
00252 ADR_LOG("Couldn't read chunk header");
00253 return false;
00254 }
00255
00256
00257 if (memcmp(chunk_id, "data", 4) == 0) {
00258
00259 ADR_LOG("Found data chunk");
00260
00261
00262 int frame_size = m_channel_count * GetSampleSize(m_sample_format);
00263
00264 m_data_chunk_location = m_file->tell();
00265 m_data_chunk_length = chunk_length / frame_size;
00266 m_frames_left_in_chunk = m_data_chunk_length;
00267 return true;
00268
00269 } else {
00270
00271 ADR_IF_DEBUG {
00272 char str[80];
00273 sprintf(str, "Skipping: %d bytes in chunk '%c%c%c%c'",
00274 (int)chunk_length,
00275 chunk_id[0], chunk_id[1], chunk_id[2], chunk_id[3]);
00276 ADR_LOG(str);
00277 }
00278
00279
00280 if (!skipBytes(chunk_length)) {
00281
00282 return false;
00283 }
00284
00285 }
00286 }
00287 }
00288
00289
00290 bool
00291 WAVInputStream::skipBytes(int size) {
00292 return m_file->seek(size, File::CURRENT);
00293 }
00294
00295
00296 }