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
);
399 wxUnusedVar( SetSoundFormatReturn
);
401 m_sndformat
= new_format
;
405 wxUint32
wxSoundStreamPcm::GetWriteSize(wxUint32 len
) const
407 // For the moment, it is simple but next time it will become more complicated
409 return (wxUint32
)(len
* m_multiplier_out
);
412 wxUint32
wxSoundStreamPcm::GetReadSize(wxUint32 len
) const
414 return (wxUint32
)(len
/ m_multiplier_in
);
417 // Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.
423 #define FLOATMASK 0xffff
424 #define INTMASK 0xffff0000
426 void ResamplingShrink_
##DEPTH##(const void *source, void *destination, wxUint32 len)
428 wxUint
##DEPTH## *source_data, *dest_data;
431 source_data
= (wxUint
##DEPTH## *)source;
432 dest_data
= (wxUint
##DEPTH## *)destination;
436 // Increment the position in the input buffer
441 *dest_data
++ = *source_data
;