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