1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
8 // --------------------------------------------------------------------------
10 #include "wx/wxprec.h"
22 #include "wx/mmedia/sndbase.h"
23 #include "wx/mmedia/sndpcm.h"
24 #include "wx/mmedia/sndcpcm.h"
26 wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream
& sndio
)
27 : wxSoundStreamCodec(sndio
)
30 m_function_out
= NULL
;
36 wxSoundStreamPcm::~wxSoundStreamPcm()
42 wxUint32
wxSoundStreamPcm::GetBestSize() const
47 // -----------------------------------------------------------------------
48 // "Converters" definitions/implementations
49 // -----------------------------------------------------------------------
51 #define DEFINE_CONV(name, input_type, output_type, convert) \
52 static void Convert_##name(const void *buf_in, void *buf_out, wxUint32 len) \
54 register input_type src; \
55 register const input_type *t_buf_in = (input_type *)buf_in; \
56 register output_type *t_buf_out = (output_type *)buf_out; \
60 *t_buf_out++ = convert; \
61 len -= sizeof(input_type); \
65 // TODO: define converters for all other formats (32, 24)
67 DEFINE_CONV(8_8_sign
, wxUint8
, wxUint8
, (src
^ 0x80))
69 DEFINE_CONV(8_16
, wxUint8
, wxUint16
, (((wxUint16
)src
) << 8))
70 DEFINE_CONV(8_16_swap
, wxUint8
, wxUint16
, (src
))
71 DEFINE_CONV(8_16_sign
, wxUint8
, wxUint16
, (((wxUint16
)(src
^ 0x80)) << 8))
72 DEFINE_CONV(8_16_sign_swap
, wxUint8
, wxUint16
, (src
^ 0x80))
74 DEFINE_CONV(16_8
, wxUint16
, wxUint8
, (wxUint8
)(src
>> 8))
75 DEFINE_CONV(16_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src
>> 8) ^ 0x80))
76 DEFINE_CONV(16_swap_8
, wxUint16
, wxUint8
, (wxUint8
)(src
& 0xff))
77 DEFINE_CONV(16_swap_8_sign
, wxUint16
, wxUint8
, (wxUint8
)((src
& 0xff) ^ 0x80))
79 //DEFINE_CONV(24_8, wxUint32, wxUint8, (wxUint8)(src >> 16))
80 //DEFINE_CONV(24_8_sig, wxUint32, wxUint8, (wxUint8)((src >> 16) ^ 0x80))
82 //DEFINE_CONV(32_8, wxUint32, wxUint8, (wxUint8)(src >> 24))
84 DEFINE_CONV(16_sign
, wxUint16
, wxUint16
, (src
^ 0x8000))
85 DEFINE_CONV(16_swap
, wxUint16
, wxUint16
, (((src
& 0xff) << 8) | ((src
>> 8) & 0xff)))
87 DEFINE_CONV(16_swap_16_sign
, wxUint16
, wxUint16
, ((((src
& 0xff) << 8) | ((src
>> 8) & 0xff)) ^ 0x80))
88 // DEFINE_CONV(16_sign_16_swap, wxUint16, wxUint16, ((((src & 0xff) << 8) | ((src >> 8) & 0xff)) ^ 0x8000))
89 DEFINE_CONV(16_swap_16_sign_swap
, wxUint16
, wxUint16
, (src
^ 0x80))
91 // -----------------------------------------------------------------------
92 // Main PCM stream converter table
93 // -----------------------------------------------------------------------
99 // XX swapped -> YY sign
101 // XX swapped -> YY swapped
102 // XX swapped -> YY swapped sign
104 // XX stereo -> YY mono
105 // XX stereo -> YY mono sign
107 // XX swapped stereo -> YY swapped mono
108 // XX swapped stereo -> YY swapped mono sign
110 // XX swapped stereo -> YY swapped mono
111 // XX swapped stereo -> YY swapped mono sign
113 static wxSoundStreamPcm::ConverterType s_converters
[4][3][2] = {
117 Convert_8_8_sign
/* 8 -> 8 sign */
130 Convert_8_16
, /* 8 -> 16 */
131 Convert_8_16_sign
/* 8 -> 16 sign */
134 Convert_8_16_swap
, /* 8 -> 16 swapped */
135 Convert_8_16_sign_swap
/* 8 -> 16 sign swapped */
144 Convert_16_8
, /* 16 -> 8 */
145 Convert_16_8_sign
/* 16 -> 8 sign */
148 Convert_16_swap_8
, /* 16 swapped -> 8 */
149 Convert_16_swap_8_sign
/* 16 swapped -> 8 sign */
160 Convert_16_sign
/* 16 -> 16 sign */
163 Convert_16_swap
, /* 16 swapped -> 16 */
164 Convert_16_swap_16_sign
/* 16 swapped -> 16 sign */
168 Convert_16_swap_16_sign_swap
/* 16 swapped -> 16 sign swapped */
173 // This is the buffer size multiplier. It gives the needed size of the output size.
174 static float s_converters_multip
[] = {1, 2, 0.5, 1};
177 // TODO: Read() and Write() aren't really safe. If you give it a buffer which
178 // is not aligned on 2, you may crash (See converter.def).
181 wxSoundStream
& wxSoundStreamPcm::Read(void *buffer
, wxUint32 len
)
185 // We must have a multiple of 2
188 if (!m_function_in
) {
189 m_sndio
->Read(buffer
, len
);
190 m_lastcount
= m_sndio
->GetLastAccess();
191 m_snderror
= m_sndio
->GetError();
195 in_bufsize
= GetReadSize(len
);
197 if (len
<= m_best_size
) {
198 m_sndio
->Read(m_prebuffer
, in_bufsize
);
199 m_snderror
= m_sndio
->GetError();
200 if (m_snderror
!= wxSOUND_NOERROR
) {
205 m_function_in(m_prebuffer
, buffer
, m_sndio
->GetLastAccess());
209 temp_buffer
= new char[in_bufsize
];
210 m_sndio
->Read(temp_buffer
, in_bufsize
);
212 m_snderror
= m_sndio
->GetError();
213 if (m_snderror
!= wxSOUND_NOERROR
) {
218 m_function_in(temp_buffer
, buffer
, m_sndio
->GetLastAccess());
220 delete[] temp_buffer
;
223 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() * m_multiplier_in
);
228 wxSoundStream
& wxSoundStreamPcm::Write(const void *buffer
, wxUint32 len
)
230 wxUint32 out_bufsize
;
232 if (!m_function_out
) {
233 m_sndio
->Write(buffer
, len
);
234 m_lastcount
= m_sndio
->GetLastAccess();
235 m_snderror
= m_sndio
->GetError();
239 out_bufsize
= GetWriteSize(len
);
241 if (len
<= m_best_size
) {
242 out_bufsize
= GetWriteSize(len
);
244 m_function_out(buffer
, m_prebuffer
, len
);
245 m_sndio
->Write(m_prebuffer
, out_bufsize
);
246 m_snderror
= m_sndio
->GetError();
247 if (m_snderror
!= wxSOUND_NOERROR
) {
254 temp_buffer
= new char[out_bufsize
];
255 m_function_out(buffer
, temp_buffer
, len
);
257 m_sndio
->Write(temp_buffer
, out_bufsize
);
258 m_snderror
= m_sndio
->GetError();
259 if (m_snderror
!= wxSOUND_NOERROR
) {
264 delete[] temp_buffer
;
267 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() / m_multiplier_out
);
272 bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase
& format
)
274 wxSoundFormatBase
*new_format
;
275 wxSoundFormatPcm
*pcm_format
, *pcm_format2
;
277 if (m_sndio
->SetSoundFormat(format
)) {
278 m_function_out
= NULL
;
279 m_function_in
= NULL
;
282 if (format
.GetType() != wxSOUND_PCM
) {
283 m_snderror
= wxSOUND_INVFRMT
;
289 new_format
= m_sndio
->GetSoundFormat().Clone();
290 pcm_format
= (wxSoundFormatPcm
*)&format
;
291 pcm_format2
= (wxSoundFormatPcm
*)new_format
;
294 // ----------------------------------------------------
295 // Test whether we need to resample
296 if (pcm_format
->GetSampleRate() != pcm_format2
->GetSampleRate()) {
297 wxUint32 src_rate
, dst_rate
;
299 src_rate
= pcm_format
->GetSampleRate();
300 dst_rate
= pcm_format2
->GetSampleRate();
301 m_needResampling
= true;
302 if (src_rate
< dst_rate
)
303 m_expandSamples
= true;
305 m_expandSamples
= false;
306 m_pitch
= (src_rate
<< FLOATBITS
) / dst_rate
;
309 // ----------------------------------------------------
310 // Select table to use:
311 // * 8 bits -> 8 bits
312 // * 16 bits -> 8 bits
313 // * 8 bits -> 16 bits
314 // * 16 bits -> 16 bits
316 int table_no
, table_no2
;
319 switch (pcm_format
->GetBPS()) {
327 // TODO: Add something here: error, log, ...
330 switch (pcm_format2
->GetBPS()) {
338 // TODO: Add something here: error, log, ...
342 if (pcm_format2
->Signed() != pcm_format
->Signed())
347 #define MY_ORDER wxBYTE_ORDER
348 #if wxBYTE_ORDER == wxLITTLE_ENDIAN
349 #define OTHER_ORDER wxBIG_ENDIAN
351 #define OTHER_ORDER wxLITTLE_ENDIAN
354 // --------------------------------------------------------
355 // Find the good converter !
357 if (pcm_format
->GetOrder() == OTHER_ORDER
) {
358 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
363 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
369 m_function_out
= s_converters
[table_no
*2+table_no2
][i_swap
][i_sign
];
370 m_function_in
= s_converters
[table_no2
*2+table_no
][i_swap
][i_sign
];
371 m_multiplier_out
= s_converters_multip
[table_no
*2+table_no2
];
372 m_multiplier_in
= s_converters_multip
[table_no2
*2+table_no2
];
375 delete[] m_prebuffer
;
377 // We try to minimize the need for dynamic memory allocation by preallocating a buffer. But
378 // to be sure it will be efficient we minimize the best size.
379 if (m_multiplier_in
< m_multiplier_out
) {
380 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() *
382 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() *
385 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() *
387 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() *
391 m_prebuffer
= new char[m_prebuffer_size
];
393 bool SetSoundFormatReturn
;
395 SetSoundFormatReturn
= m_sndio
->SetSoundFormat(*new_format
);
396 wxASSERT( SetSoundFormatReturn
);
397 wxUnusedVar( SetSoundFormatReturn
);
399 m_sndformat
= new_format
;
403 wxUint32
wxSoundStreamPcm::GetWriteSize(wxUint32 len
) const
405 // For the moment, it is simple but next time it will become more complicated
407 return (wxUint32
)(len
* m_multiplier_out
);
410 wxUint32
wxSoundStreamPcm::GetReadSize(wxUint32 len
) const
412 return (wxUint32
)(len
/ m_multiplier_in
);
415 // Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.
421 #define FLOATMASK 0xffff
422 #define INTMASK 0xffff0000
424 void ResamplingShrink_
##DEPTH##(const void *source, void *destination, wxUint32 len)
426 wxUint
##DEPTH## *source_data, *dest_data;
429 source_data
= (wxUint
##DEPTH## *)source;
430 dest_data
= (wxUint
##DEPTH## *)destination;
434 // Increment the position in the input buffer
439 *dest_data
++ = *source_data
;