]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/sndfrag.cpp
cd4a76bce8c318d00fba86b4f1e22eacade97575
[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_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(
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 char *raw_buf;
73 wxUint32 rawbuf_size;
74
75 if (!m_iodrv->OnSetupDriver(*buf, wxSND_OUTPUT))
76 return FALSE;
77
78 while (1) {
79 // Find the first free (at least partly free) output buffer
80 ptr = FindFreeBuffer(m_lstoptrs, m_maxoq);
81 // No free : go out !
82 if (!ptr)
83 return FALSE;
84
85 // Find the end of the buffer
86 raw_buf = ptr->data + ptr->ptr;
87 rawbuf_size = ptr->size - ptr->ptr;
88
89 // Fill it up
90 buf->OnNeedOutputData(raw_buf, rawbuf_size);
91
92 // No data to fill the buffer: dequeue the current wxSndBuffer
93 if (!rawbuf_size) {
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 ptr->ptr += rawbuf_size;
105
106 // Output buffer full: send it to the driver
107 if (ptr->ptr == ptr->size) {
108 ptr->state = wxBUFFER_FFILLED;
109 OnBufferFilled(ptr, wxSND_OUTPUT);
110 }
111 }
112 }
113
114 bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
115 {
116 wxFragBufPtr *ptr;
117 char *raw_buf;
118 wxUint32 rawbuf_size;
119
120 if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT))
121 return FALSE;
122
123 while (1) {
124 ptr = FindFreeBuffer(m_lstiptrs, m_maxiq);
125 if (!ptr)
126 return FALSE;
127
128 raw_buf = ptr->data + ptr->ptr;
129 rawbuf_size = ptr->size - ptr->ptr;
130
131 rawbuf_size = (buf->Available() < rawbuf_size) ? buf->Available() : rawbuf_size;
132
133 if (!rawbuf_size) {
134
135 if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
136 buf->Set(wxSND_UNQUEUEING);
137 m_iodrv->m_buffers.DeleteObject(buf);
138 }
139
140 // Get data now when there isn't anymore buffer in the queue
141 if (!LastBuffer() && ptr->ptr) {
142 ptr->state = wxBUFFER_FFILLED;
143 if (!OnBufferFilled(ptr, wxSND_INPUT))
144 return FALSE;
145 }
146 return TRUE;
147 }
148 ptr->buffers->Append(buf);
149
150 ptr->ptr += rawbuf_size;
151
152 // Input buffer full => get data
153 if (ptr->ptr == ptr->size) {
154 ptr->state = wxBUFFER_FFILLED;
155 if (!OnBufferFilled(ptr, wxSND_INPUT))
156 return FALSE;
157 }
158 }
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
216 ptr->ptr = 0;
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 }