2 * (C) GraÅžvydas "notaz" Ignotas, 2009
\r
4 * This work is licensed under the terms of any of these licenses
\r
6 * - GNU GPL, version 2 or later.
\r
7 * - GNU LGPL, version 2.1 or later.
\r
9 * See the COPYING file in the top-level directory.
\r
13 #define WIN32_LEAN_AND_MEAN
\r
14 #include <windows.h>
\r
15 #include <mmsystem.h>
\r
19 #include "../lprintf.h"
\r
22 #define RELEASE(x) if (x) x->Release(); x=NULL;
\r
24 static LPDIRECTSOUND DSound;
\r
25 static LPDIRECTSOUNDBUFFER LoopBuffer;
\r
26 static LPDIRECTSOUNDNOTIFY DSoundNotify;
\r
27 static HANDLE seg_played_event;
\r
28 static int LoopLen, LoopWrite, LoopSeg; // bytes
\r
30 static int LoopBlank(void)
\r
32 void *mema=NULL,*memb=NULL;
\r
33 DWORD sizea=0,sizeb=0;
\r
35 LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);
\r
37 if (mema) memset(mema,0,sizea);
\r
39 LoopBuffer->Unlock(mema,sizea, memb,sizeb);
\r
44 int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)
\r
48 DSBPOSITIONNOTIFY notifies[NSEGS];
\r
51 memset(&dsbd,0,sizeof(dsbd));
\r
52 memset(&wfx,0,sizeof(wfx));
\r
54 // Make wave format:
\r
55 wfx.wFormatTag=WAVE_FORMAT_PCM;
\r
56 wfx.nChannels=stereo ? 2 : 1;
\r
57 wfx.nSamplesPerSec=rate;
\r
58 wfx.wBitsPerSample=16;
\r
60 wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);
\r
61 wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;
\r
63 // Create the DirectSound interface:
\r
64 DirectSoundCreate(NULL,&DSound,NULL);
\r
65 if (DSound==NULL) return 1;
\r
67 LoopSeg = seg_samples * 2;
\r
71 LoopLen = LoopSeg * NSEGS;
\r
73 DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);
\r
74 dsbd.dwFlags=DSBCAPS_GLOBALFOCUS; // Play in background
\r
75 dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;
\r
77 // Create the looping buffer:
\r
78 dsbd.dwSize=sizeof(dsbd);
\r
79 dsbd.dwBufferBytes=LoopLen;
\r
80 dsbd.lpwfxFormat=&wfx;
\r
82 DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);
\r
83 if (LoopBuffer==NULL) return 1;
\r
85 LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);
\r
86 if (DSoundNotify == NULL) {
\r
87 lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");
\r
91 seg_played_event = CreateEvent(NULL, 0, 0, NULL);
\r
92 if (seg_played_event == NULL)
\r
95 for (i = 0; i < NSEGS; i++) {
\r
96 notifies[i].dwOffset = i * LoopSeg;
\r
97 notifies[i].hEventNotify = seg_played_event;
\r
99 i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);
\r
101 lprintf("SetNotificationPositions failed\n");
\r
107 LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);
\r
111 void DSoundExit(void)
\r
114 LoopBuffer->Stop();
\r
115 RELEASE(DSoundNotify);
\r
116 RELEASE(LoopBuffer)
\r
118 CloseHandle(seg_played_event);
\r
119 seg_played_event = NULL;
\r
122 static int WriteSeg(const void *buff)
\r
124 void *mema=NULL,*memb=NULL;
\r
125 DWORD sizea=0,sizeb=0;
\r
128 // Lock the segment at 'LoopWrite' and copy the next segment in
\r
129 ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);
\r
131 lprintf("LoopBuffer->Lock() failed: %i\n", ret);
\r
133 if (mema) memcpy(mema,buff,sizea);
\r
134 // if (memb) memcpy(memb,DSoundNext+sizea,sizeb);
\r
135 if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);
\r
137 ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);
\r
139 lprintf("LoopBuffer->Unlock() failed: %i\n", ret);
\r
144 int DSoundUpdate(const void *buff, int blocking)
\r
149 LoopBuffer->GetCurrentPosition(&play, NULL);
\r
152 // 'LoopWrite' is the next seg in the loop that we want to write
\r
153 // First check that the sound 'play' pointer has moved out of it:
\r
155 while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {
\r
156 WaitForSingleObject(seg_played_event, 5000);
\r
157 LoopBuffer->GetCurrentPosition(&play, NULL);
\r
162 if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)
\r
168 // Advance LoopWrite to next seg:
\r
169 LoopWrite += LoopSeg;
\r
170 if (LoopWrite + LoopSeg > LoopLen)
\r