]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/sndfrag.cpp
Drag'n'Drop works in a basic form
[wxWidgets.git] / utils / wxMMedia / sndfrag.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 // Name: sndfrag.cpp
3 // Purpose: wxMMedia
4 // Author: Guilhem Lavaux
5 // Created: 1997
6 // Updated: 1998
7 // Copyright: (C) 1997, 1998, Guilhem Lavaux
8 // License: wxWindows license
9 ////////////////////////////////////////////////////////////////////////////////
10 #ifdef __GNUG__
11 #pragma implementation "sndfrag.h"
12 #endif
13 #include <stdio.h>
14 #ifdef WX_PRECOMP
15 #include "wx_prec.h"
16 #else
17 #include "wx/wx.h"
18 #endif
19 #include "sndfrag.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 wxFragmentBuffer::wxFragmentBuffer(wxSound& io_drv)
26 : m_iodrv(&io_drv), m_maxoq(0), m_maxiq(0),
27 m_lstoptrs(NULL), m_lstiptrs(NULL),
28 m_buf2free(FALSE), m_dontq(FALSE), m_freeing(FALSE)
29 {
30 }
31
32 wxFragmentBuffer::~wxFragmentBuffer()
33 {
34 }
35
36 void wxFragmentBuffer::AbortBuffer(wxSndBuffer *buf)
37 {
38 for (wxUint8 i=0;i<m_maxoq;i++)
39 if (m_lstoptrs[i].buffers->Member(buf)) {
40 if (m_lstoptrs[i].state == wxBUFFER_PLAYING)
41 // TODO: Do something.
42 ;
43 m_lstoptrs[i].state = wxBUFFER_TOFREE;
44 }
45
46 for (wxUint8 i=0;i<m_maxiq;i++)
47 if (m_lstiptrs[i].buffers->Member(buf)) {
48 if (m_lstiptrs[i].state == wxBUFFER_PLAYING)
49 // Do something.
50 ;
51 m_lstiptrs[i].state = wxBUFFER_TOFREE;
52 }
53 }
54
55 wxFragmentBuffer::wxFragBufPtr *wxFragmentBuffer::FindFreeBuffer(
56 wxFragBufPtr *list, wxUint8 max_queue)
57 {
58 if (!list)
59 return NULL;
60
61 for (wxUint8 i=0;i<max_queue;i++) {
62 if (list[i].state == wxBUFFER_FREE)
63 return &list[i];
64 }
65
66 return NULL;
67 }
68
69 bool wxFragmentBuffer::NotifyOutputBuffer(wxSndBuffer *buf)
70 {
71 wxFragBufPtr *ptr;
72 wxSoundCodec *codec = buf->GetCurrentCodec();
73
74 if (!m_iodrv->OnSetupDriver(*buf, wxSND_OUTPUT))
75 return FALSE;
76
77 while (1) {
78 // Find the first free (at least partly free) output buffer
79 ptr = FindFreeBuffer(m_lstoptrs, m_maxoq);
80 // No free : go out !
81 if (ptr == NULL)
82 return FALSE;
83
84 // Normally, these three functions could be called only once.
85 codec->SetOutStream(ptr->sndbuf);
86 codec->InitIO(m_drvformat);
87 codec->InitMode(wxSoundCodec::DECODING);
88
89 // Fill it up
90 codec->Decode();
91
92 // No data to fill the buffer: dequeue the current wxSndBuffer
93 if (codec->Available() == 0) {
94 if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
95 buf->Set(wxSND_UNQUEUEING);
96 m_iodrv->m_buffers.DeleteObject(buf);
97 }
98 return TRUE;
99 }
100
101 // Data: append it to the list
102 ptr->buffers->Append(buf);
103
104 // Output buffer full: send it to the driver
105 if (ptr->sndbuf->GetDataLeft() == 0) {
106 ptr->state = wxBUFFER_FFILLED;
107 OnBufferFilled(ptr, wxSND_OUTPUT);
108 }
109 }
110 }
111
112 bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
113 {
114 wxFragBufPtr *ptr;
115 size_t inc;
116
117 if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT))
118 return FALSE;
119
120 while (1) {
121 ptr = FindFreeBuffer(m_lstiptrs, m_maxiq);
122 if (ptr == NULL)
123 return FALSE;
124
125 if (buf->Available() == 0) {
126 if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
127 buf->Set(wxSND_UNQUEUEING);
128 m_iodrv->m_buffers.DeleteObject(buf);
129 }
130
131 if (LastBuffer() == NULL && ptr->sndbuf->GetIntPosition() != 0) {
132 ptr->state = wxBUFFER_FFILLED;
133 if (!OnBufferFilled(ptr, wxSND_INPUT))
134 return FALSE;
135 }
136 return TRUE;
137 }
138 ptr->buffers->Append(buf);
139
140 // TODO: Add an "incrementer" in wxStreamBuffer.
141 inc = (buf->Available() < ptr->sndbuf->GetDataLeft()) ?
142 buf->Available() : ptr->sndbuf->GetDataLeft();
143
144 ptr->sndbuf->SetIntPosition(ptr->sndbuf->GetIntPosition() + inc);
145
146 if (ptr->sndbuf->GetDataLeft() == 0) {
147 ptr->state = wxBUFFER_FFILLED;
148 if (!OnBufferFilled(ptr, wxSND_INPUT))
149 return FALSE;
150 }
151 }
152
153 return TRUE;
154 }
155
156 void wxFragmentBuffer::FreeBufToFree(bool force)
157 {
158 wxUint8 i;
159 // Garbage collecting
160
161 m_dontq = TRUE;
162 m_buf2free = FALSE;
163
164 for (i=0;i<m_maxoq;i++) {
165 if ((m_lstoptrs[i].state == wxBUFFER_TOFREE) ||
166 (force && m_lstoptrs[i].state == wxBUFFER_FFILLED))
167 ClearBuffer(&m_lstoptrs[i]);
168 }
169
170 for (i=0;i<m_maxiq;i++) {
171 if ((m_lstiptrs[i].state == wxBUFFER_TOFREE) ||
172 (force && m_lstoptrs[i].state == wxBUFFER_FFILLED))
173 ClearBuffer(&m_lstiptrs[i]);
174 }
175
176 m_dontq = FALSE;
177 }
178
179 void wxFragmentBuffer::ClearBuffer(wxFragBufPtr *ptr)
180 {
181 wxNode *node;
182 wxSndBuffer *buf;
183 wxSoundCodec *codec;
184
185 node = ptr->buffers->First();
186
187 while (node) {
188 buf = (wxSndBuffer *)node->Data();
189
190 if (buf->GetMode() == wxSND_OUTPUT) {
191 buf->OnBufferOutFinished();
192 } else {
193 codec = buf->GetCurrentCodec();
194
195 // Normally, these three functions could be called only once.
196 codec->SetInStream(ptr->sndbuf);
197 codec->InitIO(m_drvformat);
198 codec->InitMode(wxSoundCodec::ENCODING);
199
200 // As there is an "auto-stopper" in the codec, we don't worry ...
201 codec->Encode();
202 }
203
204 if (buf->IsSet(wxSND_UNQUEUEING))
205 buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY);
206
207 delete node;
208 node = ptr->buffers->First();
209 }
210
211 ptr->sndbuf->ResetBuffer();
212 ptr->state = wxBUFFER_FREE;
213 }
214
215 void wxFragmentBuffer::OnBufferFinished(wxFragBufPtr *ptr)
216 {
217 wxNode *node;
218 wxSndBuffer *buf;
219 bool ret = TRUE;
220
221 if (m_freeing) {
222 ptr->state = wxBUFFER_TOFREE;
223 m_buf2free = TRUE;
224 return;
225 }
226 m_freeing = TRUE;
227
228 // Clean up the old buffer.
229 if (ptr && ptr->state != wxBUFFER_FREE)
230 ClearBuffer(ptr);
231
232 // Garbage collecting ...
233 if (m_buf2free)
234 FreeBufToFree();
235
236 // If we are queueing, return immediately.
237 if (m_dontq) {
238 m_freeing = FALSE;
239 return;
240 }
241
242 node = m_iodrv->m_buffers.First();
243
244 while (node && ret) {
245 buf = (wxSndBuffer *)node->Data();
246 node = node->Next();
247
248 buf->HardLock();
249
250 // Stop request on this buffer.
251 if (buf->IsSet(wxSND_BUFSTOP)) {
252 buf->Clear(wxSND_BUFSTOP);
253 continue;
254 }
255 switch (buf->GetMode()) {
256 case wxSND_OUTPUT:
257 ret = NotifyOutputBuffer(buf);
258 break;
259 case wxSND_INPUT:
260 ret = NotifyInputBuffer(buf);
261 break;
262 case wxSND_DUPLEX:
263 case wxSND_OTHER_IO:
264 // ret = NotifyDuplexBuffer(buf);
265 break;
266 }
267
268 buf->HardUnlock();
269 }
270 m_freeing = FALSE;
271 }