]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/sndfile.cpp
fix evaluation order bug (patch 1158099)
[wxWidgets.git] / contrib / src / mmedia / sndfile.cpp
CommitLineData
e8482f24
GL
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$
58b9c9ba 7// wxWindows licence
e8482f24 8// --------------------------------------------------------------------------
92a19c2e 9#include "wx/wxprec.h"
e8482f24
GL
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"
c42b1de6 22#include "wx/mmedia/sndmsad.h"
e8482f24
GL
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// --------------------------------------------------------------------------
30wxSoundRouterStream::wxSoundRouterStream(wxSoundStream& sndio)
31 : wxSoundStreamCodec(sndio)
32{
33 m_router = NULL;
34}
35
36wxSoundRouterStream::~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// --------------------------------------------------------------------------
46wxSoundStream& 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// --------------------------------------------------------------------------
63wxSoundStream& 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
dea7e44a 82// converter (G72X to PCM). If nothing works, it returns false.
e8482f24
GL
83// --------------------------------------------------------------------------
84bool 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());
dea7e44a 93 return true;
e8482f24
GL
94 }
95
96 switch(format.GetType()) {
97 case wxSOUND_NOFORMAT:
dea7e44a 98 return false;
e8482f24
GL
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;
c42b1de6
GL
111 case wxSOUND_MSADPCM:
112 m_router = new wxSoundStreamMSAdpcm(*m_sndio);
113 m_router->SetSoundFormat(format);
114 break;
e8482f24 115 default:
dea7e44a 116 return false;
e8482f24
GL
117
118 }
119 wxSoundStream::SetSoundFormat(m_router->GetSoundFormat());
dea7e44a 120 return true;
e8482f24
GL
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// --------------------------------------------------------------------------
128wxUint32 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// --------------------------------------------------------------------------
139bool wxSoundRouterStream::StartProduction(int evt)
140{
141 if (!m_router) {
142 if (m_sndio->StartProduction(evt))
dea7e44a 143 return true;
e8482f24
GL
144
145 m_snderror = m_sndio->GetError();
146 m_lastcount = m_sndio->GetLastAccess();
dea7e44a 147 return false;
e8482f24
GL
148 }
149
150 if (m_router->StartProduction(evt))
dea7e44a 151 return true;
e8482f24
GL
152
153 m_snderror = m_router->GetError();
154 m_lastcount = m_router->GetLastAccess();
dea7e44a 155 return false;
e8482f24
GL
156}
157
158// --------------------------------------------------------------------------
159// StopProduction(). See sndbase.h
160// --------------------------------------------------------------------------
161bool wxSoundRouterStream::StopProduction()
162{
163 if (!m_router) {
164 if (m_sndio->StopProduction())
dea7e44a 165 return true;
e8482f24
GL
166
167 m_snderror = m_sndio->GetError();
168 m_lastcount = m_sndio->GetLastAccess();
dea7e44a 169 return false;
e8482f24
GL
170 }
171
172 if (m_router->StopProduction())
dea7e44a 173 return true;
e8482f24
GL
174
175 m_snderror = m_router->GetError();
176 m_lastcount = m_router->GetLastAccess();
dea7e44a 177 return false;
e8482f24
GL
178}
179
180// --------------------------------------------------------------------------
181// wxSoundFileStream: generic reader
182// --------------------------------------------------------------------------
183
184wxSoundFileStream::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;
dea7e44a 191 m_prepared = false;
e8482f24
GL
192}
193
194wxSoundFileStream::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;
dea7e44a 201 m_prepared = false;
e8482f24
GL
202}
203
204wxSoundFileStream::~wxSoundFileStream()
205{
206 if (m_state != wxSOUND_FILE_STOPPED)
207 Stop();
208}
209
210bool wxSoundFileStream::Play()
211{
212 if (m_state != wxSOUND_FILE_STOPPED)
dea7e44a 213 return false;
e8482f24
GL
214
215 if (!m_prepared)
216 if (!PrepareToPlay())
dea7e44a 217 return false;
e8482f24
GL
218
219 m_state = wxSOUND_FILE_PLAYING;
220
221 if (!StartProduction(wxSOUND_OUTPUT))
dea7e44a 222 return false;
e8482f24 223
dea7e44a 224 return true;
e8482f24
GL
225}
226
227bool wxSoundFileStream::Record(wxUint32 time)
228{
229 if (m_state != wxSOUND_FILE_STOPPED)
dea7e44a 230 return false;
e8482f24
GL
231
232 if (!PrepareToRecord(time))
dea7e44a 233 return false;
e8482f24
GL
234
235 FinishPreparation(m_sndformat->GetBytesFromTime(time));
236
237 m_state = wxSOUND_FILE_RECORDING;
238 if (!StartProduction(wxSOUND_INPUT))
dea7e44a 239 return false;
e8482f24 240
dea7e44a 241 return true;
e8482f24
GL
242}
243
244bool wxSoundFileStream::Stop()
245{
246 if (m_state == wxSOUND_FILE_STOPPED)
dea7e44a 247 return false;
e8482f24
GL
248
249 if (!StopProduction())
dea7e44a 250 return false;
e8482f24 251
dea7e44a 252 m_prepared = false;
e8482f24
GL
253
254 if (m_state == wxSOUND_FILE_RECORDING)
255 if (!FinishRecording()) {
256 m_state = wxSOUND_FILE_STOPPED;
dea7e44a 257 return false;
e8482f24
GL
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;
dea7e44a 267 return true;
e8482f24
GL
268}
269
270bool wxSoundFileStream::Pause()
271{
272 if (m_state == wxSOUND_FILE_PAUSED || m_state == wxSOUND_FILE_STOPPED)
dea7e44a 273 return false;
e8482f24
GL
274
275 if (!StopProduction())
dea7e44a 276 return false;
e8482f24
GL
277
278 m_oldstate = m_state;
279 m_state = wxSOUND_FILE_PAUSED;
dea7e44a 280 return true;
e8482f24
GL
281}
282
283bool wxSoundFileStream::Resume()
284{
285 if (m_state == wxSOUND_FILE_PLAYING || m_state == wxSOUND_FILE_RECORDING ||
286 m_state == wxSOUND_FILE_STOPPED)
dea7e44a 287 return false;
e8482f24
GL
288
289 if (!StartProduction( (m_oldstate == wxSOUND_FILE_PLAYING) ?
290 wxSOUND_OUTPUT : wxSOUND_INPUT))
dea7e44a 291 return false;
e8482f24
GL
292
293 m_state = m_oldstate;
294
dea7e44a 295 return true;
e8482f24
GL
296}
297
298wxSoundStream& 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
309wxSoundStream& 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
320bool wxSoundFileStream::StartProduction(int evt)
321{
322 m_sndio->SetEventHandler(this);
323
324 if (!m_codec.StartProduction(evt))
dea7e44a 325 return false;
e8482f24 326
dea7e44a 327 return true;
e8482f24
GL
328}
329
330bool wxSoundFileStream::StopProduction()
331{
332 return m_codec.StopProduction();
333}
334
335void wxSoundFileStream::FinishPreparation(wxUint32 len)
336{
337 m_bytes_left = m_length = len;
dea7e44a 338 m_prepared = true;
e8482f24
GL
339}
340
341wxString wxSoundFileStream::GetCodecName() const
342{
343 return wxString(wxT("wxSoundFileStream base codec"));
344}
345
346wxUint32 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
354wxUint32 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
362wxUint32 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
382void 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
423bool wxSoundFileStream::SetSoundFormat(const wxSoundFormatBase& format)
424{
425 wxSoundStream::SetSoundFormat(format);
426 return m_codec.SetSoundFormat(format);
427}