PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/Samples/Chap22/todo/Record1/Record1.c

http://github.com/AndrejMitrovic/DWinProgramming
C | 409 lines | 299 code | 82 blank | 28 comment | 23 complexity | b339a3b9608542fce37247fd263e283f MD5 | raw file
  1. /*----------------------------------------
  2. RECORD1.C -- Waveform Audio Recorder
  3. (c) Charles Petzold, 1998
  4. ----------------------------------------*/
  5. #include <windows.h>
  6. #include "resource.h"
  7. #define INP_BUFFER_SIZE 16384
  8. BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ;
  9. TCHAR szAppName [] = "Record1" ;
  10. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  11. PSTR szCmdLine, int iCmdShow)
  12. {
  13. if (-1 == DialogBox (hInstance, "Record", NULL, DlgProc))
  14. {
  15. MessageBox (NULL, "This program requires Windows NT!",
  16. szAppName, MB_ICONERROR) ;
  17. }
  18. return 0 ;
  19. }
  20. void ReverseMemory (BYTE * pBuffer, int iLength)
  21. {
  22. BYTE b ;
  23. int i ;
  24. for (i = 0 ; i < iLength / 2 ; i++)
  25. {
  26. b = pBuffer [i] ;
  27. pBuffer [i] = pBuffer [iLength - i - 1] ;
  28. pBuffer [iLength - i - 1] = b ;
  29. }
  30. }
  31. BOOL CALLBACK DlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  32. {
  33. static BOOL bRecording, bPlaying, bReverse, bPaused,
  34. bEnding, bTerminating ;
  35. static DWORD dwDataLength, dwRepetitions = 1 ;
  36. static HWAVEIN hWaveIn ;
  37. static HWAVEOUT hWaveOut ;
  38. static PBYTE pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ;
  39. static PWAVEHDR pWaveHdr1, pWaveHdr2 ;
  40. static TCHAR szOpenError[] = "Error opening waveform audio!";
  41. static TCHAR szMemError [] = "Error allocating memory!" ;
  42. static WAVEFORMATEX waveform ;
  43. switch (message)
  44. {
  45. case WM_INITDIALOG:
  46. // Allocate memory for wave header
  47. pWaveHdr1 = malloc (sizeof (WAVEHDR)) ;
  48. pWaveHdr2 = malloc (sizeof (WAVEHDR)) ;
  49. // Allocate memory for save buffer
  50. pSaveBuffer = malloc (1) ;
  51. return TRUE ;
  52. case WM_COMMAND:
  53. switch (LOWORD (wParam))
  54. {
  55. case IDC_RECORD_BEG:
  56. // Allocate buffer memory
  57. pBuffer1 = malloc (INP_BUFFER_SIZE) ;
  58. pBuffer2 = malloc (INP_BUFFER_SIZE) ;
  59. if (!pBuffer1 || !pBuffer2)
  60. {
  61. if (pBuffer1) free (pBuffer1) ;
  62. if (pBuffer2) free (pBuffer2) ;
  63. MessageBeep (MB_ICONEXCLAMATION) ;
  64. MessageBox (hwnd, szMemError, szAppName,
  65. MB_ICONEXCLAMATION | MB_OK) ;
  66. return TRUE ;
  67. }
  68. // Open waveform audio for input
  69. waveform.wFormatTag = WAVE_FORMAT_PCM ;
  70. waveform.nChannels = 1 ;
  71. waveform.nSamplesPerSec = 11025 ;
  72. waveform.nAvgBytesPerSec = 11025 ;
  73. waveform.nBlockAlign = 1 ;
  74. waveform.wBitsPerSample = 8 ;
  75. waveform.cbSize = 0 ;
  76. if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,
  77. (DWORD) hwnd, 0, CALLBACK_WINDOW))
  78. {
  79. free (pBuffer1) ;
  80. free (pBuffer2) ;
  81. MessageBeep (MB_ICONEXCLAMATION) ;
  82. MessageBox (hwnd, szOpenError, szAppName,
  83. MB_ICONEXCLAMATION | MB_OK) ;
  84. }
  85. // Set up headers and prepare them
  86. pWaveHdr1->lpData = pBuffer1 ;
  87. pWaveHdr1->dwBufferLength = INP_BUFFER_SIZE ;
  88. pWaveHdr1->dwBytesRecorded = 0 ;
  89. pWaveHdr1->dwUser = 0 ;
  90. pWaveHdr1->dwFlags = 0 ;
  91. pWaveHdr1->dwLoops = 1 ;
  92. pWaveHdr1->lpNext = NULL ;
  93. pWaveHdr1->reserved = 0 ;
  94. waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
  95. pWaveHdr2->lpData = pBuffer2 ;
  96. pWaveHdr2->dwBufferLength = INP_BUFFER_SIZE ;
  97. pWaveHdr2->dwBytesRecorded = 0 ;
  98. pWaveHdr2->dwUser = 0 ;
  99. pWaveHdr2->dwFlags = 0 ;
  100. pWaveHdr2->dwLoops = 1 ;
  101. pWaveHdr2->lpNext = NULL ;
  102. pWaveHdr2->reserved = 0 ;
  103. waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
  104. return TRUE ;
  105. case IDC_RECORD_END:
  106. // Reset input to return last buffer
  107. bEnding = TRUE ;
  108. waveInReset (hWaveIn) ;
  109. return TRUE ;
  110. case IDC_PLAY_BEG:
  111. // Open waveform audio for output
  112. waveform.wFormatTag = WAVE_FORMAT_PCM ;
  113. waveform.nChannels = 1 ;
  114. waveform.nSamplesPerSec = 11025 ;
  115. waveform.nAvgBytesPerSec = 11025 ;
  116. waveform.nBlockAlign = 1 ;
  117. waveform.wBitsPerSample = 8 ;
  118. waveform.cbSize = 0 ;
  119. if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,
  120. (DWORD) hwnd, 0, CALLBACK_WINDOW))
  121. {
  122. MessageBeep (MB_ICONEXCLAMATION) ;
  123. MessageBox (hwnd, szOpenError, szAppName,
  124. MB_ICONEXCLAMATION | MB_OK) ;
  125. }
  126. return TRUE ;
  127. case IDC_PLAY_PAUSE:
  128. // Pause or restart output
  129. if (!bPaused)
  130. {
  131. waveOutPause (hWaveOut) ;
  132. SetDlgItemText (hwnd, IDC_PLAY_PAUSE, "Resume") ;
  133. bPaused = TRUE ;
  134. }
  135. else
  136. {
  137. waveOutRestart (hWaveOut) ;
  138. SetDlgItemText (hwnd, IDC_PLAY_PAUSE, "Pause") ;
  139. bPaused = FALSE ;
  140. }
  141. return TRUE ;
  142. case IDC_PLAY_END:
  143. // Reset output for close preparation
  144. bEnding = TRUE ;
  145. waveOutReset (hWaveOut) ;
  146. return TRUE ;
  147. case IDC_PLAY_REV:
  148. // Reverse save buffer and play
  149. bReverse = TRUE ;
  150. ReverseMemory (pSaveBuffer, dwDataLength) ;
  151. SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ;
  152. return TRUE ;
  153. case IDC_PLAY_REP:
  154. // Set infinite repetitions and play
  155. dwRepetitions = -1 ;
  156. SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ;
  157. return TRUE ;
  158. case IDC_PLAY_SPEED:
  159. // Open waveform audio for fast output
  160. waveform.wFormatTag = WAVE_FORMAT_PCM ;
  161. waveform.nChannels = 1 ;
  162. waveform.nSamplesPerSec = 22050 ;
  163. waveform.nAvgBytesPerSec = 22050 ;
  164. waveform.nBlockAlign = 1 ;
  165. waveform.wBitsPerSample = 8 ;
  166. waveform.cbSize = 0 ;
  167. if (waveOutOpen (&hWaveOut, 0, &waveform, (DWORD) hwnd, 0,
  168. CALLBACK_WINDOW))
  169. {
  170. MessageBeep (MB_ICONEXCLAMATION) ;
  171. MessageBox (hwnd, szOpenError, szAppName,
  172. MB_ICONEXCLAMATION | MB_OK) ;
  173. }
  174. return TRUE ;
  175. }
  176. break ;
  177. case MM_WIM_OPEN:
  178. // Shrink down the save buffer
  179. pSaveBuffer = realloc (pSaveBuffer, 1) ;
  180. // Enable and disable Buttons
  181. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ;
  182. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ;
  183. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE) ;
  184. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;
  185. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ;
  186. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), FALSE) ;
  187. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), FALSE) ;
  188. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ;
  189. SetFocus (GetDlgItem (hwnd, IDC_RECORD_END)) ;
  190. // Add the buffers
  191. waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
  192. waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
  193. // Begin sampling
  194. bRecording = TRUE ;
  195. bEnding = FALSE ;
  196. dwDataLength = 0 ;
  197. waveInStart (hWaveIn) ;
  198. return TRUE ;
  199. case MM_WIM_DATA:
  200. // Reallocate save buffer memory
  201. pNewBuffer = realloc (pSaveBuffer, dwDataLength +
  202. ((PWAVEHDR) lParam)->dwBytesRecorded) ;
  203. if (pNewBuffer == NULL)
  204. {
  205. waveInClose (hWaveIn) ;
  206. MessageBeep (MB_ICONEXCLAMATION) ;
  207. MessageBox (hwnd, szMemError, szAppName,
  208. MB_ICONEXCLAMATION | MB_OK) ;
  209. return TRUE ;
  210. }
  211. pSaveBuffer = pNewBuffer ;
  212. CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,
  213. ((PWAVEHDR) lParam)->dwBytesRecorded) ;
  214. dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;
  215. if (bEnding)
  216. {
  217. waveInClose (hWaveIn) ;
  218. return TRUE ;
  219. }
  220. // Send out a new buffer
  221. waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
  222. return TRUE ;
  223. case MM_WIM_CLOSE:
  224. // Free the buffer memory
  225. waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
  226. waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
  227. free (pBuffer1) ;
  228. free (pBuffer2) ;
  229. // Enable and disable buttons
  230. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ;
  231. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ;
  232. SetFocus (GetDlgItem (hwnd, IDC_RECORD_BEG)) ;
  233. if (dwDataLength > 0)
  234. {
  235. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ;
  236. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;
  237. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ;
  238. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), TRUE) ;
  239. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), TRUE) ;
  240. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE) ;
  241. SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ;
  242. }
  243. bRecording = FALSE ;
  244. if (bTerminating)
  245. SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
  246. return TRUE ;
  247. case MM_WOM_OPEN:
  248. // Enable and disable buttons
  249. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ;
  250. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ;
  251. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE) ;
  252. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), TRUE) ;
  253. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), TRUE) ;
  254. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), FALSE) ;
  255. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), FALSE) ;
  256. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ;
  257. SetFocus (GetDlgItem (hwnd, IDC_PLAY_END)) ;
  258. // Set up header
  259. pWaveHdr1->lpData = pSaveBuffer ;
  260. pWaveHdr1->dwBufferLength = dwDataLength ;
  261. pWaveHdr1->dwBytesRecorded = 0 ;
  262. pWaveHdr1->dwUser = 0 ;
  263. pWaveHdr1->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
  264. pWaveHdr1->dwLoops = dwRepetitions ;
  265. pWaveHdr1->lpNext = NULL ;
  266. pWaveHdr1->reserved = 0 ;
  267. // Prepare and write
  268. waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
  269. waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
  270. bEnding = FALSE ;
  271. bPlaying = TRUE ;
  272. return TRUE ;
  273. case MM_WOM_DONE:
  274. waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
  275. waveOutClose (hWaveOut) ;
  276. return TRUE ;
  277. case MM_WOM_CLOSE:
  278. // Enable and disable buttons
  279. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ;
  280. EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ;
  281. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ;
  282. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;
  283. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ;
  284. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), TRUE) ;
  285. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), TRUE) ;
  286. EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE) ;
  287. SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ;
  288. SetDlgItemText (hwnd, IDC_PLAY_PAUSE, "Pause") ;
  289. bPaused = FALSE ;
  290. dwRepetitions = 1 ;
  291. bPlaying = FALSE ;
  292. if (bReverse)
  293. {
  294. ReverseMemory (pSaveBuffer, dwDataLength) ;
  295. bReverse = FALSE ;
  296. }
  297. if (bTerminating)
  298. SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;
  299. return TRUE ;
  300. case WM_SYSCOMMAND:
  301. switch (LOWORD (wParam))
  302. {
  303. case SC_CLOSE:
  304. if (bRecording)
  305. {
  306. bTerminating = TRUE ;
  307. bEnding = TRUE ;
  308. waveInReset (hWaveIn) ;
  309. return TRUE ;
  310. }
  311. if (bPlaying)
  312. {
  313. bTerminating = TRUE ;
  314. bEnding = TRUE ;
  315. waveOutReset (hWaveOut) ;
  316. return TRUE ;
  317. }
  318. free (pWaveHdr1) ;
  319. free (pWaveHdr2) ;
  320. free (pSaveBuffer) ;
  321. EndDialog (hwnd, 0) ;
  322. return TRUE ;
  323. }
  324. break ;
  325. }
  326. return FALSE ;
  327. }