]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/sndfrag.cpp
* Stream: update in doc, fix in code.
[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 codec->SetOutStream(ptr->sndbuf);
85 codec->InitIO(m_drvformat);
86
87 // Fill it up
88 codec->Decode();
89
90 // No data to fill the buffer: dequeue the current wxSndBuffer
91 if (codec->Available() == 0) {
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
102 // Output buffer full: send it to the driver
103 if (ptr->sndbuf->GetDataLeft() == 0) {
104 ptr->state = wxBUFFER_FFILLED;
105 OnBufferFilled(ptr, wxSND_OUTPUT);
106 }
107 }
108 }
109
110 bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
111 {
112 wxFragBufPtr *ptr;
113 size_t inc;
114
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)
121 return FALSE;
122
123 if (buf->Available() == 0) {
124 if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
125 buf->Set(wxSND_UNQUEUEING);
126 m_iodrv->m_buffers.DeleteObject(buf);
127 }
128
129 if (LastBuffer() == NULL && ptr->sndbuf->GetIntPosition() != 0) {
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
138 // TODO: Add an "incrementer" in wxStreamBuffer.
139 inc = (buf->Available() < ptr->sndbuf->GetDataLeft()) ?
140 buf->Available() : ptr->sndbuf->GetDataLeft();
141
142 ptr->sndbuf->SetIntPosition(ptr->sndbuf->GetIntPosition() + inc);
143
144 if (ptr->sndbuf->GetDataLeft() == 0) {
145 ptr->state = wxBUFFER_FFILLED;
146 if (!OnBufferFilled(ptr, wxSND_INPUT))
147 return FALSE;
148 }
149 }
150
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;
181 wxSoundCodec *codec;
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 {
191 codec = buf->GetCurrentCodec();
192
193 codec->SetInStream(ptr->sndbuf);
194 codec->InitIO(m_drvformat);
195
196 // As there is an "auto-stopper" in the codec, we don't worry ...
197 codec->Encode();
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
207 ptr->sndbuf->ResetBuffer();
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 }