]>
Commit | Line | Data |
---|---|---|
1 | // -------------------------------------------------------------------------- | |
2 | // Name: sndcpcm.cpp | |
3 | // Purpose: | |
4 | // Date: 08/11/1999 | |
5 | // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000 | |
6 | // CVSID: $Id$ | |
7 | // -------------------------------------------------------------------------- | |
8 | #ifdef __GNUG__ | |
9 | #pragma implementation "sndcpcm.cpp" | |
10 | #endif | |
11 | ||
12 | #include <wx/wxprec.h> | |
13 | #include "sndbase.h" | |
14 | #include "sndpcm.h" | |
15 | #include "sndcpcm.h" | |
16 | ||
17 | wxSoundStreamPcm::wxSoundStreamPcm(wxSoundStream& sndio) | |
18 | : wxSoundStreamCodec(sndio) | |
19 | { | |
20 | m_function_in = NULL; | |
21 | m_function_out = NULL; | |
22 | } | |
23 | ||
24 | wxSoundStreamPcm::~wxSoundStreamPcm() | |
25 | { | |
26 | } | |
27 | ||
28 | ||
29 | #include "converter.def" | |
30 | ||
31 | // ----------------------------------------------------------------------- | |
32 | // Main PCM stream converter table | |
33 | // ----------------------------------------------------------------------- | |
34 | wxSoundStreamPcm::ConverterType s_converters[] = { | |
35 | NULL, | |
36 | Convert_8_8_sign, /* 8 -> 8 sign */ | |
37 | NULL, | |
38 | NULL, | |
39 | NULL, | |
40 | NULL, | |
41 | ||
42 | Convert_8_16, /* 8 -> 16 */ | |
43 | Convert_8_16_sign, /* 8 -> 16 sign */ | |
44 | Convert_8_16_swap, /* 8 -> 16 swapped */ | |
45 | Convert_8_16_sign_swap, /* 8 -> 16 sign swapped */ | |
46 | NULL, | |
47 | NULL, | |
48 | ||
49 | Convert_16_8, /* 16 -> 8 */ | |
50 | Convert_16_8_sign, /* 16 -> 8 sign */ | |
51 | Convert_16_swap_8, /* 16 swapped -> 8 */ | |
52 | Convert_16_swap_8_sign, /* 16 swapped -> 8 sign */ | |
53 | NULL, | |
54 | NULL, | |
55 | ||
56 | NULL, /* 16 -> 16 */ | |
57 | Convert_16_sign, /* 16 -> 16 sign */ | |
58 | Convert_16_swap, /* 16 swapped -> 16 */ | |
59 | Convert_16_swap_16_sign, /* 16 swapped -> 16 sign */ | |
60 | Convert_16_sign_16_swap, /* 16 sign -> 16 swapped */ | |
61 | Convert_16_swap_16_sign_swap /* 16 swapped -> 16 sign swapped */ | |
62 | }; | |
63 | ||
64 | #define CONVERT_BPS 0 | |
65 | #define CONVERT_SIGN 1 | |
66 | #define CONVERT_SWAP 2 | |
67 | #define CONVERT_SIGN_SWAP 3 | |
68 | #define CONVERT_SWAP_SIGN 4 | |
69 | #define CONVERT_SWAP_SIGN_SWAP 5 | |
70 | ||
71 | #define CONVERT_BASE_8_8 0 | |
72 | #define CONVERT_BASE_8_16 6 | |
73 | #define CONVERT_BASE_16_8 12 | |
74 | #define CONVERT_BASE_16_16 18 | |
75 | ||
76 | // | |
77 | // TODO: Read() and Write() aren't really safe. If you give it a buffer which | |
78 | // is not aligned on 2, you may crash (See converter.def). | |
79 | // | |
80 | ||
81 | wxSoundStream& wxSoundStreamPcm::Read(void *buffer, wxUint32 len) | |
82 | { | |
83 | wxUint32 real_len; | |
84 | char *tmp_buf; | |
85 | ||
86 | if (!m_function_in) { | |
87 | m_sndio->Read(buffer, len); | |
88 | m_lastcount = m_sndio->GetLastAccess(); | |
89 | m_snderror = m_sndio->GetError(); | |
90 | return *this; | |
91 | } | |
92 | ||
93 | real_len = (m_16_to_8) ? len / 2 : len; | |
94 | ||
95 | tmp_buf = new char[real_len]; | |
96 | ||
97 | m_sndio->Read(tmp_buf, real_len); | |
98 | m_lastcount = m_sndio->GetLastAccess(); | |
99 | m_snderror = m_sndio->GetError(); | |
100 | if (m_snderror != wxSOUND_NOERR) | |
101 | return *this; | |
102 | ||
103 | m_function_in(tmp_buf, (char *)buffer, m_lastcount); | |
104 | ||
105 | delete[] tmp_buf; | |
106 | ||
107 | if (m_16_to_8) | |
108 | m_lastcount *= 2; | |
109 | ||
110 | return *this; | |
111 | } | |
112 | ||
113 | wxSoundStream& wxSoundStreamPcm::Write(const void *buffer, wxUint32 len) | |
114 | { | |
115 | char *tmp_buf; | |
116 | wxUint32 len2; | |
117 | ||
118 | if (!m_function_out) | |
119 | return m_sndio->Write(buffer, len); | |
120 | ||
121 | len2 = (m_16_to_8) ? len / 2 : len; | |
122 | ||
123 | tmp_buf = new char[len2]; | |
124 | m_function_out((const char *)buffer, tmp_buf, len2); | |
125 | m_sndio->Write(tmp_buf, len); | |
126 | delete[] tmp_buf; | |
127 | ||
128 | m_lastcount = (m_16_to_8) ? | |
129 | (m_sndio->GetLastAccess() * 2) : m_sndio->GetLastAccess(); | |
130 | ||
131 | return *this; | |
132 | } | |
133 | ||
134 | bool wxSoundStreamPcm::SetSoundFormat(const wxSoundFormatBase& format) | |
135 | { | |
136 | wxSoundFormatBase *new_format; | |
137 | wxSoundFormatPcm *pcm_format, *pcm_format2; | |
138 | ConverterType *current_table_out, *current_table_in; | |
139 | int index; | |
140 | bool change_sign; | |
141 | ||
142 | if (m_sndio->SetSoundFormat(format)) { | |
143 | m_function_out = NULL; | |
144 | m_function_in = NULL; | |
145 | return TRUE; | |
146 | } | |
147 | if (format.GetType() != wxSOUND_PCM) { | |
148 | m_snderror = wxSOUND_INVFRMT; | |
149 | return FALSE; | |
150 | } | |
151 | if (m_sndformat) | |
152 | delete m_sndformat; | |
153 | ||
154 | new_format = m_sndio->GetSoundFormat().Clone(); | |
155 | pcm_format = (wxSoundFormatPcm *)&format; | |
156 | pcm_format2 = (wxSoundFormatPcm *)new_format; | |
157 | ||
158 | // ---------------------------------------------------- | |
159 | // Select table to use: | |
160 | // * 8 bits -> 8 bits | |
161 | // * 16 bits -> 8 bits | |
162 | // * 8 bits -> 16 bits | |
163 | // * 16 bits -> 16 bits | |
164 | ||
165 | m_16_to_8 = FALSE; | |
166 | if (pcm_format->GetBPS() != pcm_format2->GetBPS()) { | |
167 | m_16_to_8 = TRUE; | |
168 | if (pcm_format2->GetBPS() == 8) { | |
169 | current_table_out = &s_converters[CONVERT_BASE_16_8]; | |
170 | current_table_in = &s_converters[CONVERT_BASE_8_16]; | |
171 | } else { | |
172 | current_table_out = &s_converters[CONVERT_BASE_8_16]; | |
173 | current_table_in = &s_converters[CONVERT_BASE_16_8]; | |
174 | } | |
175 | } else if (pcm_format->GetBPS() == 16) { | |
176 | current_table_out = &s_converters[CONVERT_BASE_16_16]; | |
177 | current_table_in = &s_converters[CONVERT_BASE_16_16]; | |
178 | } else { | |
179 | current_table_out = &s_converters[CONVERT_BASE_8_8]; | |
180 | current_table_in = &s_converters[CONVERT_BASE_8_8]; | |
181 | } | |
182 | ||
183 | change_sign = (pcm_format2->Signed() != pcm_format->Signed()); | |
184 | ||
185 | #define MY_ORDER wxBYTE_ORDER | |
186 | #if wxBYTE_ORDER == wxLITTLE_ENDIAN | |
187 | #define OTHER_ORDER wxBIG_ENDIAN | |
188 | #else | |
189 | #define OTHER_ORDER wxLITTLE_ENDIAN | |
190 | #endif | |
191 | ||
192 | // -------------------------------------------------------- | |
193 | // Find the good converter ! | |
194 | ||
195 | ||
196 | if (pcm_format->GetOrder() == OTHER_ORDER && | |
197 | pcm_format2->GetOrder() == OTHER_ORDER && change_sign) | |
198 | index = CONVERT_SWAP_SIGN_SWAP; | |
199 | ||
200 | else if (pcm_format->GetOrder() == OTHER_ORDER && | |
201 | pcm_format2->GetOrder() == MY_ORDER && change_sign) | |
202 | index = CONVERT_SWAP_SIGN; | |
203 | ||
204 | else if (pcm_format->GetOrder() == MY_ORDER && | |
205 | pcm_format->GetOrder() == OTHER_ORDER && change_sign) | |
206 | index = CONVERT_SIGN_SWAP; | |
207 | ||
208 | else if (change_sign) | |
209 | index = CONVERT_SIGN; | |
210 | ||
211 | else if (!change_sign && | |
212 | pcm_format->GetOrder() != pcm_format2->GetOrder()) | |
213 | index = CONVERT_SWAP; | |
214 | ||
215 | else | |
216 | index = CONVERT_BPS; | |
217 | ||
218 | m_function_out = current_table_out[index]; | |
219 | m_function_in = current_table_in[index]; | |
220 | ||
221 | m_sndio->SetSoundFormat(*new_format); | |
222 | m_sndformat = new_format; | |
223 | return TRUE; | |
224 | } |