1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
7 // --------------------------------------------------------------------------
9 #pragma implementation "sndcpcm.cpp"
11 #include <wx/wxprec.h>
22 wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream
& sndio
)
23 : wxSoundStreamCodec(sndio
)
26 m_function_out
= NULL
;
32 wxSoundStreamPcm::~wxSoundStreamPcm()
38 wxUint32
wxSoundStreamPcm::GetBestSize() const
43 #include "converter.def"
45 // -----------------------------------------------------------------------
46 // Main PCM stream converter table
47 // -----------------------------------------------------------------------
53 // XX swapped -> YY sign
55 // XX swapped -> YY swapped
56 // XX swapped -> YY swapped sign
58 // XX stereo -> YY mono
59 // XX stereo -> YY mono sign
61 // XX swapped stereo -> YY swapped mono
62 // XX swapped stereo -> YY swapped mono sign
64 // XX swapped stereo -> YY swapped mono
65 // XX swapped stereo -> YY swapped mono sign
67 static wxSoundStreamPcm::ConverterType s_converters
[4][3][2] = {
71 Convert_8_8_sign
/* 8 -> 8 sign */
84 Convert_8_16
, /* 8 -> 16 */
85 Convert_8_16_sign
/* 8 -> 16 sign */
88 Convert_8_16_swap
, /* 8 -> 16 swapped */
89 Convert_8_16_sign_swap
/* 8 -> 16 sign swapped */
98 Convert_16_8
, /* 16 -> 8 */
99 Convert_16_8_sign
/* 16 -> 8 sign */
102 Convert_16_swap_8
, /* 16 swapped -> 8 */
103 Convert_16_swap_8_sign
/* 16 swapped -> 8 sign */
114 Convert_16_sign
/* 16 -> 16 sign */
117 Convert_16_swap
, /* 16 swapped -> 16 */
118 Convert_16_swap_16_sign
/* 16 swapped -> 16 sign */
122 Convert_16_swap_16_sign_swap
/* 16 swapped -> 16 sign swapped */
127 // This is the buffer size multiplier. It gives the needed size of the output size.
128 static float s_converters_multip
[] = {1, 2, 0.5, 1};
131 // TODO: Read() and Write() aren't really safe. If you give it a buffer which
132 // is not aligned on 2, you may crash (See converter.def).
135 wxSoundStream
& wxSoundStreamPcm::Read(void *buffer
, wxUint32 len
)
139 // We must have a multiple of 2
142 if (!m_function_in
) {
143 m_sndio
->Read(buffer
, len
);
144 m_lastcount
= m_sndio
->GetLastAccess();
145 m_snderror
= m_sndio
->GetError();
149 in_bufsize
= GetReadSize(len
);
151 if (len
<= m_best_size
) {
152 m_sndio
->Read(m_prebuffer
, in_bufsize
);
153 m_snderror
= m_sndio
->GetError();
154 if (m_snderror
!= wxSOUND_NOERROR
) {
159 m_function_in(m_prebuffer
, buffer
, m_sndio
->GetLastAccess());
163 temp_buffer
= new char[in_bufsize
];
164 m_sndio
->Read(temp_buffer
, in_bufsize
);
166 m_snderror
= m_sndio
->GetError();
167 if (m_snderror
!= wxSOUND_NOERROR
) {
172 m_function_in(temp_buffer
, buffer
, m_sndio
->GetLastAccess());
174 delete[] temp_buffer
;
177 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() * m_multiplier_in
);
182 wxSoundStream
& wxSoundStreamPcm::Write(const void *buffer
, wxUint32 len
)
184 wxUint32 out_bufsize
;
186 if (!m_function_out
) {
187 m_sndio
->Write(buffer
, len
);
188 m_lastcount
= m_sndio
->GetLastAccess();
189 m_snderror
= m_sndio
->GetError();
193 out_bufsize
= GetWriteSize(len
);
195 if (len
<= m_best_size
) {
196 out_bufsize
= GetWriteSize(len
);
198 m_function_out(buffer
, m_prebuffer
, len
);
199 m_sndio
->Write(m_prebuffer
, out_bufsize
);
200 m_snderror
= m_sndio
->GetError();
201 if (m_snderror
!= wxSOUND_NOERROR
) {
208 temp_buffer
= new char[out_bufsize
];
209 m_function_out(buffer
, temp_buffer
, len
);
211 m_sndio
->Write(temp_buffer
, out_bufsize
);
212 m_snderror
= m_sndio
->GetError();
213 if (m_snderror
!= wxSOUND_NOERROR
) {
218 delete[] temp_buffer
;
221 m_lastcount
= (wxUint32
)(m_sndio
->GetLastAccess() / m_multiplier_out
);
226 bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase
& format
)
228 wxSoundFormatBase
*new_format
;
229 wxSoundFormatPcm
*pcm_format
, *pcm_format2
;
231 if (m_sndio
->SetSoundFormat(format
)) {
232 m_function_out
= NULL
;
233 m_function_in
= NULL
;
236 if (format
.GetType() != wxSOUND_PCM
) {
237 m_snderror
= wxSOUND_INVFRMT
;
243 new_format
= m_sndio
->GetSoundFormat().Clone();
244 pcm_format
= (wxSoundFormatPcm
*)&format
;
245 pcm_format2
= (wxSoundFormatPcm
*)new_format
;
248 // ----------------------------------------------------
249 // Test whether we need to resample
250 if (pcm_format
->GetSampleRate() != pcm_format2
->GetSampleRate()) {
251 wxUint32 src_rate
, dst_rate
;
253 src_rate
= pcm_format
->GetSampleRate();
254 dst_rate
= pcm_format2
->GetSampleRate();
255 m_needResampling
= TRUE
;
256 if (src_rate
< dst_rate
)
257 m_expandSamples
= TRUE
;
259 m_expandSamples
= FALSE
;
260 m_pitch
= (src_rate
<< FLOATBITS
) / dst_rate
;
263 // ----------------------------------------------------
264 // Select table to use:
265 // * 8 bits -> 8 bits
266 // * 16 bits -> 8 bits
267 // * 8 bits -> 16 bits
268 // * 16 bits -> 16 bits
270 int table_no
, table_no2
;
273 switch (pcm_format
->GetBPS()) {
281 switch (pcm_format2
->GetBPS()) {
290 if (pcm_format2
->Signed() != pcm_format
->Signed())
295 #define MY_ORDER wxBYTE_ORDER
296 #if wxBYTE_ORDER == wxLITTLE_ENDIAN
297 #define OTHER_ORDER wxBIG_ENDIAN
299 #define OTHER_ORDER wxLITTLE_ENDIAN
302 // --------------------------------------------------------
303 // Find the good converter !
305 if (pcm_format
->GetOrder() == OTHER_ORDER
) {
306 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
311 if (pcm_format
->GetOrder() == pcm_format2
->GetOrder())
317 m_function_out
= s_converters
[table_no
*2+table_no2
][i_swap
][i_sign
];
318 m_function_in
= s_converters
[table_no2
*2+table_no
][i_swap
][i_sign
];
319 m_multiplier_out
= s_converters_multip
[table_no
*2+table_no2
];
320 m_multiplier_in
= s_converters_multip
[table_no2
*2+table_no2
];
323 delete[] m_prebuffer
;
325 // We try to minimize the need of dynamic memory allocation by preallocating a buffer. But
326 // to be sure it will be efficient we minimize the best size.
327 if (m_multiplier_in
< m_multiplier_out
) {
328 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() * m_multiplier_out
);
329 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() * m_multiplier_in
);
331 m_prebuffer_size
= (wxUint32
)(m_sndio
->GetBestSize() * m_multiplier_in
);
332 m_best_size
= (wxUint32
)(m_sndio
->GetBestSize() * m_multiplier_out
);
335 m_prebuffer
= new char[m_prebuffer_size
];
337 bool SetSoundFormatReturn
;
339 SetSoundFormatReturn
= m_sndio
->SetSoundFormat(*new_format
);
340 wxASSERT( SetSoundFormatReturn
);
342 m_sndformat
= new_format
;
346 wxUint32
wxSoundStreamPcm::GetWriteSize(wxUint32 len
) const
348 // For the moment, it is simple but next time it will become more complicated
350 return (wxUint32
)(len
* m_multiplier_out
);
353 wxUint32
wxSoundStreamPcm::GetReadSize(wxUint32 len
) const
355 return (wxUint32
)(len
/ m_multiplier_in
);
358 // Resampling engine. NOT FINISHED and NOT INCLUDED but this is a first DRAFT.
364 #define FLOATMASK 0xffff
365 #define INTMASK 0xffff0000
367 void ResamplingShrink_
##DEPTH##(const void *source, void *destination, wxUint32 len)
369 wxUint
##DEPTH## *source_data, *dest_data;
372 source_data
= (wxUint
##DEPTH## *)source;
373 dest_data
= (wxUint
##DEPTH## *)destination;
377 // Increment the position in the input buffer
382 *dest_data
++ = *source_data
;