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