]>
Commit | Line | Data |
---|---|---|
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 | } |