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

input_wav.cpp

Go to the documentation of this file.
00001 #include "input_wav.hpp"
00002 #include "endian.hpp"
00003 #include "utility.hpp"
00004 
00005 
00006 static inline adr_u16 Read16(adr_u8* m) {
00007   return (adr_u16)(
00008     (m[0] << 0) +
00009     (m[1] << 8)
00010   );
00011 }
00012 
00013 static inline adr_u32 Read32(adr_u8* m) {
00014   return (adr_u32)(
00015     (m[0] << 0) +
00016     (m[1] << 8) +
00017     (m[2] << 16)  +
00018     (m[3] << 24)
00019   );
00020 }
00021 
00022 static inline bool IsValidSampleSize(adr_u32 size) {
00023   return (size == 8 || size == 16);
00024 }
00025 
00027 
00028 WAVInputStream::WAVInputStream()
00029 {
00030   m_file = 0;
00031 
00032   m_channel_count   = 0;
00033   m_bits_per_sample = 0;
00034   m_sample_rate     = 0;
00035 
00036   m_data_chunk_location = 0;
00037   m_data_chunk_length   = 0;
00038 
00039   m_samples_left_in_chunk = 0;
00040 }
00041 
00043 
00044 WAVInputStream::~WAVInputStream()
00045 {
00046   delete m_file;
00047   m_file = 0;
00048 }
00049 
00051 
00052 bool
00053 WAVInputStream::Initialize(IFile* file)
00054 {
00055   m_file = file;
00056 
00057   // read the RIFF header
00058   char    riff_id[4];
00059   adr_u32 riff_length;
00060   char    riff_datatype[4];
00061 
00062   adr_u32 size = 0;
00063   size += file->Read(riff_id, 4);
00064   size += file->Read(&riff_length, 4);
00065   size += file->Read(riff_datatype, 4);
00066 
00067   riff_length = LittleToHost32(riff_length);
00068 
00069   if (size != 12 ||
00070       memcmp(riff_id, "RIFF", 4) != 0 ||
00071       riff_length == 0 ||
00072       memcmp(riff_datatype, "WAVE", 4) != 0) {
00073 
00074     // so we don't destroy the file
00075     m_file = 0;
00076     return false;
00077   }
00078 
00079   if (FindFormatChunk() && FindDataChunk()) {
00080     return true;
00081   } else {
00082     m_file = 0;
00083     return false;
00084   }
00085 }
00086 
00088 
00089 void
00090 WAVInputStream::GetFormat(
00091   int& channel_count,
00092   int& sample_rate,
00093   int& bits_per_sample)
00094 {
00095   channel_count   = m_channel_count;
00096   sample_rate     = m_sample_rate;
00097   bits_per_sample = m_bits_per_sample;
00098 }
00099 
00101 
00102 int
00103 WAVInputStream::Read(int sample_count, void* samples)
00104 {
00105   if (m_samples_left_in_chunk == 0) {
00106     return 0;
00107   }
00108 
00109   const int samples_to_read = adr_min(sample_count, m_samples_left_in_chunk);
00110   const int sample_size = m_channel_count * m_bits_per_sample / 8;
00111   const int bytes_to_read = samples_to_read * sample_size;
00112   
00113   const int read = m_file->Read(samples, bytes_to_read);
00114   const int samples_read = read / sample_size;
00115 
00116   // assume that if we didn't get a full read, we're done
00117   if (read != bytes_to_read) {
00118     m_samples_left_in_chunk = 0;
00119     return samples_read;
00120   }
00121 
00122   m_samples_left_in_chunk -= samples_read;
00123   return samples_read;
00124 }
00125 
00127 
00128 bool
00129 WAVInputStream::Reset()
00130 {
00131   // seek to the beginning of the data chunk
00132   m_samples_left_in_chunk = m_data_chunk_length;
00133   return m_file->Seek(m_data_chunk_location, ADR_BEGIN);
00134 }
00135 
00137 
00138 bool
00139 WAVInputStream::FindFormatChunk()
00140 {
00141   // seek to just after the RIFF header
00142   m_file->Seek(12, ADR_BEGIN);
00143 
00144   // search for a format chunk
00145   while (true) {
00146     char    chunk_id[4];
00147     adr_u32 chunk_length;
00148 
00149     int size = m_file->Read(chunk_id, 4);
00150     size    += m_file->Read(&chunk_length, 4);
00151     chunk_length = LittleToHost32(chunk_length);
00152 
00153     // if we couldn't read enough, we're done
00154     if (size != 8) {
00155       return false;
00156     }
00157 
00158     // if we found a format chunk, excellent!
00159     if (memcmp(chunk_id, "fmt ", 4) == 0 && chunk_length >= 16) {
00160 
00161       // read format chunk
00162       adr_u8 chunk[16];
00163       size = m_file->Read(chunk, 16);
00164 
00165       // could we read the entire format chunk?
00166       if (size < 16) {
00167         return false;
00168       }
00169 
00170       chunk_length -= size;
00171 
00172       // parse the memory into useful information
00173       adr_u16 format_tag         = Read16(chunk + 0);
00174       adr_u16 channel_count      = Read16(chunk + 2);
00175       adr_u32 samples_per_second = Read32(chunk + 4);
00176       adr_u32 bytes_per_second   = Read32(chunk + 8);
00177       adr_u16 block_align        = Read16(chunk + 12);
00178       adr_u16 bits_per_sample    = Read16(chunk + 14);
00179 
00180       // format_tag must be 1 (WAVE_FORMAT_PCM)
00181       // we only support mono and stereo
00182       if (format_tag != 1 ||
00183           channel_count > 2 ||
00184           !IsValidSampleSize(bits_per_sample)) {
00185         return false;
00186       }
00187 
00188       // skip the rest of the chunk
00189       if (!SkipBytes(chunk_length)) {
00190         // oops, end of stream
00191         return false;
00192       }
00193 
00194       // set format
00195       m_channel_count   = channel_count;
00196       m_bits_per_sample = bits_per_sample;
00197       m_sample_rate     = samples_per_second;
00198       return true;
00199 
00200     } else {
00201 
00202       // skip the rest of the chunk
00203       if (!SkipBytes(chunk_length)) {
00204         // oops, end of stream
00205         return false;
00206       }
00207 
00208     }
00209   }
00210 }
00211 
00213 
00214 bool
00215 WAVInputStream::FindDataChunk()
00216 {
00217   // seek to just after the RIFF header
00218   m_file->Seek(12, ADR_BEGIN);
00219 
00220   // search for a format chunk
00221   while (true) {
00222     char    chunk_id[4];
00223     adr_u32 chunk_length;
00224 
00225     int size = m_file->Read(chunk_id, 4);
00226     size    += m_file->Read(&chunk_length, 4);
00227     chunk_length = LittleToHost32(chunk_length);
00228 
00229     // if we couldn't read enough, we're done
00230     if (size != 8) {
00231       return false;
00232     }
00233 
00234     // if we found a data chunk, excellent!
00235     if (memcmp(chunk_id, "data", 4) == 0) {
00236 
00237       // calculate the sample size so we can truncate the data chunk
00238       int sample_size = m_channel_count * m_bits_per_sample / 8;
00239 
00240       m_data_chunk_location   = m_file->Tell();
00241       m_data_chunk_length     = chunk_length / sample_size;
00242       m_samples_left_in_chunk = m_data_chunk_length;
00243       return true;
00244 
00245     } else {
00246 
00247       // skip the rest of the chunk
00248       if (!SkipBytes(chunk_length)) {
00249         // oops, end of stream
00250         return false;
00251       }
00252 
00253     }
00254   }
00255 }
00256 
00258 
00259 bool
00260 WAVInputStream::SkipBytes(int size)
00261 {
00262   if (m_file->Seek(size, ADR_CURRENT)) {
00263     m_samples_left_in_chunk = m_data_chunk_length;
00264     return true;
00265   } else {
00266     return false;
00267   }
00268 }
00269 

Generated at Mon Jun 10 02:55:12 2002 for audiere by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001