1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
7 // --------------------------------------------------------------------------
9 #pragma implementation "sndwav.cpp"
12 #include <wx/wxprec.h>
22 #include "wx/stream.h"
23 #include "wx/datstrm.h"
24 #include "wx/filefn.h"
25 #include "wx/mstream.h"
27 #include "wx/mmedia/sndbase.h"
28 #include "wx/mmedia/sndcodec.h"
29 #include "wx/mmedia/sndfile.h"
30 #include "wx/mmedia/sndpcm.h"
31 #include "wx/mmedia/sndg72x.h"
32 #include "wx/mmedia/sndwav.h"
34 #define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16) | (((wxUint32)d) << 24))
36 #define RIFF_SIGNATURE BUILD_SIGNATURE('R','I','F','F')
37 #define WAVE_SIGNATURE BUILD_SIGNATURE('W','A','V','E')
38 #define FMT_SIGNATURE BUILD_SIGNATURE('f','m','t',' ')
39 #define DATA_SIGNATURE BUILD_SIGNATURE('d','a','t','a')
41 #define HEADER_SIZE 4+4 + 4+4+16 + 4+4
45 wxSoundWave::wxSoundWave(wxInputStream
& stream
, wxSoundStream
& io_sound
)
46 : wxSoundFileStream(stream
, io_sound
)
48 m_base_offset
= wxInvalidOffset
;
51 wxSoundWave::wxSoundWave(wxOutputStream
& stream
, wxSoundStream
& io_sound
)
52 : wxSoundFileStream(stream
, io_sound
)
54 m_base_offset
= wxInvalidOffset
;
57 wxSoundWave::~wxSoundWave()
61 wxString
wxSoundWave::GetCodecName() const
63 return wxString(wxT("wxSoundWave codec"));
66 #define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return FALSE; }
68 bool wxSoundWave::CanRead()
70 wxUint32 len
, signature1
, signature2
;
71 m_snderror
= wxSOUND_NOERROR
;
73 // Test the main signatures:
75 FAIL_WITH(m_input
->Read(&signature1
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
77 if (wxUINT32_SWAP_ON_BE(signature1
) != RIFF_SIGNATURE
) {
78 m_input
->Ungetch(&signature1
, 4);
82 // Pass the global length
83 m_input
->Read(&len
, 4);
84 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
86 // Get the second signature
87 FAIL_WITH(m_input
->Read(&signature2
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
89 m_input
->Ungetch(&signature2
, 4);
90 m_input
->Ungetch(&len
, 4);
91 m_input
->Ungetch(&signature1
, 4);
93 // Test the second signature
94 if (wxUINT32_SWAP_ON_BE(signature2
) != WAVE_SIGNATURE
)
100 bool wxSoundWave::HandleOutputPCM(wxDataInputStream
& data
, wxUint16 channels
,
101 wxUint32 sample_fq
, wxUint32 byte_p_sec
,
102 wxUint16 byte_p_spl
, wxUint16 bits_p_spl
)
104 wxSoundFormatPcm sndformat
;
106 sndformat
.SetSampleRate(sample_fq
);
107 sndformat
.SetBPS(bits_p_spl
);
108 sndformat
.SetChannels(channels
);
109 sndformat
.Signed(TRUE
);
110 sndformat
.SetOrder(wxLITTLE_ENDIAN
);
112 if (!SetSoundFormat(sndformat
))
118 bool wxSoundWave::HandleOutputG721(wxDataInputStream
& data
, wxUint16 channels
,
119 wxUint32 sample_fq
, wxUint32 byte_p_sec
,
120 wxUint16 byte_p_spl
, wxUint16 bits_p_spl
)
122 wxSoundFormatG72X sndformat
;
124 sndformat
.SetSampleRate(sample_fq
);
125 sndformat
.SetG72XType(wxSOUND_G721
);
127 if (!SetSoundFormat(sndformat
))
133 bool wxSoundWave::PrepareToPlay()
135 wxUint32 signature
, len
;
139 m_snderror
= wxSOUND_INVSTRM
;
143 wxDataInputStream
data(*m_input
);
144 data
.BigEndianOrdered(FALSE
);
146 // Get the first signature
147 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
148 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature
) != RIFF_SIGNATURE
, wxSOUND_INVSTRM
);
152 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
155 // Get the second signature
156 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
157 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature
) != WAVE_SIGNATURE
, wxSOUND_INVSTRM
);
162 while (!end_headers
) {
163 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
166 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
168 switch (wxUINT32_SWAP_ON_BE(signature
)) {
169 case FMT_SIGNATURE
: { // "fmt "
170 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
171 wxUint32 sample_fq
, byte_p_sec
;
173 // Get the common parameters
174 data
>> format
>> channels
>> sample_fq
175 >> byte_p_sec
>> byte_p_spl
>> bits_p_spl
;
179 if (!HandleOutputPCM(data
, channels
, sample_fq
,
180 byte_p_sec
, byte_p_spl
, bits_p_spl
))
184 if (!HandleOutputG721(data
, channels
, sample_fq
,
185 byte_p_sec
, byte_p_spl
, bits_p_spl
))
189 m_snderror
= wxSOUND_NOCODEC
;
194 case DATA_SIGNATURE
: // "data"
195 m_base_offset
= m_input
->TellI();
197 FinishPreparation(len
);
201 m_input
->SeekI(len
, wxFromCurrent
);
208 wxSoundFormatBase
*wxSoundWave::HandleInputPCM(wxDataOutputStream
& data
)
210 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
211 wxUint32 sample_fq
, byte_p_sec
;
212 wxSoundFormatPcm
*pcm
;
214 pcm
= (wxSoundFormatPcm
*)(m_sndformat
->Clone());
216 // Write block length
219 sample_fq
= pcm
->GetSampleRate();
220 bits_p_spl
= pcm
->GetBPS();
221 channels
= pcm
->GetChannels();
222 byte_p_spl
= pcm
->GetBPS() / 8;
223 byte_p_sec
= pcm
->GetBytesFromTime(1);
227 pcm
->SetOrder(wxLITTLE_ENDIAN
);
229 data
<< format
<< channels
<< sample_fq
230 << byte_p_sec
<< byte_p_spl
<< bits_p_spl
;
235 wxSoundFormatBase
*wxSoundWave::HandleInputG72X(wxDataOutputStream
& data
)
237 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
238 wxUint32 sample_fq
, byte_p_sec
;
239 wxSoundFormatG72X
*g72x
;
241 // Write block length
244 g72x
= (wxSoundFormatG72X
*)(m_sndformat
->Clone());
245 if (g72x
->GetG72XType() != wxSOUND_G721
) {
250 sample_fq
= g72x
->GetSampleRate();
254 byte_p_sec
= g72x
->GetBytesFromTime(1);
256 data
<< format
<< channels
<< sample_fq
257 << byte_p_sec
<< byte_p_spl
<< bits_p_spl
;
262 bool wxSoundWave::PrepareToRecord(wxUint32 time
)
264 #define WRITE_SIGNATURE(s,sig) \
266 signature = wxUINT32_SWAP_ON_BE(signature); \
267 FAIL_WITH(s->Write(&signature, 4).LastWrite() != 4, wxSOUND_INVSTRM);
270 wxMemoryOutputStream fmt_data
;
273 m_snderror
= wxSOUND_INVSTRM
;
277 wxDataOutputStream
data(*m_output
);
278 wxDataOutputStream
fmt_d_data(fmt_data
);
280 data
.BigEndianOrdered(FALSE
);
281 fmt_d_data
.BigEndianOrdered(FALSE
);
283 WRITE_SIGNATURE(m_output
, RIFF_SIGNATURE
);
285 FAIL_WITH(m_output
->LastWrite() != 4, wxSOUND_INVSTRM
);
287 WRITE_SIGNATURE((&fmt_data
), WAVE_SIGNATURE
);
290 wxSoundFormatBase
*frmt
;
292 WRITE_SIGNATURE((&fmt_data
), FMT_SIGNATURE
);
294 switch (m_sndformat
->GetType()) {
296 frmt
= HandleInputPCM(fmt_d_data
);
299 frmt
= HandleInputG72X(fmt_d_data
);
302 m_snderror
= wxSOUND_NOCODEC
;
306 FAIL_WITH(!frmt
, wxSOUND_NOCODEC
);
308 if (!SetSoundFormat(*frmt
)) {
316 data
<< (fmt_data
.GetSize() + m_sndformat
->GetBytesFromTime(time
));
318 // We, finally, copy the header block to the output stream
321 out_buf
= new char[fmt_data
.GetSize()];
323 fmt_data
.CopyTo(out_buf
, fmt_data
.GetSize());
324 m_output
->Write(out_buf
, fmt_data
.GetSize());
329 WRITE_SIGNATURE(m_output
, DATA_SIGNATURE
);
330 data
.Write32(m_sndformat
->GetBytesFromTime(time
));
334 bool wxSoundWave::FinishRecording()
336 if (m_output
->SeekO(0, wxFromStart
) == wxInvalidOffset
)
337 // We can't but there is no error.
340 if (m_bytes_left
== 0)
343 // TODO: Update headers when we stop before the specified time (if possible)
347 bool wxSoundWave::RepositionStream(wxUint32 position
)
349 if (m_base_offset
== wxInvalidOffset
)
351 m_input
->SeekI(m_base_offset
, wxFromStart
);
355 wxUint32
wxSoundWave::GetData(void *buffer
, wxUint32 len
)
357 return m_input
->Read(buffer
, len
).LastRead();
360 wxUint32
wxSoundWave::PutData(const void *buffer
, wxUint32 len
)
362 return m_output
->Write(buffer
, len
).LastWrite();