]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia2/lib/sndoss.cpp
Added wxSound for Windows support (successful WAV playback on VC++ 5)
[wxWidgets.git] / utils / wxMMedia2 / lib / sndoss.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndoss.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
6 // CVSID: $Id$
7 // --------------------------------------------------------------------------
8 #ifdef __GNUG__
9 #pragma implementation "sndoss.cpp"
10 #endif
11
12 #include <sys/soundcard.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/ioctl.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <wx/defs.h>
19 #include <wx/string.h>
20 #include "sndbase.h"
21 #include "sndoss.h"
22 #include "sndpcm.h"
23 #ifdef __WXGTK__
24 #include <gdk/gdk.h>
25 #endif
26
27 wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
28 {
29 wxSoundFormatPcm pcm_default;
30
31 m_fd = open(dev_name.mb_str(), O_RDWR);
32
33 if (m_fd == -1) {
34 m_snderror = wxSOUND_INVDEV;
35 return;
36 }
37
38 m_devname = dev_name;
39
40 wxSoundStreamOSS::SetSoundFormat(pcm_default);
41
42 ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &m_bufsize);
43
44 m_snderror = wxSOUND_NOERR;
45
46 close(m_fd);
47
48 m_oss_stop = TRUE;
49 m_q_filled = TRUE;
50 }
51
52 wxSoundStreamOSS::~wxSoundStreamOSS()
53 {
54 if (m_fd > 0)
55 close(m_fd);
56 }
57
58 wxUint32 wxSoundStreamOSS::GetBestSize() const
59 {
60 return m_bufsize;
61 }
62
63 wxSoundStream& wxSoundStreamOSS::Read(void *buffer, size_t len)
64 {
65 int ret;
66
67 m_lastcount = (size_t)ret = read(m_fd, buffer, len);
68 m_q_filled = TRUE;
69
70 if (ret < 0)
71 m_snderror = wxSOUND_IOERR;
72 else
73 m_snderror = wxSOUND_NOERR;
74
75 return *this;
76 }
77
78 wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, size_t len)
79 {
80 int ret;
81
82 m_lastcount = (size_t)ret = write(m_fd, buffer, len);
83 m_q_filled = TRUE;
84
85 if (ret < 0)
86 m_snderror = wxSOUND_IOERR;
87 else
88 m_snderror = wxSOUND_NOERR;
89
90 return *this;
91 }
92
93 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
94 {
95 int tmp;
96 wxSoundFormatPcm *pcm_format;
97
98 if (format.GetType() != wxSOUND_PCM) {
99 m_snderror = wxSOUND_INVFRMT;
100 return FALSE;
101 }
102
103 if (m_fd == -1) {
104 m_snderror = wxSOUND_INVDEV;
105 return FALSE;
106 }
107
108 if (m_sndformat)
109 delete m_sndformat;
110
111 m_sndformat = format.Clone();
112 if (!m_sndformat) {
113 m_snderror = wxSOUND_MEMERR;
114 return FALSE;
115 }
116 pcm_format = (wxSoundFormatPcm *)m_sndformat;
117
118 // Set the sample rate field.
119 tmp = pcm_format->GetSampleRate();
120 ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
121
122 pcm_format->SetSampleRate(tmp);
123
124 // Detect the best format
125 DetectBest(pcm_format);
126 SetupFormat(pcm_format);
127
128 tmp = pcm_format->GetChannels();
129 ioctl(m_fd, SNDCTL_DSP_CHANNELS, &tmp);
130 pcm_format->SetChannels(tmp);
131
132 m_snderror = wxSOUND_NOERR;
133 if (*pcm_format != format) {
134 m_snderror = wxSOUND_NOTEXACT;
135 return FALSE;
136 }
137 return TRUE;
138 }
139
140 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
141 {
142 int tmp;
143
144 switch(pcm_format->GetBPS()) {
145 case 8:
146 if (pcm_format->Signed())
147 tmp = AFMT_S8;
148 else
149 tmp = AFMT_U8;
150 break;
151 case 16:
152 switch (pcm_format->GetOrder()) {
153 case wxBIG_ENDIAN:
154 if (pcm_format->Signed())
155 tmp = AFMT_S16_BE;
156 else
157 tmp = AFMT_U16_BE;
158 break;
159 case wxLITTLE_ENDIAN:
160 if (pcm_format->Signed())
161 tmp = AFMT_S16_LE;
162 else
163 tmp = AFMT_U16_LE;
164 break;
165 }
166 break;
167 }
168
169 ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
170
171 // Demangling.
172 switch (tmp) {
173 case AFMT_U8:
174 pcm_format->SetBPS(8);
175 pcm_format->Signed(FALSE);
176 break;
177 case AFMT_S8:
178 pcm_format->SetBPS(8);
179 pcm_format->Signed(TRUE);
180 break;
181 case AFMT_U16_LE:
182 pcm_format->SetBPS(16);
183 pcm_format->Signed(FALSE);
184 pcm_format->SetOrder(wxLITTLE_ENDIAN);
185 break;
186 case AFMT_U16_BE:
187 pcm_format->SetBPS(16);
188 pcm_format->Signed(FALSE);
189 pcm_format->SetOrder(wxBIG_ENDIAN);
190 break;
191 case AFMT_S16_LE:
192 pcm_format->SetBPS(16);
193 pcm_format->Signed(TRUE);
194 pcm_format->SetOrder(wxLITTLE_ENDIAN);
195 break;
196 case AFMT_S16_BE:
197 pcm_format->SetBPS(16);
198 pcm_format->Signed(TRUE);
199 pcm_format->SetOrder(wxBIG_ENDIAN);
200 break;
201 }
202 return TRUE;
203 }
204
205 #ifdef __WXGTK__
206 static void _wxSound_OSS_CBack(gpointer data, int source,
207 GdkInputCondition condition)
208 {
209 wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
210
211 switch (condition) {
212 case GDK_INPUT_READ:
213 oss->WakeUpEvt(wxSOUND_INPUT);
214 break;
215 case GDK_INPUT_WRITE:
216 oss->WakeUpEvt(wxSOUND_OUTPUT);
217 break;
218 default:
219 break;
220 }
221 }
222 #endif
223
224 void wxSoundStreamOSS::WakeUpEvt(int evt)
225 {
226 m_q_filled = FALSE;
227 OnSoundEvent(evt);
228 }
229
230 bool wxSoundStreamOSS::StartProduction(int evt)
231 {
232 wxSoundFormatBase *old_frmt;
233
234 if (!m_oss_stop)
235 StopProduction();
236
237 old_frmt = m_sndformat->Clone();
238
239 if (evt == wxSOUND_OUTPUT)
240 m_fd = open(m_devname.mb_str(), O_WRONLY);
241 else if (evt == wxSOUND_INPUT)
242 m_fd = open(m_devname.mb_str(), O_RDONLY);
243
244 if (m_fd == -1) {
245 m_snderror = wxSOUND_INVDEV;
246 return FALSE;
247 }
248
249 SetSoundFormat(*old_frmt);
250 delete old_frmt;
251
252 #ifdef __WXGTK__
253 int trig;
254
255 if (evt == wxSOUND_OUTPUT) {
256 m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
257 trig = PCM_ENABLE_OUTPUT;
258 } else {
259 m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
260 trig = PCM_ENABLE_INPUT;
261 }
262 #else
263 while (!m_oss_stop)
264 OnSoundEvent(evt);
265 #endif
266
267 ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
268
269 m_oss_stop = FALSE;
270 m_q_filled = FALSE;
271
272 return TRUE;
273 }
274
275 bool wxSoundStreamOSS::StopProduction()
276 {
277 if (m_oss_stop)
278 return FALSE;
279
280 #ifdef __WXGTK__
281 gdk_input_remove(m_tag);
282 #endif
283
284 close(m_fd);
285 m_oss_stop = TRUE;
286 m_q_filled = TRUE;
287 return TRUE;
288 }
289
290 bool wxSoundStreamOSS::QueueFilled() const
291 {
292 return m_q_filled;
293 }
294
295 //
296 // Detect the closest format (The best).
297 //
298 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
299 {
300 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
301
302 int fmt_mask;
303 wxSoundFormatPcm best_pcm;
304
305 // We change neither the number of channels nor the sample rate
306
307 best_pcm.SetSampleRate(pcm->GetSampleRate());
308 best_pcm.SetChannels(pcm->GetChannels());
309
310 // Get the supported format by the sound card
311 ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
312
313 // It supports 16 bits
314 if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
315 best_pcm.SetBPS(16);
316
317 // It supports big endianness
318 if (pcm->GetOrder() == wxBIG_ENDIAN && ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
319 best_pcm.SetOrder(wxBIG_ENDIAN);
320
321 // It supports little endianness
322 if (pcm->GetOrder() == wxLITTLE_ENDIAN && ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
323 best_pcm.SetOrder(wxLITTLE_ENDIAN);
324
325 // It supports signed samples
326 if (pcm->Signed() && ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
327 best_pcm.Signed(TRUE);
328
329 // It supports unsigned samples
330 if (!pcm->Signed() && ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
331 best_pcm.Signed(FALSE);
332
333 // Finally recopy the new format
334 *pcm = best_pcm;
335 }