1 /* PROJECT:         ReactOS sndrec32
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * FILE:            base/applications/sndrec32/sndrec32.cpp
4  * PURPOSE:         Sound recording
5  * PROGRAMMERS:     Marco Pagliaricci (irc: rendar)
6  *                  Robert Naumann (gonzoMD)
7  */
8 
9 #include "stdafx.h"
10 
11 #include <commctrl.h>
12 #include <commdlg.h>
13 #include <winnls.h>
14 
15 #include "sndrec32.h"
16 #include "shellapi.h"
17 
18 #ifndef _UNICODE
19 #define gprintf _snprintf
20 #else
21 #define gprintf _snwprintf
22 #endif
23 
24 HINSTANCE hInst;
25 TCHAR szTitle[MAX_LOADSTRING];
26 TCHAR szWindowClass[MAX_LOADSTRING];
27 
28 ATOM MyRegisterClass(HINSTANCE hInstance);
29 ATOM MyRegisterClass_wave(HINSTANCE hInstance);
30 BOOL InitInstance(HINSTANCE, int);
31 BOOL InitInstance_wave(HWND, HINSTANCE, int);
32 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
33 LRESULT CALLBACK WndProc_wave(HWND, UINT, WPARAM, LPARAM);
34 
35 BOOL win_first, wout_first;
36 
37 HWND main_win;
38 HWND wave_win;
39 HWND slider;
40 HWND buttons[5];
41 HBITMAP butbmps[5];
42 HBITMAP butbmps_dis[5];
43 WNDPROC buttons_std_proc;
44 
45 BOOL butdisabled[5];
46 BOOL stopped_flag;
47 BOOL isnew;
48 BOOL display_dur;
49 
50 DWORD slider_pos;
51 WORD slider_min;
52 WORD slider_max;
53 
54 DWORD samples_max;
55 
56 OPENFILENAME ofn;
57 TCHAR file_path[MAX_PATH];
58 TCHAR str_pos[MAX_LOADSTRING];
59 TCHAR str_dur[MAX_LOADSTRING];
60 TCHAR str_buf[MAX_LOADSTRING];
61 TCHAR str_fmt[MAX_LOADSTRING];
62 TCHAR str_chan[MAX_LOADSTRING];
63 
64 TCHAR str_mono[10];
65 TCHAR str_stereo[10];
66 
67 BOOL path_set;
68 
69 snd::audio_membuffer *AUD_BUF;
70 snd::audio_waveout *AUD_OUT;
71 snd::audio_wavein *AUD_IN;
72 
73 BOOL s_recording;
74 
75 NONCLIENTMETRICS s_info;
76 
77 RECT text_rect;
78 RECT text2_rect;
79 RECT cli;
80 
81 INT_PTR
82 CALLBACK
83 AboutDlgProc(HWND hWnd,
84              UINT msg,
85              WPARAM wp,
86              LPARAM lp)
87 {
88     switch (msg)
89     {
90         case WM_COMMAND:
91             switch (LOWORD(wp))
92             {
93                 case IDOK:
94                     EndDialog(hWnd, 0);
95                     return TRUE;
96             }
97             break;
98         case WM_CLOSE:
99             EndDialog(hWnd, 0);
100             return TRUE;
101     }
102     return FALSE;
103 }
104 
105 int
106 APIENTRY
107 _tWinMain(HINSTANCE hInstance,
108           HINSTANCE hPrevInstance,
109           LPTSTR lpCmdLine,
110           int nCmdShow)
111 {
112     UNREFERENCED_PARAMETER(hPrevInstance);
113     UNREFERENCED_PARAMETER(lpCmdLine);
114 
115     MSG msg;
116     HACCEL hAccelTable;
117 
118     s_info.cbSize = sizeof( NONCLIENTMETRICS );
119 
120     InitCommonControls();
121 
122 	switch (GetUserDefaultUILanguage())
123     {
124         case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
125             SetProcessDefaultLayout(LAYOUT_RTL);
126             break;
127 
128         default:
129             break;
130     }
131 
132     win_first = wout_first = FALSE;
133 
134     text_rect.left = REFRESHA_X;
135     text_rect.top = REFRESHA_Y;
136     text_rect.right = REFRESHA_CX;
137     text_rect.bottom = REFRESHA_CY;
138 
139     text2_rect.left = REFRESHB_X;
140     text2_rect.top = REFRESHB_Y;
141     text2_rect.right = REFRESHB_CX;
142     text2_rect.bottom = REFRESHB_CY;
143 
144     /* Retrieving default system font, and others system informations */
145     SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
146                          sizeof(NONCLIENTMETRICS),
147                          &s_info,
148                          0);
149 
150     /* Set font size */
151     s_info.lfMenuFont.lfHeight = 14;
152 
153     /* Inits buttons bitmaps */
154 
155     butbmps[0] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_START));
156     butbmps[1] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_END));
157     butbmps[2] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_PLAY));
158     butbmps[3] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_STOP));
159     butbmps[4] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_REC));
160 
161     butbmps_dis[0] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_START_DIS));
162     butbmps_dis[1] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_END_DIS));
163     butbmps_dis[2] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_PLAY_DIS));
164     butbmps_dis[3] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_STOP_DIS));
165     butbmps_dis[4] = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2_REC_DIS));
166 
167     /* Inits audio devices and buffers */
168 
169     snd::audio_membuffer AUD_buffer(snd::A44100_16BIT_STEREO);
170     snd::audio_waveout AUD_waveout(snd::A44100_16BIT_STEREO, AUD_buffer);
171     snd::audio_wavein AUD_wavein(snd::A44100_16BIT_STEREO, AUD_buffer);
172 
173     AUD_buffer.play_finished = l_play_finished;
174     AUD_buffer.audio_arrival = l_audio_arrival;
175     AUD_buffer.buffer_resized = l_buffer_resized;
176 
177     AUD_buffer.alloc_seconds(INITIAL_BUFREC_SECONDS);
178 
179     AUD_IN = &AUD_wavein;
180     AUD_OUT = &AUD_waveout;
181     AUD_BUF = &AUD_buffer;
182 
183     /* Inits slider default parameters */
184 
185     slider_pos = 0;
186     slider_min = 0;
187     slider_max = SLIDER_W;
188 
189     stopped_flag = FALSE;
190     path_set = FALSE;
191     isnew = TRUE;
192     display_dur = TRUE;
193 
194     samples_max = AUD_buffer.total_samples();
195 
196     s_recording = false;
197 
198     /* Inits strings */
199     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
200     LoadString(hInstance, IDC_REACTOS_SNDREC32, szWindowClass, MAX_LOADSTRING);
201     LoadString(hInstance, IDS_STRPOS, str_pos, MAX_LOADSTRING);
202     LoadString(hInstance, IDS_STRDUR, str_dur, MAX_LOADSTRING);
203     LoadString(hInstance, IDS_STRBUF, str_buf, MAX_LOADSTRING);
204     LoadString(hInstance, IDS_STRFMT, str_fmt, MAX_LOADSTRING);
205     LoadString(hInstance, IDS_STRCHAN, str_chan, MAX_LOADSTRING);
206     LoadString(hInstance, IDS_STRMONO, str_mono, 10);
207     LoadString(hInstance, IDS_STRSTEREO, str_stereo, 10);
208 
209     /* Registers sndrec32 window class */
210     MyRegisterClass(hInstance);
211     MyRegisterClass_wave(hInstance);
212 
213     if (!InitInstance(hInstance, nCmdShow))
214     {
215         MessageBox(0, TEXT("CreateWindow() Error!"), TEXT("ERROR"), MB_ICONERROR);
216         return FALSE;
217     }
218 
219     /* Loads key accelerators */
220     hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_REACTOS_SNDREC32));
221 
222     /* Starts main loop */
223     while (GetMessage(&msg, NULL, 0, 0))
224     {
225         if (!TranslateAccelerator(main_win, hAccelTable, &msg))
226         {
227             TranslateMessage(&msg);
228             DispatchMessage(&msg);
229         }
230     }
231 
232     if (wout_first)
233     {
234         AUD_waveout.close();
235     }
236 
237     if (win_first)
238     {
239         AUD_wavein.close();
240     }
241 
242     AUD_buffer.clear();
243 
244     return (int)msg.wParam;
245 }
246 
247 ATOM
248 MyRegisterClass(HINSTANCE hInstance)
249 {
250     WNDCLASSEX wcex;
251 
252     wcex.cbSize = sizeof(WNDCLASSEX);
253 
254     wcex.style = CS_HREDRAW | CS_VREDRAW;
255     wcex.lpfnWndProc = WndProc;
256     wcex.cbClsExtra = 0;
257     wcex.cbWndExtra = 0;
258     wcex.hInstance = hInstance;
259     wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SNDREC32));
260     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
261     wcex.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
262     wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
263     wcex.lpszClassName = szWindowClass;
264     wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SNDREC32));
265 
266     return RegisterClassEx(&wcex);
267 }
268 
269 BOOL
270 InitInstance(HINSTANCE hInstance, int nCmdShow)
271 {
272     HWND hWnd;
273 
274     hInst = hInstance;
275 
276     hWnd = CreateWindow(szWindowClass,
277                         szTitle,
278                         WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
279                         CW_USEDEFAULT,
280                         CW_USEDEFAULT,
281                         MAINWINDOW_W,
282                         MAINWINDOW_H,
283                         NULL,
284                         NULL,
285                         hInstance,
286                         NULL);
287     if (!hWnd)
288     {
289         return FALSE;
290     }
291 
292     ShowWindow(hWnd, nCmdShow);
293     UpdateWindow(hWnd);
294 
295     main_win = hWnd;
296 
297     return TRUE;
298 }
299 
300 ATOM
301 MyRegisterClass_wave(HINSTANCE hInstance)
302 {
303     WNDCLASSEX wcex;
304 
305     wcex.cbSize = sizeof(WNDCLASSEX);
306 
307     wcex.style = CS_HREDRAW | CS_VREDRAW;
308     wcex.lpfnWndProc = WndProc_wave;
309     wcex.cbClsExtra = 0;
310     wcex.cbWndExtra = 0;
311     wcex.hInstance = hInstance;
312     wcex.hIcon = 0;
313     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
314     wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
315     wcex.lpszMenuName = 0;
316     wcex.lpszClassName = TEXT("sndrec32_wave");
317     wcex.hIconSm = 0;
318 
319     return RegisterClassEx(&wcex);
320 }
321 
322 BOOL
323 InitInstance_wave(HWND f,
324                   HINSTANCE hInstance,
325                   int nCmdShow)
326 {
327     HWND hWnd;
328 
329     hInst = hInstance;
330 
331     hWnd = CreateWindowEx(WS_EX_STATICEDGE,
332                           TEXT("sndrec32_wave"),
333                           TEXT(""),
334                           WS_VISIBLE | WS_CHILD,
335                           WAVEBAR_X,
336                           WAVEBAR_Y,
337                           WAVEBAR_CX,
338                           WAVEBAR_CY,
339                           f,
340                           (HMENU)8,
341                           hInstance,
342                           0);
343 
344     if (!hWnd )
345     {
346         return FALSE;
347     }
348 
349     ShowWindow(hWnd, nCmdShow);
350     UpdateWindow(hWnd);
351 
352     wave_win = hWnd;
353 
354     return TRUE;
355 }
356 
357 LRESULT
358 CALLBACK
359 WndProc_wave(HWND hWnd,
360              UINT message,
361              WPARAM wParam,
362              LPARAM lParam)
363 {
364     PAINTSTRUCT ps;
365     HDC hdc;
366     HPEN pen;
367     HPEN oldpen;
368 
369     unsigned int max_h = (cli.bottom / 2);
370     unsigned int samples;
371     unsigned int x, line_h;
372 
373     switch (message)
374     {
375         case WM_CREATE:
376             GetClientRect(hWnd, &cli);
377             break;
378 
379         case WM_PAINT:
380             /* Initialize hdc objects */
381             hdc = BeginPaint(hWnd, &ps);
382             pen = (HPEN)CreatePen(PS_SOLID, 1, WAVEBAR_COLOR);
383             oldpen = (HPEN) SelectObject(hdc, (HBRUSH)pen);
384             if (AUD_OUT->current_status() == snd::WAVEOUT_PLAYING)
385             {
386                 samples = AUD_OUT->tot_samples_buf();
387                 for (unsigned int i = 0; i < WAVEBAR_CX; ++i)
388                 {
389                     x = (i * samples) / WAVEBAR_CX;
390                     line_h = (AUD_OUT->nsample(x) * max_h) / AUD_OUT->samplevalue_max();
391                     if (line_h)
392                     {
393                         MoveToEx(hdc, i, max_h, 0);
394                         LineTo(hdc, i, max_h - (line_h * 2));
395                         LineTo(hdc, i, max_h + (line_h * 2));
396                     }
397                     else
398                     {
399                         SetPixel(hdc, i, max_h, WAVEBAR_COLOR);
400                     }
401                 }
402             }
403             else if (AUD_IN->current_status() == snd::WAVEIN_RECORDING)
404             {
405                 samples = AUD_IN->tot_samples_buf();
406                 for (unsigned int i = 0; i < WAVEBAR_CX; ++i)
407                 {
408                     x = (i * samples) / WAVEBAR_CX;
409                     line_h = (AUD_IN->nsample(x) * max_h) / AUD_IN->samplevalue_max();
410                     if (line_h)
411                     {
412                         MoveToEx(hdc, i, max_h, 0);
413                         LineTo(hdc, i, max_h - (line_h * 2));
414                         LineTo(hdc, i, max_h + (line_h * 2));
415                     }
416                     else
417                     {
418                         SetPixel( hdc, i, max_h, WAVEBAR_COLOR );
419                     }
420                 }
421             }
422             else
423             {
424                 /* In standby mode draw a simple line */
425                 MoveToEx(hdc, 0, cli.bottom / 2, 0);
426                 LineTo(hdc, WAVEBAR_CX, cli.bottom  / 2);
427             }
428 
429             SelectObject(hdc, oldpen);
430             DeleteObject( pen );
431             EndPaint( hWnd, &ps );
432             break;
433 
434         case WM_USER:
435             break;
436 
437         default:
438             return DefWindowProc(hWnd, message, wParam, lParam);
439     }
440 
441     return 0;
442 }
443 
444 LRESULT
445 CALLBACK
446 WndProc(HWND hWnd,
447         UINT message,
448         WPARAM wParam,
449         LPARAM lParam)
450 {
451     int wmId;
452     TCHAR str_tmp[MAX_LOADSTRING];
453     PAINTSTRUCT ps;
454     HDC hdc;
455     HFONT font;
456     HFONT oldfont;
457     long long slid_samp = 0;
458 
459     /* Checking for global pointers to buffer and io audio devices */
460     if ((!AUD_IN) || (!AUD_OUT) || (!AUD_BUF))
461     {
462         MessageBox(0, TEXT("Buffer Error"), 0, 0);
463         return 1;
464     }
465 
466     switch (message)
467     {
468         case WM_CREATE:
469             /* Creating the wave bar */
470             if (!InitInstance_wave(hWnd, hInst, SW_SHOWNORMAL))
471             {
472                 MessageBox(0, TEXT("CreateWindow() Error!"), TEXT("ERROR"), MB_ICONERROR);
473                 return FALSE;
474             }
475 
476             /* Creating ALL the buttons */
477             for (int i = 0; i < 5; ++i)
478             {
479                 buttons[i] = CreateWindow(TEXT("button"),
480                                           TEXT(""),
481                                           WS_CHILD | WS_VISIBLE | BS_BITMAP,
482                                           BUTTONS_CX + (i * (BUTTONS_W + ((i == 0) ? 0 : BUTTONS_SPACE))),
483                                           BUTTONS_CY,
484                                           BUTTONS_W,
485                                           BUTTONS_H,
486                                           hWnd,
487                                           (HMENU)UlongToPtr(i),
488                                           hInst,
489                                           0);
490                 if (!buttons[i])
491                 {
492                     MessageBox(0, 0, TEXT("CreateWindow() Error!"), 0);
493                     return FALSE;
494                 }
495 
496                 /* Realize the button bmp image */
497                 SendMessage(buttons[i], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps[i]);
498                 UpdateWindow(buttons[i]);
499                 disable_but(i);
500             }
501 
502             /* Creating the SLIDER window */
503             slider = CreateWindow(TRACKBAR_CLASS,
504                                   TEXT(""),
505                                   WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | TBS_ENABLESELRANGE,
506                                   SLIDER_CX,
507                                   SLIDER_CY,
508                                   SLIDER_W,
509                                   SLIDER_H,
510                                   hWnd,
511                                   (HMENU)SLIDER_ID,
512                                   hInst,
513                                   0);
514             if (!slider)
515             {
516                 MessageBox(0, 0, TEXT( "CreateWindow() Error!" ), 0);
517                 return FALSE;
518             }
519 
520             /* Sets slider limits */
521             SendMessage(slider,
522                         TBM_SETRANGE,
523                         (WPARAM)TRUE,
524                         (LPARAM)MAKELONG(slider_min, slider_max));
525 
526             UpdateWindow(slider);
527             enable_but(BUTREC_ID);
528             EnableWindow(slider, FALSE);
529             break;
530 
531         /* Implements slider logic */
532         case WM_HSCROLL:
533         {
534             switch (LOWORD(wParam))
535             {
536                 case SB_ENDSCROLL:
537                     break;
538                 case SB_PAGERIGHT:
539                 case SB_PAGELEFT:
540                 case TB_THUMBTRACK:
541                     /* If the user touch the slider bar, set the
542                        audio start position properly */
543                     slider_pos = SendMessage(slider, TBM_GETPOS, 0, 0);
544                     slid_samp = (__int64)slider_pos * (__int64)samples_max;
545                     AUD_BUF->set_position(AUD_BUF->audinfo().bytes_in_samples((unsigned int)(slid_samp / (__int64)slider_max)));
546                     InvalidateRect(hWnd, &text_rect, TRUE);
547                     break;
548             }
549             break;
550         }
551 
552         case WM_COMMAND:
553             wmId = LOWORD(wParam);
554             if ((wmId >= 0) && (wmId < 5) && (butdisabled[wmId] != FALSE))
555                 break;
556 
557             switch (wmId)
558             {
559                 case ID_FILE_NEW:
560                     if (!isnew)
561                     {
562                         if (AUD_IN->current_status() == snd::WAVEIN_RECORDING)
563                             AUD_IN->stop_recording();
564 
565                         if ((AUD_OUT->current_status() == snd::WAVEOUT_PLAYING) ||
566                             (AUD_OUT->current_status() == snd::WAVEOUT_PAUSED))
567                             AUD_OUT->stop();
568 
569                         AUD_BUF->reset();
570 
571                         enable_but(BUTREC_ID);
572                         disable_but(BUTSTART_ID);
573                         disable_but(BUTEND_ID);
574                         disable_but(BUTSTOP_ID);
575                         disable_but(BUTPLAY_ID);
576 
577                         samples_max = AUD_BUF->total_samples();
578                         slider_pos = 0;
579 
580                         SendMessage(slider, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) slider_pos);
581 
582                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_GRAYED);
583                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_GRAYED);
584 
585                         isnew = TRUE;
586                         display_dur = TRUE;
587 
588                         ZeroMemory(file_path, MAX_PATH * sizeof(TCHAR));
589 
590                         EnableWindow(slider, FALSE);
591 
592                         InvalidateRect(hWnd, &text_rect, TRUE);
593                         InvalidateRect(hWnd, &text2_rect, TRUE);
594                     }
595                     break;
596 
597                 case ID_FILE_OPEN:
598                     ZeroMemory(&ofn, sizeof(ofn));
599 
600                     ofn.lStructSize = sizeof(ofn);
601                     ofn.hwndOwner = hWnd;
602                     ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0");
603                     ofn.lpstrFile = file_path;
604                     ofn.nMaxFile = MAX_PATH;
605                     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
606                     ofn.lpstrDefExt = TEXT("wav");
607 
608                     if (GetOpenFileName(&ofn))
609                     {
610                         open_wav(file_path);
611                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_ENABLED);
612                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_ENABLED);
613 
614                         EnableWindow(slider, TRUE);
615                     }
616 
617                     InvalidateRect(hWnd, &text_rect, TRUE);
618                     InvalidateRect(hWnd, &text2_rect, TRUE);
619                     break;
620 
621                 case ID_ABOUT:
622                     DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutDlgProc);
623                     return TRUE;
624                     break;
625 
626                 case ID_FILE_SAVEAS:
627                     ZeroMemory(&ofn, sizeof(ofn));
628 
629                     ofn.lStructSize = sizeof(ofn);
630                     ofn.hwndOwner = hWnd ;
631                     ofn.Flags = OFN_OVERWRITEPROMPT;
632                     ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0");
633                     ofn.lpstrFile = file_path;
634                     ofn.nMaxFile = MAX_PATH;
635 
636                     ofn.lpstrDefExt = TEXT("wav");
637 
638                     if (GetSaveFileName (&ofn))
639                     {
640                         write_wav(file_path);
641                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_ENABLED);
642                     }
643                     break;
644 
645 
646                 case ID_EDIT_AUDIOPROPS:
647                     ShellExecute(NULL, NULL, _T("rundll32.exe"), _T("shell32.dll,Control_RunDLL mmsys.cpl,ShowAudioPropertySheet"), NULL, SW_SHOWNORMAL);
648                     break;
649 
650                 case ID_FILE_EXIT:
651                     DestroyWindow(hWnd);
652                     break;
653 
654                 /* Sndrec32 buttons routines */
655                 case BUTSTART_ID:
656                     AUD_BUF->set_position_start();
657                     slider_pos = 0;
658                     SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
659                     break;
660 
661                 case BUTEND_ID:
662                     DestroyWindow(hWnd);
663                     break;
664 
665                 case BUTPLAY_ID:
666                     if (wout_first == false)
667                     {
668                         AUD_OUT->open();
669                         wout_first = true;
670                     }
671 
672                     AUD_OUT->play();
673 
674                     disable_but(BUTSTART_ID);
675                     disable_but(BUTEND_ID);
676                     disable_but(BUTREC_ID);
677                     disable_but(BUTPLAY_ID);
678 
679                     SetTimer(hWnd, 1, 250, 0);
680                     SetTimer(hWnd, WAVEBAR_TIMERID, WAVEBAR_TIMERTIME, 0);
681 
682                     break;
683 
684                 case BUTSTOP_ID:
685                     if (s_recording)
686                     {
687                         s_recording = FALSE;
688 
689                         AUD_IN->stop_recording();
690 
691                         /* Resetting slider position */
692                         slider_pos = 0;
693                         SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
694 
695                         samples_max = AUD_BUF->samples_received();
696 
697                         EnableMenuItem((HMENU)IDR_MENU1, ID_FILE_SAVEAS, MF_ENABLED);
698 
699                         enable_but(BUTSTART_ID);
700                         enable_but(BUTEND_ID);
701                         enable_but(BUTREC_ID);
702                         enable_but(BUTPLAY_ID);
703 
704                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_ENABLED);
705                         EnableWindow(slider, TRUE);
706 
707                         display_dur = FALSE;
708 
709                         AUD_BUF->truncate();
710 
711                         InvalidateRect(hWnd, &text_rect, TRUE);
712                         InvalidateRect(wave_win, 0, TRUE);
713 
714                     }
715                     else
716                     {
717                         AUD_OUT->pause();
718 
719                         enable_but(BUTSTART_ID);
720                         enable_but(BUTEND_ID);
721                         enable_but(BUTREC_ID);
722                         enable_but(BUTPLAY_ID);
723 
724                     }
725 
726                     KillTimer(hWnd, 1);
727                     KillTimer(hWnd, WAVEBAR_TIMERID);
728 
729                     InvalidateRect(hWnd, &text_rect, TRUE);
730 
731                     break;
732 
733                 case BUTREC_ID:
734                     if (win_first == false)
735                     {
736                         AUD_IN->open();
737                         win_first = true;
738                     }
739 
740                     s_recording = TRUE;
741 
742                     samples_max = AUD_BUF->total_samples();
743 
744                     AUD_IN->start_recording();
745 
746                     enable_but(BUTSTOP_ID);
747 
748                     disable_but(BUTSTART_ID);
749                     disable_but(BUTEND_ID);
750                     disable_but(BUTREC_ID);
751                     disable_but(BUTPLAY_ID);
752 
753                     isnew = FALSE;
754 
755                     EnableWindow(slider, FALSE);
756 
757                     SetTimer(hWnd, 1, 150, 0);
758                     SetTimer(hWnd, WAVEBAR_TIMERID, WAVEBAR_TIMERTIME, 0);
759 
760                     break;
761 
762                 default:
763                     return DefWindowProc(hWnd, message, wParam, lParam);
764             }
765             break;
766 
767         case WM_TIMER:
768             switch (wParam)
769             {
770                 case 1:
771                     if (stopped_flag)
772                     {
773                         KillTimer(hWnd, 1);
774                         KillTimer(hWnd, WAVEBAR_TIMERID);
775                         slider_pos = 0;
776                         enable_but(BUTPLAY_ID);
777                         stopped_flag = FALSE;
778                     }
779 
780                     SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
781                     InvalidateRect(hWnd, &text_rect, TRUE);
782                     break;
783 
784                 case WAVEBAR_TIMERID:
785                     InvalidateRect(wave_win, 0, TRUE);
786                     SendMessage(wave_win, WM_USER, 0, 0);
787                     break;
788             }
789             break;
790 
791         case WM_PAINT:
792             hdc = BeginPaint(hWnd, &ps);
793             font = CreateFontIndirect(&s_info.lfMenuFont);
794             oldfont = (HFONT) SelectObject(hdc, font);
795             SetBkMode(hdc, TRANSPARENT);
796 
797             if (AUD_IN->current_status() == snd::WAVEIN_RECORDING)
798             {
799                 gprintf(str_tmp,
800                         MAX_LOADSTRING,
801                         str_pos,
802                         (float)((float)AUD_BUF->bytes_recorded() / (float)AUD_BUF->audinfo().byte_rate()));
803 
804             }
805             else if (AUD_OUT->current_status() == snd::WAVEOUT_PLAYING)
806             {
807                 gprintf(str_tmp,
808                         MAX_LOADSTRING,
809                         str_pos,
810                         (float)((float)AUD_BUF->bytes_played() / (float)AUD_BUF->audinfo().byte_rate()));
811             }
812             else
813             {
814                 gprintf(str_tmp,
815                         MAX_LOADSTRING,
816                         str_pos,
817                         (float)((((float)slider_pos * (float)samples_max) / (float)slider_max) / (float)AUD_BUF->audinfo().sample_rate()));
818             }
819 
820             ExtTextOut(hdc,
821                        STRPOS_X,
822                        STRPOS_Y,
823                        ETO_OPAQUE,
824                        0,
825                        str_tmp,
826                        _tcslen(str_tmp),
827                        0);
828 
829             if (display_dur)
830             {
831                 gprintf(str_tmp,
832                         MAX_LOADSTRING,
833                         str_dur,
834                         AUD_BUF->fseconds_total());
835             }
836             else
837             {
838                 gprintf(str_tmp,
839                         MAX_LOADSTRING,
840                         str_dur,
841                         AUD_BUF->fseconds_recorded());
842             }
843 
844             ExtTextOut(hdc,
845                        STRDUR_X,
846                        STRDUR_Y,
847                        ETO_OPAQUE,
848                        0,
849                        str_tmp,
850                        _tcslen(str_tmp),
851                        0);
852 
853             gprintf(str_tmp,
854                     MAX_LOADSTRING,
855                     str_buf,
856                     (float)((float)AUD_BUF->mem_size() / 1024.0f));
857 
858             ExtTextOut(hdc,
859                        STRBUF_X,
860                        STRBUF_Y,
861                        ETO_OPAQUE,
862                        0,
863                        str_tmp,
864                        _tcslen(str_tmp),
865                        0);
866 
867             gprintf(str_tmp,
868                     MAX_LOADSTRING,
869                     str_fmt,
870                     (float)((float)AUD_BUF->audinfo().sample_rate() / 1000.0f),
871                     AUD_BUF->audinfo().bits(),
872                     AUD_BUF->audinfo().channels() == 2 ? str_mono : str_stereo);
873 
874             ExtTextOut(hdc,
875                        STRFMT_X,
876                        STRFMT_Y,
877                        ETO_OPAQUE,
878                        0,
879                        str_tmp,
880                        _tcslen(str_tmp),
881                        0);
882 
883             gprintf(str_tmp,
884                     MAX_LOADSTRING,
885                     str_chan,
886                     AUD_BUF->audinfo().channels() == 2 ? str_stereo : str_mono);
887 
888             ExtTextOut(hdc,
889                        STRCHAN_X,
890                        STRCHAN_Y,
891                        ETO_OPAQUE,
892                        0,
893                        str_tmp,
894                        _tcslen(str_tmp),
895                        0);
896 
897             SelectObject(hdc, oldfont);
898             DeleteObject(font);
899             EndPaint(hWnd, &ps);
900             break;
901 
902         case WM_DESTROY:
903             PostQuitMessage(0);
904             break;
905         default:
906             return DefWindowProc(hWnd, message, wParam, lParam);
907     }
908 
909     return 0;
910 }
911 
912 void l_play_finished(void)
913 {
914     stopped_flag = true;
915 
916     enable_but(BUTSTART_ID);
917     enable_but(BUTEND_ID);
918     enable_but(BUTREC_ID);
919     enable_but(BUTPLAY_ID);
920 
921     InvalidateRect(wave_win, 0, TRUE);
922 }
923 
924 void l_audio_arrival(unsigned int samples_arrival)
925 {
926     slider_pos += (DWORD)((slider_max * samples_arrival) / samples_max);
927 }
928 
929 void l_buffer_resized(unsigned int new_size)
930 {
931 }
932 
933 VOID enable_but(DWORD id)
934 {
935     butdisabled[id] = FALSE;
936     SendMessage(buttons[id], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps[id]);
937 }
938 
939 VOID disable_but(DWORD id)
940 {
941     butdisabled[id] = TRUE;
942     SendMessage(buttons[id], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps_dis[id]);
943 }
944 
945 BOOL open_wav(TCHAR *f)
946 {
947     HANDLE file;
948 
949     riff_hdr r;
950     wave_hdr w;
951     data_chunk d;
952 
953     BOOL b;
954 
955     DWORD bytes_recorded_in_wav = 0;
956     DWORD is_read = 0;
957 
958     file = CreateFile(f,
959                       GENERIC_READ,
960                       0,
961                       0,
962                       OPEN_EXISTING,
963                       FILE_ATTRIBUTE_NORMAL,
964                       0);
965     if (!file)
966     {
967         MessageBox(main_win,
968                    TEXT("Cannot open file. CreateFile() error."),
969                    TEXT("ERROR"),
970                    MB_OK | MB_ICONERROR);
971 
972         return FALSE;
973     }
974 
975     b = ReadFile(file, (LPVOID)&r, sizeof(r), &is_read, 0);
976     if (!b)
977     {
978         MessageBox(main_win,
979                    TEXT("Cannot read RIFF header."),
980                    TEXT("ERROR"),
981                    MB_OK | MB_ICONERROR);
982 
983         CloseHandle(file);
984         return FALSE;
985     }
986 
987     b = ReadFile(file, (LPVOID)&w, sizeof(w), &is_read, 0);
988     if (!b)
989     {
990         MessageBox(main_win,
991                    TEXT("Cannot read WAVE header."),
992                    TEXT("ERROR"),
993                    MB_OK | MB_ICONERROR);
994 
995         CloseHandle(file);
996         return FALSE;
997     }
998 
999     b = ReadFile(file, (LPVOID)&d, sizeof(d), &is_read, 0);
1000     if (!b)
1001     {
1002         MessageBox(main_win,
1003                    TEXT("Cannot read WAVE subchunk."),
1004                    TEXT("ERROR"),
1005                    MB_OK | MB_ICONERROR);
1006 
1007         CloseHandle(file);
1008         return FALSE;
1009     }
1010 
1011     bytes_recorded_in_wav = r.chunksize - 36;
1012     if (bytes_recorded_in_wav == 0)
1013     {
1014         MessageBox(main_win,
1015                    TEXT("Cannot read file. No audio data."),
1016                    TEXT("ERROR"),
1017                    MB_OK | MB_ICONERROR);
1018 
1019         CloseHandle(file);
1020         return FALSE;
1021     }
1022 
1023     snd::audio_format openfmt(w.SampleRate, w.BitsPerSample, w.NumChannels);
1024 
1025     AUD_BUF->clear();
1026     AUD_BUF->alloc_bytes(bytes_recorded_in_wav);
1027 
1028     b = ReadFile(file,
1029                  (LPVOID)AUD_BUF->audio_buffer(),
1030                  bytes_recorded_in_wav,
1031                  &is_read,
1032                  0);
1033 
1034     AUD_BUF->set_b_received(bytes_recorded_in_wav);
1035 
1036     if ((!b) || (is_read != bytes_recorded_in_wav))
1037     {
1038         MessageBox(main_win,
1039                    TEXT("Cannot read file. Error reading audio data."),
1040                    TEXT("ERROR"),
1041                    MB_OK | MB_ICONERROR);
1042 
1043         CloseHandle(file);
1044 
1045         AUD_BUF->reset();
1046         return FALSE;
1047     }
1048 
1049     CloseHandle(file);
1050 
1051     enable_but(BUTPLAY_ID);
1052     enable_but(BUTSTOP_ID);
1053     enable_but(BUTSTART_ID);
1054     enable_but(BUTEND_ID);
1055     enable_but(BUTREC_ID);
1056 
1057     samples_max = AUD_BUF->samples_received();
1058 
1059     isnew = FALSE;
1060 
1061     return TRUE;
1062 }
1063 
1064 BOOL
1065 write_wav(TCHAR *f)
1066 {
1067     HANDLE file;
1068     DWORD written;
1069     BOOL is_writ;
1070     int i;
1071     riff_hdr r;
1072     wave_hdr w;
1073     data_chunk d;
1074 
1075     file = CreateFile(f, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
1076     if (!file)
1077     {
1078         i = MessageBox(main_win,
1079                        TEXT("File already exist. Overwrite it?"),
1080                        TEXT("Warning"),
1081                        MB_YESNO | MB_ICONQUESTION);
1082 
1083         if (i == IDYES)
1084         {
1085             file = CreateFile(f, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1086             if (!file)
1087             {
1088                 MessageBox(main_win,
1089                            TEXT("File Error, CreateFile() failed."),
1090                            TEXT("ERROR"),
1091                            MB_OK | MB_ICONERROR);
1092 
1093                 return FALSE;
1094             }
1095 
1096         } else
1097             return FALSE;
1098     }
1099 
1100     r.magic = 0x46464952;
1101     r.format = 0x45564157;
1102     r.chunksize = 36 + AUD_BUF->bytes_recorded();
1103 
1104     w.Subchunkid = 0x20746d66;
1105     w.Subchunk1Size = 16;
1106     w.AudioFormat = 1;
1107     w.NumChannels = AUD_BUF->audinfo().channels();
1108     w.SampleRate = AUD_BUF->audinfo().sample_rate();
1109     w.ByteRate = AUD_BUF->audinfo().byte_rate();
1110     w.BlockAlign = AUD_BUF->audinfo().block_align();
1111     w.BitsPerSample = AUD_BUF->audinfo().bits();
1112 
1113     d.subc = 0x61746164;
1114     d.subc_size = AUD_BUF->bytes_recorded();
1115 
1116     /* Writing headers */
1117     is_writ = WriteFile(file, (LPCVOID)&r, sizeof(r), &written, 0);
1118     if (!is_writ)
1119     {
1120         MessageBox(main_win,
1121                    TEXT("File Error, WriteFile() failed."),
1122                    TEXT("ERROR"),
1123                    MB_OK | MB_ICONERROR);
1124 
1125         CloseHandle(file);
1126         return FALSE;
1127     }
1128 
1129     is_writ = WriteFile(file, (LPCVOID)&w, sizeof(w), &written, 0);
1130     if (!is_writ)
1131     {
1132         MessageBox(main_win,
1133                    TEXT("File Error, WriteFile() failed."),
1134                    TEXT("ERROR"),
1135                    MB_OK | MB_ICONERROR);
1136 
1137         CloseHandle(file);
1138         return FALSE;
1139     }
1140 
1141     is_writ = WriteFile(file, (LPCVOID)&d, sizeof(d), &written, 0);
1142     if (!is_writ)
1143     {
1144         MessageBox(main_win,
1145                    TEXT("File Error, WriteFile() failed."),
1146                    TEXT("ERROR"),
1147                    MB_OK | MB_ICONERROR);
1148 
1149         CloseHandle(file);
1150         return FALSE;
1151     }
1152 
1153     is_writ = WriteFile(file,
1154                         (LPCVOID)AUD_BUF->audio_buffer(),
1155                         AUD_BUF->bytes_recorded(),
1156                         &written,
1157                         0);
1158     if (!is_writ)
1159     {
1160         MessageBox(main_win,
1161                    TEXT("File Error, WriteFile() failed."),
1162                    TEXT("ERROR"),
1163                    MB_OK | MB_ICONERROR);
1164 
1165         CloseHandle(file);
1166         return FALSE;
1167     }
1168 
1169     CloseHandle(file);
1170     return TRUE;
1171 }
1172