ecere/gui/Window: Prevent uninitialized values if base Window methods not overridden...
[sdk] / 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(bool value)
188 {
189    if(value)
190    {
191       dSoundThread.bDone = true;
192       SetEvent(dSoundThread.g_hNotificationEvent);
193       dSoundThread.Wait();
194    }
195    else
196    {
197       PlayBuffer(false);
198       dSoundThread.Create();
199    }
200 }
201
202 public void CloseAudio()
203 {
204    if(dSoundThread)
205    {
206       dSoundThread.bDone = true;
207       SetEvent(dSoundThread.g_hNotificationEvent);
208       dSoundThread.Wait();
209    }
210    delete streamingSound;
211 }
212
213 static bool PlayBuffer( bool bLooped )
214 {
215    //void * pDSB;
216    if(!streamingSound)
217       return false;
218
219    if(streamingSound.Reset())
220       return false;
221
222    //pDSB = streamingSound.GetBuffer( 0 );
223
224    SetEvent(dSoundThread.g_hNotificationEvent);
225    return true;
226 }
227
228 static class StreamingSound
229 {
230    IDirectSoundBuffer ** apDSBuffer;
231    IDirectSoundBuffer * pDSB;
232
233    uint dwDSBufferSize;
234    uint dwNumBuffers;
235    uint dwCreationFlags;
236    uint dwLastPlayPos;
237    uint dwPlayProgress;
238    uint dwNotifySize;
239    uint dwNextWriteOffset;
240    bool bFillNextNotificationWithSilence;
241    void (*callback)(void * data, void * buffer, int len);
242    void * data;
243    double volume;
244
245    public property double volume
246    {
247       set
248       {
249          int vol = (int)(20 * log10(value) * 100);
250          vol = Max(-10000, vol);
251          IDirectSoundBuffer_SetVolume(apDSBuffer[0], vol);
252          volume = value;
253       }
254       get
255       {
256          return volume;
257       }
258    };
259
260    public property double balance
261    {
262       set
263       {
264          int pan = -2173 + (int)(value * 2173 * 2);
265          IDirectSoundBuffer_SetPan(apDSBuffer[0], pan);
266       }
267    }
268
269    property uint dwNumBuffers
270    {
271       set
272       {
273          dwNumBuffers = value;
274          apDSBuffer = new0 IDirectSoundBuffer *[dwNumBuffers];
275       }
276    }
277
278    property IDirectSoundBuffer ** apDSBuffer
279    {
280       set
281       {
282          if( apDSBuffer )
283          {
284             uint i;
285             for( i=0; i<dwNumBuffers; i++ )
286                apDSBuffer[i] = value[i];
287          }
288       }
289    }
290
291    ~StreamingSound()
292    {
293       uint i;
294       for( i=0; i<dwNumBuffers; i++ )
295       {
296          if(apDSBuffer[i])
297          {
298             IDirectSoundBuffer_Release( apDSBuffer[i] );
299             apDSBuffer[i] = 0;
300          }
301       }
302
303       delete( apDSBuffer );
304    }
305
306    int RestoreBuffer( IDirectSoundBuffer * pDSB, bool* pbWasRestored )
307    {
308       int hr;
309       DWORD dwStatus;
310
311       if( pDSB == null )
312          return CO_E_NOTINITIALIZED;
313       if( pbWasRestored )
314          *pbWasRestored = false;
315
316       if( FAILED( hr = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus) ) )
317          return 1; //DXUT_ERR( L"GetStatus", hr );
318
319       if( dwStatus & DSBSTATUS_BUFFERLOST )
320       {
321          // Since the app could have just been activated, then
322          // DirectSound may not be giving us control yet, so
323          // the restoring the buffer may fail.
324          // If it does, sleep until DirectSound gives us control.
325          do
326          {
327             hr = IDirectSoundBuffer_Restore(pDSB);
328             if( hr == DSERR_BUFFERLOST )
329                Sleep( 10 );
330          }
331          while( ( hr = IDirectSoundBuffer_Restore(pDSB) ) == DSERR_BUFFERLOST );
332
333          if( pbWasRestored != null )
334             *pbWasRestored = true;
335
336          return S_OK;
337       }
338       else
339       {
340          return S_OK; //FALSE;
341       }
342    }
343
344    IDirectSoundBuffer * GetFreeBuffer()
345    {
346       uint i;
347       if(!apDSBuffer)
348          return null;
349
350       for( i=0; i<dwNumBuffers; i++ )
351       {
352          if( apDSBuffer[i] )
353          {
354             DWORD dwStatus = 0;
355             IDirectSoundBuffer_GetStatus(apDSBuffer[i], &dwStatus );
356             if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
357                break;
358          }
359       }
360
361       if( i != dwNumBuffers )
362          return apDSBuffer[ i ];
363       else
364          return apDSBuffer[ rand() % dwNumBuffers ];
365    }
366
367    IDirectSoundBuffer * GetBuffer( uint dwIndex )
368    {
369       if( apDSBuffer == null )
370          return null;
371       if( dwIndex >= dwNumBuffers )
372          return null;
373
374       return apDSBuffer[dwIndex];
375    }
376
377    int Play( uint dwPriority, uint dwFlags, uint lVolume, uint lFrequency, uint lPan )
378    {
379       int result;
380       int hr;
381       bool bRestored;
382       //IDirectSoundBuffer * pDSB;
383
384       // For Streaming Sound
385       dwFlags |= DSBPLAY_LOOPING;
386
387       if( apDSBuffer == null )
388          return CO_E_NOTINITIALIZED;
389
390       pDSB = GetFreeBuffer();
391
392       if( pDSB == null )
393          return 1; //DXUT_ERR( L"GetFreeBuffer", E_FAIL );
394
395       // Restore the buffer if it was lost
396       if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
397          return 1; //DXUT_ERR( L"RestoreBuffer", hr );
398
399       if( bRestored )
400       {
401          // The buffer was restored, so we need to fill it with new data
402          if( FAILED( hr = FillBufferWithSound( pDSB, false ) ) )
403             return 1; //DXUT_ERR( L"FillBufferWithSound", hr );
404       }
405
406       if( dwCreationFlags & DSBCAPS_CTRLVOLUME )
407       {
408          //IDirectSoundBuffer_SetVolume(pDSB, lVolume);
409       }
410
411       if( lFrequency != -1 &&
412          (dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
413       {
414          IDirectSoundBuffer_SetFrequency(pDSB, lFrequency);
415       }
416
417       if( dwCreationFlags & DSBCAPS_CTRLPAN )
418       {
419          //IDirectSoundBuffer_SetPan(pDSB, lPan);
420       }
421       result = IDirectSoundBuffer_Play(pDSB, 0, dwPriority, dwFlags);
422       return result;
423    }
424
425    /*
426    int Stop()
427    {
428       int hr = 0;
429       uint i;
430       if( apDSBuffer == null )
431          return CO_E_NOTINITIALIZED;
432
433       for( i=0; i<dwNumBuffers; i++ )
434          hr |= IDirectSoundBuffer_Stop(apDSBuffer[i]);
435
436       return hr;
437    }
438    */
439
440    bool HandleWaveStreamNotification(  )
441    {
442       DWORD dwCurrentPlayPos;
443       void * pDSLockedBuffer = null;
444       void * pDSLockedBuffer2 = null;
445       DWORD dwDSLockedBufferSize;
446       DWORD dwDSLockedBufferSize2;
447       uint playCursor, writeCursor;
448       uint start, size;
449       bool written = true;
450       int c;
451
452       while(written)
453       {
454          written = false;
455
456          // Figure out how much data has been played so far.  When we have played
457          // past the end of the file, we will either need to start filling the
458          // buffer with silence or starting reading from the beginning of the file,
459          // depending if the user wants to loop the sound
460          if(IDirectSoundBuffer_GetCurrentPosition(apDSBuffer[0], &dwCurrentPlayPos, null))
461          {
462             return false;
463          }
464          playCursor = (dwCurrentPlayPos / dwNotifySize);
465          writeCursor = dwNextWriteOffset;
466
467          //printf("Play Cursor : %d, Write Cursor %d\n", playCursor, writeCursor);
468          if(writeCursor > playCursor)
469          {
470             start = writeCursor;
471             size = (dwDSBufferSize / dwNotifySize) - start;
472             for(c = start; c<start + size; c++)
473             if(size)
474             {
475                written = true;
476                //printf("Writing %d - %d\n", c, c);
477                IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
478                //printf("In callback...");
479                callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
480                //printf("Out\n");
481                IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
482                dwNextWriteOffset = 0;
483             }
484
485             if(start > 0)
486             {
487                start = 0;
488                size = playCursor;
489                for(c = start; c<start + size; c++)
490                if(size)
491                {
492                   written = true;
493                   //printf("Writing %d - %d\n", c, c);
494                   IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
495                   //printf("In callback...");
496                   callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
497                   //printf("Out\n");
498                   IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
499                   dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
500                }
501             }
502          }
503          else
504          {
505             start = writeCursor;
506             size = playCursor - writeCursor;
507             for(c = start; c<start + size; c++)
508             if(size)
509             {
510                written = true;
511                //printf("Writing %d - %d\n", c, c);
512                IDirectSoundBuffer_Lock(apDSBuffer[0], c * dwNotifySize, 1 * dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L);
513                //printf("In callback...");
514                callback(data, pDSLockedBuffer, dwDSLockedBufferSize);
515                //printf("Out\n");
516                IDirectSoundBuffer_Unlock(apDSBuffer[0], pDSLockedBuffer, dwDSLockedBufferSize, null, 0 );
517                dwNextWriteOffset = (playCursor) % (dwDSBufferSize / dwNotifySize);
518             }
519          }
520          //printf("Next Offset: %d\n", dwNextWriteOffset);
521          }
522       return true;
523    }
524
525    int Reset()
526    {
527       bool bRestored;
528       int result;
529
530       if(!apDSBuffer[0])
531          return 1;
532
533       dwLastPlayPos     = 0;
534       dwPlayProgress    = 0;
535       dwNextWriteOffset = 0;
536       bFillNextNotificationWithSilence = false;
537
538       // Restore the buffer if it was lost
539       if(RestoreBuffer( apDSBuffer[0], &bRestored ))
540          return 1;
541
542       if( bRestored )
543       {
544          // The buffer was restored, so we need to fill it with new data
545          if(FillBufferWithSound( apDSBuffer[0], false))
546             return 1;
547       }
548
549       result = IDirectSoundBuffer_SetCurrentPosition(apDSBuffer[0], 0L );
550       return result;
551    }
552
553    int FillBufferWithSound( IDirectSoundBuffer * pDSB, bool bRepeatWavIfBufferLarger )
554    {
555       void * pDSLockedBuffer = null; // Pointer to locked buffer memory
556       DWORD dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
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       // 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       IDirectSoundBuffer * pDSBuffer = null;
656       uint dwDSBufferSize = 0;
657       DSBPOSITIONNOTIFY * aPosNotify = null;
658       IDirectSoundNotify * pDSNotify = null;
659       DSBUFFERDESC dsbd;
660       uint i;
661
662       if(!pDS)
663          return false;
664       if(!ppStreamingSound || !hNotifyEvent)
665          return false;
666
667       dwDSBufferSize = dwNotifySize * dwNotifyCount;
668
669       ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
670       dsbd.dwSize= sizeof(DSBUFFERDESC);
671       dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;
672       dsbd.dwBufferBytes = dwDSBufferSize;
673       dsbd.guid3DAlgorithm = DS3DALG_DEFAULT;
674       dsbd.lpwfxFormat = new0 WAVEFORMATEX[1];
675       dsbd.lpwfxFormat->wFormatTag = WAVE_FORMAT_PCM;
676       dsbd.lpwfxFormat->nChannels = (uint16)nChannels;
677       dsbd.lpwfxFormat->nSamplesPerSec = freq;
678       dsbd.lpwfxFormat->wBitsPerSample = (uint16)bits;
679       dsbd.lpwfxFormat->nBlockAlign = dsbd.lpwfxFormat->nChannels * dsbd.lpwfxFormat->wBitsPerSample / 8;
680       dsbd.lpwfxFormat->nAvgBytesPerSec = dsbd.lpwfxFormat->nSamplesPerSec * dsbd.lpwfxFormat->nBlockAlign;
681
682       if(IDirectSound_CreateSoundBuffer(pDS, &dsbd, &pDSBuffer, null))
683       {
684          delete dsbd.lpwfxFormat;
685          return false;
686       }
687       delete dsbd.lpwfxFormat;
688
689       if(IDirectSoundBuffer_QueryInterface(pDSBuffer, &IID_IDirectSoundNotify, (void**)&pDSNotify))
690       {
691          delete aPosNotify;
692          return false;
693       }
694
695       aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
696       if( aPosNotify == null )
697          return false;
698
699       for( i = 0; i < dwNotifyCount; i++ )
700       {
701          aPosNotify[i].dwOffset     = (dwNotifySize * i) + dwNotifySize - 1;
702          aPosNotify[i].hEventNotify = hNotifyEvent;
703       }
704
705       if(IDirectSoundNotify_SetNotificationPositions(pDSNotify, dwNotifyCount, aPosNotify ))
706       {
707          if(pDSNotify)
708             IDirectSoundNotify_Release(pDSNotify);
709          delete( aPosNotify );
710          return false;
711       }
712
713       if(pDSNotify)
714          IDirectSoundNotify_Release(pDSNotify);
715       delete aPosNotify;
716
717       *ppStreamingSound = StreamingSound
718       {
719          dwCreationFlags = DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME, dwNumBuffers = 1, dwNotifySize = dwNotifySize, dwDSBufferSize = dwDSBufferSize, apDSBuffer = &pDSBuffer,
720
721          callback = callback, data = data
722       };
723       // ppStreamingSound->FillBufferWithSound( pDSBuffer, false );
724       return true;
725    }
726 }
727
728 static DSoundThread dSoundThread { };
729
730 static CSoundManager g_pSoundManager { };
731 static StreamingSound streamingSound;
732
733 static class DSoundThread : Thread
734 {
735    void * g_hNotificationEvent;
736    bool bDone;
737    DSoundThread()
738    {
739       g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
740    }
741    ~DSoundThread()
742    {
743       CloseHandle( g_hNotificationEvent );
744    }
745    uint Main( )
746    {
747       bool filled = false;
748       SetPriority(timeCritical);
749       while( !bDone )
750       {
751          WaitForSingleObject(g_hNotificationEvent, INFINITE);
752          if(streamingSound)
753          {
754             if(!filled)
755             {
756                streamingSound.FillBufferWithSound( streamingSound.GetBuffer( 0 ), false );
757                streamingSound.Play( 0, 0, 0, -1, 0);
758                filled = true;
759             }
760             else if(!streamingSound.HandleWaveStreamNotification())
761             {
762                bDone = true;
763             }
764          }
765       }
766       return 0;
767    }
768 }
769
770 #endif