]> git.saurik.com Git - wxWidgets.git/blame - utils/wxMMedia/sndfrag.cpp
fixed somebody's poorly done StreamSize-->GetSize transition
[wxWidgets.git] / utils / wxMMedia / sndfrag.cpp
CommitLineData
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
25wxFragmentBuffer::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
32wxFragmentBuffer::~wxFragmentBuffer()
33{
34}
35
36void 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
55wxFragmentBuffer::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
69bool 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
8a7c9dcc 84 // Normally, these three functions could be called only once.
926c550d
GL
85 codec->SetOutStream(ptr->sndbuf);
86 codec->InitIO(m_drvformat);
8a7c9dcc 87 codec->InitMode(wxSoundCodec::DECODING);
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
9fc0fe37 93 if (codec->Available() == 0) {
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
9fc0fe37 105 if (ptr->sndbuf->GetDataLeft() == 0) {
4d6306eb
GL
106 ptr->state = wxBUFFER_FFILLED;
107 OnBufferFilled(ptr, wxSND_OUTPUT);
108 }
109 }
110}
111
112bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf)
113{
9fc0fe37
GL
114 wxFragBufPtr *ptr;
115 size_t inc;
926c550d 116
9fc0fe37
GL
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)
4d6306eb 123 return FALSE;
4d6306eb 124
9fc0fe37 125 if (buf->Available() == 0) {
4d6306eb
GL
126 if (buf->IsNotSet(wxSND_KEEPQUEUED)) {
127 buf->Set(wxSND_UNQUEUEING);
128 m_iodrv->m_buffers.DeleteObject(buf);
129 }
130
9fc0fe37 131 if (LastBuffer() == NULL && ptr->sndbuf->GetIntPosition() != 0) {
4d6306eb
GL
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
9fc0fe37
GL
140 // TODO: Add an "incrementer" in wxStreamBuffer.
141 inc = (buf->Available() < ptr->sndbuf->GetDataLeft()) ?
142 buf->Available() : ptr->sndbuf->GetDataLeft();
4d6306eb 143
9fc0fe37 144 ptr->sndbuf->SetIntPosition(ptr->sndbuf->GetIntPosition() + inc);
926c550d 145
9fc0fe37 146 if (ptr->sndbuf->GetDataLeft() == 0) {
4d6306eb
GL
147 ptr->state = wxBUFFER_FFILLED;
148 if (!OnBufferFilled(ptr, wxSND_INPUT))
149 return FALSE;
150 }
151 }
926c550d 152
4d6306eb
GL
153 return TRUE;
154}
155
156void 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
179void wxFragmentBuffer::ClearBuffer(wxFragBufPtr *ptr)
180{
181 wxNode *node;
182 wxSndBuffer *buf;
9fc0fe37 183 wxSoundCodec *codec;
4d6306eb
GL
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 {
9fc0fe37
GL
193 codec = buf->GetCurrentCodec();
194
8a7c9dcc 195 // Normally, these three functions could be called only once.
9fc0fe37
GL
196 codec->SetInStream(ptr->sndbuf);
197 codec->InitIO(m_drvformat);
8a7c9dcc 198 codec->InitMode(wxSoundCodec::ENCODING);
4d6306eb 199
9fc0fe37
GL
200 // As there is an "auto-stopper" in the codec, we don't worry ...
201 codec->Encode();
4d6306eb
GL
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
926c550d 211 ptr->sndbuf->ResetBuffer();
4d6306eb
GL
212 ptr->state = wxBUFFER_FREE;
213}
214
215void 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 }
8a7c9dcc
GL
255 switch (buf->GetMode()) {
256 case wxSND_OUTPUT:
4d6306eb 257 ret = NotifyOutputBuffer(buf);
8a7c9dcc
GL
258 break;
259 case wxSND_INPUT:
4d6306eb 260 ret = NotifyInputBuffer(buf);
8a7c9dcc
GL
261 break;
262 case wxSND_DUPLEX:
263 case wxSND_OTHER_IO:
264 // ret = NotifyDuplexBuffer(buf);
265 break;
266 }
4d6306eb
GL
267
268 buf->HardUnlock();
269 }
270 m_freeing = FALSE;
271}