Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

input_wav.cpp

Go to the documentation of this file.
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;  // reasonable default?
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     // read the RIFF header
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       // so we don't destroy the file
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       // make little endian into host endian
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     // assume that if we didn't get a full read, we're done
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     // seek to the beginning of the data chunk
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     // seek to just after the RIFF header
00146     m_file->seek(12, File::BEGIN);
00147 
00148     // search for a format chunk
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       // if we couldn't read enough, we're done
00158       if (size != 8) {
00159         return false;
00160       }
00161 
00162       // if we found a format chunk, excellent!
00163       if (memcmp(chunk_id, "fmt ", 4) == 0 && chunk_length >= 16) {
00164 
00165         // read format chunk
00166         u8 chunk[16];
00167         size = m_file->read(chunk, 16);
00168 
00169         // could we read the entire format chunk?
00170         if (size < 16) {
00171           return false;
00172         }
00173 
00174         chunk_length -= size;
00175 
00176         // parse the memory into useful information
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         // format_tag must be 1 (WAVE_FORMAT_PCM)
00185         // we only support mono and stereo
00186         if (format_tag != 1 ||
00187             channel_count > 2 ||
00188             !IsValidSampleSize(bits_per_sample)) {
00189           return false;
00190         }
00191 
00192         // skip the rest of the chunk
00193         if (!SkipBytes(chunk_length)) {
00194           // oops, end of stream
00195           return false;
00196         }
00197 
00198         // figure out the sample format
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         // store the other important .wav attributes
00208         m_channel_count = channel_count;
00209         m_sample_rate   = samples_per_second;
00210         return true;
00211 
00212       } else {
00213 
00214         // skip the rest of the chunk
00215         if (!SkipBytes(chunk_length)) {
00216           // oops, end of stream
00217           return false;
00218         }
00219 
00220       }
00221     }
00222   }
00223 
00224 
00225   bool
00226   WAVInputStream::FindDataChunk() {
00227     // seek to just after the RIFF header
00228     m_file->seek(12, File::BEGIN);
00229 
00230     // search for a format chunk
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       // if we couldn't read enough, we're done
00240       if (size != 8) {
00241         return false;
00242       }
00243 
00244       // if we found a data chunk, excellent!
00245       if (memcmp(chunk_id, "data", 4) == 0) {
00246 
00247         // calculate the frame size so we can truncate the data chunk
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         // skip the rest of the chunk
00258         if (!SkipBytes(chunk_length)) {
00259           // oops, end of stream
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 }

Generated on Sat Oct 12 01:43:03 2002 for audiere by doxygen1.2.17