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