1// --------------------------------------------------------------------------
2// Name: sndaiff.cpp
3// Purpose:
4// Date: 08/11/1999
5// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
6// CVSID: $Id: sndaiff.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#ifdef __BORLANDC__
17    #pragma hdrstop
18#endif
19
20#include "wx/stream.h"
21#include "wx/datstrm.h"
22#include "wx/filefn.h"
23
24#include "wx/mmedia/sndbase.h"
25#include "wx/mmedia/sndcodec.h"
26#include "wx/mmedia/sndfile.h"
27#include "wx/mmedia/sndpcm.h"
28#include "wx/mmedia/sndaiff.h"
29
30#define BUILD_SIGNATURE(a,b,c,d) (((wxUint32)a) | (((wxUint32)b) << 8) | (((wxUint32)c) << 16)  | (((wxUint32)d) << 24))
31
32#define FORM_SIGNATURE BUILD_SIGNATURE('F','O','R','M')
33#define AIFF_SIGNATURE BUILD_SIGNATURE('A','I','F','F')
34#define AIFC_SIGNATURE BUILD_SIGNATURE('A','I','F','C')
35#define COMM_SIGNATURE BUILD_SIGNATURE('C','O','M','M')
36#define SSND_SIGNATURE BUILD_SIGNATURE('S','S','N','D')
37
38wxSoundAiff::wxSoundAiff(wxInputStream& stream, wxSoundStream& io_sound)
39  : wxSoundFileStream(stream, io_sound)
40{
41    m_base_offset = wxInvalidOffset;
42}
43
44wxSoundAiff::wxSoundAiff(wxOutputStream& stream, wxSoundStream& io_sound)
45  : wxSoundFileStream(stream, io_sound)
46{
47    m_base_offset = wxInvalidOffset;
48}
49
50wxSoundAiff::~wxSoundAiff()
51{
52}
53
54wxString wxSoundAiff::GetCodecName() const
55{
56    return wxT("wxSoundAiff codec");
57}
58
59bool wxSoundAiff::CanRead()
60{
61    wxUint32 signature1, signature2, len;
62
63    if (m_input->Read(&signature1, 4).LastRead() != 4)
64        return false;
65
66    if (wxUINT32_SWAP_ON_BE(signature1) != FORM_SIGNATURE) {
67        m_input->Ungetch(&signature1, 4);
68        return false;
69    }
70
71    m_input->Read(&len, 4);
72    if (m_input->LastRead() != 4) {
73        m_input->Ungetch(&len, m_input->LastRead());
74        m_input->Ungetch(&signature1, 4);
75        return false;
76    }
77
78    if (m_input->Read(&signature2, 4).LastRead() != 4) {
79        m_input->Ungetch(&signature2, m_input->LastRead());
80        m_input->Ungetch(&len, 4);
81        m_input->Ungetch(&signature1, 4);
82        return false;
83    }
84
85    m_input->Ungetch(&signature2, 4);
86    m_input->Ungetch(&len, 4);
87    m_input->Ungetch(&signature1, 4);
88
89    if (
90        wxUINT32_SWAP_ON_BE(signature2) != AIFF_SIGNATURE &&
91        wxUINT32_SWAP_ON_BE(signature2) != AIFC_SIGNATURE)
92        return false;
93
94    return true;
95}
96
97#define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return false; }
98
99bool wxSoundAiff::PrepareToPlay()
100{
101    wxDataInputStream data(*m_input);
102    wxUint32 signature, len, ssnd;
103    bool end_headers;
104
105    if (!m_input) {
106        m_snderror = wxSOUND_INVSTRM;
107        return false;
108    }
109    m_snderror = wxSOUND_NOERROR;
110
111    data.BigEndianOrdered(true);
112
113    FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
114    FAIL_WITH(wxUINT32_SWAP_ON_BE(signature) != FORM_SIGNATURE, wxSOUND_INVSTRM);
115    // "FORM"
116
117    len = data.Read32();
118    wxUnusedVar(len);
119    FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM);
120    // dummy len
121
122    FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
123    FAIL_WITH(
124        wxUINT32_SWAP_ON_BE(signature) != AIFF_SIGNATURE &&
125        wxUINT32_SWAP_ON_BE(signature) != AIFC_SIGNATURE, wxSOUND_INVSTRM);
126    // "AIFF" / "AIFC"
127
128    end_headers = false;
129    while (!end_headers) {
130        FAIL_WITH(m_input->Read(&signature, 4).LastRead() != 4, wxSOUND_INVSTRM);
131
132        len = data.Read32();
133        FAIL_WITH(m_input->LastRead() != 4, wxSOUND_INVSTRM);
134
135        switch (wxUINT32_SWAP_ON_BE(signature)) {
136            case COMM_SIGNATURE: { // "COMM"
137                wxUint16 channels, bps;
138                wxUint32 num_samples;
139                double srate;
140                wxSoundFormatPcm sndformat;
141
142                // Get sound data informations
143                data >> channels >> num_samples >> bps >> srate;
144
145                // Convert them in a wxSoundFormat object
146                sndformat.SetSampleRate((wxUint32) srate);
147                sndformat.SetBPS(bps);
148                sndformat.SetChannels(channels);
149                sndformat.Signed(false);
150                sndformat.SetOrder(wxBIG_ENDIAN);
151
152                if (!SetSoundFormat(sndformat))
153                    return false;
154                // We pass all data left
155                m_input->SeekI(len-18, wxFromCurrent);
156                break;
157            }
158            case SSND_SIGNATURE: {  // "SSND"
159                data >> ssnd;
160                // m_input->SeekI(4, wxFromCurrent);  // Pass an INT32
161                // m_input->SeekI(len-4, wxFromCurrent); // Pass the rest
162                m_input->SeekI(ssnd + 4, wxFromCurrent);
163                m_base_offset = m_input->TellI();
164                // len-8 bytes of samples
165                FinishPreparation(len - 8);
166                end_headers = true;
167                break;
168            }
169            default:
170                m_input->SeekI(len, wxFromCurrent);
171                break;
172        }
173    }
174    return true;
175}
176
177bool wxSoundAiff::PrepareToRecord(wxUint32 WXUNUSED(time))
178{
179    // TODO
180    return false;
181}
182
183bool wxSoundAiff::FinishRecording()
184{
185    // TODO
186    return false;
187}
188
189bool wxSoundAiff::RepositionStream(wxUint32 WXUNUSED(position))
190{
191    // If the stream is not seekable "TellI() returns wxInvalidOffset" we cannot reposition stream
192    if (m_base_offset == wxInvalidOffset)
193        return false;
194    m_input->SeekI(m_base_offset, wxFromStart);
195    return true;
196}
197
198wxUint32 wxSoundAiff::GetData(void *buffer, wxUint32 len)
199{
200    return m_input->Read(buffer, len).LastRead();
201}
202
203wxUint32 wxSoundAiff::PutData(const void *buffer, wxUint32 len)
204{
205    return m_output->Write(buffer, len).LastWrite();
206}
207