]>
Commit | Line | Data |
---|---|---|
526ddb13 GL |
1 | // -------------------------------------------------------------------------- |
2 | // Name: sndwav.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 "sndwav.cpp" | |
10 | #endif | |
11 | ||
6c5e6376 GL |
12 | #include <wx/wxprec.h> |
13 | ||
526ddb13 GL |
14 | #include <wx/stream.h> |
15 | #include <wx/datstrm.h> | |
16 | #include <wx/filefn.h> | |
6c5e6376 | 17 | |
526ddb13 GL |
18 | #include "sndbase.h" |
19 | #include "sndcodec.h" | |
20 | #include "sndfile.h" | |
21 | #include "sndpcm.h" | |
22 | #include "sndwav.h" | |
23 | ||
24 | #define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16) | (((wxUint32)d) << 24)) | |
25 | ||
26 | #define RIFF_SIGNATURE BUILD_SIGNATURE('R','I','F','F') | |
27 | #define WAVE_SIGNATURE BUILD_SIGNATURE('W','A','V','E') | |
28 | #define FMT_SIGNATURE BUILD_SIGNATURE('f','m','t',' ') | |
29 | #define DATA_SIGNATURE BUILD_SIGNATURE('d','a','t','a') | |
30 | ||
31 | #define HEADER_SIZE 4+4 + 4+4+16 + 4+4 | |
32 | // 4+4 => NAME + LEN | |
33 | // 16 => fmt size | |
34 | ||
35 | wxSoundWave::wxSoundWave(wxInputStream& stream, wxSoundStream& io_sound) | |
36 | : wxSoundFileStream(stream, io_sound) | |
37 | { | |
38 | } | |
39 | ||
40 | wxSoundWave::wxSoundWave(wxOutputStream& stream, wxSoundStream& io_sound) | |
41 | : wxSoundFileStream(stream, io_sound) | |
42 | { | |
43 | } | |
44 | ||
45 | wxSoundWave::~wxSoundWave() | |
46 | { | |
47 | } | |
48 | ||
49 | #define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return FALSE; } | |
50 | ||
51 | bool wxSoundWave::CanRead() | |
52 | { | |
53 | wxUint32 len, signature; | |
54 | m_snderror = wxSOUND_NOERR; | |
55 | ||
56 | FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); | |
57 | ||
58 | if (wxUINT32_SWAP_ON_BE(signature) != RIFF_SIGNATURE) { | |
59 | m_input->Ungetch(&signature, 4); | |
60 | return FALSE; | |
61 | } | |
62 | ||
63 | m_input->Read(&len, 4); | |
64 | FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); | |
65 | ||
66 | FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); | |
67 | if (wxUINT32_SWAP_ON_BE(signature) != WAVE_SIGNATURE) { | |
68 | m_input->Ungetch(&signature, 4); | |
69 | return FALSE; | |
70 | } | |
71 | ||
72 | m_input->Ungetch("RIFF", 4); | |
73 | m_input->Ungetch(&len, 4); | |
74 | m_input->Ungetch("WAVE", 4); | |
75 | ||
76 | return TRUE; | |
77 | } | |
78 | ||
79 | bool wxSoundWave::PrepareToPlay() | |
80 | { | |
81 | wxUint32 signature, len; | |
82 | bool end_headers; | |
83 | ||
84 | if (!m_input) { | |
85 | m_snderror = wxSOUND_INVSTRM; | |
86 | return FALSE; | |
87 | } | |
88 | ||
89 | wxDataInputStream data(*m_input); | |
90 | data.BigEndianOrdered(FALSE); | |
91 | ||
92 | FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); | |
93 | FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != RIFF_SIGNATURE, wxSOUND_INVSTRM); | |
94 | // "RIFF" | |
95 | ||
96 | len = data.Read32(); | |
97 | FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); | |
98 | // dummy len | |
99 | ||
100 | FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); | |
101 | FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != WAVE_SIGNATURE, wxSOUND_INVSTRM); | |
102 | // "WAVE" | |
103 | ||
104 | end_headers = FALSE; | |
105 | while (!end_headers) { | |
106 | FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM); | |
107 | ||
108 | len = data.Read32(); | |
109 | FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM); | |
110 | ||
111 | switch (wxUINT32_SWAP_ON_BE(signature)) { | |
112 | case FMT_SIGNATURE: { // "fmt " | |
113 | wxUint16 format, channels, byte_p_spl, bits_p_spl; | |
114 | wxUint32 sample_fq, byte_p_sec; | |
115 | wxSoundFormatPcm sndformat; | |
116 | ||
117 | data >> format >> channels >> sample_fq | |
118 | >> byte_p_sec >> byte_p_spl >> bits_p_spl; | |
119 | FAIL_WITH(format != 1, wxSOUND_NOCODEC); | |
120 | ||
121 | sndformat.SetSampleRate(sample_fq); | |
122 | sndformat.SetBPS(bits_p_spl); | |
123 | sndformat.SetChannels(channels); | |
124 | sndformat.Signed(TRUE); | |
125 | sndformat.SetOrder(wxLITTLE_ENDIAN); | |
126 | ||
127 | if (!SetSoundFormat(sndformat)) | |
128 | return FALSE; | |
129 | m_input->SeekI(len-16, wxFromCurrent); | |
130 | break; | |
131 | } | |
132 | case DATA_SIGNATURE: // "data" | |
133 | end_headers = TRUE; | |
134 | break; | |
135 | default: | |
136 | m_input->SeekI(len, wxFromCurrent); | |
137 | break; | |
138 | } | |
139 | } | |
140 | return TRUE; | |
141 | } | |
142 | ||
143 | bool wxSoundWave::PrepareToRecord(unsigned long time) | |
144 | { | |
145 | #define WRITE_SIGNATURE(sig) \ | |
146 | signature = sig; \ | |
147 | signature = wxUINT32_SWAP_ON_BE(signature); \ | |
148 | FAIL_WITH(m_output->Write(&signature, 4).LastWrite() != 4, wxSOUND_INVSTRM); | |
149 | ||
150 | wxUint32 signature, len; | |
151 | ||
152 | if (!m_output) { | |
153 | m_snderror = wxSOUND_INVSTRM; | |
154 | return FALSE; | |
155 | } | |
156 | ||
157 | wxDataOutputStream data(*m_output); | |
158 | data.BigEndianOrdered(FALSE); | |
159 | ||
622e48cb | 160 | len = m_sndformat->GetBytesFromTime(time); |
526ddb13 GL |
161 | |
162 | len += HEADER_SIZE; | |
163 | ||
164 | WRITE_SIGNATURE(RIFF_SIGNATURE); | |
165 | ||
166 | data << len; | |
167 | FAIL_WITH(m_output->LastWrite() != 4, wxSOUND_INVSTRM); | |
168 | ||
169 | WRITE_SIGNATURE(WAVE_SIGNATURE); | |
170 | ||
171 | { | |
172 | wxUint16 format, channels, byte_p_spl, bits_p_spl; | |
173 | wxUint32 sample_fq, byte_p_sec; | |
174 | wxSoundFormatPcm *pcm; | |
175 | ||
176 | if (m_sndformat->GetType() != wxSOUND_PCM) { | |
177 | m_snderror = wxSOUND_NOCODEC; | |
178 | return FALSE; | |
179 | } | |
180 | ||
181 | pcm = (wxSoundFormatPcm *)(m_sndformat->Clone()); | |
182 | ||
183 | WRITE_SIGNATURE(FMT_SIGNATURE); | |
184 | data.Write32(16); | |
185 | ||
186 | sample_fq = pcm->GetSampleRate(); | |
187 | bits_p_spl = pcm->GetBPS(); | |
188 | channels = pcm->GetChannels(); | |
189 | byte_p_spl = pcm->GetBPS() / 8; | |
622e48cb | 190 | byte_p_sec = pcm->GetBytesFromTime(1); |
526ddb13 GL |
191 | format = 1; |
192 | data << format << channels << sample_fq | |
193 | << byte_p_sec << byte_p_spl << bits_p_spl; | |
194 | ||
195 | pcm->Signed(TRUE); | |
196 | pcm->SetOrder(wxLITTLE_ENDIAN); | |
197 | ||
198 | if (!SetSoundFormat(*pcm)) | |
199 | return FALSE; | |
200 | ||
201 | delete pcm; | |
202 | } | |
203 | ||
204 | WRITE_SIGNATURE(DATA_SIGNATURE); | |
622e48cb | 205 | data.Write32(m_sndformat->GetBytesFromTime(time)); |
526ddb13 GL |
206 | return TRUE; |
207 | } | |
208 | ||
209 | bool wxSoundWave::FinishRecording() | |
210 | { | |
211 | // TODO: Update headers when we stop before the specified time (if possible) | |
212 | return TRUE; | |
213 | } | |
214 | ||
215 | size_t wxSoundWave::GetData(void *buffer, size_t len) | |
216 | { | |
217 | return m_input->Read(buffer, len).LastRead(); | |
218 | } | |
219 | ||
220 | size_t wxSoundWave::PutData(const void *buffer, size_t len) | |
221 | { | |
222 | return m_output->Write(buffer, len).LastWrite(); | |
223 | } |