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 
436     /* Checking for global pointers to buffer and io audio devices */
437     if ((!AUD_IN) || (!AUD_OUT) || (!AUD_BUF))
438     {
439         MessageBox(0, TEXT("Buffer Error"), 0, 0);
440         return 1;
441     }
442 
443     switch (message)
444     {
445         case WM_CREATE:
446             /* Creating the wave bar */
447             if (!InitInstance_wave(hWnd, hInst, SW_SHOWNORMAL))
448             {
449                 MessageBox(0, TEXT("InitInstance_wave() Error!"), TEXT("ERROR"), MB_ICONERROR);
450                 return FALSE;
451             }
452 
453             /* Creating ALL the buttons */
454             for (int i = 0; i < 5; ++i)
455             {
456                 buttons[i] = CreateWindow(TEXT("button"),
457                                           TEXT(""),
458                                           WS_CHILD | WS_VISIBLE | BS_BITMAP,
459                                           BUTTONS_CX + (i * (BUTTONS_W + ((i == 0) ? 0 : BUTTONS_SPACE))),
460                                           BUTTONS_CY,
461                                           BUTTONS_W,
462                                           BUTTONS_H,
463                                           hWnd,
464                                           (HMENU)UlongToPtr(i),
465                                           hInst,
466                                           0);
467                 if (!buttons[i])
468                 {
469                     MessageBox(0, 0, TEXT("CreateWindow() Error!"), 0);
470                     return FALSE;
471                 }
472 
473                 /* Realize the button bmp image */
474                 SendMessage(buttons[i], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps[i]);
475                 UpdateWindow(buttons[i]);
476                 disable_but(i);
477             }
478 
479             /* Creating the SLIDER window */
480             slider = CreateWindow(TRACKBAR_CLASS,
481                                   TEXT(""),
482                                   WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | TBS_ENABLESELRANGE,
483                                   SLIDER_CX,
484                                   SLIDER_CY,
485                                   SLIDER_W,
486                                   SLIDER_H,
487                                   hWnd,
488                                   (HMENU)SLIDER_ID,
489                                   hInst,
490                                   0);
491             if (!slider)
492             {
493                 MessageBox(0, 0, TEXT( "CreateWindow() Error!" ), 0);
494                 return FALSE;
495             }
496 
497             /* Sets slider limits */
498             SendMessage(slider,
499                         TBM_SETRANGE,
500                         (WPARAM)TRUE,
501                         (LPARAM)MAKELONG(slider_min, slider_max));
502 
503             UpdateWindow(slider);
504             enable_but(BUTREC_ID);
505             EnableWindow(slider, FALSE);
506             break;
507 
508         /* Implements slider logic */
509         case WM_HSCROLL:
510         {
511             switch (LOWORD(wParam))
512             {
513                 case SB_ENDSCROLL:
514                     break;
515                 case SB_PAGERIGHT:
516                 case SB_PAGELEFT:
517                 case TB_THUMBTRACK:
518                     /* If the user touch the slider bar, set the
519                        audio start position properly */
520                     slider_pos = SendMessage(slider, TBM_GETPOS, 0, 0);
521                     slid_samp = (__int64)slider_pos * (__int64)samples_max;
522                     AUD_BUF->set_position(AUD_BUF->audinfo().bytes_in_samples((unsigned int)(slid_samp / (__int64)slider_max)));
523                     InvalidateRect(hWnd, &text_rect, TRUE);
524                     break;
525             }
526             break;
527         }
528 
529         case WM_COMMAND:
530             wmId = LOWORD(wParam);
531             if ((wmId >= 0) && (wmId < 5) && (butdisabled[wmId] != FALSE))
532                 break;
533 
534             switch (wmId)
535             {
536                 case ID_FILE_NEW:
537                     if (!isnew)
538                     {
539                         if (AUD_IN->current_status() == snd::WAVEIN_RECORDING)
540                             AUD_IN->stop_recording();
541 
542                         if ((AUD_OUT->current_status() == snd::WAVEOUT_PLAYING) ||
543                             (AUD_OUT->current_status() == snd::WAVEOUT_PAUSED))
544                             AUD_OUT->stop();
545 
546                         AUD_BUF->reset();
547 
548                         enable_but(BUTREC_ID);
549                         disable_but(BUTSTART_ID);
550                         disable_but(BUTEND_ID);
551                         disable_but(BUTSTOP_ID);
552                         disable_but(BUTPLAY_ID);
553 
554                         samples_max = AUD_BUF->total_samples();
555                         slider_pos = 0;
556 
557                         SendMessage(slider, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) slider_pos);
558 
559                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_GRAYED);
560                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_GRAYED);
561 
562                         isnew = TRUE;
563                         display_dur = TRUE;
564 
565                         ZeroMemory(file_path, MAX_PATH * sizeof(TCHAR));
566 
567                         EnableWindow(slider, FALSE);
568 
569                         InvalidateRect(hWnd, &text_rect, TRUE);
570                         InvalidateRect(hWnd, &text2_rect, TRUE);
571                     }
572                     break;
573 
574                 case ID_FILE_OPEN:
575                     ZeroMemory(&ofn, sizeof(ofn));
576 
577                     ofn.lStructSize = sizeof(ofn);
578                     ofn.hwndOwner = hWnd;
579                     ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0");
580                     ofn.lpstrFile = file_path;
581                     ofn.nMaxFile = MAX_PATH;
582                     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
583                     ofn.lpstrDefExt = TEXT("wav");
584 
585                     if (GetOpenFileName(&ofn))
586                     {
587                         open_wav(file_path);
588                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_ENABLED);
589                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_ENABLED);
590 
591                         EnableWindow(slider, TRUE);
592                     }
593 
594                     InvalidateRect(hWnd, &text_rect, TRUE);
595                     InvalidateRect(hWnd, &text2_rect, TRUE);
596                     break;
597 
598                 case ID_ABOUT:
599                     LoadStringW(hInst, IDS_APP_TITLE, szAppName, _countof(szAppName));
600                     ShellAboutW(hWnd, szAppName, NULL,
601                                 LoadIconW(hInst, MAKEINTRESOURCEW(IDI_REACTOS_SNDREC32)));
602                     break;
603 
604                 case ID_FILE_SAVEAS:
605                     ZeroMemory(&ofn, sizeof(ofn));
606 
607                     ofn.lStructSize = sizeof(ofn);
608                     ofn.hwndOwner = hWnd ;
609                     ofn.Flags = OFN_OVERWRITEPROMPT;
610                     ofn.lpstrFilter = TEXT("Audio Files (*.wav)\0*.wav\0All Files (*.*)\0*.*\0");
611                     ofn.lpstrFile = file_path;
612                     ofn.nMaxFile = MAX_PATH;
613 
614                     ofn.lpstrDefExt = TEXT("wav");
615 
616                     if (GetSaveFileName (&ofn))
617                     {
618                         write_wav(file_path);
619                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVE, MF_ENABLED);
620                     }
621                     break;
622 
623 
624                 case ID_EDIT_AUDIOPROPS:
625                     ShellExecute(NULL, NULL, _T("rundll32.exe"), _T("shell32.dll,Control_RunDLL mmsys.cpl,ShowAudioPropertySheet"), NULL, SW_SHOWNORMAL);
626                     break;
627 
628                 case ID_FILE_EXIT:
629                     DestroyWindow(hWnd);
630                     break;
631 
632                 /* Sndrec32 buttons routines */
633                 case BUTSTART_ID:
634                     AUD_BUF->set_position_start();
635                     slider_pos = 0;
636                     SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
637                     break;
638 
639                 case BUTEND_ID:
640                     DestroyWindow(hWnd);
641                     break;
642 
643                 case BUTPLAY_ID:
644                     if (wout_first == false)
645                     {
646                         AUD_OUT->open();
647                         wout_first = true;
648                     }
649 
650                     AUD_OUT->play();
651 
652                     disable_but(BUTSTART_ID);
653                     disable_but(BUTEND_ID);
654                     disable_but(BUTREC_ID);
655                     disable_but(BUTPLAY_ID);
656 
657                     SetTimer(hWnd, 1, 250, 0);
658                     SetTimer(hWnd, WAVEBAR_TIMERID, WAVEBAR_TIMERTIME, 0);
659 
660                     break;
661 
662                 case BUTSTOP_ID:
663                     if (s_recording)
664                     {
665                         s_recording = FALSE;
666 
667                         AUD_IN->stop_recording();
668 
669                         /* Resetting slider position */
670                         slider_pos = 0;
671                         SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
672 
673                         samples_max = AUD_BUF->samples_received();
674 
675                         EnableMenuItem((HMENU)IDR_MENU1, ID_FILE_SAVEAS, MF_ENABLED);
676 
677                         enable_but(BUTSTART_ID);
678                         enable_but(BUTEND_ID);
679                         enable_but(BUTREC_ID);
680                         enable_but(BUTPLAY_ID);
681 
682                         EnableMenuItem(GetMenu(hWnd), ID_FILE_SAVEAS, MF_ENABLED);
683                         EnableWindow(slider, TRUE);
684 
685                         display_dur = FALSE;
686 
687                         AUD_BUF->truncate();
688 
689                         InvalidateRect(hWnd, &text_rect, TRUE);
690                         InvalidateRect(wave_win, 0, TRUE);
691 
692                     }
693                     else
694                     {
695                         AUD_OUT->pause();
696 
697                         enable_but(BUTSTART_ID);
698                         enable_but(BUTEND_ID);
699                         enable_but(BUTREC_ID);
700                         enable_but(BUTPLAY_ID);
701 
702                     }
703 
704                     KillTimer(hWnd, 1);
705                     KillTimer(hWnd, WAVEBAR_TIMERID);
706 
707                     InvalidateRect(hWnd, &text_rect, TRUE);
708 
709                     break;
710 
711                 case BUTREC_ID:
712                     if (win_first == false)
713                     {
714                         AUD_IN->open();
715                         win_first = true;
716                     }
717 
718                     s_recording = TRUE;
719 
720                     samples_max = AUD_BUF->total_samples();
721 
722                     AUD_IN->start_recording();
723 
724                     enable_but(BUTSTOP_ID);
725 
726                     disable_but(BUTSTART_ID);
727                     disable_but(BUTEND_ID);
728                     disable_but(BUTREC_ID);
729                     disable_but(BUTPLAY_ID);
730 
731                     isnew = FALSE;
732 
733                     EnableWindow(slider, FALSE);
734 
735                     SetTimer(hWnd, 1, 150, 0);
736                     SetTimer(hWnd, WAVEBAR_TIMERID, WAVEBAR_TIMERTIME, 0);
737 
738                     break;
739 
740                 default:
741                     return DefWindowProc(hWnd, message, wParam, lParam);
742             }
743             break;
744 
745         case WM_TIMER:
746             switch (wParam)
747             {
748                 case 1:
749                     if (stopped_flag)
750                     {
751                         KillTimer(hWnd, 1);
752                         KillTimer(hWnd, WAVEBAR_TIMERID);
753                         slider_pos = 0;
754                         enable_but(BUTPLAY_ID);
755                         stopped_flag = FALSE;
756                     }
757 
758                     SendMessage(slider, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)slider_pos);
759                     InvalidateRect(hWnd, &text_rect, TRUE);
760                     break;
761 
762                 case WAVEBAR_TIMERID:
763                     InvalidateRect(wave_win, 0, TRUE);
764                     SendMessage(wave_win, WM_USER, 0, 0);
765                     break;
766             }
767             break;
768 
769         case WM_PAINT:
770             hdc = BeginPaint(hWnd, &ps);
771             font = CreateFontIndirect(&s_info.lfMenuFont);
772             oldfont = (HFONT) SelectObject(hdc, font);
773             SetBkMode(hdc, TRANSPARENT);
774 
775             if (AUD_IN->current_status() == snd::WAVEIN_RECORDING)
776             {
777                 gprintf(str_tmp,
778                         MAX_LOADSTRING,
779                         str_pos,
780                         (float)((float)AUD_BUF->bytes_recorded() / (float)AUD_BUF->audinfo().byte_rate()));
781 
782             }
783             else if (AUD_OUT->current_status() == snd::WAVEOUT_PLAYING)
784             {
785                 gprintf(str_tmp,
786                         MAX_LOADSTRING,
787                         str_pos,
788                         (float)((float)AUD_BUF->bytes_played() / (float)AUD_BUF->audinfo().byte_rate()));
789             }
790             else
791             {
792                 gprintf(str_tmp,
793                         MAX_LOADSTRING,
794                         str_pos,
795                         (float)((((float)slider_pos * (float)samples_max) / (float)slider_max) / (float)AUD_BUF->audinfo().sample_rate()));
796             }
797 
798             ExtTextOut(hdc,
799                        STRPOS_X,
800                        STRPOS_Y,
801                        0,
802                        0,
803                        str_tmp,
804                        _tcslen(str_tmp),
805                        0);
806 
807             if (display_dur)
808             {
809                 gprintf(str_tmp,
810                         MAX_LOADSTRING,
811                         str_dur,
812                         AUD_BUF->fseconds_total());
813             }
814             else
815             {
816                 gprintf(str_tmp,
817                         MAX_LOADSTRING,
818                         str_dur,
819                         AUD_BUF->fseconds_recorded());
820             }
821 
822             ExtTextOut(hdc,
823                        STRDUR_X,
824                        STRDUR_Y,
825                        0,
826                        0,
827                        str_tmp,
828                        _tcslen(str_tmp),
829                        0);
830 
831             gprintf(str_tmp,
832                     MAX_LOADSTRING,
833                     str_buf,
834                     (float)((float)AUD_BUF->mem_size() / 1024.0f));
835 
836             ExtTextOut(hdc,
837                        STRBUF_X,
838                        STRBUF_Y,
839                        0,
840                        0,
841                        str_tmp,
842                        _tcslen(str_tmp),
843                        0);
844 
845             gprintf(str_tmp,
846                     MAX_LOADSTRING,
847                     str_fmt,
848                     (float)((float)AUD_BUF->audinfo().sample_rate() / 1000.0f),
849                     AUD_BUF->audinfo().bits(),
850                     AUD_BUF->audinfo().channels() == 2 ? str_mono : str_stereo);
851 
852             ExtTextOut(hdc,
853                        STRFMT_X,
854                        STRFMT_Y,
855                        0,
856                        0,
857                        str_tmp,
858                        _tcslen(str_tmp),
859                        0);
860 
861             gprintf(str_tmp,
862                     MAX_LOADSTRING,
863                     str_chan,
864                     AUD_BUF->audinfo().channels() == 2 ? str_stereo : str_mono);
865 
866             ExtTextOut(hdc,
867                        STRCHAN_X,
868                        STRCHAN_Y,
869                        0,
870                        0,
871                        str_tmp,
872                        _tcslen(str_tmp),
873                        0);
874 
875             SelectObject(hdc, oldfont);
876             DeleteObject(font);
877             EndPaint(hWnd, &ps);
878             break;
879 
880         case WM_DESTROY:
881             PostQuitMessage(0);
882             break;
883         default:
884             return DefWindowProc(hWnd, message, wParam, lParam);
885     }
886 
887     return 0;
888 }
889 
890 void l_play_finished(void)
891 {
892     stopped_flag = true;
893 
894     enable_but(BUTSTART_ID);
895     enable_but(BUTEND_ID);
896     enable_but(BUTREC_ID);
897     enable_but(BUTPLAY_ID);
898 
899     InvalidateRect(wave_win, 0, TRUE);
900 }
901 
902 void l_audio_arrival(unsigned int samples_arrival)
903 {
904     slider_pos += (DWORD)((slider_max * samples_arrival) / samples_max);
905 }
906 
907 void l_buffer_resized(unsigned int new_size)
908 {
909 }
910 
911 VOID enable_but(DWORD id)
912 {
913     butdisabled[id] = FALSE;
914     SendMessage(buttons[id], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps[id]);
915 }
916 
917 VOID disable_but(DWORD id)
918 {
919     butdisabled[id] = TRUE;
920     SendMessage(buttons[id], BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)butbmps_dis[id]);
921 }
922 
923 BOOL open_wav(TCHAR *f)
924 {
925     HANDLE file;
926 
927     riff_hdr r;
928     wave_hdr w;
929     data_chunk d;
930 
931     BOOL b;
932 
933     DWORD bytes_recorded_in_wav = 0;
934     DWORD is_read = 0;
935 
936     file = CreateFile(f,
937                       GENERIC_READ,
938                       0,
939                       0,
940                       OPEN_EXISTING,
941                       FILE_ATTRIBUTE_NORMAL,
942                       0);
943     if (!file)
944     {
945         MessageBox(main_win,
946                    TEXT("Cannot open file. CreateFile() error."),
947                    TEXT("ERROR"),
948                    MB_OK | MB_ICONERROR);
949 
950         return FALSE;
951     }
952 
953     b = ReadFile(file, (LPVOID)&r, sizeof(r), &is_read, 0);
954     if (!b)
955     {
956         MessageBox(main_win,
957                    TEXT("Cannot read RIFF header."),
958                    TEXT("ERROR"),
959                    MB_OK | MB_ICONERROR);
960 
961         CloseHandle(file);
962         return FALSE;
963     }
964 
965     b = ReadFile(file, (LPVOID)&w, sizeof(w), &is_read, 0);
966     if (!b)
967     {
968         MessageBox(main_win,
969                    TEXT("Cannot read WAVE header."),
970                    TEXT("ERROR"),
971                    MB_OK | MB_ICONERROR);
972 
973         CloseHandle(file);
974         return FALSE;
975     }
976 
977     b = ReadFile(file, (LPVOID)&d, sizeof(d), &is_read, 0);
978     if (!b)
979     {
980         MessageBox(main_win,
981                    TEXT("Cannot read WAVE subchunk."),
982                    TEXT("ERROR"),
983                    MB_OK | MB_ICONERROR);
984 
985         CloseHandle(file);
986         return FALSE;
987     }
988 
989     bytes_recorded_in_wav = r.chunksize - 36;
990     if (bytes_recorded_in_wav == 0)
991     {
992         MessageBox(main_win,
993                    TEXT("Cannot read file. No audio data."),
994                    TEXT("ERROR"),
995                    MB_OK | MB_ICONERROR);
996 
997         CloseHandle(file);
998         return FALSE;
999     }
1000 
1001     snd::audio_format openfmt(w.SampleRate, w.BitsPerSample, w.NumChannels);
1002 
1003     AUD_BUF->clear();
1004     AUD_BUF->alloc_bytes(bytes_recorded_in_wav);
1005 
1006     b = ReadFile(file,
1007                  (LPVOID)AUD_BUF->audio_buffer(),
1008                  bytes_recorded_in_wav,
1009                  &is_read,
1010                  0);
1011 
1012     AUD_BUF->set_b_received(bytes_recorded_in_wav);
1013 
1014     if ((!b) || (is_read != bytes_recorded_in_wav))
1015     {
1016         MessageBox(main_win,
1017                    TEXT("Cannot read file. Error reading audio data."),
1018                    TEXT("ERROR"),
1019                    MB_OK | MB_ICONERROR);
1020 
1021         CloseHandle(file);
1022 
1023         AUD_BUF->reset();
1024         return FALSE;
1025     }
1026 
1027     CloseHandle(file);
1028 
1029     enable_but(BUTPLAY_ID);
1030     enable_but(BUTSTOP_ID);
1031     enable_but(BUTSTART_ID);
1032     enable_but(BUTEND_ID);
1033     enable_but(BUTREC_ID);
1034 
1035     samples_max = AUD_BUF->samples_received();
1036 
1037     isnew = FALSE;
1038 
1039     return TRUE;
1040 }
1041 
1042 BOOL
1043 write_wav(TCHAR *f)
1044 {
1045     HANDLE file;
1046     DWORD written;
1047     BOOL is_writ;
1048     int i;
1049     riff_hdr r;
1050     wave_hdr w;
1051     data_chunk d;
1052 
1053     file = CreateFile(f, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
1054     if (!file)
1055     {
1056         i = MessageBox(main_win,
1057                        TEXT("File already exist. Overwrite it?"),
1058                        TEXT("Warning"),
1059                        MB_YESNO | MB_ICONQUESTION);
1060 
1061         if (i == IDYES)
1062         {
1063             file = CreateFile(f, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1064             if (!file)
1065             {
1066                 MessageBox(main_win,
1067                            TEXT("File Error, CreateFile() failed."),
1068                            TEXT("ERROR"),
1069                            MB_OK | MB_ICONERROR);
1070 
1071                 return FALSE;
1072             }
1073 
1074         } else
1075             return FALSE;
1076     }
1077 
1078     r.magic = 0x46464952;
1079     r.format = 0x45564157;
1080     r.chunksize = 36 + AUD_BUF->bytes_recorded();
1081 
1082     w.Subchunkid = 0x20746d66;
1083     w.Subchunk1Size = 16;
1084     w.AudioFormat = 1;
1085     w.NumChannels = AUD_BUF->audinfo().channels();
1086     w.SampleRate = AUD_BUF->audinfo().sample_rate();
1087     w.ByteRate = AUD_BUF->audinfo().byte_rate();
1088     w.BlockAlign = AUD_BUF->audinfo().block_align();
1089     w.BitsPerSample = AUD_BUF->audinfo().bits();
1090 
1091     d.subc = 0x61746164;
1092     d.subc_size = AUD_BUF->bytes_recorded();
1093 
1094     /* Writing headers */
1095     is_writ = WriteFile(file, (LPCVOID)&r, sizeof(r), &written, 0);
1096     if (!is_writ)
1097     {
1098         MessageBox(main_win,
1099                    TEXT("File Error, WriteFile() failed."),
1100                    TEXT("ERROR"),
1101                    MB_OK | MB_ICONERROR);
1102 
1103         CloseHandle(file);
1104         return FALSE;
1105     }
1106 
1107     is_writ = WriteFile(file, (LPCVOID)&w, sizeof(w), &written, 0);
1108     if (!is_writ)
1109     {
1110         MessageBox(main_win,
1111                    TEXT("File Error, WriteFile() failed."),
1112                    TEXT("ERROR"),
1113                    MB_OK | MB_ICONERROR);
1114 
1115         CloseHandle(file);
1116         return FALSE;
1117     }
1118 
1119     is_writ = WriteFile(file, (LPCVOID)&d, sizeof(d), &written, 0);
1120     if (!is_writ)
1121     {
1122         MessageBox(main_win,
1123                    TEXT("File Error, WriteFile() failed."),
1124                    TEXT("ERROR"),
1125                    MB_OK | MB_ICONERROR);
1126 
1127         CloseHandle(file);
1128         return FALSE;
1129     }
1130 
1131     is_writ = WriteFile(file,
1132                         (LPCVOID)AUD_BUF->audio_buffer(),
1133                         AUD_BUF->bytes_recorded(),
1134                         &written,
1135                         0);
1136     if (!is_writ)
1137     {
1138         MessageBox(main_win,
1139                    TEXT("File Error, WriteFile() failed."),
1140                    TEXT("ERROR"),
1141                    MB_OK | MB_ICONERROR);
1142 
1143         CloseHandle(file);
1144         return FALSE;
1145     }
1146 
1147     CloseHandle(file);
1148     return TRUE;
1149 }
1150