Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

directsound.cpp

Go to the documentation of this file.
00001 /*
00002         ClanSound, sound mixing library written for ClanLib.
00003         Copyright (c)1998 Magnus Norddahl / ClanSoft.
00004 */
00005 
00006 #ifdef WIN32
00007 #pragma warning (disable:4786)
00008 #endif
00009 
00010 #include "directsound.h"
00011 #include <API/Core/System/error.h>
00012 #include <API/Core/System/cl_assert.h>
00013 #include <Core/System/Win32/init_win32.h>
00014 #include <iostream>
00015 
00016 extern LONG WINAPI MainMessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00017 
00018 bool has_sound = true;
00019 
00020 CL_CSOutput::CL_CSOutput()
00021 : directsound(NULL), soundbuffer(NULL), sleep_event(NULL)
00022 {
00023         HRESULT err;
00024         err = DirectSoundCreate(NULL, &directsound, NULL);
00025         
00026         if (err != DS_OK)
00027         {
00028                 // throw CL_Error("Cannot open sound device.");
00029                 frag_size = 22050/2;
00030                 has_sound = false;
00031                 return;
00032         }
00033 
00034         // We need a hwnd for our directsound interface:
00035         HWND hwnd = NULL;
00036 //      if (CL_Display::cards.size() > 0) hwnd = ((CL_DisplayCard_Win32Compatible *) CL_Display::cards[0])->get_hwnd();
00037         if (hwnd == NULL)
00038         {
00039                 WNDCLASS wndclass;
00040 
00041                 wndclass.style = 0;
00042                 wndclass.lpfnWndProc = (WNDPROC) MainMessageHandler;
00043                 wndclass.cbClsExtra = 0;
00044                 wndclass.cbWndExtra = 0;
00045                 wndclass.hInstance = CL_System_Win32::hInstance;
00046                 wndclass.hIcon = NULL;
00047                 wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
00048                 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
00049                 wndclass.lpszMenuName = "ClanSound";
00050                 wndclass.lpszClassName = "ClanSound";
00051 
00052                 RegisterClass(&wndclass);
00053 
00054                 hwnd = CreateWindow(
00055                         "ClanSound",
00056                         "ClanSound",
00057                         0, // WS_POPUP,
00058                         0,
00059                         0,
00060                         1,
00061                         1,
00062                         NULL,
00063                         NULL,
00064                         CL_System_Win32::hInstance,
00065                         NULL);
00066         }
00067         cl_assert(hwnd != NULL);
00068 
00069         err = directsound->SetCooperativeLevel(hwnd, DSSCL_NORMAL);
00070         cl_assert(err == DS_OK);
00071 
00072 
00073         // Create mixing buffer.
00074         WAVEFORMATEX format;
00075         format.wFormatTag = WAVE_FORMAT_PCM; 
00076         format.nChannels = 2;
00077         format.nSamplesPerSec = 22050;
00078         format.wBitsPerSample = 16;
00079         format.nBlockAlign = format.wBitsPerSample * format.nChannels / 8; 
00080         format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; 
00081         format.cbSize = 0;
00082 
00083         bytes_per_sample = format.nBlockAlign;
00084 
00085         frag_size = 2500; // 0.12 sec latency
00086         int num_fragments = 8;
00087 
00088         DSBUFFERDESC desc;
00089         desc.dwSize = sizeof(DSBUFFERDESC); 
00090         desc.dwFlags = /*DSBCAPS_PRIMARYBUFFER |*/ DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS;
00091 
00092         desc.dwBufferBytes = frag_size * bytes_per_sample * num_fragments;
00093         desc.dwReserved = 0;
00094         desc.lpwfxFormat = &format; 
00095 
00096         err = directsound->CreateSoundBuffer(&desc, &soundbuffer, NULL);
00097         if (err != DS_OK) throw CL_Error("Cannot get primary sound buffer.");
00098 
00099         // Find size of buffer:
00100 
00101         DSBCAPS caps;
00102         memset(&caps, 0, sizeof(DSBCAPS));
00103         caps.dwSize = sizeof(DSBCAPS);
00104         
00105         err = soundbuffer->GetCaps(&caps);
00106         cl_assert(err == DS_OK);
00107 
00108         buffer_size = caps.dwBufferBytes;
00109         cl_assert(buffer_size == frag_size * bytes_per_sample * num_fragments);
00110 
00111         // Clear buffer at beginning (good for debugging):
00112         DWORD size1, size2;
00113         void *ptr1;
00114         void *ptr2;
00115         err = soundbuffer->Lock(0, buffer_size, &ptr1, &size1, &ptr2, &size2, 0);
00116         cl_assert(err == DS_OK);
00117 
00118         memset(ptr1, 0, size1);
00119         if (ptr2 != NULL) memset(ptr2, 0, size2);
00120 
00121         soundbuffer->Unlock(ptr1, size1, ptr2, size2);
00122 
00123         // Setup some sleeping :)
00124         sleep_event = CreateEvent(NULL, TRUE, FALSE, NULL);
00125 
00126         err = soundbuffer->QueryInterface(IID_IDirectSoundNotify, (void **) &notify);
00127 //      cl_assert(err == DS_OK);
00128         if (err != DS_OK) // directsoundnotify doesnt exist on nt4 with dx3. No sound avail.
00129         {
00130                 // throw CL_Error("Cannot open sound device.");
00131                 frag_size = 22050/2;
00132                 has_sound = false;
00133                 return;
00134         }
00135 
00136         DSBPOSITIONNOTIFY *notify_pos = new DSBPOSITIONNOTIFY[num_fragments];
00137         for (int i=0; i<num_fragments; i++)
00138         {
00139                 notify_pos[i].dwOffset = i*frag_size*bytes_per_sample;
00140                 notify_pos[i].hEventNotify = sleep_event;
00141         }
00142         notify->SetNotificationPositions(num_fragments, notify_pos);
00143         delete[] notify_pos;
00144 
00145         err = soundbuffer->Play(0, 0, DSBPLAY_LOOPING);
00146         cl_assert(err == DS_OK);
00147 }
00148 
00149 CL_CSOutput::~CL_CSOutput()
00150 {
00151         if (soundbuffer != NULL) soundbuffer->Release();
00152         if (directsound != NULL) directsound->Release();
00153         if (sleep_event != NULL) CloseHandle(sleep_event);
00154 }
00155 
00156 void CL_CSOutput::silence()
00157 {
00158 }
00159 
00160 bool CL_CSOutput::is_full()
00161 {
00162         if (!has_sound) return false;
00163         
00164         cl_info(info_sound, "CL_CSOutput::is_full() is not implemented! Program will assert now.");
00165         cl_assert(false);
00166         return false;
00167 }
00168 
00169 void CL_CSOutput::write_fragment(short *data)
00170 {
00171         if (!has_sound) return;
00172         
00173         HRESULT err;
00174 
00175         DWORD play, write;
00176         err = soundbuffer->GetCurrentPosition(&play, &write);
00177         cl_assert(err == DS_OK);
00178 
00179         int frag_bytes = frag_size*bytes_per_sample;
00180 
00181         int pos = (write / frag_bytes + 1) * frag_bytes;
00182         if (pos >= buffer_size) pos -= buffer_size;
00183 
00184         DWORD size1, size2;
00185         void *ptr1 = NULL, *ptr2 = NULL;
00186         err = soundbuffer->Lock(
00187                 pos,
00188                 frag_bytes,
00189                 (void **) &ptr1,
00190                 &size1,
00191                 (void **) &ptr2,
00192                 &size2,
00193                 0);
00194         cl_assert(err == DS_OK);
00195 /*
00196         std::cout
00197                 << "#" << pos / frag_bytes
00198                 << " play ptr: " << play
00199                 << ", write ptr: " << write
00200                 << ", pos: " << pos
00201                 << ", size1: " << size1
00202                 << ", size2: " << size2
00203                 << std::endl;
00204 */
00205         char *_data = (char *) data;
00206         if (ptr1 != NULL) memcpy(ptr1, _data, size1);
00207         if (ptr2 != NULL) memcpy(ptr2, _data+size1, size2);
00208 
00209         err = soundbuffer->Unlock(ptr1, size1, ptr2, size2);
00210         cl_assert(err == DS_OK);
00211 }
00212 
00213 void CL_CSOutput::wait()
00214 {
00215         if(!has_sound)
00216         {
00217                 CL_System::sleep(100);
00218                 return;
00219         }
00220         
00221         WaitForSingleObject(sleep_event, INFINITE);
00222         ResetEvent(sleep_event);
00223 }

Generated at Wed Apr 4 19:53:59 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001