Makefile: Added missing EcereAudio clean rules
[sdk] / extras / audio / dsound.ec
1 #if defined(__WIN32__)
2
3 #define byte _byte
4 #define Method _Method
5 #define Function _Function
6 #define int64 _int64
7 #define WIN32_LEAN_AND_MEAN
8 #define MessageBox _MessageBox
9 #define Array _Array
10 #define String _String
11
12 #include <windows.h>
13
14 #include <mmsystem.h>
15 #include <dsound.h>
16 #undef Array
17 #undef MessageBox
18 #undef byte
19 #undef Method
20 #undef Function
21 #undef int64
22 #undef String
23
24 import "audio"
25
26 public void AudioSetBalance(double percent)
27 {
28    if(streamingSound)
29       streamingSound.balance = percent;
30 }
31
32 static HWAVEOUT hWaveOut;
33 static HMIXEROBJ hmx;
34
35 public void OpenMixer()
36 {
37    WAVEFORMATEX  waveFormat = { 0 };
38    waveFormat.nSamplesPerSec = 44100; //(cur_stream && cur_stream->audio_st && cur_stream->audio_st->codec) ? cur_stream->audio_st->codec->sample_rate : 44100;
39    waveFormat.wBitsPerSample = 16;
40    waveFormat.nChannels = 2;
41    waveFormat.cbSize = 0;
42    waveFormat.wFormatTag = WAVE_FORMAT_PCM;
43    waveFormat.nBlockAlign = (uint16)((waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels);
44    waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;
45
46    waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
47    mixerOpen((HMIXER *)&hmx, (uint)(uintptr)hWaveOut, 0, 0, MIXER_OBJECTF_HWAVEOUT);
48 }
49
50 public void CloseMixer()
51 {
52    mixerClose((HMIXER)hmx);
53    waveOutClose(hWaveOut);
54 }
55
56 public bool AudioSetVolume(VolumeControl type, double percent)
57 {
58    bool result = false;
59    if(type == application)
60    {
61       if(streamingSound)
62       {
63          streamingSound.volume = percent;
64          result = true;
65       }
66    }
67    else
68    {
69       MIXERLINE uMixerLine;
70
71       // waveOutSetVolume((HWAVEOUT)0, (uint)(percent * 0xFFFF) | ((uint)(percent * 0xFFFF) << 16));
72
73       uMixerLine.cbStruct = sizeof(MIXERLINE);
74       uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
75       if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
76       {
77          MIXERLINECONTROLS uMixerLineControls;
78          MIXERCONTROL mixerControl;
79
80          uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
81          uMixerLineControls.dwLineID = uMixerLine.dwLineID;
82          uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
83          uMixerLineControls.cControls = 1;
84          uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
85          uMixerLineControls.pamxctrl = &mixerControl;
86          if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
87          {
88             MIXERCONTROLDETAILS uDetails;
89             uint value;
90
91             uDetails.cMultipleItems = 0;
92             uDetails.dwControlID = mixerControl.dwControlID;
93             uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
94             uDetails.cbDetails = sizeof(uint);
95             uDetails.paDetails = &value;
96             uDetails.cChannels = 1;
97             value = (uint)(percent * mixerControl.Bounds.lMaximum);
98             mixerSetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
99             result = true;
100          }
101       }
102    }
103    return result;
104 }
105
106 public bool AudioGetVolume(VolumeControl type, double * percent)
107 {
108    bool result = false;
109    if(type == application)
110    {
111       if(streamingSound)
112       {
113          *percent = streamingSound.volume;
114          result = true;
115       }
116    }
117    else
118    {
119       MIXERLINE uMixerLine;
120
121       uMixerLine.cbStruct = sizeof(MIXERLINE);
122       uMixerLine.dwComponentType = (type == pcm) ? MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
123       if(mixerGetLineInfo(hmx, &uMixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR)
124       {
125          MIXERLINECONTROLS uMixerLineControls;
126          MIXERCONTROL mixerControl;
127
128          uMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
129          uMixerLineControls.dwLineID = uMixerLine.dwLineID;
130          uMixerLineControls.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
131          uMixerLineControls.cControls = 1;
132          uMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
133
134          uMixerLineControls.pamxctrl = &mixerControl;
135          if(mixerGetLineControls(hmx, &uMixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
136          {
137             MIXERCONTROLDETAILS uDetails;
138             uint value;
139
140             uDetails.cMultipleItems = 0;
141             uDetails.dwControlID = mixerControl.dwControlID;
142             uDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
143             uDetails.cbDetails = sizeof(uint);
144             uDetails.paDetails = &value;
145             uDetails.cChannels = 1;
146             mixerGetControlDetails(hmx, &uDetails, MIXER_SETCONTROLDETAILSF_VALUE);
147             *percent = (double)value / mixerControl.Bounds.lMaximum;
148             result = true;
149          }
150       }
151    }
152    return result;
153 }
154
155 public int OpenAudio(AudioSpec wanted, AudioSpec result)
156 {
157    #define NUM_PLAY_NOTIFICATIONS  16
158    uint nBlockAlign, dwNotifySize;
159
160    delete streamingSound;
161
162    g_pSoundManager.Initialize(wanted.windowHandle);
163    g_pSoundManager.SetPrimaryBufferFormat(wanted.channels, wanted.freq, wanted.bits);
164
165    if(!wanted.channels)
166       wanted.channels = 2;
167    nBlockAlign = wanted.bits / 8 * wanted.channels;
168    // dwNotifySize = 16384 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
169    dwNotifySize = wanted.freq / 2 / NUM_PLAY_NOTIFICATIONS; //wanted.freq * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
170    dwNotifySize -= dwNotifySize % nBlockAlign;
171    result = wanted;
172    result.size = dwNotifySize * NUM_PLAY_NOTIFICATIONS;
173
174    g_pSoundManager.InitStreaming(&streamingSound, NUM_PLAY_NOTIFICATIONS, dwNotifySize, dSoundThread.g_hNotificationEvent,
175       (void *)wanted.callback, wanted.userdata, wanted.channels, wanted.freq, wanted.bits);
176    if(streamingSound)
177    {
178       streamingSound.volume = wanted.volume;
179       dSoundThread.bDone = false;
180
181       //dSoundThread.Create();
182       return 1;
183    }
184    return 0;
185 }
186
187 public void PauseAudio(int value)
188 {
189    if(!value)
190    {
191       PlayBuffer(false);
192       dSoundThread.Create();
193    }
194 }
195
196 public void CloseAudio()
197 {
198    if(dSoundThread)
199    {
200       dSoundThread.bDone = true;
201       SetEvent(dSoundThread.g_hNotificationEvent);
202       dSoundThread.Wait();
203    }
204    delete streamingSound;
205 }
206
207 static bool PlayBuffer( bool bLooped )
208 {
209    //void * pDSB;
210    if(!streamingSound)
211       return false;
212
213    if(streamingSound.Reset())
214       return false;
215
216    //pDSB = streamingSound.GetBuffer( 0 );
217
218    SetEvent(dSoundThread.g_hNotificationEvent);
219    return true;
220 }
221
222 static class StreamingSound
223 {
224    IDirectSoundBuffer ** apDSBuffer;
225    IDirectSoundBuffer * pDSB;
226
227    uint dwDSBufferSize;
228    uint dwNumBuffers;
229    uint dwCreationFlags;
230    uint dwLastPlayPos;
231    uint dwPlayProgress;
232    uint dwNotifySize;
233    uint dwNextWriteOffset;
234    bool bFillNextNotificationWithSilence;
235    void (*callback)(void * data, void * buffer, int len);
236    void * data;
237    double volume;
238
239    public property double volume
240    {
241       set
242       {
243          int vol = (int)(20 * log10(value) * 100);
244          vol = Max(-10000, vol);
245          IDirectSoundBuffer_SetVolume(apDSBuffer[0], vol);
246          volume = value;
247       }
248       get
249       {
250          return volume;
251       }
252    };
253
254    public property double balance
255    {
256       set
257       {
258          int pan = -2173 + (int)(value * 2173 * 2);
259          IDirectSoundBuffer_SetPan(apDSBuffer[0], pan);
260       }
261    }
262
263    property uint dwNumBuffers
264    {
265       set
266       {
267          dwNumBuffers = value;
268          apDSBuffer = new0 IDirectSoundBuffer *[dwNumBuffers];
269       }
270    }
271
272    property IDirectSoundBuffer ** apDSBuffer
273    {
274       set
275       {
276          if( apDSBuffer )
277          {
278             uint i;
279             for( i=0; i<dwNumBuffers; i++ )
280                apDSBuffer[i] = value[i];
281          }
282       }
283    }
284
285    ~StreamingSound()
286    {
287       uint i;
288       for( i=0; i<dwNumBuffers; i++ )
289       {
290          if(apDSBuffer[i])
291          {
292             IDirectSoundBuffer_Release( apDSBuffer[i] );
293             apDSBuffer[i] = 0;
294          }
295       }
296
297       delete( apDSBuffer );
298    }
299
300    int RestoreBuffer( IDirectSoundBuffer * pDSB, bool* pbWasRestored )
301    {
302       int hr;
303       DWORD dwStatus;
304
305       if( pDSB == null )
306          return CO_E_NOTINITIALIZED;
307       if( pbWasRestored )
308          *pbWasRestored = false;
309
310       if( FAILED( hr = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus) ) )
311          return 1; //DXUT_ERR( L"GetStatus", hr );
312
313       if( dwStatus & DSBSTATUS_BUFFERLOST )
314       {
315          // Since the app could have just been activated, then
316          // DirectSound may not be giving us control yet, so
317          // the restoring the buffer may fail.
318          // If it does, sleep until DirectSound gives us control.
319          do
320          {
321             hr = IDirectSoundBuffer_Restore(pDSB);
322             if( hr == DSERR_BUFFERLOST )
323                Sleep( 10 );
324          }
325          while( ( hr = IDirectSoundBuffer_Restore(pDSB) ) == DSERR_BUFFERLOST );
326
327          if( pbWasRestored != null )
328             *pbWasRestored = true;
329
330          return S_OK;
331       }
332       else
333       {
334          return S_OK; //FALSE;
335       }
336    }
337
338    IDirectSoundBuffer * GetFreeBuffer()
339    {
340       uint i;
341       if(!apDSBuffer)
342          return null;
343
344       for( i=0; i<dwNumBuffers; i++ )
345       {
346          if( apDSBuffer[i] )
347          {
348             DWORD dwStatus = 0;
349             IDirectSoundBuffer_GetStatus(apDSBuffer[i], &dwStatus );
350             if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
351                break;
352          }
353       }
354
355       if( i != dwNumBuffers )
356          return apDSBuffer[ i ];
357       else
358          return apDSBuffer[ rand() % dwNumBuffers ];
359    }
360
361    IDirectSoundBuffer * GetBuffer( uint dwIndex )
362    {
363       if( apDSBuffer == null )
364          return null;
365       if( dwIndex >= dwNumBuffers )
366          return null;
367
368       return apDSBuffer[dwIndex];
369    }
370
371    int Play( uint dwPriority, uint dwFlags, uint lVolume, uint lFrequency, uint lPan )
372    {
373       int result;
374       int hr;
375       bool bRestored;
376       //IDirectSoundBuffer * pDSB;
377
378       // For Streaming Sound
379       dwFlags |= DSBPLAY_LOOPING;
380
381       if( apDSBuffer == null )
382          return CO_E_NOTINITIALIZED;
383
384       pDSB = GetFreeBuffer();
385
386       if( pDSB == null )
387          return 1; //DXUT_ERR( L"GetFreeBuffer", E_FAIL );
388
389       // Restore the buffer if it was lost
390       if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
391          return 1; //DXUT_ERR( L"RestoreBuffer", hr );
392
393       if( bRestored )
394       {
395          // The buffer was restored, so we need to fill it with new data
396          if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) )
397             return 1; //DXUT_ERR( L"FillBufferWithSound", hr );
398       }
399
400       if( dwCreationFlags & DSBCAPS_CTRLVOLUME )
401       {
402          //IDirectSoundBuffer_SetVolume(pDSB, lVolume);
403       }
404
405       if( lFrequency != -1 &&
406          (dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
407       {
408          IDirectSoundBuffer_SetFrequency(pDSB, lFrequency);
409       }
410
411       if( dwCreationFlags & DSBCAPS_CTRLPAN )
412       {
413          //IDirectSoundBuffer_SetPan(pDSB, lPan);
414       }
415       result = IDirectSoundBuffer_Play(pDSB, 0, dwPriority, dwFlags);
416       return result;
417    }
418
419    /*
420    int Stop()
421    {
422       int hr = 0;
423       uint i;
424       if( apDSBuffer == null )
425          return CO_E_NOTINITIALIZED;
426
427       for( i=0; i<dwNumBuffers; i++ )
428          hr |= IDirectSoundBuffer_Stop(apDSBuffer[i]);
429
430       return hr;
431    }
432    */
433
434    bool HandleWaveStreamNotification(  )
435    {
436       DWORD dwCurrentPlayPos;
437       void * pDSLockedBuffer = null;
438       void * pDSLockedBuffer2 = null;
439       DWORD dwDSLockedBufferSize;
440       DWORD dwDSLockedBufferSize2;
441       uint playCursor, writeCursor;
442       uint start, size;
443       bool written = true;
444       int c;
445
446       while(written)
447       {
448          written = false;
449
450          // Figure out how much data has been played so far.  When we have played
451          // past the end of the file, we will either need to start filling the
452          // buffer with silence or starting reading from the beginning of the file,
453          // depending if the user wants to loop the sound
454          if(IDirectSoundBuffer_GetCurrentPosition(apDSBuffer[0], &dwCurrentPlayPos, null))
455          {
456             return false;
457          }
458          playCursor = (dwCurrentPlayPos / dwNotifySize);
459          writeCursor = dwNextWriteOffset;
460
461          //printf("Play Cursor : %d, Write Cursor %d\n", playCursor, writeCursor);
462          if(writeCursor > playCursor)
463          {
464             start = writeCursor;
465             size = (dwDSBufferSize / dwNotifySize) - start;
466             for(c = start; c<start + size; c++)
467             if(size)
468             {
469                written = true;
470                //printf("Writing %d - %d\n", c, c);
471                IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
472                //printf("In callback...");
473                callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
474                //printf("Out\n");
475                IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
476                dwNextWriteOffset = 0;
477             }
478
479             if(start > 0)
480             {
481                start = 0;
482                size = playCursor;
483                for(c = start; c<start + size; c++)
484                if(size)
485                {
486                   written = true;
487                   //printf("Writing %d - %d\n", c, c);
488                   IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
489                   //printf("In callback...");
490                   callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
491                   //printf("Out\n");
492                   IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
493                   dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
494                }
495             }
496          }
497          else
498          {
499             start = writeCursor;
500             size = playCursor - writeCursor;
501             for(c = start; c<start + size; c++)
502             if(size)
503             {
504                written = true;
505                //printf("Writing %d - %d\n", c, c);
506                IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
507                //printf("In callback...");
508                callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
509                //printf("Out\n");
510                IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
511                dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
512             }
513          }
514          //printf("Next Offset: %d\n", dwNextWriteOffset);
515          }
516       return true;
517    }
518
519    int Reset()
520    {
521       bool bRestored;
522       int result;
523
524       if(!apDSBuffer[0])
525          return 1;
526
527       dwLastPlayPos     = 0;
528       dwPlayProgress    = 0;
529       dwNextWriteOffset = 0;
530       bFillNextNotificationWithSilence = false;
531
532       // Restore the buffer if it was lost
533       if(RestoreBuffer( apDSBuffer[0], &bRestored ))
534          return 1;
535
536       if( bRestored )
537       {
538          // The buffer was restored, so we need to fill it with new data
539          if(FillBufferWithSound( apDSBuffer[0], false))
540             return 1;
541       }
542
543       result = IDirectSoundBuffer_SetCurrentPosition(apDSBuffer[0], 0L );
544       return result;
545    }
546
547    int FillBufferWithSound( IDirectSoundBuffer * pDSB, bool bRepeatWavIfBufferLarger )
548    {
549       void * pDSLockedBuffer = null; // Pointer to locked buffer memory
550       DWORD dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
551
552       if( pDSB == null )
553          return CO_E_NOTINITIALIZED;
554
555       // Make sure we have focus, and we didn't just switch in from
556       // an app which had a DirectSound device
557       if(RestoreBuffer( pDSB, null ))
558          return 1;
559
560       // Lock the buffer down
561       if(IDirectSoundBuffer_Lock(pDSB, 0, dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize, null, null, 0L ))
562          return 1;
563
564       callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
565
566       // printf("Filling 16 spots\n");
567       IDirectSoundBuffer_Unlock(pDSB, pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
568
569       //dwNextWriteOffset = dwNotifySize*2;
570       return S_OK;
571    }
572 }
573
574 static class CSoundManager
575 {
576    IDirectSound8* pDS;
577
578    ~CSoundManager()
579    {
580       if(pDS)
581          IDirectSound_Release( pDS );
582    }
583
584    int Initialize( void * hWnd )
585    {
586       int hr;
587
588       if(pDS)
589       {
590          IDirectSound_Release( pDS );
591          pDS = null;
592       }
593
594       // Create IDirectSound using the primary sound device
595       if( FAILED( hr = DirectSoundCreate8( null, &pDS, null ) ) )
596          return 1; //DXUT_ERR( L"DirectSoundCreate8", hr );
597
598       // Set DirectSound coop level
599       if( FAILED( hr = IDirectSound_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY ) ) )
600          return 1; //DXUT_ERR( L"SetCooperativeLevel", hr );
601
602       return S_OK;
603    }
604
605
606    int SetPrimaryBufferFormat( uint dwPrimaryChannels, uint dwPrimaryFreq, uint dwPrimaryBitRate )
607    {
608       int hr;
609       IDirectSoundBuffer * pDSBPrimary = null;
610       DSBUFFERDESC dsbd;
611       WAVEFORMATEX wfx;
612
613       if( pDS == null )
614          return CO_E_NOTINITIALIZED;
615
616       // Get the primary buffer
617       ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
618       dsbd.dwSize        = sizeof(DSBUFFERDESC);
619       dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
620       dsbd.dwBufferBytes = 0;
621       dsbd.lpwfxFormat   = null;
622
623       if( FAILED( hr = IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBPrimary, null ) ) )
624          return 1; // DXUT_ERR( L"CreateSoundBuffer", hr );
625
626       ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
627       wfx.wFormatTag      = (WORD) WAVE_FORMAT_PCM;
628       wfx.nChannels       = (WORD) dwPrimaryChannels;
629       wfx.nSamplesPerSec  = (uint) dwPrimaryFreq;
630       wfx.wBitsPerSample  = (WORD) dwPrimaryBitRate;
631       wfx.nBlockAlign     = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
632       wfx.nAvgBytesPerSec = (uint) (wfx.nSamplesPerSec * wfx.nBlockAlign);
633
634       if( FAILED( hr = IDirectSoundBuffer_SetFormat(pDSBPrimary, &wfx) ) )
635          return 1; //DXUT_ERR( L"SetFormat", hr );
636
637       if(pDSBPrimary)
638       {
639          IDirectSoundBuffer_Release( pDSBPrimary );
640          pDSBPrimary = null;
641       }
642       return S_OK;
643    }
644
645
646    bool InitStreaming(StreamingSound * ppStreamingSound, uint dwNotifyCount, uint dwNotifySize, void * hNotifyEvent,
647                       void (*callback)(void * data, void * buffer, int len), void * data, int nChannels, int freq,int bits)
648    {
649       IDirectSoundBuffer * pDSBuffer = null;
650       uint dwDSBufferSize = 0;
651       DSBPOSITIONNOTIFY * aPosNotify = null;
652       IDirectSoundNotify * pDSNotify = null;
653       DSBUFFERDESC dsbd;
654       uint i;
655
656       if(!pDS)
657          return false;
658       if(!ppStreamingSound || !hNotifyEvent)
659          return false;
660
661       dwDSBufferSize = dwNotifySize * dwNotifyCount;
662
663       ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
664       dsbd.dwSize= sizeof(DSBUFFERDESC);
665       dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
666       dsbd.dwBufferBytes = dwDSBufferSize;
667       dsbd.guid3DAlgorithm = DS3DALG_DEFAULT;
668       dsbd.lpwfxFormat = new0 WAVEFORMATEX[1];
669       dsbd.lpwfxFormat->wFormatTag = WAVE_FORMAT_PCM;
670       dsbd.lpwfxFormat->nChannels = (uint16)nChannels;
671       dsbd.lpwfxFormat->nSamplesPerSec = freq;
672       dsbd.lpwfxFormat->wBitsPerSample = (uint16)bits;
673       dsbd.lpwfxFormat->nBlockAlign = dsbd.lpwfxFormat->nChannels * dsbd.lpwfxFormat->wBitsPerSample / 8;
674       dsbd.lpwfxFormat->nAvgBytesPerSec = dsbd.lpwfxFormat->nSamplesPerSec * dsbd.lpwfxFormat->nBlockAlign;
675
676       if(IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBuffer, null))
677       {
678          delete dsbd.lpwfxFormat;
679          return false;
680       }
681       delete dsbd.lpwfxFormat;
682
683       if(IDirectSoundBuffer_QueryInterface(pDSBuffer, &IID_IDirectSoundNotify, (void**)&pDSNotify))
684       {
685          delete aPosNotify;
686          return false;
687       }
688
689       aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
690       if( aPosNotify == null )
691          return false;
692
693       for( i = 0; i < dwNotifyCount; i++ )
694       {
695          aPosNotify[i].dwOffset     = (dwNotifySize * i) + dwNotifySize - 1;
696          aPosNotify[i].hEventNotify = hNotifyEvent;
697       }
698
699       if(IDirectSoundNotify_SetNotificationPositions(pDSNotify, dwNotifyCount, aPosNotify ))
700       {
701          if(pDSNotify)
702             IDirectSoundNotify_Release(pDSNotify);
703          delete( aPosNotify );
704          return false;
705       }
706
707       if(pDSNotify)
708          IDirectSoundNotify_Release(pDSNotify);
709       delete aPosNotify;
710
711       *ppStreamingSound = StreamingSound
712       {
713          dwCreationFlags = DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME, dwNumBuffers = 1, dwNotifySize = dwNotifySize, dwDSBufferSize = dwDSBufferSize, apDSBuffer = &pDSBuffer,
714
715          callback = callback, data = data
716       };
717       // ppStreamingSound->FillBufferWithSound( pDSBuffer, false );
718       return true;
719    }
720 }
721
722 static DSoundThread dSoundThread { };
723
724 static CSoundManager g_pSoundManager { };
725 static StreamingSound streamingSound;
726
727 static class DSoundThread : Thread
728 {
729    void * g_hNotificationEvent;
730    bool bDone;
731    DSoundThread()
732    {
733       g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
734    }
735    ~DSoundThread()
736    {
737       CloseHandle( g_hNotificationEvent );
738    }
739    uint Main( )
740    {
741       bool filled = false;
742       SetPriority(timeCritical);
743       while( !bDone )
744       {
745          WaitForSingleObject(g_hNotificationEvent, INFINITE);
746          if(streamingSound)
747          {
748             if(!filled)
749             {
750                streamingSound.FillBufferWithSound( streamingSound.GetBuffer( 0 ), false );
751                streamingSound.Play( 0, 0, 0, -1, 0);
752                filled = true;
753             }
754             else if(!streamingSound.HandleWaveStreamNotification())
755             {
756                bDone = true;
757             }
758          }
759       }
760       return 0;
761    }
762 }
763
764 #endif