1// -------------------------------------------------------------------------- 2// Name: sndwav.cpp 3// Purpose: 4// Date: 08/11/1999 5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999 6// CVSID: $Id: sndwav.cpp 35650 2005-09-23 12:56:45Z MR $ 7// wxWindows licence 8// -------------------------------------------------------------------------- 9 10#include "wx/wxprec.h" 11 12#ifndef WX_PRECOMP 13 #include "wx/defs.h" 14#endif 15 16#ifdef __BORLANDC__ 17 #pragma hdrstop 18#endif 19 20#include "wx/stream.h" 21#include "wx/datstrm.h" 22#include "wx/filefn.h" 23#include "wx/mstream.h" 24 25#include "wx/mmedia/sndbase.h" 26#include "wx/mmedia/sndcodec.h" 27#include "wx/mmedia/sndfile.h" 28#include "wx/mmedia/sndpcm.h" 29#include "wx/mmedia/sndg72x.h" 30#include "wx/mmedia/sndmsad.h" 31#include "wx/mmedia/sndwav.h" 32 33#define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16) | (((wxUint32)d) << 24)) 34 35#define RIFF_SIGNATURE BUILD_SIGNATURE('R','I','F','F') 36#define WAVE_SIGNATURE BUILD_SIGNATURE('W','A','V','E') 37#define FMT_SIGNATURE BUILD_SIGNATURE('f','m','t',' ') 38#define DATA_SIGNATURE BUILD_SIGNATURE('d','a','t','a') 39 40#define HEADER_SIZE 4+4 + 4+4+16 + 4+4 41// 4+4 => NAME + LEN 42// 16 => fmt size 43 44wxSoundWave::wxSoundWave(wxInputStream& stream, wxSoundStream& io_sound) 45 : wxSoundFileStream(stream, io_sound) 46{ 47 m_base_offset = wxInvalidOffset; 48} 49 50wxSoundWave::wxSoundWave(wxOutputStream& stream, wxSoundStream& io_sound) 51 : wxSoundFileStream(stream, io_sound) 52{ 53 m_base_offset = wxInvalidOffset; 54} 55 56wxSoundWave::~wxSoundWave() 57{ 58} 59 60wxString wxSoundWave::GetCodecName() const 61{ 62 return wxString(wxT("wxSoundWave codec")); 63} 64 65#define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return false; } 66 67bool wxSoundWave::CanRead() 68{ 69 wxUint32 len, signature1, signature2; 70 m_snderror = wxSOUND_NOERROR; 71 72 // Test the main signatures: 73 // "RIFF" 74 FAIL_WITH(m_input->Read(&signature1, 4).LastRead() != 4, wxSOUND_INVSTRM); 75 76 if (wxUINT32_SWAP_ON_BE(signature1) != RIFF_SIGNATURE) { 77 m_input->Ungetch(&signature1, 4); 78 return false; 79 } 80 81 // Pass the global length 82 m_input->Read(&len, 4); 83 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); 84 85 // Get the second signature 86 FAIL_WITH(m_input->Read(&signature2, 4).LastRead() != 4, wxSOUND_INVSTRM); 87 // Ungetch all 88 m_input->Ungetch(&signature2, 4); 89 m_input->Ungetch(&len, 4); 90 m_input->Ungetch(&signature1, 4); 91 92 // Test the second signature 93 if (wxUINT32_SWAP_ON_BE(signature2) != WAVE_SIGNATURE) 94 return false; 95 96 return true; 97} 98 99bool wxSoundWave::HandleOutputPCM(wxDataInputStream& WXUNUSED(data), wxUint32 len, 100 wxUint16 channels, 101 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec), 102 wxUint16 WXUNUSED(byte_p_spl), wxUint16 bits_p_spl) 103{ 104 wxSoundFormatPcm sndformat; 105 106 sndformat.SetSampleRate(sample_fq); 107 sndformat.SetBPS(bits_p_spl); 108 sndformat.SetChannels(channels); 109 sndformat.Signed(true); 110 sndformat.SetOrder(wxLITTLE_ENDIAN); 111 112 if (!SetSoundFormat(sndformat)) 113 return false; 114 115 m_input->SeekI(len, wxFromCurrent); 116 117 return true; 118} 119 120bool wxSoundWave::HandleOutputMSADPCM(wxDataInputStream& data, wxUint32 len, 121 wxUint16 channels, 122 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec), 123 wxUint16 WXUNUSED(byte_p_spl), wxUint16 WXUNUSED(bits_p_spl)) 124{ 125 wxSoundFormatMSAdpcm sndformat; 126 wxInt16 *coefs[2]; 127 wxUint16 coefs_len, i; 128 wxUint16 block_size; 129 130 sndformat.SetSampleRate(sample_fq); 131 sndformat.SetChannels(channels); 132 133 block_size = data.Read16(); 134 coefs_len = data.Read16(); 135 136 coefs[0] = new wxInt16[coefs_len]; 137 coefs[1] = new wxInt16[coefs_len]; 138 139 for (i=0;i<coefs_len;i++) { 140 coefs[0][i] = data.Read16(); 141 coefs[1][i] = data.Read16(); 142 } 143 144 sndformat.SetCoefs(coefs, 2, coefs_len); 145 sndformat.SetBlockSize(block_size); 146 147 delete[] coefs[0]; 148 delete[] coefs[1]; 149 150 if (!SetSoundFormat(sndformat)) 151 return false; 152 153 len -= coefs_len*4 + 4; 154 155 m_input->SeekI(len, wxFromCurrent); 156 157 return true; 158} 159 160bool wxSoundWave::HandleOutputG721(wxDataInputStream& WXUNUSED(data), wxUint32 len, 161 wxUint16 WXUNUSED(channels), 162 wxUint32 sample_fq, wxUint32 WXUNUSED(byte_p_sec), 163 wxUint16 WXUNUSED(byte_p_spl), wxUint16 WXUNUSED(bits_p_spl)) 164{ 165 wxSoundFormatG72X sndformat; 166 167 sndformat.SetSampleRate(sample_fq); 168 sndformat.SetG72XType(wxSOUND_G721); 169 170 if (!SetSoundFormat(sndformat)) 171 return false; 172 173 m_input->SeekI(len, wxFromCurrent); 174 175 return true; 176} 177 178bool wxSoundWave::PrepareToPlay() 179{ 180 wxUint32 signature, len; 181 bool end_headers; 182 183 if (!m_input) { 184 m_snderror = wxSOUND_INVSTRM; 185 return false; 186 } 187 188 wxDataInputStream data(*m_input); 189 data.BigEndianOrdered(false); 190 191 // Get the first signature 192 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); 193 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != RIFF_SIGNATURE, wxSOUND_INVSTRM); 194 // "RIFF" 195 196 len = data.Read32(); 197 wxUnusedVar(len); 198 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); 199 // dummy len 200 201 // Get the second signature 202 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); 203 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != WAVE_SIGNATURE, wxSOUND_INVSTRM); 204 // "WAVE" 205 206 end_headers = false; 207 // Chunk loop 208 while (!end_headers) { 209 FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); 210 211 len = data.Read32(); 212 FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); 213 214 switch (wxUINT32_SWAP_ON_BE(signature)) { 215 case FMT_SIGNATURE: { // "fmt " 216 wxUint16 format, channels, byte_p_spl, bits_p_spl; 217 wxUint32 sample_fq, byte_p_sec; 218 219 // Get the common parameters 220 data >> format >> channels >> sample_fq 221 >> byte_p_sec >> byte_p_spl >> bits_p_spl; 222 len -= 16; 223 224 switch (format) { 225 case 0x01: // PCM 226 if (!HandleOutputPCM(data, len, channels, sample_fq, 227 byte_p_sec, byte_p_spl, 228 bits_p_spl)) 229 return false; 230 break; 231 case 0x02: // MS ADPCM 232 if (!HandleOutputMSADPCM(data, len, 233 channels, sample_fq, 234 byte_p_sec, byte_p_spl, 235 bits_p_spl)) 236 return false; 237 break; 238 case 0x40: // G721 239 if (!HandleOutputG721(data, len, 240 channels, sample_fq, 241 byte_p_sec, byte_p_spl, 242 bits_p_spl)) 243 return false; 244 break; 245 default: 246 m_snderror = wxSOUND_NOCODEC; 247 return false; 248 } 249 break; 250 } 251 case DATA_SIGNATURE: // "data" 252 m_base_offset = m_input->TellI(); 253 end_headers = true; 254 FinishPreparation(len); 255 break; 256 default: 257 // We pass the chunk 258 m_input->SeekI(len, wxFromCurrent); 259 break; 260 } 261 } 262 return true; 263} 264 265wxSoundFormatBase *wxSoundWave::HandleInputPCM(wxDataOutputStream& data) 266{ 267 wxUint16 format, channels, byte_p_spl, bits_p_spl; 268 wxUint32 sample_fq, byte_p_sec; 269 wxSoundFormatPcm *pcm; 270 271 pcm = (wxSoundFormatPcm *)(m_sndformat->Clone()); 272 273 // Write block length 274 data.Write32(16); 275 276 sample_fq = pcm->GetSampleRate(); 277 bits_p_spl = pcm->GetBPS(); 278 channels = pcm->GetChannels(); 279 byte_p_spl = pcm->GetBPS() / 8; 280 byte_p_sec = pcm->GetBytesFromTime(1); 281 format = 0x01; 282 283 pcm->Signed(true); 284 pcm->SetOrder(wxLITTLE_ENDIAN); 285 286 data << format << channels << sample_fq 287 << byte_p_sec << byte_p_spl << bits_p_spl; 288 289 return pcm; 290} 291 292wxSoundFormatBase *wxSoundWave::HandleInputG72X(wxDataOutputStream& data) 293{ 294 wxUint16 format, channels, byte_p_spl, bits_p_spl; 295 wxUint32 sample_fq, byte_p_sec; 296 wxSoundFormatG72X *g72x; 297 298 // Write block length 299 data.Write32(16); 300 301 g72x = (wxSoundFormatG72X *)(m_sndformat->Clone()); 302 if (g72x->GetG72XType() != wxSOUND_G721) { 303 delete g72x; 304 return NULL; 305 } 306 307 sample_fq = g72x->GetSampleRate(); 308 bits_p_spl = 4; 309 channels = 1; 310 byte_p_spl = 0; 311 byte_p_sec = g72x->GetBytesFromTime(1); 312 format = 0x40; 313 data << format << channels << sample_fq 314 << byte_p_sec << byte_p_spl << bits_p_spl; 315 316 return g72x; 317} 318 319bool wxSoundWave::PrepareToRecord(wxUint32 time) 320{ 321#define WRITE_SIGNATURE(s,sig) \ 322signature = sig; \ 323signature = wxUINT32_SWAP_ON_BE(signature); \ 324FAIL_WITH(s->Write(&signature, 4).LastWrite() != 4, wxSOUND_INVSTRM); 325 326 wxUint32 signature; 327 wxMemoryOutputStream fmt_data; 328 329 if (!m_output) { 330 m_snderror = wxSOUND_INVSTRM; 331 return false; 332 } 333 334 wxDataOutputStream data(*m_output); 335 wxDataOutputStream fmt_d_data(fmt_data); 336 337 data.BigEndianOrdered(false); 338 fmt_d_data.BigEndianOrdered(false); 339 340 WRITE_SIGNATURE(m_output, RIFF_SIGNATURE); 341 342 FAIL_WITH(m_output->LastWrite() != 4, wxSOUND_INVSTRM); 343 344 WRITE_SIGNATURE((&fmt_data), WAVE_SIGNATURE); 345 346 { 347 wxSoundFormatBase *frmt; 348 349 WRITE_SIGNATURE((&fmt_data), FMT_SIGNATURE); 350 351 switch (m_sndformat->GetType()) { 352 case wxSOUND_PCM: 353 frmt = HandleInputPCM(fmt_d_data); 354 break; 355 case wxSOUND_G72X: 356 frmt = HandleInputG72X(fmt_d_data); 357 break; 358 default: 359 m_snderror = wxSOUND_NOCODEC; 360 return false; 361 } 362 363 FAIL_WITH(!frmt, wxSOUND_NOCODEC); 364 365 if (!SetSoundFormat(*frmt)) { 366 delete frmt; 367 return false; 368 } 369 370 delete frmt; 371 } 372 373 data << (wxUint32)(fmt_data.GetSize() + m_sndformat->GetBytesFromTime(time)); 374 375 // We, finally, copy the header block to the output stream 376 { 377 char *out_buf; 378 out_buf = new char[fmt_data.GetSize()]; 379 380 fmt_data.CopyTo(out_buf, fmt_data.GetSize()); 381 m_output->Write(out_buf, fmt_data.GetSize()); 382 383 delete[] out_buf; 384 } 385 386 WRITE_SIGNATURE(m_output, DATA_SIGNATURE); 387 data.Write32(m_sndformat->GetBytesFromTime(time)); 388 return true; 389} 390 391bool wxSoundWave::FinishRecording() 392{ 393 if (m_output->SeekO(0, wxFromStart) == wxInvalidOffset) 394 // We can't but there is no error. 395 return true; 396 397 if (m_bytes_left == 0) 398 return true; 399 400 // TODO: Update headers when we stop before the specified time (if possible) 401 return true; 402} 403 404bool wxSoundWave::RepositionStream(wxUint32 WXUNUSED(position)) 405{ 406 if (m_base_offset == wxInvalidOffset) 407 return false; 408 m_input->SeekI(m_base_offset, wxFromStart); 409 return true; 410} 411 412wxUint32 wxSoundWave::GetData(void *buffer, wxUint32 len) 413{ 414 return m_input->Read(buffer, len).LastRead(); 415} 416 417wxUint32 wxSoundWave::PutData(const void *buffer, wxUint32 len) 418{ 419 return m_output->Write(buffer, len).LastWrite(); 420} 421