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