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