PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Chap22/SineWave/SineWave.d

http://github.com/AndrejMitrovic/DWinProgramming
D | 306 lines | 227 code | 66 blank | 13 comment | 16 complexity | a4ad23c707b9fd8e161d926fce45ad99 MD5 | raw file
  1. /+
  2. + Copyright (c) Charles Petzold, 1998.
  3. + Ported to the D Programming Language by Andrej Mitrovic, 2011.
  4. +/
  5. module SineWave;
  6. import core.memory;
  7. import core.runtime;
  8. import core.thread;
  9. import std.algorithm : max, min;
  10. import std.conv;
  11. import std.math;
  12. import std.range;
  13. import std.string;
  14. import std.utf;
  15. auto toUTF16z(S)(S s)
  16. {
  17. return toUTFz!(const(wchar)*)(s);
  18. }
  19. pragma(lib, "gdi32.lib");
  20. pragma(lib, "comdlg32.lib");
  21. pragma(lib, "winmm.lib");
  22. import core.sys.windows.windef;
  23. import core.sys.windows.winuser;
  24. import core.sys.windows.wingdi;
  25. import core.sys.windows.winbase;
  26. import core.sys.windows.commdlg;
  27. import core.sys.windows.mmsystem;
  28. import resource;
  29. string appName = "SineWave";
  30. string description = "";
  31. HINSTANCE hinst;
  32. extern (Windows)
  33. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  34. {
  35. int result;
  36. try
  37. {
  38. Runtime.initialize();
  39. result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
  40. Runtime.terminate();
  41. }
  42. catch (Throwable o)
  43. {
  44. MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
  45. result = 0;
  46. }
  47. return result;
  48. }
  49. int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  50. {
  51. if (DialogBox(hInstance, appName.toUTF16z, NULL, &DlgProc) == -1)
  52. {
  53. MessageBox(NULL, "This program requires Windows NT!",
  54. appName.toUTF16z, MB_ICONERROR);
  55. }
  56. return 0;
  57. }
  58. enum SAMPLE_RATE = 11025;
  59. enum FREQ_MIN = 20;
  60. enum FREQ_MAX = 5000;
  61. enum FREQ_INIT = 440;
  62. enum OUT_BUFFER_SIZE = 4096;
  63. VOID FillBuffer(ref char* pBuffer, int iFreq)
  64. {
  65. static double fAngle = 0.0;
  66. foreach (index; 0 .. OUT_BUFFER_SIZE)
  67. {
  68. pBuffer[index] = cast(char)(127 + 127 * sin(fAngle));
  69. fAngle += 2 * PI * iFreq / SAMPLE_RATE;
  70. if (fAngle > 2 * PI)
  71. fAngle -= 2 * PI;
  72. }
  73. }
  74. VOID FillBuffer(ref ubyte[] pBuffer, int iFreq)
  75. {
  76. static double fAngle = 0.0;
  77. foreach (ref sample; pBuffer)
  78. {
  79. sample = cast(ubyte)(127 + 127 * sin(fAngle));
  80. fAngle += 2 * PI * iFreq / SAMPLE_RATE;
  81. if (fAngle > 2 * PI)
  82. fAngle -= 2 * PI;
  83. }
  84. }
  85. extern (Windows)
  86. BOOL DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  87. {
  88. static BOOL bShutOff, bClosing;
  89. static HWAVEOUT hWaveOut;
  90. static HWND hwndScroll;
  91. static int iFreq = FREQ_INIT;
  92. static ubyte[] pBuffer1, pBuffer2;
  93. static PWAVEHDR pWaveHdr1, pWaveHdr2;
  94. static WAVEFORMATEX waveformat;
  95. int iDummy;
  96. switch (message)
  97. {
  98. case WM_INITDIALOG:
  99. hwndScroll = GetDlgItem(hwnd, IDC_SCROLL);
  100. SetScrollRange(hwndScroll, SB_CTL, FREQ_MIN, FREQ_MAX, FALSE);
  101. SetScrollPos(hwndScroll, SB_CTL, FREQ_INIT, TRUE);
  102. SetDlgItemInt(hwnd, IDC_TEXT, FREQ_INIT, FALSE);
  103. return TRUE;
  104. case WM_HSCROLL:
  105. switch (LOWORD(wParam))
  106. {
  107. case SB_LINELEFT:
  108. iFreq -= 1; break;
  109. case SB_LINERIGHT:
  110. iFreq += 1; break;
  111. case SB_PAGELEFT:
  112. iFreq /= 2; break;
  113. case SB_PAGERIGHT:
  114. iFreq *= 2; break;
  115. case SB_THUMBTRACK:
  116. iFreq = HIWORD(wParam);
  117. break;
  118. case SB_TOP:
  119. GetScrollRange(hwndScroll, SB_CTL, &iFreq, &iDummy);
  120. break;
  121. case SB_BOTTOM:
  122. GetScrollRange(hwndScroll, SB_CTL, &iDummy, &iFreq);
  123. break;
  124. default:
  125. }
  126. iFreq = max(FREQ_MIN, min(FREQ_MAX, iFreq));
  127. SetScrollPos(hwndScroll, SB_CTL, iFreq, TRUE);
  128. SetDlgItemInt(hwnd, IDC_TEXT, iFreq, FALSE);
  129. return TRUE;
  130. case WM_COMMAND:
  131. switch (LOWORD(wParam))
  132. {
  133. case IDC_ONOFF:
  134. // If turning on waveform, hWaveOut is NULL
  135. if (hWaveOut == NULL)
  136. {
  137. // Allocate memory for 2 headers and 2 buffers
  138. pWaveHdr1 = cast(typeof(pWaveHdr1))GC.malloc(WAVEHDR.sizeof);
  139. pWaveHdr2 = cast(typeof(pWaveHdr1))GC.malloc(WAVEHDR.sizeof);
  140. pBuffer1.length = OUT_BUFFER_SIZE;
  141. pBuffer2.length = OUT_BUFFER_SIZE;
  142. // Variable to indicate Off button pressed
  143. bShutOff = FALSE;
  144. // Open waveform audio for output
  145. waveformat.wFormatTag = WAVE_FORMAT_PCM;
  146. waveformat.nChannels = 1;
  147. waveformat.nSamplesPerSec = SAMPLE_RATE;
  148. waveformat.nAvgBytesPerSec = SAMPLE_RATE;
  149. waveformat.nBlockAlign = 1;
  150. waveformat.wBitsPerSample = 8;
  151. waveformat.cbSize = 0;
  152. if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveformat, cast(DWORD)hwnd, 0, CALLBACK_WINDOW)
  153. != MMSYSERR_NOERROR)
  154. {
  155. hWaveOut = cast(typeof(hWaveOut))NULL;
  156. MessageBeep(MB_ICONEXCLAMATION);
  157. MessageBox(hwnd,
  158. "Error opening waveform audio device!",
  159. appName.toUTF16z, MB_ICONEXCLAMATION | MB_OK);
  160. return TRUE;
  161. }
  162. // Set up headers and prepare them
  163. pWaveHdr1.lpData = cast(typeof(pWaveHdr1.lpData))pBuffer1.ptr;
  164. pWaveHdr1.dwBufferLength = OUT_BUFFER_SIZE;
  165. pWaveHdr1.dwBytesRecorded = 0;
  166. pWaveHdr1.dwUser = 0;
  167. pWaveHdr1.dwFlags = 0;
  168. pWaveHdr1.dwLoops = 1;
  169. pWaveHdr1.lpNext = NULL;
  170. pWaveHdr1.reserved = 0;
  171. waveOutPrepareHeader(hWaveOut, pWaveHdr1,
  172. WAVEHDR.sizeof);
  173. pWaveHdr2.lpData = cast(typeof(pWaveHdr2.lpData))pBuffer2.ptr;
  174. pWaveHdr2.dwBufferLength = OUT_BUFFER_SIZE;
  175. pWaveHdr2.dwBytesRecorded = 0;
  176. pWaveHdr2.dwUser = 0;
  177. pWaveHdr2.dwFlags = 0;
  178. pWaveHdr2.dwLoops = 1;
  179. pWaveHdr2.lpNext = NULL;
  180. pWaveHdr2.reserved = 0;
  181. waveOutPrepareHeader(hWaveOut, pWaveHdr2,
  182. WAVEHDR.sizeof);
  183. }
  184. // If turning off waveform, reset waveform audio
  185. else
  186. {
  187. bShutOff = TRUE;
  188. waveOutReset(hWaveOut);
  189. }
  190. return TRUE;
  191. default:
  192. }
  193. break;
  194. // Message generated from waveOutOpen call
  195. case MM_WOM_OPEN:
  196. SetDlgItemText(hwnd, IDC_ONOFF, "Turn Off");
  197. // Send two buffers to waveform output device
  198. FillBuffer(pBuffer1, iFreq);
  199. waveOutWrite(hWaveOut, pWaveHdr1, WAVEHDR.sizeof);
  200. FillBuffer(pBuffer2, iFreq);
  201. waveOutWrite(hWaveOut, pWaveHdr2, WAVEHDR.sizeof);
  202. return TRUE;
  203. // Message generated when a buffer is finished
  204. case MM_WOM_DONE:
  205. if (bShutOff)
  206. {
  207. waveOutClose(hWaveOut);
  208. return TRUE;
  209. }
  210. FillBuffer((cast(PWAVEHDR)lParam).lpData, iFreq);
  211. waveOutWrite(hWaveOut, cast(PWAVEHDR)lParam, WAVEHDR.sizeof);
  212. return TRUE;
  213. case MM_WOM_CLOSE:
  214. waveOutUnprepareHeader(hWaveOut, pWaveHdr1, WAVEHDR.sizeof);
  215. waveOutUnprepareHeader(hWaveOut, pWaveHdr2, WAVEHDR.sizeof);
  216. SetDlgItemText(hwnd, IDC_ONOFF, "Turn On");
  217. hWaveOut = cast(typeof(hWaveOut))NULL;
  218. if (bClosing)
  219. EndDialog(hwnd, 0);
  220. return TRUE;
  221. case WM_SYSCOMMAND:
  222. switch (wParam)
  223. {
  224. case SC_CLOSE:
  225. if (hWaveOut != NULL)
  226. {
  227. bShutOff = TRUE;
  228. bClosing = TRUE;
  229. waveOutReset(hWaveOut);
  230. }
  231. else
  232. EndDialog(hwnd, 0);
  233. return TRUE;
  234. default:
  235. }
  236. break;
  237. default:
  238. }
  239. return FALSE;
  240. }