1// --------------------------------------------------------------------------
2// Name: sndg72x.cpp
3// Purpose:
4// Date: 08/26/1999
5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
6// CVSID: $Id: sndg72x.cpp 35650 2005-09-23 12:56:45Z MR $
7// wxWindows licence
8// --------------------------------------------------------------------------
9
10#include "wx/wxprec.h"
11
12#ifndef WX_PRECOMP
13    #include "wx/defs.h"
14#endif
15
16#include "wx/mmedia/sndbase.h"
17#include "wx/mmedia/sndfile.h"
18#include "wx/mmedia/sndpcm.h"
19#include "wx/mmedia/sndg72x.h"
20#include "wx/mmedia/internal/g72x.h"
21
22// --------------------------------------------------------------------------
23// wxSoundFormatG72X
24// --------------------------------------------------------------------------
25
26wxSoundFormatG72X::wxSoundFormatG72X()
27        : m_srate(22050)
28{
29}
30
31wxSoundFormatG72X::~wxSoundFormatG72X()
32{
33}
34
35void wxSoundFormatG72X::SetSampleRate(wxUint32 srate)
36{
37    m_srate = srate;
38}
39
40wxUint32 wxSoundFormatG72X::GetSampleRate() const
41{
42    return m_srate;
43}
44
45void wxSoundFormatG72X::SetG72XType(wxSoundG72XType type)
46{
47    m_g72x_type = type;
48}
49
50wxSoundFormatBase *wxSoundFormatG72X::Clone() const
51{
52    wxSoundFormatG72X *g72x = new wxSoundFormatG72X();
53
54    g72x->m_srate = m_srate;
55    g72x->m_g72x_type = m_g72x_type;
56    return g72x;
57}
58
59wxUint32 wxSoundFormatG72X::GetTimeFromBytes(wxUint32 bytes) const
60{
61    int n_bits;
62
63    switch (m_g72x_type) {
64        case wxSOUND_G721:
65            n_bits = 4;
66            break;
67        case wxSOUND_G723_24:
68            n_bits = 3;
69            break;
70        case wxSOUND_G723_40:
71            n_bits = 5;
72            break;
73        default:
74            n_bits = 0;
75            break;
76    }
77    return (wxUint32)((bytes / m_srate) * n_bits) / 8;
78}
79
80wxUint32 wxSoundFormatG72X::GetBytesFromTime(wxUint32 time) const
81{
82    int n_bits;
83
84    switch (m_g72x_type) {
85        case wxSOUND_G721:
86            n_bits = 4;
87            break;
88        case wxSOUND_G723_24:
89            n_bits = 3;
90            break;
91        case wxSOUND_G723_40:
92            n_bits = 5;
93            break;
94        default:
95            n_bits = 0;
96    }
97    return (wxUint32)((time * m_srate * n_bits) / 8);
98}
99
100bool wxSoundFormatG72X::operator !=(const wxSoundFormatBase& frmt2) const
101{
102    wxSoundFormatG72X *g72x = (wxSoundFormatG72X *)&frmt2;
103
104    if (frmt2.GetType() != wxSOUND_G72X)
105        return true;
106
107    return (g72x->m_srate != m_srate || g72x->m_g72x_type != m_g72x_type);
108}
109
110// --------------------------------------------------------------------------
111// wxSoundStreamG72X
112// --------------------------------------------------------------------------
113
114wxSoundStreamG72X::wxSoundStreamG72X(wxSoundStream& sndio)
115        : wxSoundStreamCodec(sndio)
116{
117    // PCM converter
118    m_router = new wxSoundRouterStream(sndio);
119    m_state  = new g72state;
120    g72x_init_state(m_state);
121}
122
123wxSoundStreamG72X::~wxSoundStreamG72X()
124{
125    delete m_router;
126}
127
128wxSoundStream& wxSoundStreamG72X::Read(void *buffer, wxUint32 len)
129{
130    wxUint16 *old_linear;
131    register wxUint16 *linear_buffer;
132    register wxUint32 real_len;
133    register wxUint32 countdown = len;
134
135    real_len = (len * 8 / m_n_bits);
136
137    old_linear = linear_buffer = new wxUint16[real_len];
138
139    m_router->Read(linear_buffer, real_len);
140
141    real_len = (wxUint32)(m_router->GetLastAccess() * ((float)m_n_bits / 8));
142    if (!real_len)
143        return *m_router;
144
145    m_io_buffer = (wxUint8 *)buffer;
146    m_current_b_pos = 0;
147
148    while (countdown != 0) {
149        PutBits(m_coder(*linear_buffer++, AUDIO_ENCODING_LINEAR, m_state));
150        countdown--;
151    }
152    m_lastcount = real_len;
153    m_snderror = m_router->GetError();
154
155    delete[] old_linear;
156
157    return *this;
158}
159
160wxSoundStream& wxSoundStreamG72X::Write(const void *buffer, wxUint32 len)
161{
162    wxUint16 *old_linear;
163    register wxUint16 *linear_buffer;
164    register wxUint32 countdown = len;
165    register wxUint32 real_len;
166
167    // Compute the real length (PCM format) to sendt to the sound card
168    real_len = (len * m_n_bits / 8);
169
170    // Allocate a temporary buffer
171    old_linear = linear_buffer = new wxUint16[real_len];
172
173    // Bad, we override the const
174    m_io_buffer = (wxUint8 *)buffer;
175    m_current_b_pos = 0;
176
177    // Decode the datas
178    while (countdown != 0) {
179        *linear_buffer++ = m_decoder(GetBits(), AUDIO_ENCODING_LINEAR, m_state);
180        countdown--;
181    }
182    m_lastcount = len;
183
184    // Send them to the sound card
185    m_router->Write(old_linear, real_len);
186
187    // Destroy the temporary buffer
188    delete[] old_linear;
189
190    return *m_router;
191}
192
193bool wxSoundStreamG72X::SetSoundFormat(const wxSoundFormatBase& format)
194{
195    if (format.GetType() != wxSOUND_G72X) {
196        m_snderror = wxSOUND_INVFRMT;
197        return false;
198    }
199
200    wxSoundFormatPcm pcm;
201    wxSoundFormatG72X *g72x;
202
203    wxSoundStreamCodec::SetSoundFormat(format);
204
205    g72x = (wxSoundFormatG72X *)m_sndformat;
206
207    // Set PCM as the output format of the codec
208    pcm.SetSampleRate(g72x->GetSampleRate());
209    pcm.SetBPS(16);
210    pcm.SetChannels(1); // Only mono supported
211    pcm.Signed(true);
212    pcm.SetOrder(wxBYTE_ORDER);
213
214    // Look for the correct codec to use and set its bit width
215    switch (g72x->GetG72XType()) {
216        case wxSOUND_G721:
217            m_n_bits  = 4;
218            m_coder   = g721_encoder;
219            m_decoder = g721_decoder;
220            break;
221        case wxSOUND_G723_24:
222            m_n_bits  = 3;
223            m_coder   = g723_24_encoder;
224            m_decoder = g723_24_decoder;
225            break;
226        case wxSOUND_G723_40:
227            m_n_bits  = 5;
228            m_coder   = g723_40_encoder;
229            m_decoder = g723_40_decoder;
230            break;
231    }
232
233    // Let the router finish the work
234    m_router->SetSoundFormat(pcm);
235
236    return true;
237}
238
239#define BYTE_SIZE 8
240
241wxUint8 wxSoundStreamG72X::GetBits()
242{
243    register wxUint8 bits;
244
245    // We have two bytes to compute
246    if (m_current_b_pos < m_n_bits) {
247        register wxUint8 b_left;
248
249        // TRANSLATE the mask
250        m_current_mask >>= m_current_b_pos;
251
252        // GET the last bits: 0001..1
253        bits = (m_current_byte & m_current_mask) << (m_n_bits - m_current_b_pos);
254
255        // GEN: 1. n times .1000
256        b_left = BYTE_SIZE-m_n_bits;
257        m_current_mask = ((1 << m_n_bits) - 1) << b_left;
258
259        // GET the next byte
260        m_current_byte = *m_io_buffer++;
261
262        register wxUint8 tmp_mask;
263
264        // COMPUTE a new temporary mask to get the last bits
265        b_left = m_n_bits - b_left;
266        tmp_mask = (1 << b_left) - 1;
267        // TRANSLATE the old mask to get ready for the next time
268        m_current_mask >>= b_left;
269
270        // COMPUTE the new bit position
271        b_left = BYTE_SIZE - b_left;
272        m_current_b_pos = b_left;
273        tmp_mask <<= b_left;
274
275        // GET the last bits
276        bits |= (m_current_byte & tmp_mask) >> b_left;
277    } else {
278        m_current_mask >>= m_n_bits;
279        m_current_b_pos -= m_n_bits;
280        bits = (m_current_byte & m_current_mask) >> m_current_b_pos;
281    }
282    return bits;
283}
284
285void wxSoundStreamG72X::PutBits(wxUint8 bits)
286{
287    if (m_current_b_pos < m_n_bits) {
288        register wxUint8 tmp_mask;
289        register wxUint8 diff;
290
291        diff = m_n_bits - m_current_b_pos;
292        // Pack bits and put the byte in the buffer
293        m_current_byte |= bits >> diff;
294        *m_io_buffer++ = m_current_byte;
295
296        // Gen a mask
297        tmp_mask = ~((1 << diff) - 1);
298
299        m_current_b_pos = BYTE_SIZE - (m_n_bits - m_current_b_pos);
300
301        m_current_byte = (bits & (tmp_mask)) << m_current_b_pos;
302    } else {
303        m_current_b_pos -= m_n_bits;
304        bits           <<= m_current_b_pos;
305        m_current_byte |= bits;
306    }
307}
308