]>
Commit | Line | Data |
---|---|---|
4d6306eb GL |
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_optrs(NULL), m_iptrs(NULL), 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( | |
926c550d | 56 | xFragBufPtr *list, wxUint8 max_queue) |
4d6306eb GL |
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 | char *raw_buf; | |
73 | wxUint32 rawbuf_size; | |
926c550d | 74 | wxSoundCodec *codec = buf->GetCurrentCodec(); |
4d6306eb GL |
75 | |
76 | if (!m_iodrv->OnSetupDriver(*buf, wxSND_OUTPUT)) | |
77 | return FALSE; | |
78 | ||
79 | while (1) { | |
80 | // Find the first free (at least partly free) output buffer | |
81 | ptr = FindFreeBuffer(m_lstoptrs, m_maxoq); | |
82 | // No free : go out ! | |
83 | if (!ptr) | |
84 | return FALSE; | |
85 | ||
926c550d GL |
86 | codec->SetOutStream(ptr->sndbuf); |
87 | codec->InitIO(m_drvformat); | |
4d6306eb GL |
88 | |
89 | // Fill it up | |
926c550d | 90 | codec->Decode(); |
4d6306eb GL |
91 | |
92 | // No data to fill the buffer: dequeue the current wxSndBuffer | |
926c550d | 93 | if (!codec->Available()) { |
4d6306eb GL |
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 | ||
4d6306eb | 104 | // Output buffer full: send it to the driver |
926c550d | 105 | if (ptr->sndbuf->GetDataLeft()) { |
4d6306eb GL |
106 | ptr->state = wxBUFFER_FFILLED; |
107 | OnBufferFilled(ptr, wxSND_OUTPUT); | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
112 | bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf) | |
113 | { | |
926c550d GL |
114 | /* |
115 | wxFragBufPtr *ptr; | |
116 | char *raw_buf; | |
117 | wxUint32 rawbuf_size; | |
118 | ||
119 | if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT)) | |
4d6306eb GL |
120 | return FALSE; |
121 | ||
926c550d GL |
122 | while (1) { |
123 | ptr = FindFreeBuffer(m_lstiptrs, m_maxiq); | |
124 | if (!ptr) | |
125 | return FALSE; | |
126 | ||
4d6306eb GL |
127 | raw_buf = ptr->data + ptr->ptr; |
128 | rawbuf_size = ptr->size - ptr->ptr; | |
129 | ||
130 | rawbuf_size = (buf->Available() < rawbuf_size) ? buf->Available() : rawbuf_size; | |
131 | ||
132 | if (!rawbuf_size) { | |
133 | ||
134 | if (buf->IsNotSet(wxSND_KEEPQUEUED)) { | |
135 | buf->Set(wxSND_UNQUEUEING); | |
136 | m_iodrv->m_buffers.DeleteObject(buf); | |
137 | } | |
138 | ||
4d6306eb GL |
139 | if (!LastBuffer() && ptr->ptr) { |
140 | ptr->state = wxBUFFER_FFILLED; | |
141 | if (!OnBufferFilled(ptr, wxSND_INPUT)) | |
142 | return FALSE; | |
143 | } | |
144 | return TRUE; | |
145 | } | |
146 | ptr->buffers->Append(buf); | |
147 | ||
148 | ptr->ptr += rawbuf_size; | |
149 | ||
926c550d | 150 | |
4d6306eb GL |
151 | if (ptr->ptr == ptr->size) { |
152 | ptr->state = wxBUFFER_FFILLED; | |
153 | if (!OnBufferFilled(ptr, wxSND_INPUT)) | |
154 | return FALSE; | |
155 | } | |
156 | } | |
926c550d GL |
157 | */ |
158 | ||
4d6306eb GL |
159 | return TRUE; |
160 | } | |
161 | ||
162 | void wxFragmentBuffer::FreeBufToFree(bool force) | |
163 | { | |
164 | wxUint8 i; | |
165 | // Garbage collecting | |
166 | ||
167 | m_dontq = TRUE; | |
168 | m_buf2free = FALSE; | |
169 | ||
170 | for (i=0;i<m_maxoq;i++) { | |
171 | if ((m_lstoptrs[i].state == wxBUFFER_TOFREE) || | |
172 | (force && m_lstoptrs[i].state == wxBUFFER_FFILLED)) | |
173 | ClearBuffer(&m_lstoptrs[i]); | |
174 | } | |
175 | ||
176 | for (i=0;i<m_maxiq;i++) { | |
177 | if ((m_lstiptrs[i].state == wxBUFFER_TOFREE) || | |
178 | (force && m_lstoptrs[i].state == wxBUFFER_FFILLED)) | |
179 | ClearBuffer(&m_lstiptrs[i]); | |
180 | } | |
181 | ||
182 | m_dontq = FALSE; | |
183 | } | |
184 | ||
185 | void wxFragmentBuffer::ClearBuffer(wxFragBufPtr *ptr) | |
186 | { | |
187 | wxNode *node; | |
188 | wxSndBuffer *buf; | |
189 | char *data; | |
190 | wxUint32 size, data_read; | |
191 | ||
192 | data = ptr->data; | |
193 | size = ptr->size; | |
194 | ||
195 | node = ptr->buffers->First(); | |
196 | ||
197 | while (node) { | |
198 | buf = (wxSndBuffer *)node->Data(); | |
199 | ||
200 | if (buf->GetMode() == wxSND_OUTPUT) { | |
201 | buf->OnBufferOutFinished(); | |
202 | } else { | |
203 | data_read = buf->OnBufferInFinished(data, size); | |
204 | ||
205 | data += data_read; | |
206 | size -= data_read; | |
207 | } | |
208 | ||
209 | if (buf->IsSet(wxSND_UNQUEUEING)) | |
210 | buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY); | |
211 | ||
212 | delete node; | |
213 | node = ptr->buffers->First(); | |
214 | } | |
215 | ||
926c550d | 216 | ptr->sndbuf->ResetBuffer(); |
4d6306eb GL |
217 | ptr->state = wxBUFFER_FREE; |
218 | } | |
219 | ||
220 | void wxFragmentBuffer::OnBufferFinished(wxFragBufPtr *ptr) | |
221 | { | |
222 | wxNode *node; | |
223 | wxSndBuffer *buf; | |
224 | bool ret = TRUE; | |
225 | ||
226 | if (m_freeing) { | |
227 | ptr->state = wxBUFFER_TOFREE; | |
228 | m_buf2free = TRUE; | |
229 | return; | |
230 | } | |
231 | m_freeing = TRUE; | |
232 | ||
233 | // Clean up the old buffer. | |
234 | if (ptr && ptr->state != wxBUFFER_FREE) | |
235 | ClearBuffer(ptr); | |
236 | ||
237 | // Garbage collecting ... | |
238 | if (m_buf2free) | |
239 | FreeBufToFree(); | |
240 | ||
241 | // If we are queueing, return immediately. | |
242 | if (m_dontq) { | |
243 | m_freeing = FALSE; | |
244 | return; | |
245 | } | |
246 | ||
247 | node = m_iodrv->m_buffers.First(); | |
248 | ||
249 | while (node && ret) { | |
250 | buf = (wxSndBuffer *)node->Data(); | |
251 | node = node->Next(); | |
252 | ||
253 | buf->HardLock(); | |
254 | ||
255 | // Stop request on this buffer. | |
256 | if (buf->IsSet(wxSND_BUFSTOP)) { | |
257 | buf->Clear(wxSND_BUFSTOP); | |
258 | continue; | |
259 | } | |
260 | if (buf->GetMode() == wxSND_OUTPUT) | |
261 | ret = NotifyOutputBuffer(buf); | |
262 | else | |
263 | ret = NotifyInputBuffer(buf); | |
264 | ||
265 | buf->HardUnlock(); | |
266 | } | |
267 | m_freeing = FALSE; | |
268 | } |