1 // -------------------------------------------------------------------------- 
   5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000 
   7 // -------------------------------------------------------------------------- 
   9 #pragma implementation "sndcpcm.cpp" 
  12 #include "wx/wxprec.h" 
  24 #include "wx/mmedia/sndbase.h" 
  25 #include "wx/mmedia/sndpcm.h" 
  26 #include "wx/mmedia/sndcpcm.h" 
  28 wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream
& sndio
) 
  29         : wxSoundStreamCodec(sndio
) 
  32     m_function_out 
= NULL
; 
  38 wxSoundStreamPcm::~wxSoundStreamPcm() 
  44 wxUint32 
wxSoundStreamPcm::GetBestSize() const 
  49 // ----------------------------------------------------------------------- 
  50 // "Converters" definitions/implementations 
  51 // ----------------------------------------------------------------------- 
  53 #define DEFINE_CONV(name, input_type, output_type, convert) \ 
  54 static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \ 
  56   register input_type src; \ 
  57   register const input_type *t_buf_in = (input_type *)buf_in; \ 
  58   register output_type *t_buf_out = (output_type *)buf_out; \ 
  62     *t_buf_out++ = convert; \ 
  63     len -= sizeof(input_type); \ 
  67 // TODO: define converters for all other formats (32, 24) 
  69 DEFINE_CONV(8_8_sign
, wxUint8
, wxUint8
, (src 
^ 0x80)) 
  71 DEFINE_CONV(8_16
, wxUint8
, wxUint16
, (((wxUint16
)src
) << 8)) 
  72 DEFINE_CONV(8_16_swap
, wxUint8
, wxUint16
, (src
)) 
  73 DEFINE_CONV(8_16_sign
, wxUint8
, wxUint16
, (((wxUint16
)(src 
^ 0x80)) << 8)) 
  74 DEFINE_CONV(8_16_sign_swap
, wxUint8
, wxUint16
, (src 
^ 0x80)) 
  76 DEFINE_CONV(16_8
, wxUint16
, wxUint8
, (wxUint8
)(src 
>> 8)) 
  77 DEFINE_CONV(16_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src 
>> 8) ^ 0x80)) 
  78 DEFINE_CONV(16_swap_8
, wxUint16
, wxUint8
, (wxUint8
)(src 
& 0xff)) 
  79 DEFINE_CONV(16_swap_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src 
& 0xff) ^ 0x80)) 
  81 //DEFINE_CONV(24_8, wxUint32, wxUint8, (wxUint8)(src >> 16)) 
  82 //DEFINE_CONV(24_8_sig, wxUint32, wxUint8, (wxUint8)((src >> 16) ^ 0x80)) 
  84 //DEFINE_CONV(32_8, wxUint32, wxUint8, (wxUint8)(src >> 24)) 
  86 DEFINE_CONV(16_sign
, wxUint16
, wxUint16
, (src 
^ 0x8000)) 
  87 DEFINE_CONV(16_swap
, wxUint16
, wxUint16
, (((src 
& 0xff) << 8) | ((src 
>> 8) & 0xff))) 
  89 DEFINE_CONV(16_swap_16_sign
, wxUint16
, wxUint16
, ((((src 
& 0xff) << 8) | ((src 
>> 8) & 0xff)) ^ 0x80)) 
  90 // DEFINE_CONV(16_sign_16_swap, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x8000)) 
  91 DEFINE_CONV(16_swap_16_sign_swap
, wxUint16
, wxUint16
, (src 
^ 0x80)) 
  93 // ----------------------------------------------------------------------- 
  94 // Main PCM stream converter table 
  95 // ----------------------------------------------------------------------- 
 101 //   XX swapped -> YY sign 
 103 //   XX swapped -> YY swapped 
 104 //   XX swapped -> YY swapped sign 
 106 //   XX stereo -> YY mono 
 107 //   XX stereo -> YY mono sign 
 109 //   XX swapped stereo -> YY swapped mono 
 110 //   XX swapped stereo -> YY swapped mono sign 
 112 //   XX swapped stereo -> YY swapped mono 
 113 //   XX swapped stereo -> YY swapped mono sign 
 115 static wxSoundStreamPcm::ConverterType s_converters
[4][3][2] = {  
 119             Convert_8_8_sign                    
/* 8 -> 8 sign */ 
 132             Convert_8_16
,                       /* 8 -> 16 */ 
 133             Convert_8_16_sign                   
/* 8 -> 16 sign */ 
 136             Convert_8_16_swap
,                  /* 8 -> 16 swapped */ 
 137             Convert_8_16_sign_swap              
/* 8 -> 16 sign swapped */ 
 146             Convert_16_8
,                       /* 16 -> 8 */ 
 147             Convert_16_8_sign                   
/* 16 -> 8 sign */ 
 150             Convert_16_swap_8
,                  /* 16 swapped -> 8 */ 
 151             Convert_16_swap_8_sign              
/* 16 swapped -> 8 sign */ 
 162             Convert_16_sign                     
/* 16 -> 16 sign */ 
 165             Convert_16_swap
,                    /* 16 swapped -> 16 */ 
 166             Convert_16_swap_16_sign             
/* 16 swapped -> 16 sign */ 
 170             Convert_16_swap_16_sign_swap        
/* 16 swapped -> 16 sign swapped */ 
 175 // This is the buffer size multiplier. It gives the needed size of the output size. 
 176 static float s_converters_multip
[] = {1, 2, 0.5, 1}; 
 179 // TODO: Read() and Write() aren't really safe. If you give it a buffer which 
 180 // is not aligned on 2, you may crash (See converter.def). 
 183 wxSoundStream
& wxSoundStreamPcm::Read(void *buffer
, wxUint32 len
) 
 187     // We must have a multiple of 2 
 190     if (!m_function_in
) { 
 191         m_sndio
->Read(buffer
, len
); 
 192         m_lastcount 
= m_sndio
->GetLastAccess(); 
 193         m_snderror 
= m_sndio
->GetError(); 
 197     in_bufsize 
= GetReadSize(len
); 
 199     if (len 
<= m_best_size
) { 
 200         m_sndio
->Read(m_prebuffer
, in_bufsize
); 
 201         m_snderror  
= m_sndio
->GetError(); 
 202         if (m_snderror 
!= wxSOUND_NOERROR
) { 
 207         m_function_in(m_prebuffer
, buffer
, m_sndio
->GetLastAccess()); 
 211         temp_buffer 
= new char[in_bufsize
]; 
 212         m_sndio
->Read(temp_buffer
, in_bufsize
); 
 214         m_snderror 
=  m_sndio
->GetError(); 
 215         if (m_snderror 
!= wxSOUND_NOERROR
) { 
 220         m_function_in(temp_buffer
, buffer
, m_sndio
->GetLastAccess()); 
 222         delete[] temp_buffer
; 
 225     m_lastcount 
= (wxUint32
)(m_sndio
->GetLastAccess() * m_multiplier_in
); 
 230 wxSoundStream
& wxSoundStreamPcm::Write(const void *buffer
, wxUint32 len
) 
 232     wxUint32 out_bufsize
; 
 234     if (!m_function_out
) { 
 235         m_sndio
->Write(buffer
, len
); 
 236         m_lastcount 
= m_sndio
->GetLastAccess(); 
 237         m_snderror  
= m_sndio
->GetError(); 
 241     out_bufsize 
= GetWriteSize(len
); 
 243     if (len 
<= m_best_size
) { 
 244         out_bufsize 
= GetWriteSize(len
); 
 246         m_function_out(buffer
, m_prebuffer
, len
); 
 247         m_sndio
->Write(m_prebuffer
, out_bufsize
); 
 248         m_snderror  
= m_sndio
->GetError(); 
 249         if (m_snderror 
!= wxSOUND_NOERROR
) { 
 256         temp_buffer 
= new char[out_bufsize
]; 
 257         m_function_out(buffer
, temp_buffer
, len
); 
 259         m_sndio
->Write(temp_buffer
, out_bufsize
); 
 260         m_snderror 
=  m_sndio
->GetError(); 
 261         if (m_snderror 
!= wxSOUND_NOERROR
) { 
 266         delete[] temp_buffer
; 
 269     m_lastcount 
= (wxUint32
)(m_sndio
->GetLastAccess() / m_multiplier_out
); 
 274 bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase
& format
) 
 276     wxSoundFormatBase 
*new_format
; 
 277     wxSoundFormatPcm 
*pcm_format
, *pcm_format2
; 
 279     if (m_sndio
->SetSoundFormat(format
)) { 
 280         m_function_out 
= NULL
; 
 281         m_function_in 
= NULL
; 
 284     if (format
.GetType() != wxSOUND_PCM
) { 
 285         m_snderror 
= wxSOUND_INVFRMT
; 
 291     new_format 
= m_sndio
->GetSoundFormat().Clone(); 
 292     pcm_format 
= (wxSoundFormatPcm 
*)&format
; 
 293     pcm_format2 
= (wxSoundFormatPcm 
*)new_format
; 
 296     // ---------------------------------------------------- 
 297     // Test whether we need to resample 
 298     if (pcm_format
->GetSampleRate() != pcm_format2
->GetSampleRate()) { 
 299         wxUint32 src_rate
, dst_rate
; 
 301         src_rate 
= pcm_format
->GetSampleRate(); 
 302         dst_rate 
= pcm_format2
->GetSampleRate(); 
 303         m_needResampling 
= TRUE
; 
 304         if (src_rate 
< dst_rate
) 
 305             m_expandSamples 
= TRUE
; 
 307             m_expandSamples 
= FALSE
; 
 308         m_pitch 
= (src_rate 
<< FLOATBITS
) / dst_rate
; 
 311     // ---------------------------------------------------- 
 312     // Select table to use: 
 313     //     * 8 bits -> 8 bits 
 314     //     * 16 bits -> 8 bits 
 315     //     * 8 bits -> 16 bits 
 316     //     * 16 bits -> 16 bits 
 318     int table_no
, table_no2
; 
 321     switch (pcm_format
->GetBPS()) { 
 329             // TODO: Add something here: error, log, ... 
 332     switch (pcm_format2
->GetBPS()) { 
 340             // TODO: Add something here: error, log, ... 
 344     if (pcm_format2
->Signed() != pcm_format
->Signed()) 
 349 #define MY_ORDER wxBYTE_ORDER 
 350 #if wxBYTE_ORDER == wxLITTLE_ENDIAN 
 351 #define OTHER_ORDER wxBIG_ENDIAN 
 353 #define OTHER_ORDER wxLITTLE_ENDIAN 
 356     // -------------------------------------------------------- 
 357     // Find the good converter ! 
 359     if (pcm_format
->GetOrder() == OTHER_ORDER
) { 
 360         if (pcm_format
->GetOrder() == pcm_format2
->GetOrder()) 
 365         if (pcm_format
->GetOrder() == pcm_format2
->GetOrder()) 
 371     m_function_out 
= s_converters
[table_no
*2+table_no2
][i_swap
][i_sign
]; 
 372     m_function_in  
= s_converters
[table_no2
*2+table_no
][i_swap
][i_sign
]; 
 373     m_multiplier_out 
= s_converters_multip
[table_no
*2+table_no2
]; 
 374     m_multiplier_in  
= s_converters_multip
[table_no2
*2+table_no2
]; 
 377         delete[] m_prebuffer
; 
 379     // We try to minimize the need of dynamic memory allocation by preallocating a buffer. But 
 380     // to be sure it will be efficient we minimize the best size. 
 381     if (m_multiplier_in 
< m_multiplier_out
) { 
 382         m_prebuffer_size 
= (wxUint32
)(m_sndio
->GetBestSize() * 
 384         m_best_size 
= (wxUint32
)(m_sndio
->GetBestSize() * 
 387         m_prebuffer_size 
= (wxUint32
)(m_sndio
->GetBestSize() * 
 389         m_best_size 
= (wxUint32
)(m_sndio
->GetBestSize() * 
 393     m_prebuffer 
= new char[m_prebuffer_size
]; 
 395     bool SetSoundFormatReturn
; 
 397     SetSoundFormatReturn 
= m_sndio
->SetSoundFormat(*new_format
); 
 398     wxASSERT( SetSoundFormatReturn 
); 
 400     m_sndformat 
= new_format
; 
 404 wxUint32 
wxSoundStreamPcm::GetWriteSize(wxUint32 len
) const 
 406     // For the moment, it is simple but next time it will become more complicated 
 408     return (wxUint32
)(len 
* m_multiplier_out
); 
 411 wxUint32 
wxSoundStreamPcm::GetReadSize(wxUint32 len
) const 
 413     return (wxUint32
)(len 
/ m_multiplier_in
); 
 416 // Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT. 
 422 #define FLOATMASK 0xffff 
 423 #define INTMASK 0xffff0000 
 425 void ResamplingShrink_
##DEPTH##(const void *source, void *destination, wxUint32 len) 
 427     wxUint
##DEPTH## *source_data, *dest_data; 
 430     source_data 
= (wxUint
##DEPTH## *)source; 
 431     dest_data   
= (wxUint
##DEPTH## *)destination; 
 435         // Increment the position in the input buffer 
 440             *dest_data 
++ = *source_data
;