1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
8 // --------------------------------------------------------------------------
10 #pragma implementation "sndwav.cpp"
13 #include "wx/wxprec.h"
23 #include "wx/stream.h"
24 #include "wx/datstrm.h"
25 #include "wx/filefn.h"
26 #include "wx/mstream.h"
28 #include "wx/mmedia/sndbase.h"
29 #include "wx/mmedia/sndcodec.h"
30 #include "wx/mmedia/sndfile.h"
31 #include "wx/mmedia/sndpcm.h"
32 #include "wx/mmedia/sndg72x.h"
33 #include "wx/mmedia/sndmsad.h"
34 #include "wx/mmedia/sndwav.h"
36 #define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16) | (((wxUint32)d) << 24))
38 #define RIFF_SIGNATURE BUILD_SIGNATURE('R','I','F','F')
39 #define WAVE_SIGNATURE BUILD_SIGNATURE('W','A','V','E')
40 #define FMT_SIGNATURE BUILD_SIGNATURE('f','m','t',' ')
41 #define DATA_SIGNATURE BUILD_SIGNATURE('d','a','t','a')
43 #define HEADER_SIZE 4+4 + 4+4+16 + 4+4
47 wxSoundWave::wxSoundWave(wxInputStream
& stream
, wxSoundStream
& io_sound
)
48 : wxSoundFileStream(stream
, io_sound
)
50 m_base_offset
= wxInvalidOffset
;
53 wxSoundWave::wxSoundWave(wxOutputStream
& stream
, wxSoundStream
& io_sound
)
54 : wxSoundFileStream(stream
, io_sound
)
56 m_base_offset
= wxInvalidOffset
;
59 wxSoundWave::~wxSoundWave()
63 wxString
wxSoundWave::GetCodecName() const
65 return wxString(wxT("wxSoundWave codec"));
68 #define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return false; }
70 bool wxSoundWave::CanRead()
72 wxUint32 len
, signature1
, signature2
;
73 m_snderror
= wxSOUND_NOERROR
;
75 // Test the main signatures:
77 FAIL_WITH(m_input
->Read(&signature1
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
79 if (wxUINT32_SWAP_ON_BE(signature1
) != RIFF_SIGNATURE
) {
80 m_input
->Ungetch(&signature1
, 4);
84 // Pass the global length
85 m_input
->Read(&len
, 4);
86 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
88 // Get the second signature
89 FAIL_WITH(m_input
->Read(&signature2
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
91 m_input
->Ungetch(&signature2
, 4);
92 m_input
->Ungetch(&len
, 4);
93 m_input
->Ungetch(&signature1
, 4);
95 // Test the second signature
96 if (wxUINT32_SWAP_ON_BE(signature2
) != WAVE_SIGNATURE
)
102 bool wxSoundWave::HandleOutputPCM(wxDataInputStream
& WXUNUSED(data
), wxUint32 len
,
104 wxUint32 sample_fq
, wxUint32
WXUNUSED(byte_p_sec
),
105 wxUint16
WXUNUSED(byte_p_spl
), wxUint16 bits_p_spl
)
107 wxSoundFormatPcm sndformat
;
109 sndformat
.SetSampleRate(sample_fq
);
110 sndformat
.SetBPS(bits_p_spl
);
111 sndformat
.SetChannels(channels
);
112 sndformat
.Signed(true);
113 sndformat
.SetOrder(wxLITTLE_ENDIAN
);
115 if (!SetSoundFormat(sndformat
))
118 m_input
->SeekI(len
, wxFromCurrent
);
123 bool wxSoundWave::HandleOutputMSADPCM(wxDataInputStream
& data
, wxUint32 len
,
125 wxUint32 sample_fq
, wxUint32
WXUNUSED(byte_p_sec
),
126 wxUint16
WXUNUSED(byte_p_spl
), wxUint16
WXUNUSED(bits_p_spl
))
128 wxSoundFormatMSAdpcm sndformat
;
130 wxUint16 coefs_len
, i
;
133 sndformat
.SetSampleRate(sample_fq
);
134 sndformat
.SetChannels(channels
);
136 block_size
= data
.Read16();
137 coefs_len
= data
.Read16();
139 coefs
[0] = new wxInt16
[coefs_len
];
140 coefs
[1] = new wxInt16
[coefs_len
];
142 for (i
=0;i
<coefs_len
;i
++) {
143 coefs
[0][i
] = data
.Read16();
144 coefs
[1][i
] = data
.Read16();
147 sndformat
.SetCoefs(coefs
, 2, coefs_len
);
148 sndformat
.SetBlockSize(block_size
);
153 if (!SetSoundFormat(sndformat
))
156 len
-= coefs_len
*4 + 4;
158 m_input
->SeekI(len
, wxFromCurrent
);
163 bool wxSoundWave::HandleOutputG721(wxDataInputStream
& WXUNUSED(data
), wxUint32 len
,
164 wxUint16
WXUNUSED(channels
),
165 wxUint32 sample_fq
, wxUint32
WXUNUSED(byte_p_sec
),
166 wxUint16
WXUNUSED(byte_p_spl
), wxUint16
WXUNUSED(bits_p_spl
))
168 wxSoundFormatG72X sndformat
;
170 sndformat
.SetSampleRate(sample_fq
);
171 sndformat
.SetG72XType(wxSOUND_G721
);
173 if (!SetSoundFormat(sndformat
))
176 m_input
->SeekI(len
, wxFromCurrent
);
181 bool wxSoundWave::PrepareToPlay()
183 wxUint32 signature
, len
;
187 m_snderror
= wxSOUND_INVSTRM
;
191 wxDataInputStream
data(*m_input
);
192 data
.BigEndianOrdered(false);
194 // Get the first signature
195 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
196 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature
) != RIFF_SIGNATURE
, wxSOUND_INVSTRM
);
201 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
204 // Get the second signature
205 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
206 FAIL_WITH(wxUINT32_SWAP_ON_BE(signature
) != WAVE_SIGNATURE
, wxSOUND_INVSTRM
);
211 while (!end_headers
) {
212 FAIL_WITH(m_input
->Read(&signature
, 4).LastRead() != 4, wxSOUND_INVSTRM
);
215 FAIL_WITH(m_input
->LastRead() != 4, wxSOUND_INVSTRM
);
217 switch (wxUINT32_SWAP_ON_BE(signature
)) {
218 case FMT_SIGNATURE
: { // "fmt "
219 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
220 wxUint32 sample_fq
, byte_p_sec
;
222 // Get the common parameters
223 data
>> format
>> channels
>> sample_fq
224 >> byte_p_sec
>> byte_p_spl
>> bits_p_spl
;
229 if (!HandleOutputPCM(data
, len
, channels
, sample_fq
,
230 byte_p_sec
, byte_p_spl
,
234 case 0x02: // MS ADPCM
235 if (!HandleOutputMSADPCM(data
, len
,
237 byte_p_sec
, byte_p_spl
,
242 if (!HandleOutputG721(data
, len
,
244 byte_p_sec
, byte_p_spl
,
249 m_snderror
= wxSOUND_NOCODEC
;
254 case DATA_SIGNATURE
: // "data"
255 m_base_offset
= m_input
->TellI();
257 FinishPreparation(len
);
261 m_input
->SeekI(len
, wxFromCurrent
);
268 wxSoundFormatBase
*wxSoundWave::HandleInputPCM(wxDataOutputStream
& data
)
270 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
271 wxUint32 sample_fq
, byte_p_sec
;
272 wxSoundFormatPcm
*pcm
;
274 pcm
= (wxSoundFormatPcm
*)(m_sndformat
->Clone());
276 // Write block length
279 sample_fq
= pcm
->GetSampleRate();
280 bits_p_spl
= pcm
->GetBPS();
281 channels
= pcm
->GetChannels();
282 byte_p_spl
= pcm
->GetBPS() / 8;
283 byte_p_sec
= pcm
->GetBytesFromTime(1);
287 pcm
->SetOrder(wxLITTLE_ENDIAN
);
289 data
<< format
<< channels
<< sample_fq
290 << byte_p_sec
<< byte_p_spl
<< bits_p_spl
;
295 wxSoundFormatBase
*wxSoundWave::HandleInputG72X(wxDataOutputStream
& data
)
297 wxUint16 format
, channels
, byte_p_spl
, bits_p_spl
;
298 wxUint32 sample_fq
, byte_p_sec
;
299 wxSoundFormatG72X
*g72x
;
301 // Write block length
304 g72x
= (wxSoundFormatG72X
*)(m_sndformat
->Clone());
305 if (g72x
->GetG72XType() != wxSOUND_G721
) {
310 sample_fq
= g72x
->GetSampleRate();
314 byte_p_sec
= g72x
->GetBytesFromTime(1);
316 data
<< format
<< channels
<< sample_fq
317 << byte_p_sec
<< byte_p_spl
<< bits_p_spl
;
322 bool wxSoundWave::PrepareToRecord(wxUint32 time
)
324 #define WRITE_SIGNATURE(s,sig) \
326 signature = wxUINT32_SWAP_ON_BE(signature); \
327 FAIL_WITH(s->Write(&signature, 4).LastWrite() != 4, wxSOUND_INVSTRM);
330 wxMemoryOutputStream fmt_data
;
333 m_snderror
= wxSOUND_INVSTRM
;
337 wxDataOutputStream
data(*m_output
);
338 wxDataOutputStream
fmt_d_data(fmt_data
);
340 data
.BigEndianOrdered(false);
341 fmt_d_data
.BigEndianOrdered(false);
343 WRITE_SIGNATURE(m_output
, RIFF_SIGNATURE
);
345 FAIL_WITH(m_output
->LastWrite() != 4, wxSOUND_INVSTRM
);
347 WRITE_SIGNATURE((&fmt_data
), WAVE_SIGNATURE
);
350 wxSoundFormatBase
*frmt
;
352 WRITE_SIGNATURE((&fmt_data
), FMT_SIGNATURE
);
354 switch (m_sndformat
->GetType()) {
356 frmt
= HandleInputPCM(fmt_d_data
);
359 frmt
= HandleInputG72X(fmt_d_data
);
362 m_snderror
= wxSOUND_NOCODEC
;
366 FAIL_WITH(!frmt
, wxSOUND_NOCODEC
);
368 if (!SetSoundFormat(*frmt
)) {
376 data
<< (wxUint32
)(fmt_data
.GetSize() + m_sndformat
->GetBytesFromTime(time
));
378 // We, finally, copy the header block to the output stream
381 out_buf
= new char[fmt_data
.GetSize()];
383 fmt_data
.CopyTo(out_buf
, fmt_data
.GetSize());
384 m_output
->Write(out_buf
, fmt_data
.GetSize());
389 WRITE_SIGNATURE(m_output
, DATA_SIGNATURE
);
390 data
.Write32(m_sndformat
->GetBytesFromTime(time
));
394 bool wxSoundWave::FinishRecording()
396 if (m_output
->SeekO(0, wxFromStart
) == wxInvalidOffset
)
397 // We can't but there is no error.
400 if (m_bytes_left
== 0)
403 // TODO: Update headers when we stop before the specified time (if possible)
407 bool wxSoundWave::RepositionStream(wxUint32
WXUNUSED(position
))
409 if (m_base_offset
== wxInvalidOffset
)
411 m_input
->SeekI(m_base_offset
, wxFromStart
);
415 wxUint32
wxSoundWave::GetData(void *buffer
, wxUint32 len
)
417 return m_input
->Read(buffer
, len
).LastRead();
420 wxUint32
wxSoundWave::PutData(const void *buffer
, wxUint32 len
)
422 return m_output
->Write(buffer
, len
).LastWrite();