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