1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
8 // --------------------------------------------------------------------------
10 #pragma implementation "sndcpcm.cpp"
13 #include "wx/wxprec.h"
25 #include "wx/mmedia/sndbase.h"
26 #include "wx/mmedia/sndpcm.h"
27 #include "wx/mmedia/sndcpcm.h"
29 wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream
& sndio
)
30 : wxSoundStreamCodec(sndio
)
33 m_function_out
= NULL
;
39 wxSoundStreamPcm::~wxSoundStreamPcm()
45 wxUint32
wxSoundStreamPcm::GetBestSize() const
50 // -----------------------------------------------------------------------
51 // "Converters" definitions/implementations
52 // -----------------------------------------------------------------------
54 #define DEFINE_CONV(name, input_type, output_type, convert) \
55 static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \
57 register input_type src; \
58 register const input_type *t_buf_in = (input_type *)buf_in; \
59 register output_type *t_buf_out = (output_type *)buf_out; \
63 *t_buf_out++ = convert; \
64 len -= sizeof(input_type); \
68 // TODO: define converters for all other formats (32, 24)
70 DEFINE_CONV(8_8_sign
, wxUint8
, wxUint8
, (src
^ 0x80))
72 DEFINE_CONV(8_16
, wxUint8
, wxUint16
, (((wxUint16
)src
) << 8))
73 DEFINE_CONV(8_16_swap
, wxUint8
, wxUint16
, (src
))
74 DEFINE_CONV(8_16_sign
, wxUint8
, wxUint16
, (((wxUint16
)(src
^ 0x80)) << 8))
75 DEFINE_CONV(8_16_sign_swap
, wxUint8
, wxUint16
, (src
^ 0x80))
77 DEFINE_CONV(16_8
, wxUint16
, wxUint8
, (wxUint8
)(src
>> 8))
78 DEFINE_CONV(16_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src
>> 8) ^ 0x80))
79 DEFINE_CONV(16_swap_8
, wxUint16
, wxUint8
, (wxUint8
)(src
& 0xff))
80 DEFINE_CONV(16_swap_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src
& 0xff) ^ 0x80))
82 //DEFINE_CONV(24_8, wxUint32, wxUint8, (wxUint8)(src >> 16))
83 //DEFINE_CONV(24_8_sig, wxUint32, wxUint8, (wxUint8)((src >> 16) ^ 0x80))
85 //DEFINE_CONV(32_8, wxUint32, wxUint8, (wxUint8)(src >> 24))
87 DEFINE_CONV(16_sign
, wxUint16
, wxUint16
, (src
^ 0x8000))
88 DEFINE_CONV(16_swap
, wxUint16
, wxUint16
, (((src
& 0xff) << 8) | ((src
>> 8) & 0xff)))
90 DEFINE_CONV(16_swap_16_sign
, wxUint16
, wxUint16
, ((((src
& 0xff) << 8) | ((src
>> 8) & 0xff)) ^ 0x80))
91 // DEFINE_CONV(16_sign_16_swap, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x8000))
92 DEFINE_CONV(16_swap_16_sign_swap
, wxUint16
, wxUint16
, (src
^ 0x80))
94 // -----------------------------------------------------------------------
95 // Main PCM stream converter table
96 // -----------------------------------------------------------------------
102 // XX swapped -> YY sign
104 // XX swapped -> YY swapped
105 // XX swapped -> YY swapped sign
107 // XX stereo -> YY mono
108 // XX stereo -> YY mono sign
110 // XX swapped stereo -> YY swapped mono
111 // XX swapped stereo -> YY swapped mono sign
113 // XX swapped stereo -> YY swapped mono
114 // XX swapped stereo -> YY swapped mono sign
116 static wxSoundStreamPcm::ConverterType s_converters
[4][3][2] = {
120 Convert_8_8_sign
/* 8 -> 8 sign */
133 Convert_8_16
, /* 8 -> 16 */
134 Convert_8_16_sign
/* 8 -> 16 sign */
137 Convert_8_16_swap
, /* 8 -> 16 swapped */
138 Convert_8_16_sign_swap
/* 8 -> 16 sign swapped */
147 Convert_16_8
, /* 16 -> 8 */
148 Convert_16_8_sign
/* 16 -> 8 sign */
151 Convert_16_swap_8
, /* 16 swapped -> 8 */
152 Convert_16_swap_8_sign
/* 16 swapped -> 8 sign */
163 Convert_16_sign
/* 16 -> 16 sign */
166 Convert_16_swap
, /* 16 swapped -> 16 */
167 Convert_16_swap_16_sign
/* 16 swapped -> 16 sign */
171 Convert_16_swap_16_sign_swap
/* 16 swapped -> 16 sign swapped */
176 // This is the buffer size multiplier. It gives the needed size of the output size.
177 static float s_converters_multip
[] = {1, 2, 0.5, 1};
180 // TODO: Read() and Write() aren't really safe. If you give it a buffer which
181 // is not aligned on 2, you may crash (See converter.def).
184 wxSoundStream
& wxSoundStreamPcm::Read(void *buffer
, wxUint32 len
)
188 // We must have a multiple of 2
191 if (!m_function_in
) {
192 m_sndio
->Read(buffer
, len
);
193 m_lastcount
= m_sndio
->GetLastAccess();
194 m_snderror
= m_sndio
->GetError();
198 in_bufsize
= GetReadSize(len
);
200 if (len
<= m_best_size
) {
201 m_sndio
->Read(m_prebuffer
, in_bufsize
);
202 m_snderror
= m_sndio
->GetError();
203 if (m_snderror
!= wxSOUND_NOERROR
) {
208 m_function_in(m_prebuffer
, buffer
, m_sndio
->GetLastAccess());
212 temp_buffer
= new char[in_bufsize
];
213 m_sndio
->Read(temp_buffer
, in_bufsize
);
215 m_snderror
= m_sndio
->GetError();
216 if (m_snderror
!= wxSOUND_NOERROR
) {
221 m_function_in(temp_buffer
, buffer
, m_sndio
->GetLastAccess());
223 delete[] temp_buffer
;
226 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() * m_multiplier_in
);
231 wxSoundStream
& wxSoundStreamPcm::Write(const void *buffer
, wxUint32 len
)
233 wxUint32 out_bufsize
;
235 if (!m_function_out
) {
236 m_sndio
->Write(buffer
, len
);
237 m_lastcount
= m_sndio
->GetLastAccess();
238 m_snderror
= m_sndio
->GetError();
242 out_bufsize
= GetWriteSize(len
);
244 if (len
<= m_best_size
) {
245 out_bufsize
= GetWriteSize(len
);
247 m_function_out(buffer
, m_prebuffer
, len
);
248 m_sndio
->Write(m_prebuffer
, out_bufsize
);
249 m_snderror
= m_sndio
->GetError();
250 if (m_snderror
!= wxSOUND_NOERROR
) {
257 temp_buffer
= new char[out_bufsize
];
258 m_function_out(buffer
, temp_buffer
, len
);
260 m_sndio
->Write(temp_buffer
, out_bufsize
);
261 m_snderror
= m_sndio
->GetError();
262 if (m_snderror
!= wxSOUND_NOERROR
) {
267 delete[] temp_buffer
;
270 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() / m_multiplier_out
);
275 bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase
& format
)
277 wxSoundFormatBase
*new_format
;
278 wxSoundFormatPcm
*pcm_format
, *pcm_format2
;
280 if (m_sndio
->SetSoundFormat(format
)) {
281 m_function_out
= NULL
;
282 m_function_in
= NULL
;
285 if (format
.GetType() != wxSOUND_PCM
) {
286 m_snderror
= wxSOUND_INVFRMT
;
292 new_format
= m_sndio
->GetSoundFormat().Clone();
293 pcm_format
= (wxSoundFormatPcm
*)&format
;
294 pcm_format2
= (wxSoundFormatPcm
*)new_format
;
297 // ----------------------------------------------------
298 // Test whether we need to resample
299 if (pcm_format
->GetSampleRate() != pcm_format2
->GetSampleRate()) {
300 wxUint32 src_rate
, dst_rate
;
302 src_rate
= pcm_format
->GetSampleRate();
303 dst_rate
= pcm_format2
->GetSampleRate();
304 m_needResampling
= true;
305 if (src_rate
< dst_rate
)
306 m_expandSamples
= true;
308 m_expandSamples
= false;
309 m_pitch
= (src_rate
<< FLOATBITS
) / dst_rate
;
312 // ----------------------------------------------------
313 // Select table to use:
314 // * 8 bits -> 8 bits
315 // * 16 bits -> 8 bits
316 // * 8 bits -> 16 bits
317 // * 16 bits -> 16 bits
319 int table_no
, table_no2
;
322 switch (pcm_format
->GetBPS()) {
330 // TODO: Add something here: error, log, ...
333 switch (pcm_format2
->GetBPS()) {
341 // TODO: Add something here: error, log, ...
345 if (pcm_format2
->Signed() != pcm_format
->Signed())
350 #define MY_ORDER wxBYTE_ORDER
351 #if wxBYTE_ORDER == wxLITTLE_ENDIAN
352 #define OTHER_ORDER wxBIG_ENDIAN
354 #define OTHER_ORDER wxLITTLE_ENDIAN
357 // --------------------------------------------------------
358 // Find the good converter !
360 if (pcm_format
->GetOrder() == OTHER_ORDER
) {
361 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
366 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
372 m_function_out
= s_converters
[table_no
*2+table_no2
][i_swap
][i_sign
];
373 m_function_in
= s_converters
[table_no2
*2+table_no
][i_swap
][i_sign
];
374 m_multiplier_out
= s_converters_multip
[table_no
*2+table_no2
];
375 m_multiplier_in
= s_converters_multip
[table_no2
*2+table_no2
];
378 delete[] m_prebuffer
;
380 // We try to minimize the need for dynamic memory allocation by preallocating a buffer. But
381 // to be sure it will be efficient we minimize the best size.
382 if (m_multiplier_in
< m_multiplier_out
) {
383 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() *
385 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() *
388 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() *
390 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() *
394 m_prebuffer
= new char[m_prebuffer_size
];
396 bool SetSoundFormatReturn
;
398 SetSoundFormatReturn
= m_sndio
->SetSoundFormat(*new_format
);
399 wxASSERT( SetSoundFormatReturn
);
400 wxUnusedVar( SetSoundFormatReturn
);
402 m_sndformat
= new_format
;
406 wxUint32
wxSoundStreamPcm::GetWriteSize(wxUint32 len
) const
408 // For the moment, it is simple but next time it will become more complicated
410 return (wxUint32
)(len
* m_multiplier_out
);
413 wxUint32
wxSoundStreamPcm::GetReadSize(wxUint32 len
) const
415 return (wxUint32
)(len
/ m_multiplier_in
);
418 // Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.
424 #define FLOATMASK 0xffff
425 #define INTMASK 0xffff0000
427 void ResamplingShrink_
##DEPTH##(const void *source, void *destination, wxUint32 len)
429 wxUint
##DEPTH## *source_data, *dest_data;
432 source_data
= (wxUint
##DEPTH## *)source;
433 dest_data
= (wxUint
##DEPTH## *)destination;
437 // Increment the position in the input buffer
442 *dest_data
++ = *source_data
;