1// -------------------------------------------------------------------------- 2// Name: sndulaw.cpp 3// Purpose: 4// Date: 08/11/1999 5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999 6// CVSID: $Id: sndmsad.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 #include "wx/memory.h" 15 #include "wx/log.h" 16#endif 17 18#include "wx/mmedia/sndbase.h" 19#include "wx/mmedia/sndfile.h" 20#include "wx/mmedia/sndpcm.h" 21#include "wx/mmedia/sndmsad.h" 22 23// -------------------------------------------------------------------------- 24// wxSoundFormatMSAdpcm 25// -------------------------------------------------------------------------- 26 27wxSoundFormatMSAdpcm::wxSoundFormatMSAdpcm() 28 : m_srate(22050) 29{ 30 m_ncoefs = 0; 31 m_coefs_len = 0; 32 m_coefs = NULL; 33} 34 35wxSoundFormatMSAdpcm::~wxSoundFormatMSAdpcm() 36{ 37 if (m_ncoefs) { 38 wxUint16 i; 39 40 for (i=0;i<m_ncoefs;i++) 41 delete[] m_coefs[i]; 42 delete[] m_coefs; 43 } 44 45} 46 47void wxSoundFormatMSAdpcm::SetSampleRate(wxUint32 srate) 48{ 49 m_srate = srate; 50} 51 52wxUint32 wxSoundFormatMSAdpcm::GetSampleRate() const 53{ 54 return m_srate; 55} 56 57void wxSoundFormatMSAdpcm::SetChannels(wxUint16 nchannels) 58{ 59 m_nchannels = nchannels; 60} 61 62wxUint16 wxSoundFormatMSAdpcm::GetChannels() const 63{ 64 return m_nchannels; 65} 66 67void wxSoundFormatMSAdpcm::SetCoefs(wxInt16 **WXUNUSED(coefs), wxUint16 ncoefs, 68 wxUint16 coefs_len) 69{ 70 wxUint16 i; 71 72 if (m_ncoefs) { 73 for (i=0;i<m_ncoefs;i++) 74 delete[] (m_coefs[i]); 75 delete[] m_coefs; 76 } 77 // TODO: Add some memory checking here 78 m_coefs = new wxInt16 *[ncoefs]; 79 80 for (i=0;i<ncoefs;i++) 81 m_coefs[i] = new wxInt16[coefs_len]; 82 83 m_ncoefs = ncoefs; 84 m_coefs_len = coefs_len; 85} 86 87void wxSoundFormatMSAdpcm::GetCoefs(wxInt16 **& coefs, wxUint16& ncoefs, 88 wxUint16& coefs_len) const 89{ 90 coefs = m_coefs; 91 ncoefs = m_ncoefs; 92 coefs_len = m_coefs_len; 93} 94 95void wxSoundFormatMSAdpcm::SetBlockSize(wxUint16 block_size) 96{ 97 m_block_size = block_size; 98} 99 100wxUint16 wxSoundFormatMSAdpcm::GetBlockSize() const 101{ 102 return m_block_size; 103} 104 105wxSoundFormatBase *wxSoundFormatMSAdpcm::Clone() const 106{ 107 wxSoundFormatMSAdpcm *adpcm = new wxSoundFormatMSAdpcm(); 108 109 adpcm->m_srate = m_srate; 110 adpcm->SetCoefs(m_coefs, m_ncoefs, m_coefs_len); 111 adpcm->m_nchannels = m_nchannels; 112 adpcm->m_block_size = m_block_size; 113 return adpcm; 114} 115 116wxUint32 wxSoundFormatMSAdpcm::GetTimeFromBytes(wxUint32 bytes) const 117{ 118 return 2 * bytes / (m_nchannels * m_srate); 119} 120 121wxUint32 wxSoundFormatMSAdpcm::GetBytesFromTime(wxUint32 time) const 122{ 123 return time * m_nchannels * m_srate / 2; 124} 125 126bool wxSoundFormatMSAdpcm::operator !=(const wxSoundFormatBase& frmt2) const 127{ 128 const wxSoundFormatMSAdpcm *adpcm = (const wxSoundFormatMSAdpcm *)&frmt2; 129 130 if (frmt2.GetType() != wxSOUND_MSADPCM) 131 return true; 132 133 return (adpcm->m_srate != m_srate) && (adpcm->m_nchannels != m_nchannels); 134} 135 136// -------------------------------------------------------------------------- 137// wxSoundStreamMSAdpcm 138// -------------------------------------------------------------------------- 139wxSoundStreamMSAdpcm::wxSoundStreamMSAdpcm(wxSoundStream& sndio) 140 : wxSoundStreamCodec(sndio) 141{ 142 // PCM converter 143 m_router = new wxSoundRouterStream(sndio); 144 m_got_header = false; 145 m_stereo = false; 146} 147 148wxSoundStreamMSAdpcm::~wxSoundStreamMSAdpcm() 149{ 150 delete m_router; 151} 152 153wxSoundStream& wxSoundStreamMSAdpcm::Read(void *WXUNUSED(buffer), wxUint32 WXUNUSED(len)) 154{ 155 m_snderror = wxSOUND_NOCODEC; 156 m_lastcount = 0; 157 return *this; 158} 159 160static wxInt16 gl_ADPCMcoeff_delta[] = { 161 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 162 230, 230, 230 163}; 164 165wxUint32 wxSoundStreamMSAdpcm::DecodeMonoADPCM(const void *in_buffer, 166 void *out_buffer, 167 wxUint32 in_len) 168{ 169 wxUint8 *ADPCMdata; 170 wxInt16 *PCMdata; 171 AdpcmState *state; 172 wxUint32 out_len; 173 174 ADPCMdata = (wxUint8 *)in_buffer; 175 PCMdata = (wxInt16 *)out_buffer; 176 state = &m_state[0]; 177 178#define GET_DATA_16(i) i = *ADPCMdata++, i |= ((wxUint32)(*ADPCMdata++) << 8) 179#define GET_DATA_8(i) i = (*ADPCMdata++) 180 181 out_len = 0; 182 while (in_len != 0) { 183 if (m_next_block == 0) { 184 GET_DATA_8(state->predictor); 185 GET_DATA_16(state->iDelta); 186 187 GET_DATA_16(state->samp1); 188 GET_DATA_16(state->samp2); 189 190 state->coeff[0] = state->coeff[1] = m_coefs[0][ state->predictor ]; 191 192 *PCMdata++ = state->samp2; 193 *PCMdata++ = state->samp1; 194 in_len -= 7; 195 out_len += 4; 196 m_next_block = m_block_size; 197 continue; 198 } 199 200 while (in_len != 0 && m_next_block != 0) { 201 wxUint8 nib[2]; 202 203 GET_DATA_8(nib[0]); 204 nib[1] = (nib[0] >> 4) & 0x0f; 205 nib[0] &= 0x0f; 206 207 Nibble(nib[0], state, &PCMdata); 208 Nibble(nib[1], state, &PCMdata); 209 210 in_len -= 4; 211 out_len += 4; 212 m_next_block -= 4; 213 } 214 } 215 216 return out_len; 217 218#undef GET_DATA_16 219#undef GET_DATA_8 220} 221 222wxUint32 wxSoundStreamMSAdpcm::DecodeStereoADPCM(const void *in_buffer, 223 void *out_buffer, 224 wxUint32 in_len) 225{ 226 wxUint8 *ADPCMdata; 227 wxInt16 *PCMdata; 228 AdpcmState *state0, *state1; 229 wxUint32 out_len; 230 231 ADPCMdata = (wxUint8 *)in_buffer; 232 PCMdata = (wxInt16 *)out_buffer; 233 234 state0 = &m_state[0]; 235 state1 = &m_state[1]; 236 237#define GET_DATA_16(i) i = *ADPCMdata++, i |= ((wxUint32)(*ADPCMdata++) << 8) 238#define GET_DATA_8(i) i = (*ADPCMdata++) 239 240 out_len = 0; 241 while (in_len != 0) { 242 if (!m_next_block) { 243 GET_DATA_8(state0->predictor); 244 GET_DATA_8(state1->predictor); 245 246 GET_DATA_16(state0->iDelta); 247 GET_DATA_16(state1->iDelta); 248 249 GET_DATA_16(state0->samp1); 250 GET_DATA_16(state1->samp1); 251 GET_DATA_16(state0->samp2); 252 GET_DATA_16(state1->samp2); 253 254 *PCMdata++ = state0->samp2; 255 *PCMdata++ = state1->samp2; 256 *PCMdata++ = state0->samp1; 257 *PCMdata++ = state1->samp1; 258 259 in_len -= 14; 260 out_len += 8; 261 m_next_block = m_block_size; 262 continue; 263 } 264 265 while (in_len != 0 && m_next_block > 0) { 266 wxUint8 nib[2]; 267 268 GET_DATA_8(nib[0]); 269 nib[1] = (nib[0] >> 4) & 0x0f; 270 nib[0] &= 0x0f; 271 272 Nibble(nib[0], state0, &PCMdata); 273 Nibble(nib[1], state1, &PCMdata); 274 275 in_len -= 4; 276 out_len += 4; 277 m_next_block -= 4; 278 } 279 } 280 281 return out_len; 282 283#undef GET_DATA_16 284#undef GET_DATA_8 285} 286 287void wxSoundStreamMSAdpcm::Nibble(wxInt8 nyb, 288 AdpcmState *state, 289 wxInt16 **out_buffer) 290{ 291 wxUint32 new_delta; 292 wxInt32 new_sample; 293 294 // First: compute the next delta value 295 new_delta = (state->iDelta * gl_ADPCMcoeff_delta[nyb]) >> 8; 296 // If null, minor it by 16 297 if (!new_delta) 298 new_delta = 16; 299 300 // Barycentre 301 new_sample = (state->samp1 * state->coeff[0] + 302 state->samp2 * state->coeff[1]) / 256; 303 304 // Regenerate the sign 305 if (nyb & 0x08) 306 nyb -= 0x10; 307 308 new_sample += state->iDelta * nyb; 309 310 // Samples must be in [-32767, 32768] 311 if (new_sample < -32768) 312 new_sample = -32768; 313 else if (new_sample > 32767) 314 new_sample = 32767; 315 316 state->iDelta = new_delta; 317 state->samp2 = state->samp1; 318 state->samp1 = new_sample; 319 320 *(*out_buffer)++ = new_sample; 321} 322 323wxSoundStream& wxSoundStreamMSAdpcm::Write(const void *buffer, wxUint32 len) 324{ 325 wxUint8 *out_buf; 326 wxUint32 new_len; 327 328 // TODO: prealloc the output buffer 329 out_buf = new wxUint8[len*2]; 330 331 if (!m_stereo) 332 new_len = DecodeMonoADPCM(buffer, out_buf, len); 333 else 334 new_len = DecodeStereoADPCM(buffer, out_buf, len); 335 336 m_router->Write(out_buf, new_len); 337 338 m_lastcount = len; 339 m_snderror = wxSOUND_NOERROR; 340 341 delete[] out_buf; 342 343 return *this; 344} 345 346wxUint32 wxSoundStreamMSAdpcm::GetBestSize() const 347{ 348 return m_sndio->GetBestSize() / 2; 349} 350 351bool wxSoundStreamMSAdpcm::SetSoundFormat(const wxSoundFormatBase& format) 352{ 353 if (format.GetType() != wxSOUND_MSADPCM) { 354 m_snderror = wxSOUND_INVFRMT; 355 return false; 356 } 357 358 wxSoundFormatPcm pcm; 359 wxSoundFormatMSAdpcm *adpcm; 360 wxUint16 ncoefs, coefs_len; 361 362 wxSoundStreamCodec::SetSoundFormat(format); 363 364 adpcm = (wxSoundFormatMSAdpcm *)m_sndformat; 365 366 adpcm->GetCoefs(m_coefs, ncoefs, coefs_len); 367 368 if (!ncoefs) { 369 wxLogError(wxT("Number of ADPCM coefficients must be non null")); 370 return false; 371 } 372 373 pcm.SetSampleRate(adpcm->GetSampleRate()); 374 pcm.SetBPS(16); 375 pcm.SetChannels(adpcm->GetChannels()); 376 pcm.Signed(true); 377 pcm.SetOrder(wxBYTE_ORDER); 378 379 m_stereo = (adpcm->GetChannels() == 2); 380 m_block_size = adpcm->GetBlockSize(); 381 m_next_block = 0; 382 383 m_router->SetSoundFormat(pcm); 384 385 return true; 386} 387 388