]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndfile.cpp
Applied [ 1283696 ] wxDC::GetPartialTextExtents crashes on empty strings
[wxWidgets.git] / contrib / src / mmedia / sndfile.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndfile.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
6 // CVSID: $Id$
7 // wxWindows licence
8 // --------------------------------------------------------------------------
9 #include "wx/wxprec.h"
10
11 #ifndef WX_PRECOMP
12 #include <wx/defs.h>
13 #include <wx/stream.h>
14 #endif
15
16 #include "wx/mmedia/sndbase.h"
17 #include "wx/mmedia/sndcodec.h"
18 #include "wx/mmedia/sndfile.h"
19 #include "wx/mmedia/sndcpcm.h"
20 #include "wx/mmedia/sndulaw.h"
21 #include "wx/mmedia/sndg72x.h"
22 #include "wx/mmedia/sndmsad.h"
23
24 // --------------------------------------------------------------------------
25 // Sound codec router
26 // A very important class: it ensures that everybody is satisfied.
27 // It is supposed to create as many codec as it is necessary to transform
28 // a signal in a specific format in an another.
29 // --------------------------------------------------------------------------
30 wxSoundRouterStream::wxSoundRouterStream(wxSoundStream& sndio)
31 : wxSoundStreamCodec(sndio)
32 {
33 m_router = NULL;
34 }
35
36 wxSoundRouterStream::~wxSoundRouterStream()
37 {
38 if (m_router)
39 delete m_router;
40 }
41
42 // --------------------------------------------------------------------------
43 // Read(void *buffer, wxUint32 len): It reads data synchronously. See sndbase.h
44 // for possible errors and behaviours ...
45 // --------------------------------------------------------------------------
46 wxSoundStream& wxSoundRouterStream::Read(void *buffer, wxUint32 len)
47 {
48 if (m_router) {
49 m_router->Read(buffer, len);
50 m_snderror = m_router->GetError();
51 m_lastcount = m_router->GetLastAccess();
52 } else {
53 m_sndio->Read(buffer, len);
54 m_snderror = m_sndio->GetError();
55 m_lastcount = m_sndio->GetLastAccess();
56 }
57 return *this;
58 }
59
60 // --------------------------------------------------------------------------
61 // Write(const void *buffer, wxUint32 len): It writes data synchronously
62 // --------------------------------------------------------------------------
63 wxSoundStream& wxSoundRouterStream::Write(const void *buffer, wxUint32 len)
64 {
65 if (m_router) {
66 m_router->Write(buffer, len);
67 m_snderror = m_router->GetError();
68 m_lastcount = m_router->GetLastAccess();
69 } else {
70 m_sndio->Write(buffer, len);
71 m_snderror = m_sndio->GetError();
72 m_lastcount = m_sndio->GetLastAccess();
73 }
74 return *this;
75 }
76
77 // --------------------------------------------------------------------------
78 // SetSoundFormat(const wxSoundFormatBase& format) first tries to setup the
79 // sound driver using the specified format. If this fails, it uses personnal
80 // codec converters: for the moment there is a PCM converter (PCM to PCM:
81 // with optional resampling, ...), an ULAW converter (ULAW to PCM), a G72X
82 // converter (G72X to PCM). If nothing works, it returns false.
83 // --------------------------------------------------------------------------
84 bool wxSoundRouterStream::SetSoundFormat(const wxSoundFormatBase& format)
85 {
86 if (m_router)
87 delete m_router;
88
89 // First, we try to setup the sound device
90 if (m_sndio->SetSoundFormat(format)) {
91 // We are lucky, it is working.
92 wxSoundStream::SetSoundFormat(m_sndio->GetSoundFormat());
93 return true;
94 }
95
96 switch(format.GetType()) {
97 case wxSOUND_NOFORMAT:
98 return false;
99 case wxSOUND_PCM:
100 m_router = new wxSoundStreamPcm(*m_sndio);
101 m_router->SetSoundFormat(format);
102 break;
103 case wxSOUND_ULAW:
104 m_router = new wxSoundStreamUlaw(*m_sndio);
105 m_router->SetSoundFormat(format);
106 break;
107 case wxSOUND_G72X:
108 m_router = new wxSoundStreamG72X(*m_sndio);
109 m_router->SetSoundFormat(format);
110 break;
111 case wxSOUND_MSADPCM:
112 m_router = new wxSoundStreamMSAdpcm(*m_sndio);
113 m_router->SetSoundFormat(format);
114 break;
115 default:
116 return false;
117
118 }
119 wxSoundStream::SetSoundFormat(m_router->GetSoundFormat());
120 return true;
121 }
122
123 // --------------------------------------------------------------------------
124 // GetBestSize() returns the specific best buffer size a sound driver
125 // can manage. It means that it will be easier for it to manage the buffer
126 // and so it will be faster and in some case more accurate for real-time event.
127 // --------------------------------------------------------------------------
128 wxUint32 wxSoundRouterStream::GetBestSize() const
129 {
130 if (m_router)
131 return m_router->GetBestSize();
132 else
133 return m_sndio->GetBestSize();
134 }
135
136 // --------------------------------------------------------------------------
137 // StartProduction(int evt). See sndbase.h
138 // --------------------------------------------------------------------------
139 bool wxSoundRouterStream::StartProduction(int evt)
140 {
141 if (!m_router) {
142 if (m_sndio->StartProduction(evt))
143 return true;
144
145 m_snderror = m_sndio->GetError();
146 m_lastcount = m_sndio->GetLastAccess();
147 return false;
148 }
149
150 if (m_router->StartProduction(evt))
151 return true;
152
153 m_snderror = m_router->GetError();
154 m_lastcount = m_router->GetLastAccess();
155 return false;
156 }
157
158 // --------------------------------------------------------------------------
159 // StopProduction(). See sndbase.h
160 // --------------------------------------------------------------------------
161 bool wxSoundRouterStream::StopProduction()
162 {
163 if (!m_router) {
164 if (m_sndio->StopProduction())
165 return true;
166
167 m_snderror = m_sndio->GetError();
168 m_lastcount = m_sndio->GetLastAccess();
169 return false;
170 }
171
172 if (m_router->StopProduction())
173 return true;
174
175 m_snderror = m_router->GetError();
176 m_lastcount = m_router->GetLastAccess();
177 return false;
178 }
179
180 // --------------------------------------------------------------------------
181 // wxSoundFileStream: generic reader
182 // --------------------------------------------------------------------------
183
184 wxSoundFileStream::wxSoundFileStream(wxInputStream& stream,
185 wxSoundStream& io_sound)
186 : m_codec(io_sound), m_sndio(&io_sound),
187 m_input(&stream), m_output(NULL), m_state(wxSOUND_FILE_STOPPED)
188 {
189 m_length = 0;
190 m_bytes_left = 0;
191 m_prepared = false;
192 }
193
194 wxSoundFileStream::wxSoundFileStream(wxOutputStream& stream,
195 wxSoundStream& io_sound)
196 : m_codec(io_sound), m_sndio(&io_sound),
197 m_input(NULL), m_output(&stream), m_state(wxSOUND_FILE_STOPPED)
198 {
199 m_length = 0;
200 m_bytes_left = 0;
201 m_prepared = false;
202 }
203
204 wxSoundFileStream::~wxSoundFileStream()
205 {
206 if (m_state != wxSOUND_FILE_STOPPED)
207 Stop();
208 }
209
210 bool wxSoundFileStream::Play()
211 {
212 if (m_state != wxSOUND_FILE_STOPPED)
213 return false;
214
215 if (!m_prepared)
216 if (!PrepareToPlay())
217 return false;
218
219 m_state = wxSOUND_FILE_PLAYING;
220
221 if (!StartProduction(wxSOUND_OUTPUT))
222 return false;
223
224 return true;
225 }
226
227 bool wxSoundFileStream::Record(wxUint32 time)
228 {
229 if (m_state != wxSOUND_FILE_STOPPED)
230 return false;
231
232 if (!PrepareToRecord(time))
233 return false;
234
235 FinishPreparation(m_sndformat->GetBytesFromTime(time));
236
237 m_state = wxSOUND_FILE_RECORDING;
238 if (!StartProduction(wxSOUND_INPUT))
239 return false;
240
241 return true;
242 }
243
244 bool wxSoundFileStream::Stop()
245 {
246 if (m_state == wxSOUND_FILE_STOPPED)
247 return false;
248
249 if (!StopProduction())
250 return false;
251
252 m_prepared = false;
253
254 if (m_state == wxSOUND_FILE_RECORDING)
255 if (!FinishRecording()) {
256 m_state = wxSOUND_FILE_STOPPED;
257 return false;
258 }
259
260 if (m_input)
261 m_input->SeekI(0, wxFromStart);
262
263 if (m_output)
264 m_output->SeekO(0, wxFromStart);
265
266 m_state = wxSOUND_FILE_STOPPED;
267 return true;
268 }
269
270 bool wxSoundFileStream::Pause()
271 {
272 if (m_state == wxSOUND_FILE_PAUSED || m_state == wxSOUND_FILE_STOPPED)
273 return false;
274
275 if (!StopProduction())
276 return false;
277
278 m_oldstate = m_state;
279 m_state = wxSOUND_FILE_PAUSED;
280 return true;
281 }
282
283 bool wxSoundFileStream::Resume()
284 {
285 if (m_state == wxSOUND_FILE_PLAYING || m_state == wxSOUND_FILE_RECORDING ||
286 m_state == wxSOUND_FILE_STOPPED)
287 return false;
288
289 if (!StartProduction( (m_oldstate == wxSOUND_FILE_PLAYING) ?
290 wxSOUND_OUTPUT : wxSOUND_INPUT))
291 return false;
292
293 m_state = m_oldstate;
294
295 return true;
296 }
297
298 wxSoundStream& wxSoundFileStream::Read(void *buffer, wxUint32 len)
299 {
300 if (!m_prepared || m_state != wxSOUND_FILE_PLAYING) {
301 m_snderror = wxSOUND_NOTSTARTED;
302 m_lastcount = 0;
303 return *this;
304 }
305 m_lastcount = GetData(buffer, len);
306 return *this;
307 }
308
309 wxSoundStream& wxSoundFileStream::Write(const void *buffer, wxUint32 len)
310 {
311 if (!m_prepared || m_state != wxSOUND_FILE_RECORDING) {
312 m_snderror = wxSOUND_NOTSTARTED;
313 m_lastcount = 0;
314 return *this;
315 }
316 m_lastcount = PutData(buffer, len);
317 return *this;
318 }
319
320 bool wxSoundFileStream::StartProduction(int evt)
321 {
322 m_sndio->SetEventHandler(this);
323
324 if (!m_codec.StartProduction(evt))
325 return false;
326
327 return true;
328 }
329
330 bool wxSoundFileStream::StopProduction()
331 {
332 return m_codec.StopProduction();
333 }
334
335 void wxSoundFileStream::FinishPreparation(wxUint32 len)
336 {
337 m_bytes_left = m_length = len;
338 m_prepared = true;
339 }
340
341 wxString wxSoundFileStream::GetCodecName() const
342 {
343 return wxString(wxT("wxSoundFileStream base codec"));
344 }
345
346 wxUint32 wxSoundFileStream::GetLength()
347 {
348 if (m_input && !m_prepared && GetError() == wxSOUND_NOERROR)
349 return (PrepareToPlay()) ? m_length : 0;
350
351 return m_length;
352 }
353
354 wxUint32 wxSoundFileStream::GetPosition()
355 {
356 if (!m_prepared && m_input != NULL && GetError() == wxSOUND_NOERROR)
357 PrepareToPlay();
358
359 return m_length-m_bytes_left;
360 }
361
362 wxUint32 wxSoundFileStream::SetPosition(wxUint32 new_position)
363 {
364 if (!m_prepared && m_input != NULL && GetError() == wxSOUND_NOERROR)
365 PrepareToPlay();
366
367 if (!m_prepared)
368 return 0;
369
370 if (!RepositionStream(new_position))
371 return m_length-m_bytes_left;
372
373 if (new_position >= m_length) {
374 m_bytes_left = 0;
375 return m_length;
376 }
377
378 m_bytes_left = m_length-new_position;
379 return new_position;
380 }
381
382 void wxSoundFileStream::OnSoundEvent(int evt)
383 {
384 wxUint32 len = m_codec.GetBestSize();
385 char *buffer;
386
387 buffer = new char[len];
388 wxSoundStream::OnSoundEvent(evt);
389
390 while (!m_sndio->QueueFilled()) {
391 switch(evt) {
392 case wxSOUND_INPUT:
393 if (len > m_bytes_left)
394 len = m_bytes_left;
395
396 len = m_codec.Read(buffer, len).GetLastAccess();
397 PutData(buffer, len);
398 m_bytes_left -= len;
399 if (m_bytes_left == 0) {
400 Stop();
401 delete[] buffer;
402 return;
403 }
404 break;
405 case wxSOUND_OUTPUT:
406 if (len > m_bytes_left)
407 len = m_bytes_left;
408
409 len = GetData(buffer, len);
410 m_bytes_left -= len;
411 if (m_bytes_left == 0) {
412 Stop();
413 delete[] buffer;
414 return;
415 }
416 m_codec.Write(buffer, len);
417 break;
418 }
419 }
420 delete[] buffer;
421 }
422
423 bool wxSoundFileStream::SetSoundFormat(const wxSoundFormatBase& format)
424 {
425 wxSoundStream::SetSoundFormat(format);
426 return m_codec.SetSoundFormat(format);
427 }