rtoss - Blame information for rev 26

Subversion Repositories:
Rev:
Rev Author Line No. Line
14 roytam 1 #include <windows.h>
2 #include "maplay.h"
3 #include "helper.h"
4 #include "output.h"
5 #include "effect.h"
6  
7 #define FADE_BITS       16
8 #define FADE_TIME       750
9 #define FADE_BASE       0
10  
11 COutput::COutput()
12 {
13         m_fScanPeek = FALSE;
14         m_hwo = NULL;
15         m_pHdr = NULL;
16         m_hEvent = NULL;
17         m_cWritten = 0;
18         m_dwWritten = 0;
19         m_pbBuf = NULL;
20         m_nCurrent = 0;
21  
26 roytam 22         m_dwBufLen = 1000;
14 roytam 23         m_cBuf = 8;
24         m_cbBuf = 16 * 1024;
25  
26         m_nLPeek = 0;
27         m_nRPeek = 0;
28         memset(&m_pcm, 0, sizeof(PCMWAVEFORMAT));
29  
30         m_fFade = FALSE;
31         m_nFadeSamples = 0;
32  
33         m_dwTotalSamples = 0;
34         m_fPaused = FALSE;
35         m_fDoubleBuf = FALSE;
36         m_hEventThread = NULL;
37         m_hThread = NULL;
38         m_dwThreadId = 0;
39         m_pbSubBuf = NULL;
40         m_nHdrOut = 0;
41         m_nWriteCur = 0;
42         memset(m_HdrOut, 0, sizeof(m_HdrOut));
26 roytam 43         m_dwVolume = MAX_WAVEOUTVOLUME;
14 roytam 44 }
45  
46 COutput::~COutput()
47 {
48 }
49  
50 BOOL COutput::SetOutputParam(DWORD dwBufLen, BOOL fDoubleBuf, BOOL fFade)
51 {
52         CAutoLock lock(&m_csecDevice);
53         if (m_hwo)
54                 return FALSE;
55  
56         if (dwBufLen < 10)
57                 return FALSE;
58  
59         m_dwBufLen = dwBufLen;
60         m_fFade = fFade;
61         m_fDoubleBuf = fDoubleBuf;
62         return TRUE;
63 }
64  
65 void COutput::GetOutputParam(LPDWORD pdwBufLen, LPBOOL pfDoubleBuf, LPBOOL pfFade)
66 {
67         *pdwBufLen = m_dwBufLen;
68         *pfFade = m_fFade;
69         *pfDoubleBuf = m_fDoubleBuf;
70 }
71  
72 BOOL COutput::Open(int nChannels, int nSamplingRate, int nBitsPerSample)
73 {
74         MMRESULT mmr;
75         int i, nCount = 0;
76  
77         CAutoLock lock(&m_csecDevice);
78         if (!waveOutGetNumDevs())
79                 goto fail;
80  
81         if (nChannels == m_pcm.wf.nChannels &&
82                 (int)m_pcm.wf.nSamplesPerSec == nSamplingRate &&
83                 m_pcm.wBitsPerSample == nBitsPerSample)
84                 return TRUE;
85  
86         CloseAll();
87  
88         m_cbBuf = BUFLEN_BASE;
89         if (nSamplingRate > 11025)
90                 m_cbBuf *= 2;
91         if (nSamplingRate > 22050)
92                 m_cbBuf *= 2;
93         if (nChannels > 1)
94                 m_cbBuf *= 2;
95         if (nBitsPerSample > 8)
96                 m_cbBuf *= 2;
97  
98         m_pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
99         m_pcm.wf.nChannels = nChannels;
100         m_pcm.wf.nSamplesPerSec = nSamplingRate;
101         m_pcm.wf.nAvgBytesPerSec = nBitsPerSample * nSamplingRate * nChannels / 8;
102         m_pcm.wf.nBlockAlign = nBitsPerSample * nChannels / 8;
103         m_pcm.wBitsPerSample = nBitsPerSample;
104  
105         for (i = 0; i < 10; i++) {
106                 if (m_fDoubleBuf)
107                         mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, (LPWAVEFORMATEX)&m_pcm, (DWORD)WaveOutCallback2, 0, CALLBACK_FUNCTION);
108                 else
109                         mmr = waveOutOpen(&m_hwo, WAVE_MAPPER, (LPWAVEFORMATEX)&m_pcm, (DWORD)WaveOutCallback, 0, CALLBACK_FUNCTION);
110  
111                 if (mmr == MMSYSERR_NOERROR)
112                         break;
113                 else if (mmr != MMSYSERR_ALLOCATED)
114                         goto fail;
115                 Sleep(100);
116         }
117         m_fPaused = FALSE;
118         m_dwWritten = 0;
119  
26 roytam 120         waveOutSetVolume(m_hwo, m_dwVolume);
121  
14 roytam 122         if (!PrepareBuffer())
123                 goto fail;
124  
125         if (m_fDoubleBuf && !PrepareSubBuffer())
126                 goto fail;
127  
128         m_nLPeek = 0;
129         m_nRPeek = 0;
130  
131         if (m_fFade) {
132                 m_nFadeCurrent = FADE_BASE << FADE_BITS;
133                 m_nFadeSamples = m_pcm.wf.nSamplesPerSec * FADE_TIME / 1000;
134                 m_nFadeRate = (int)((((double)1 - FADE_BASE) / m_nFadeSamples) * (1 << FADE_BITS));
135                 m_nFadeRate += 1;
136         }
137  
138         return TRUE;
139  
140 fail:
141         CloseAll();
142         return FALSE;
143 }
144  
145 void COutput::Close()
146 {
147         CAutoLock lock(&m_csecDevice);
148  
149         if (!m_fDoubleBuf) {
150                 CloseAll();
151                 return;
152         }
153  
154         Reset();
155 }
156  
157 WAVEHDR* COutput::GetBuffer()
158 {
159         WaitForSingleObject(m_hEvent, INFINITE);
160         return &m_pHdr[m_nCurrent];
161 }
162  
163 void COutput::PutBuffer(WAVEHDR* pHdr)
164 {
165         if (m_fScanPeek)
166                 CheckPeek(pHdr);
167  
168         CAutoLock lock(&m_csecBuff);
169         SetEvent(m_hEvent);
170         m_cWritten--;
171 }
172  
173 void COutput::OutputBuffer(WAVEHDR* pHdr)
174 {
175         if (!pHdr->dwBytesRecorded) {
176                 CAutoLock lock(&m_csecBuff);
177                 SetEvent(m_hEvent);
178                 return;
179         }
180  
181         if (m_fDoubleBuf) {
182                 FadeIn((LPBYTE)pHdr->lpData, pHdr->dwBytesRecorded);
183                 CAutoLock lockBuf(&m_csecBuff); // !!!!
184                 m_cWritten++;
185                 if (m_cWritten >= m_cBuf)
186                         ResetEvent(m_hEvent);
187  
188                 m_nCurrent = (m_nCurrent + 1) % m_cBuf;
189                 m_dwWritten += pHdr->dwBytesRecorded / m_pcm.wf.nBlockAlign;
190         }
191         else {
192                 CAutoLock lockDev(&m_csecDevice);
193                 FadeIn((LPBYTE)pHdr->lpData, pHdr->dwBytesRecorded);
194                 waveOutWrite(m_hwo, pHdr, sizeof(WAVEHDR));
195  
196                 CAutoLock lockBuf(&m_csecBuff);
197                 m_cWritten++;
198                 if (m_cWritten >= m_cBuf)
199                         ResetEvent(m_hEvent);
200  
201                 m_nCurrent = (m_nCurrent + 1) % m_cBuf;
202                 m_dwWritten += pHdr->dwBytesRecorded / m_pcm.wf.nBlockAlign;
203         }
204 }
205  
206 BOOL COutput::PrepareBuffer()
207 {
208         CAutoLock lock(&m_csecBuff);
209  
210         if (m_pHdr)
211                 return FALSE;
212  
213         m_cBuf = m_dwBufLen * m_pcm.wf.nAvgBytesPerSec / m_cbBuf / 1000 + 1;
214         if (m_cBuf < 2) m_cBuf = 2;
215  
216         m_pHdr = new WAVEHDR[m_cBuf];
217         if (!m_pHdr)
218                 return FALSE;
219  
220         m_pbBuf = new BYTE[m_cBuf * m_cbBuf];
221         if (!m_pbBuf)
222                 return FALSE;
223  
224         memset(m_pbBuf, 0, m_cBuf * m_cbBuf);
225         for (UINT i = 0; i < m_cBuf; i++) {
226                 memset(&m_pHdr[i], 0, sizeof(WAVEHDR));
227                 m_pHdr[i].lpData = (LPSTR)m_pbBuf + (m_cbBuf * i);
228                 m_pHdr[i].dwBufferLength = m_cbBuf;
229                 if (m_fDoubleBuf)
230                         m_pHdr[i].dwUser = 0;
231                 else {
232                         m_pHdr[i].dwUser = (DWORD)this;
233                         waveOutPrepareHeader(m_hwo, &m_pHdr[i] , sizeof(WAVEHDR));
234                 }
235         }
236         m_nCurrent = 0;
237         m_cWritten = 0;
238         m_hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
239         return TRUE;
240 }
241  
242 void COutput::FreeBuffer()
243 {
244         CAutoLock lock(&m_csecBuff);
245  
246         if (m_pHdr) {
247                 delete [] m_pHdr;
248                 m_pHdr =  NULL;
249         }
250  
251         if (m_pbBuf) {
252                 delete [] m_pbBuf;
253                 m_pbBuf = NULL;
254         }
255  
256         if (m_hEvent) {
257                 CloseHandle(m_hEvent);
258                 m_hEvent = NULL;
259         }
260         m_nCurrent = 0;
261 }
262  
263 void COutput::Reset()
264 {
265         if (!m_hwo)
266                 return;
267  
268         if (m_fDoubleBuf) {
269                 CAutoLock lockDev(&m_csecDevice);
270                 SetEvent(m_hEvent);
271                 m_cWritten = 0;
272                 m_dwWritten = 0;
273                 m_nCurrent = 0;
274                 m_nWriteCur = 0;
275                 m_fPaused = TRUE;
276                 m_dwTotalSamples = 0;
277  
278                 if (m_pHdr) {
279                         CAutoLock lock(&m_csecBuff);
280                         for (DWORD i = 0; i < m_cBuf; i++)
281                                 m_pHdr[i].dwUser = 0;
282                 }
283         }
284         else {
285                 CAutoLock lock(&m_csecDevice);
286                 waveOutPause(m_hwo);
287                 waveOutReset(m_hwo);
288  
289                 SetEvent(m_hEvent);
290                 m_cWritten = 0;
291                 m_dwWritten = 0;
292                 m_nCurrent = 0;
293                 m_nWriteCur = 0;
294                 waveOutPause(m_hwo);
295         }
296  
297         m_nLPeek = 0;
298         m_nRPeek = 0;
299         if (m_fFade) {
300                 m_nFadeCurrent = FADE_BASE << FADE_BITS;
301                 m_nFadeSamples = m_pcm.wf.nSamplesPerSec * FADE_TIME / 1000;
302                 m_nFadeRate = (int)((((double)1 - FADE_BASE) / m_nFadeSamples) * (1 << FADE_BITS));
303                 m_nFadeRate += 1;
304         }
305 }
306  
307 void CALLBACK COutput::WaveOutCallback(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
308 {
309         if (uMsg == WOM_DONE) {
310                 COutput* pOutput = (COutput*)((WAVEHDR*)dwParam1)->dwUser;
311                 pOutput->PutBuffer((WAVEHDR*)dwParam1);
312         }
313 }
314  
315 void CALLBACK COutput::WaveOutCallback2(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
316 {
317         if (uMsg == WOM_DONE) {
318                 COutput* pOutput = (COutput*)((WAVEHDR*)dwParam1)->dwUser;
319                 if (pOutput->m_fScanPeek)
320                         pOutput->CheckPeek((WAVEHDR*)dwParam1);
321                 InterlockedIncrement((long*)&pOutput->m_nSubBuf);
322                 SetEvent(pOutput->m_hEventThread);
323         }
324 }
325  
326 void COutput::Pause(BOOL fPause)
327 {
328         if (!m_hwo)
329                 return;
330  
331         if (m_fDoubleBuf)
332                 m_fPaused = fPause;
333         else {
334                 CAutoLock lock(&m_csecDevice);
335                 if (fPause)
336                         waveOutPause(m_hwo);
337                 else
338                         waveOutRestart(m_hwo);
339         }
340 }
341  
342 DWORD COutput::GetCurrent()
343 {
344         CAutoLock lock(&m_csecDevice);
345         if (!m_hwo)
346                 return 0;
347  
348         if (m_fDoubleBuf)
349                 return m_dwTotalSamples;
350  
351         MMTIME time;
352         memset(&time, 0, sizeof(MMTIME));
353         time.wType = TIME_SAMPLES;
354         waveOutGetPosition(m_hwo, &time, sizeof(MMTIME));
355         return time.u.sample;
356 }
357  
358 BOOL COutput::IsFlushed()
359 {
360         return GetCurrent() >= m_dwWritten;
361 }
362  
363 void COutput::GetBufferInfo(DWORD* pcbTotal, DWORD* pcbBuffered)
364 {
365         if (!m_pHdr) {
366                 *pcbTotal = 0;
367                 *pcbBuffered = 0;
368                 return;
369         }
370  
371         *pcbTotal = m_cBuf * m_cbBuf;
372         *pcbBuffered = m_cWritten * m_cbBuf;
373 }
374  
375 void COutput::CheckPeek(WAVEHDR* pHdr)
376 {
377         // 絶対値とってないけどまあいいか(笑
378         // オレっていいかげん(笑
379         int nSamples;
380         if (m_pcm.wBitsPerSample == 16) {
381                 short* p = (short*)pHdr->lpData;
382                 m_nLPeek = m_nRPeek = 0;
383                 nSamples = pHdr->dwBufferLength / 2 / m_pcm.wf.nChannels;
384  
385                 if (m_pcm.wf.nChannels == 2) {
386                         for (int i = 0; i < nSamples; i++) {
387                                 m_nLPeek = m_nLPeek > *p ? m_nLPeek : *p;
388                                 p++;
389                                 m_nRPeek = m_nRPeek > *p ? m_nRPeek : *p;
390                                 p++;
391                         }
392                         m_nLPeek = m_nLPeek * 100 / 0x7FFF;
393                         m_nRPeek = m_nRPeek * 100 / 0x7FFF;
394                 }
395                 else {
396                         for (int i = 0; i < nSamples; i++) {
397                                 m_nLPeek = m_nLPeek > *p ? m_nLPeek : *p;
398                                 p++;
399                         }
400                         m_nLPeek = m_nLPeek * 100 / 0x8FFF;
401                         m_nRPeek = m_nLPeek;
402                 }
403         }
404         else {
405                 unsigned char* p = (unsigned char*)pHdr->lpData;
406                 m_nLPeek = m_nRPeek = 0x80;
407                 nSamples = pHdr->dwBufferLength / m_pcm.wf.nChannels;
408                 if (m_pcm.wf.nChannels == 2) {
409                         for (int i = 0; i < nSamples; i++) {
410                                 m_nLPeek = m_nLPeek > *p ? m_nLPeek : *p;
411                                 p++;
412                                 m_nRPeek = m_nRPeek > *p ? m_nRPeek : *p;
413                                 p++;
414                         }
415                         m_nLPeek = (m_nLPeek - 0x80) * 100 / 0x7F;
416                         m_nRPeek = (m_nRPeek - 0x80) * 100 / 0x7F;
417                 }
418                 else {
419                         for (int i = 0; i < nSamples; i++) {
420                                 m_nLPeek = m_nLPeek > *p ? m_nLPeek : *p;
421                                 p++;
422                         }
423                         m_nLPeek = (m_nLPeek - 0x80) * 100 / 0x7F;
424                         m_nRPeek = m_nLPeek;
425                 }
426         }
427 }
428  
429 void COutput::FadeIn(LPBYTE pbBuf, DWORD cbBuf)
430 {
431         int n;
432         DWORD cb = 0;
433         while ((cbBuf - cb) && m_nFadeSamples) {
434                 for (int nChannel = 0; nChannel < m_pcm.wf.nChannels; nChannel++) {
435                         if (m_pcm.wBitsPerSample == 16) {
436                                 n = ((int)*((short*)(pbBuf + cb))) * m_nFadeCurrent;
437                                 *((short*)(pbBuf + cb)) = n >> FADE_BITS;
438                                 cb += 2;
439                         }
440                         else {
441                                 n = (UINT8_TO_INT16((int)*(pbBuf + cb))) * m_nFadeCurrent;
442                                 *(pbBuf + cb) = INT16_TO_UINT8(n >> FADE_BITS);
443                                 cb++;
444                         }
445                 }
446                 m_nFadeCurrent += m_nFadeRate;
447                 m_nFadeSamples--;
448  
449                 if (m_nFadeCurrent >= (1 << FADE_BITS)) {
450                         m_nFadeSamples = 0;
451                         break;
452                 }
453         }
454 }
455  
456 short Clip16(int s);
457 unsigned char Clip8(int s);
458 void COutput::Preamp(LPBYTE pbBuf, DWORD cbBuf, int nRate)
459 {
460         int n;
461  
462         if (nRate == PREAMP_FIXED_FLAT)
463                 return;
464  
465         if (m_pcm.wBitsPerSample == 16) {
466                 for (DWORD cb = 0; cb < cbBuf; ) {
467                         for (int nChannel = 0; nChannel < m_pcm.wf.nChannels; nChannel++) {
468                                 n = (int)*((short*)(pbBuf + cb)) * nRate;
469                                 *((short*)(pbBuf + cb)) = Clip16(n >> PREAMP_FIXED_BITS);
470                                 cb += 2;
471                         }
472                 }
473         }
474         else {
475                 for (DWORD cb = 0; cb < cbBuf; ) {
476                         for (int nChannel = 0; nChannel < m_pcm.wf.nChannels; nChannel++) {
477                                 n = UINT8_TO_INT16((int)*(pbBuf + cb)) * nRate;
478                                 *(pbBuf + cb) = Clip8(INT16_TO_UINT8(n >> PREAMP_FIXED_BITS));
479                                 cb++;
480                         }
481                 }
482         }
483 }
484  
485 #define ZERO_SAMPLE_MAX         16
486 DWORD COutput::ScanZeroSamples(BOOL fForward, LPBYTE pbBuf, DWORD cbBuf)
487 {
488         int nZeroSamples = 0;
489         int nBytesPerSample = m_pcm.wf.nChannels * m_pcm.wBitsPerSample / 8;
490         int nSamples = cbBuf / nBytesPerSample;
491  
492         if (m_pcm.wBitsPerSample == 16) {
493                 short* pSample;
494                 if (fForward) {
495                         pSample = (short*)pbBuf;
496                 }
497                 else {
498                         pSample = (short*)(pbBuf + cbBuf - nBytesPerSample);
499                         nBytesPerSample = -nBytesPerSample;
500                 }
501  
502                 if (m_pcm.wf.nChannels == 2) {
503                         for (int i = 0; i < nSamples; i++) {
504                                 if ((*pSample > ZERO_SAMPLE_MAX) || (*pSample < -ZERO_SAMPLE_MAX) ||
505                                         (*(pSample + 1) > ZERO_SAMPLE_MAX) || (*(pSample + 1) < -ZERO_SAMPLE_MAX))
506                                         break;
507                                 nZeroSamples++;
508                                 pSample = (short*)((BYTE*)pSample + nBytesPerSample);
509                         }
510                 }
511                 else {
512                         for (int i = 0; i < nSamples; i++) {
513                                 if ((*pSample > ZERO_SAMPLE_MAX) || (*pSample < -ZERO_SAMPLE_MAX))
514                                         break;
515                                 nZeroSamples++;
516                                 pSample = (short*)((BYTE*)pSample + nBytesPerSample);
517                         }
518                 }
519         }
520         else {
521                 BYTE* pSample;
522                 if (fForward) {
523                         pSample = pbBuf;
524                 }
525                 else {
526                         pSample = pbBuf + cbBuf - nBytesPerSample;
527                         nBytesPerSample = -nBytesPerSample;
528                 }
529  
530                 if (m_pcm.wf.nChannels == 2) {
531                         for (int i = 0; i < nSamples; i++) {
532                                 if (*pSample != 0x80 || *(pSample + 1) != 0x80)
533                                         break;
534                                 nZeroSamples++;
535                                 pSample += nBytesPerSample;
536                         }
537                 }
538                 else {
539                         for (int i = 0; i < nSamples; i++) {
540                                 if (*pSample != 0x80)
541                                         break;
542                                 nZeroSamples++;
543                                 pSample += nBytesPerSample;
544                         }
545                 }
546         }
547  
548         return nZeroSamples * m_pcm.wf.nChannels * (m_pcm.wBitsPerSample / 8);
549 }
550  
551 void COutput::CloseAll()
552 {
553         if (m_hThread) {
554                 PostThreadMessage(m_dwThreadId, WM_QUIT, 0, 0);
555                 WaitForSingleObject(m_hThread, INFINITE);
556                 CloseHandle(m_hThread);
557                 m_hThread = NULL;
558         }
559         if (m_hwo) {
560                 Reset();
561  
562                 CAutoLock lockDev(&m_csecDevice);
563                 if (m_fDoubleBuf) {
564                         m_fPaused = TRUE;
565                         waveOutReset(m_hwo);
566  
567                         CAutoLock lock(&m_csecBuff);
568                         for (UINT i = 0; i < SUBBUF_COUNT; i++)
569                                 waveOutUnprepareHeader(m_hwo, &m_HdrOut[i] , sizeof(WAVEHDR));
570                 }
571                 else {
572                         CAutoLock lock(&m_csecBuff);
573                         for (UINT i = 0; i < m_cBuf; i++)
574                                 waveOutUnprepareHeader(m_hwo, &m_pHdr[i] , sizeof(WAVEHDR));
575                 }
576  
577                 waveOutClose(m_hwo);
578                 m_hwo = NULL;
579         }
580  
581         if (m_hEventThread) {
582                 CloseHandle(m_hEventThread);
583                 m_hEventThread = NULL;
584         }
585  
586         FreeSubBuffer();
587         FreeBuffer();
588         memset(&m_pcm, 0, sizeof(m_pcm));
589 }
590  
591 DWORD WINAPI COutput::WaveOutThreadProc(LPVOID pParam)
592 {
593         ((COutput*)pParam)->WaveOutThread();
594         return 0;
595 }
596  
597 void COutput::WaveOutThread()
598 {
599         DWORD cb;
600         while (MsgWaitForMultipleObjects(1, &m_hEventThread, FALSE, INFINITE, QS_ALLEVENTS) == WAIT_OBJECT_0) {
601                 InterlockedDecrement((long*)&m_nSubBuf);
602                 if (!m_nSubBuf) ResetEvent(m_hEventThread);
603                 CAutoLock lockDev(&m_csecDevice);
604                 m_HdrOut[m_nHdrOut].dwBytesRecorded = 0;
605                 while (m_HdrOut[m_nHdrOut].dwBytesRecorded < m_HdrOut[m_nHdrOut].dwBufferLength) {
606                         if (!m_cWritten || m_fPaused) {
607                                 if (!m_HdrClear[m_nHdrOut]) {
608                                         if (!m_HdrOut[m_nHdrOut].dwBytesRecorded)
609                                                 m_HdrClear[m_nHdrOut] = 1;
610  
611                                         memset(m_HdrOut[m_nHdrOut].lpData + m_HdrOut[m_nHdrOut].dwBytesRecorded, 0,
612                                                 m_HdrOut[m_nHdrOut].dwBufferLength - m_HdrOut[m_nHdrOut].dwBytesRecorded);
613                                         m_HdrOut[m_nHdrOut].dwBytesRecorded = m_HdrOut[m_nHdrOut].dwBufferLength;
614                                 }
615                                 break;
616                         }
617  
618                         CAutoLock lockBuf(&m_csecBuff);
619                         cb = min(m_HdrOut[m_nHdrOut].dwBufferLength - m_HdrOut[m_nHdrOut].dwBytesRecorded,
620                                         m_pHdr[m_nWriteCur].dwBytesRecorded - m_pHdr[m_nWriteCur].dwUser);
621                         memcpy(m_HdrOut[m_nHdrOut].lpData + m_HdrOut[m_nHdrOut].dwBytesRecorded,
622                                 m_pHdr[m_nWriteCur].lpData + m_pHdr[m_nWriteCur].dwUser, cb);
623  
624                         m_pHdr[m_nWriteCur].dwUser += cb;
625                         m_HdrOut[m_nHdrOut].dwBytesRecorded += cb;
626                         m_HdrClear[m_nHdrOut] = 0;
627                         m_dwTotalSamples += cb / m_pcm.wf.nBlockAlign;
628                         if (m_pHdr[m_nWriteCur].dwUser == m_pHdr[m_nWriteCur].dwBytesRecorded) {
629                                 m_pHdr[m_nWriteCur].dwUser = 0;
630                                 m_nWriteCur = (m_nWriteCur + 1) % m_cBuf;
631                                 m_cWritten--;
632                                 SetEvent(m_hEvent);
633                         }
634                 }
635  
636                 waveOutWrite(m_hwo, &m_HdrOut[m_nHdrOut], sizeof(WAVEHDR));
637                 m_nHdrOut = (m_nHdrOut + 1) % SUBBUF_COUNT;
638         }
639 }
640  
641 BOOL COutput::PrepareSubBuffer()
642 {
643         CAutoLock lock(&m_csecBuff);
644         if (m_pbSubBuf)
645                 return FALSE;
646  
647         int cb = SUBBUF_SIZE;
648         if (m_pcm.wf.nSamplesPerSec > 11025)
649                 cb *= 2;
650         if (m_pcm.wf.nSamplesPerSec > 22050)
651                 cb *= 2;
652         if (m_pcm.wBitsPerSample > 8)
653                 cb *= 2;
654         cb *= m_pcm.wf.nChannels;
655  
656         m_pbSubBuf = new BYTE[cb * SUBBUF_COUNT];
657         memset(m_pbSubBuf, 0, cb * SUBBUF_COUNT);
658         for (UINT i = 0; i < SUBBUF_COUNT; i++) {
659                 memset(&m_HdrOut[i], 0, sizeof(WAVEHDR));
660                 m_HdrOut[i].lpData = (LPSTR)m_pbSubBuf + (cb * i);
661                 m_HdrOut[i].dwBufferLength = cb;
662                 m_HdrOut[i].dwUser = (DWORD)this;
663                 waveOutPrepareHeader(m_hwo, &m_HdrOut[i] , sizeof(WAVEHDR));
664                 m_HdrClear[i] = 1;
665         }
666         m_nHdrOut = 0;
667         m_nWriteCur = 0;
668         m_nSubBuf = SUBBUF_COUNT;
669         m_dwTotalSamples = 0;
670  
671         m_hEventThread = CreateEvent(NULL, TRUE, TRUE, NULL);
672         m_hThread = CreateThread(NULL, 0, WaveOutThreadProc, this, CREATE_SUSPENDED, &m_dwThreadId);
673         if (!m_hThread)
674                 return FALSE;
675  
676 #ifdef _WIN32_WCE
677         SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
678         HMODULE hModule = LoadLibrary(_T("Coredll.dll"));
679         if (hModule) {
680                 BOOL (WINAPI *pCeSetThreadPriority)(HANDLE hThread, int nPriority);
681                 (FARPROC&)pCeSetThreadPriority = GetProcAddress(hModule, _T("CeSetThreadPriority"));
682                 if (pCeSetThreadPriority)
683                         pCeSetThreadPriority(GetCurrentThread(), 160);
684                 FreeLibrary(hModule);
685         }
686 #else
687         SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
688 #endif
689         ResumeThread(m_hThread);
690         return TRUE;
691 }
692  
693 void COutput::FreeSubBuffer()
694 {
695         CAutoLock lock(&m_csecBuff);
696         if (m_pbSubBuf) {
697                 delete m_pbSubBuf;
698                 m_pbSubBuf = NULL;
699         }
700         memset(m_HdrOut, 0, sizeof(m_HdrOut));
701 }
702  
703 DWORD COutput::GetBufferingSamples()
704 {
705         DWORD dwCurrent = GetCurrent();
706         return m_dwWritten - dwCurrent;
707 }
708  
26 roytam 709 DWORD COutput::GetVolume()
710 {
711         return m_dwVolume;
712 }
713  
714 void COutput::SetVolume(DWORD dwVolume)
715 {
716         m_dwVolume = dwVolume;
717         if (m_hwo) {
718                 waveOutSetVolume(m_hwo, m_dwVolume);
719         }
720 }