Spinning Topp Logo BlackTopp Studios
inc
wavdecoder.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine 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.
8 
9  The Mezzanine Engine 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.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 // Copyright (c) 2008-2010 Raynaldo (Wildicv) Rivera, Joshua (Dark_Kilauea) Jones
41 // This file is part of the "cAudio Engine"
42 // For conditions of distribution and use, see copyright notice in cAudio-ZLIBLicense.txt
43 #ifndef _audiowavdecoder_cpp
44 #define _audiowavdecoder_cpp
45 
46 #ifdef ENABLE_WAV_ENCODE
47 
48 #include "Audio/wavdecoder.h"
49 
50 #include <cstring>
51 
52 namespace Mezzanine
53 {
54  namespace Audio
55  {
56  WavDecoder::WavDecoder(Resource::DataStreamPtr Stream) :
57  WavStream(Stream),
58  WavStreamSize(0),
59  WavStreamPos(0),
60  SampleRate(0),
61  ByteRate(0),
62  DataSize(0),
63  DataOffset(0),
64  Channels(0),
65  BlockAlign(0),
66  BitsPerSample(0),
67  Valid(false)
68  {
69  this->WavStream->seekg(0,std::ios_base::end);
70  this->WavStreamSize = this->WavStream->tellg();
71 
72  this->ReadWavMetaData(Stream);
73  }
74 
75  WavDecoder::~WavDecoder()
76  { }
77 
78  void WavDecoder::ReadWavMetaData(Resource::DataStreamPtr Stream)
79  {
80  const char* RIFFTAG = "RIFF";
81  const char* WAVETAG = "WAVE";
82  const char* FORMATTAG = "fmt ";
83  const char* DATATAG = "data";
84 
85  char Ident[4];
86  Int32 Temp32 = 0;
87  Int16 Temp16 = 0;
88  //Int8 Temp8 = 0;
89  UInt32 StartOffset = 0;
90 
91  // Read the first 4 bytes
92  this->WavStream->seekg(0);
93  this->WavStream->read(Ident,4);
94  // Check to see if it is a valid RIFF file
95  if( strncmp(Ident,RIFFTAG,4) == 0 ) {
96  this->WavStream->read((char*)&Temp32,4);
97  // Check to see if the file is big enough to be valid (not completely accurate)
98  if( Temp32 >= 44 ) {
99  this->WavStream->read(Ident,4);
100  // Check that it is a wave file
101  if( strncmp(Ident,WAVETAG,4) == 0 ) {
102  // Save our position
103  StartOffset = this->WavStream->tellg();
104  // Scan for the first fmt chuck (not necessarily right after)
105  do{
106  this->WavStream->read(Ident,4);
107  } while( ( strncmp(Ident,FORMATTAG,4) != 0 ) && ( this->WavStream->tellg() < this->WavStreamSize ) );
108  //Did we find it?
109  if( this->WavStream->tellg() < ( this->WavStreamSize - 16 ) ) {
110  //Yes, read it in
111  this->WavStream->read((char*)&Temp32,4);
112  if( Temp32 >= 16 ) {
113  // Check that it is in PCM format, we don't support compressed wavs
114  this->WavStream->read((char*)&Temp16,2);
115  this->Channels = Temp16;
116  // We only support mono or stereo wavs
117  if( this->Channels == 1 || this->Channels == 2 ) {
118  this->WavStream->read((char*)&Temp32,4);
119  this->SampleRate = Temp32;
120  this->WavStream->read((char*)&Temp32,4);
121  this->ByteRate = Temp32;
122  this->WavStream->read((char*)&Temp16,2);
123  this->BlockAlign = Temp16;
124  this->WavStream->read((char*)&Temp16,2);
125  this->BitsPerSample = Temp16;
126 
127  // We only support 8 bit or 16 bit wavs
128  if( this->BitsPerSample == 8 || this->BitsPerSample == 16 ) {
129  // Reset our pointer to start scanning for the data block
130  this->WavStream->seekg(StartOffset);
131  // Scan for the first data chuck (not necessarily right after)
132  do{
133  this->WavStream->read(Ident,4);
134  } while( ( strncmp(Ident,DATATAG,4) != 0 ) && ( this->WavStream->tellg() < this->WavStreamSize ) );
135 
136  // Did we find it?
137  if( this->WavStream->tellg() < this->WavStreamSize ) {
138  // Get size of data block
139  this->WavStream->read((char*)&Temp32,4);
140  this->DataSize = Temp32;
141  this->DataOffset = this->WavStream->tellg();
142  this->Valid = true;
143  }
144  }
145  }
146  }
147  }
148  }
149  }
150  }
151  }
152 
153  void WavDecoder::ClearStreamErrors()
154  {
155  if( this->WavStream->eof() ) {
156  this->WavStream->clear( this->WavStream->rdstate() ^ ( std::ios::eofbit | std::ios::failbit ) );
157  }
158  }
159 
160  ///////////////////////////////////////////////////////////////////////////////
161  // Utility
162 
163  Boole WavDecoder::IsValid()
164  {
165  return this->Valid;
166  }
167 
168  Audio::Encoding WavDecoder::GetEncoding() const
169  {
170  return Audio::Enc_WAV;
171  }
172 
173  Boole WavDecoder::IsSeekingSupported()
174  {
175  return true;
176  }
177 
178  Audio::BitConfig WavDecoder::GetBitConfiguration() const
179  {
180  if(this->Channels == 1 && this->BitsPerSample == 8)
181  return Audio::BC_8Bit_Mono;
182  else if(this->Channels == 1 && this->BitsPerSample == 16)
183  return Audio::BC_16Bit_Mono;
184  else if(this->Channels == 2 && this->BitsPerSample == 8)
185  return Audio::BC_8Bit_Stereo;
186  else if(this->Channels == 2 && this->BitsPerSample == 16)
187  return Audio::BC_16Bit_Stereo;
188  else
189  return Audio::BC_8Bit_Mono;//fallback return
190  }
191 
192  UInt32 WavDecoder::GetFrequency() const
193  {
194  return this->SampleRate;
195  }
196 
197  Resource::DataStreamPtr WavDecoder::GetStream() const
198  {
199  return this->WavStream;
200  }
201 
202  Boole WavDecoder::IsEndOfStream() const
203  {
204  return ( this->WavStream->eof() || this->WavStream->tellg() >= this->WavStreamSize );
205  }
206 
207  Boole WavDecoder::SetPosition(Int32 Position, const Boole Relative)
208  {
209  Int32 CurrPos = this->WavStream->tellg();
210  Int32 StartPos = this->DataOffset;
211  Int32 EndPos = this->DataOffset + this->DataSize;
212 
213  if( Relative ) {
214  if( CurrPos + Position < StartPos ) Position = StartPos;
215  else if( CurrPos + Position > EndPos ) Position = EndPos;
216  }else{
217  if( Position < StartPos ) Position = StartPos;
218  else if( Position > EndPos ) Position = EndPos;
219  }
220 
221  this->WavStream->seekg(Position);
222  return true;
223  }
224 
225  Boole WavDecoder::Seek(const Real Seconds, const Boole Relative)
226  {
227  Int32 SeekInBytes = ( Seconds * static_cast<Real>(this->SampleRate) * static_cast<Real>(this->Channels) * (static_cast<Real>(this->BitsPerSample) / 8.0) );
228  return this->SetPosition(SeekInBytes,Relative);
229  }
230 
231  UInt32 WavDecoder::ReadAudioData(void* Output, UInt32 Amount)
232  {
233  Int32 CurrPos = this->WavStream->tellg();
234  Int32 StartPos = this->DataOffset;
235  Int32 EndPos = this->DataOffset + this->DataSize;
236  Int32 ReadClamped = Amount;
237 
238  if( CurrPos > EndPos ) {
239  return 0;
240  }
241 
242  if( CurrPos < StartPos ) {
243  this->WavStream->seekg(StartPos);
244  CurrPos = this->WavStream->tellg();
245  }
246 
247  if( CurrPos + ReadClamped > EndPos )
248  ReadClamped = EndPos - CurrPos;
249 
250  if( ReadClamped < 0 )
251  return 0;
252 
253  this->WavStream->read(static_cast<char*>(Output),ReadClamped);
254  return this->WavStream->gcount();
255  }
256 
257  ///////////////////////////////////////////////////////////////////////////////
258  // Stream Stats
259 
260  Real WavDecoder::GetTotalTime() const
261  {
262  Real Second = ( static_cast<Real>(this->SampleRate) * static_cast<Real>(this->Channels) * (static_cast<Real>(this->BitsPerSample) / 8.0) );
263  return static_cast<Real>(this->WavStreamSize) / Second;
264  }
265 
266  Real WavDecoder::GetCurrentTime() const
267  {
268  Real Second = ( static_cast<Real>(this->SampleRate) * static_cast<Real>(this->Channels) * (static_cast<Real>(this->BitsPerSample) / 8.0) );
269  return static_cast<Real>(this->WavStream->tellg()) / Second;
270  }
271 
272  UInt32 WavDecoder::GetTotalSize() const
273  {
274  return this->WavStreamSize;
275  }
276 
277  UInt32 WavDecoder::GetCompressedSize() const
278  {
279  return this->WavStreamSize;
280  }
281 
282  UInt32 WavDecoder::GetCurrentPosition() const
283  {
284  return this->WavStream->tellg();
285  }
286 
287  UInt32 WavDecoder::GetCurrentCompressedPosition() const
288  {
289  return this->WavStream->tellg();
290  }
291  }//Audio
292 }//Mezzanine
293 
294 #endif //ENABLE_WAV_ENCODE
295 
296 #endif
int32_t Int32
An 32-bit integer.
Definition: datatypes.h:124
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
uint32_t UInt32
An 32-bit unsigned integer.
Definition: datatypes.h:126
int16_t Int16
An 16-bit integer.
Definition: datatypes.h:120
Encoding
The encoding to use when reading or writing an audio buffer.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
CountedPtr< DataStream > DataStreamPtr
This is a convenience type for a data stream in a counted pointer.
Definition: datastream.h:383
Used in .wav files.
BitConfig
Used to describe the different bit configurations supported by this audio system. ...