1 /**
2  *
3  * Lame ACM wrapper, encode/decode MP3 based RIFF/AVI files in MS Windows
4  *
5  *  Copyright (c) 2002 Steve Lhomme <steve.lhomme at free.fr>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 
23 /*!
24 	\author Steve Lhomme
25 	\version \$Id: ACM.cpp,v 1.20 2007/05/17 22:25:40 robert Exp $
26 */
27 
28 #if !defined(STRICT)
29 #define STRICT
30 #endif // STRICT
31 
32 #include <algorithm>
33 
34 #include <windows.h>
35 #include <windowsx.h>
36 #include <intshcut.h>
37 
38 #include <mmreg.h>
39 #include <msacm.h>
40 #include <msacmdrv.h>
41 
42 #include <assert.h>
43 
44 #include <lame.h>
45 
46 #include "adebug.h"
47 #include "resource.h"
48 #include "ACMStream.h"
49 
50 #ifdef ENABLE_DECODING
51 #include "DecodeStream.h"
52 #endif // ENABLE_DECODING
53 
54 #include "ACM.h"
55 
56 #ifndef IDC_HAND
57 #define IDC_HAND            MAKEINTRESOURCE(32649)
58 #endif // IDC_HAND
59 
60 char ACM::VersionString[120];
61 
62 const char ACM_VERSION[] = "0.9.2";
63 
64 #ifdef WIN32
65 //
66 //  32-bit versions
67 //
68 #if (WINVER >= 0x0400)
69  #define VERSION_ACM_DRIVER  MAKE_ACM_VERSION(4,  0, 0)
70 #else
71 #define VERSION_ACM_DRIVER  MAKE_ACM_VERSION(3, 51, 0)
72 #endif
73 #define VERSION_MSACM MAKE_ACM_VERSION(3, 50, 0)
74 
75 #else
76 //
77 //  16-bit versions
78 //
79 #define VERSION_ACM_DRIVER MAKE_ACM_VERSION(1, 0, 0)
80 #define VERSION_MSACM MAKE_ACM_VERSION(2, 1, 0)
81 
82 #endif
83 
84 #define PERSONAL_FORMAT WAVE_FORMAT_MPEGLAYER3
85 #define SIZE_FORMAT_STRUCT sizeof(MPEGLAYER3WAVEFORMAT)
86 //#define SIZE_FORMAT_STRUCT 0
87 
88 //static const char channel_mode[][13] = {"mono","stereo","joint stereo","dual channel"};
89 static const char channel_mode[][13] = {"mono","stereo"};
90 static const unsigned int mpeg1_freq[] = {48000,44100,32000};
91 static const unsigned int mpeg2_freq[] = {24000,22050,16000,12000,11025,8000};
92 static const unsigned int mpeg1_bitrate[] = {320, 256, 224, 192, 160, 128, 112, 96, 80, 64, 56, 48, 40, 32};
93 static const unsigned int mpeg2_bitrate[] = {160, 144, 128, 112,  96,  80,  64, 56, 48, 40, 32, 24, 16,  8};
94 
95 #define SIZE_CHANNEL_MODE (sizeof(channel_mode)  / (sizeof(char) * 13))
96 #define SIZE_FREQ_MPEG1 (sizeof(mpeg1_freq)    / sizeof(unsigned int))
97 #define SIZE_FREQ_MPEG2 (sizeof(mpeg2_freq)    / sizeof(unsigned int))
98 #define SIZE_BITRATE_MPEG1 (sizeof(mpeg1_bitrate) / sizeof(unsigned int))
99 #define SIZE_BITRATE_MPEG2 (sizeof(mpeg2_bitrate) / sizeof(unsigned int))
100 
101 static const int FORMAT_TAG_MAX_NB = 2; // PCM and PERSONAL (mandatory to have at least PCM and your format)
102 static const int FILTER_TAG_MAX_NB = 0; // this is a codec, not a filter
103 
104 // number of supported PCM formats
105 static const int FORMAT_MAX_NB_PCM =
106 	2 *                                           // number of PCM channel mode (stereo/mono)
107 		(SIZE_FREQ_MPEG1 + // number of MPEG 1 sampling freq
108 		SIZE_FREQ_MPEG2); // number of MPEG 2 sampling freq
109 
110 //////////////////////////////////////////////////////////////////////
111 //
112 //////////////////////////////////////////////////////////////////////
operator <(const bitrate_item & other_bitrate) const113 bool bitrate_item::operator<(const bitrate_item & other_bitrate) const
114 {
115 	return (other_bitrate.frequency < frequency ||
116 		    (other_bitrate.frequency == frequency &&
117 			 (other_bitrate.bitrate < bitrate ||
118 			  (other_bitrate.bitrate == bitrate &&
119 			   (other_bitrate.channels < channels)))));
120 }
121 
122 //////////////////////////////////////////////////////////////////////
123 // Configuration Dialog
124 //////////////////////////////////////////////////////////////////////
125 /*
126 static CALLBACK ConfigProc(
127   HWND hwndDlg,  // handle to dialog box
128 UINT uMsg,     // message
129 WPARAM wParam, // first message parameter
130 LPARAM lParam  // second message parameter
131 )
132 {
133 	BOOL bResult;
134 
135 	switch (uMsg) {
136 		case WM_COMMAND:
137 			UINT command;
138 			command = GET_WM_COMMAND_ID(wParam, lParam);
139             if (IDOK == command)
140             {
141                 EndDialog(hwndDlg, (IDOK == command));
142             } else if (IDCANCEL == command)
143             {
144                 EndDialog(hwndDlg, (IDOK == command));
145             }
146             bResult = FALSE;
147 			break;
148 		default:
149 			bResult = FALSE; // will be treated by DefWindowProc
150 }
151 	return bResult;
152 }
153 
154 
155 inline DWORD ACM::Configure(HWND hParentWindow, LPDRVCONFIGINFO pConfig)
156 {
157 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM : Configure (Parent Window = 0x%08X)",hParentWindow);
158 
159 	DialogBoxParam( my_hModule, MAKEINTRESOURCE(IDD_CONFIG), hParentWindow, ::ConfigProc , (LPARAM)this);
160 
161 	return DRVCNF_OK; // Can also return
162 					// DRVCNF_CANCEL
163 					// and DRVCNF_RESTART
164 }
165 */
166 //////////////////////////////////////////////////////////////////////
167 // About Dialog
168 //////////////////////////////////////////////////////////////////////
169 
AboutProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)170 static BOOL CALLBACK AboutProc(
171   HWND hwndDlg,  // handle to dialog box
172 UINT uMsg,     // message
173 WPARAM wParam, // first message parameter
174 LPARAM lParam  // second message parameter
175 )
176 {
177 	static HBRUSH hBrushStatic = NULL;
178 //	static LOGFONT lf;  // structure for font information
179 //	static HFONT hfnt;
180 	static HCURSOR hcOverCursor = NULL;
181 	BOOL bResult;
182 
183 	switch (uMsg) {
184 		case WM_INITDIALOG:
185 			char tmp[150];
186 			wsprintf(tmp,"LAME MP3 codec v%s", ACM::GetVersionString());
187 			::SetWindowText(GetDlgItem( hwndDlg, IDC_STATIC_ABOUT_TITLE), tmp);
188 
189 /*
190 			::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
191 			lf.lfUnderline = TRUE;
192 
193 			hfnt = ::CreateFontIndirect(&lf);
194 
195 			::SendMessage(::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), WM_SETFONT, (WPARAM) hfnt, TRUE);
196 * /
197 			hBrushStatic = ::CreateSolidBrush(::GetSysColor (COLOR_BTNFACE));
198 */			hcOverCursor = ::LoadCursor(NULL,(LPCTSTR)IDC_HAND);
199 			if (hcOverCursor == NULL)
200 				hcOverCursor = ::LoadCursor(NULL,(LPCTSTR)IDC_CROSS);
201 
202 			bResult = TRUE;
203 			break;
204 /*
205 		case WM_CTLCOLORSTATIC:
206 			/// \todo only if there are URLs
207 			if ((HWND)lParam == ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL))
208 			{
209 				::SetTextColor((HDC)wParam, ::GetSysColor (COLOR_HIGHLIGHT));
210 				::SetBkColor((HDC)wParam, ::GetSysColor (COLOR_BTNFACE));
211 
212 				return (LRESULT) hBrushStatic;
213 			}
214 			else
215 				return (LRESULT) NULL;
216 */
217 		case WM_MOUSEMOVE:
218 			{
219 				POINT pnt;
220 				::GetCursorPos(&pnt);
221 
222 				RECT rect;
223 				::GetWindowRect( ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), &rect);
224 
225 				if (  ::PtInRect(&rect,pnt)  )
226 				{
227 					::SetCursor(hcOverCursor);
228 				}
229 
230 
231 			}
232 			break;
233 
234 		case WM_LBUTTONUP:
235 			{
236 				POINT pnt;
237 				::GetCursorPos(&pnt);
238 
239 				RECT rect;
240 				::GetWindowRect( ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), &rect);
241 
242 				TCHAR Url[200];
243 				bool bUrl = false;
244 				if (::PtInRect(&rect,pnt))
245 				{
246 					wsprintf(Url,get_lame_url());
247 					bUrl = true;
248 				}
249 
250 				if (bUrl)
251 				{
252 					LPSTR tmpStr;
253 					HRESULT hresult = ::TranslateURL(Url, TRANSLATEURL_FL_GUESS_PROTOCOL|TRANSLATEURL_FL_GUESS_PROTOCOL, &tmpStr);
254 					if (hresult == S_OK)
255 						::ShellExecute(hwndDlg,"open",tmpStr,NULL,"",SW_SHOWMAXIMIZED );
256 					else if (hresult == S_FALSE)
257 						::ShellExecute(hwndDlg,"open",Url,NULL,"",SW_SHOWMAXIMIZED );
258 				}
259 
260 			}
261 			break;
262 
263 		case WM_COMMAND:
264 			UINT command;
265 			command = GET_WM_COMMAND_ID(wParam, lParam);
266             if (IDOK == command)
267             {
268                 EndDialog(hwndDlg, TRUE);
269             }
270             bResult = FALSE;
271 			break;
272 
273 		case IDC_STATIC_ABOUT_URL:
274 			break;
275 		default:
276 			bResult = FALSE; // will be treated by DefWindowProc
277 }
278 	return bResult;
279 }
280 
About(HWND hParentWindow)281 inline DWORD ACM::About(HWND hParentWindow)
282 {
283 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM : About (Parent Window = 0x%08X)",hParentWindow);
284 
285 	DialogBoxParam( my_hModule, MAKEINTRESOURCE(IDD_ABOUT), hParentWindow, ::AboutProc , (LPARAM)this);
286 
287 	return DRVCNF_OK; // Can also return
288 // DRVCNF_CANCEL
289 // and DRVCNF_RESTART
290 }
291 
292 
293 //////////////////////////////////////////////////////////////////////
294 // Construction/Destruction
295 //////////////////////////////////////////////////////////////////////
296 
ACM(HMODULE hModule)297 ACM::ACM( HMODULE hModule )
298  :my_hModule(hModule),
299   my_hIcon(NULL),
300   my_debug(ADbg(DEBUG_LEVEL_CREATION)),
301   my_EncodingProperties(hModule)
302 {
303 	my_EncodingProperties.ParamsRestore();
304 
305 	/// \todo get the debug level from the registry
306 	unsigned char DebugFileName[512];
307 
308 	char tmp[128];
309 	wsprintf(tmp,"LAMEacm 0x%08X",this);
310 	my_debug.setPrefix(tmp); /// \todo get it from the registry
311 	my_debug.setIncludeTime(true);  /// \todo get it from the registry
312 
313 	// Check in the registry if we have to Output Debug information
314 	DebugFileName[0] = '\0';
315 
316 	HKEY OssKey;
317 	if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\MUKOLI", 0, KEY_READ , &OssKey ) == ERROR_SUCCESS) {
318 		DWORD DataType;
319 		DWORD DebugFileNameSize = 512;
320 		if (RegQueryValueEx( OssKey, "DebugFile", NULL, &DataType, DebugFileName, &DebugFileNameSize ) == ERROR_SUCCESS) {
321 			if (DataType == REG_SZ) {
322 				my_debug.setUseFile(true);
323 				my_debug.setDebugFile((char *)DebugFileName);
324 				my_debug.OutPut("Debug file is %s",(char *)DebugFileName);
325 			}
326 		}
327 	}
328         wsprintf(VersionString,"%s - %s", ACM_VERSION, get_lame_version() );
329 	BuildBitrateTable();
330 
331 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "New ACM Creation (0x%08X)",this);
332 }
333 
~ACM()334 ACM::~ACM()
335 {
336 // not used, it's done automatically when closing the driver	if (my_hIcon != NULL)
337 //		CloseHandle(my_hIcon);
338 
339 	bitrate_table.clear();
340 
341 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM Deleted (0x%08X)",this);
342 }
343 
344 //////////////////////////////////////////////////////////////////////
345 // Main message handler
346 //////////////////////////////////////////////////////////////////////
347 
DriverProcedure(const HDRVR hdrvr,const UINT msg,LONG lParam1,LONG lParam2)348 LONG ACM::DriverProcedure(const HDRVR hdrvr, const UINT msg, LONG lParam1, LONG lParam2)
349 {
350     DWORD dwRes = 0L;
351 
352 //my_debug.OutPut(DEBUG_LEVEL_MSG, "message 0x%08X for ThisACM 0x%08X", msg, this);
353 
354 switch (msg) {
355     case DRV_INSTALL:
356 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_INSTALL");
357 		// Sent when the driver is installed.
358 		dwRes = DRVCNF_OK;  // Can also return
359 		break;              // DRVCNF_CANCEL
360 							// and DRV_RESTART
361 
362 	case DRV_REMOVE:
363 		// Sent when the driver is removed.
364 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_REMOVE");
365 		dwRes = 1L;  // return value ignored
366 		break;
367 
368     case DRV_QUERYCONFIGURE:
369 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_QUERYCONFIGURE");
370 		// Sent to determine if the driver can be
371 		// configured.
372 		dwRes = 1L;  // Zero indicates configuration
373 		break;       // NOT supported
374 
375 	case DRV_CONFIGURE:
376 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_CONFIGURE");
377 		// Sent to display the configuration
378 		// dialog box for the driver.
379 //		dwRes = Configure( (HWND) lParam1, (LPDRVCONFIGINFO) lParam2 );
380 		if (my_EncodingProperties.Config(my_hModule, (HWND) lParam1))
381 		{
382 			dwRes = DRVCNF_OK; // Can also return
383 					// DRVCNF_CANCEL
384 					// and DRVCNF_RESTART
385 		} else {
386 			dwRes = DRVCNF_CANCEL;
387 		}
388 		break;
389 
390 	/**************************************
391 	// ACM additional messages
392 	***************************************/
393 
394 	case ACMDM_DRIVER_ABOUT:
395 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_ABOUT");
396 
397 		dwRes = About( (HWND) lParam1 );
398 
399         break;
400 
401 	case ACMDM_DRIVER_DETAILS: // acmDriverDetails
402 		// Fill-in general informations about the driver/codec
403 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_DETAILS");
404 
405 		dwRes = OnDriverDetails(hdrvr, (LPACMDRIVERDETAILS) lParam1);
406 
407 		break;
408 
409 	case ACMDM_FORMATTAG_DETAILS: // acmFormatTagDetails
410 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMATTAG_DETAILS");
411 
412 		dwRes = OnFormatTagDetails((LPACMFORMATTAGDETAILS) lParam1, lParam2);
413 
414         break;
415 
416 	case ACMDM_FORMAT_DETAILS: // acmFormatDetails
417 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_DETAILS");
418 
419 		dwRes = OnFormatDetails((LPACMFORMATDETAILS) lParam1, lParam2);
420 
421         break;
422 
423     case ACMDM_FORMAT_SUGGEST: // acmFormatSuggest
424 		// Sent to determine if the driver can be
425 		// configured.
426 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_SUGGEST");
427 		dwRes = OnFormatSuggest((LPACMDRVFORMATSUGGEST) lParam1);
428         break;
429 
430 	/**************************************
431 	// ACM stream messages
432 	***************************************/
433 
434 	case ACMDM_STREAM_OPEN:
435 	// Sent to determine if the driver can be
436 	// configured.
437 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_OPEN");
438 		dwRes = OnStreamOpen((LPACMDRVSTREAMINSTANCE) lParam1);
439         break;
440 
441 	case ACMDM_STREAM_SIZE:
442 	// returns a recommended size for a source
443 	// or destination buffer on an ACM stream
444 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_SIZE");
445 		dwRes = OnStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
446         break;
447 
448 	case ACMDM_STREAM_PREPARE:
449 	// prepares an ACMSTREAMHEADER structure for
450 	// an ACM stream conversion
451 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_PREPARE");
452 		dwRes = OnStreamPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
453         break;
454 
455 	case ACMDM_STREAM_UNPREPARE:
456 	// cleans up the preparation performed by
457 	// the ACMDM_STREAM_PREPARE message for an ACM stream
458 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_UNPREPARE");
459 		dwRes = OnStreamUnPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
460         break;
461 
462 	case ACMDM_STREAM_CONVERT:
463 	// perform a conversion on the specified conversion stream
464 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CONVERT");
465 		dwRes = OnStreamConvert((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMHEADER) lParam2);
466 
467         break;
468 
469 	case ACMDM_STREAM_CLOSE:
470 	// closes an ACM conversion stream
471 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CLOSE");
472 		dwRes = OnStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
473         break;
474 
475 	/**************************************
476 	// Unknown message
477 	***************************************/
478 
479 	default:
480 	// Process any other messages.
481 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACM::DriverProc unknown message (0x%08X), lParam1 = 0x%08X, lParam2 = 0x%08X", msg, lParam1, lParam2);
482 		return DefDriverProc ((DWORD)this, hdrvr, msg, lParam1, lParam2);
483     }
484 
485     return dwRes;
486 }
487 
488 //////////////////////////////////////////////////////////////////////
489 // Special message handlers
490 //////////////////////////////////////////////////////////////////////
491 /*!
492 	Retreive the config details of this ACM driver
493 	The index represent the specified format
494 
495 	\param a_FormatDetails will be filled with all the corresponding data
496 */
OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails,const LPARAM a_Query)497 inline DWORD ACM::OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails, const LPARAM a_Query)
498 {
499 	DWORD Result = ACMERR_NOTPOSSIBLE;
500 
501 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILS a_Query = 0x%08X",a_Query);
502 	switch (a_Query & ACM_FORMATDETAILSF_QUERYMASK) {
503 
504 		// Fill-in the informations corresponding to the FormatDetails->dwFormatTagIndex
505 		case ACM_FORMATDETAILSF_INDEX :
506 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "enter ACM_FORMATDETAILSF_INDEX for index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
507 			if (a_FormatDetails->dwFormatTag == PERSONAL_FORMAT) {
508 				if (a_FormatDetails->dwFormatIndex < GetNumberEncodingFormats()) {
509 					LPWAVEFORMATEX WaveExt;
510 					WaveExt = a_FormatDetails->pwfx;
511 
512 					WaveExt->wFormatTag = PERSONAL_FORMAT;
513 
514 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in  : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
515 					GetMP3FormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
516 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
517 					Result = MMSYSERR_NOERROR;
518 				}
519 				else
520 				{
521 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
522 				}
523 			}
524 			else if (a_FormatDetails->dwFormatTag == WAVE_FORMAT_PCM) {
525 				if (a_FormatDetails->dwFormatIndex < FORMAT_MAX_NB_PCM) {
526 					LPWAVEFORMATEX WaveExt;
527 					WaveExt = a_FormatDetails->pwfx;
528 
529 					WaveExt->wFormatTag = WAVE_FORMAT_PCM;
530 
531 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in  : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
532 					GetPCMFormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
533 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
534 					Result = MMSYSERR_NOERROR;
535 				}
536 				else
537 				{
538 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
539 				}
540 			}
541 			else
542 			{
543 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Unknown a_FormatDetails->dwFormatTag = 0x%08X",a_FormatDetails->dwFormatTag);
544 			}
545 
546 		case ACM_FORMATDETAILSF_FORMAT :
547 			/// \todo we may output the corresponding strong (only for personal format)
548 			LPWAVEFORMATEX WaveExt;
549 			WaveExt = a_FormatDetails->pwfx;
550 
551 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "enter ACM_FORMATDETAILSF_FORMAT : 0x%04X:%03d, format in : channels %d, sample rate %d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex, WaveExt->nChannels, WaveExt->nSamplesPerSec);
552 
553 			Result = MMSYSERR_NOERROR;
554 			break;
555 
556 		default:
557 			Result = ACMERR_NOTPOSSIBLE;
558 			break;
559 	}
560 
561 	a_FormatDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
562 
563 	return Result;
564 }
565 
566 /*!
567 	Retreive the details of each known format by this ACM driver
568 	The index represent the specified format (0 = MP3 / 1 = PCM)
569 
570 	\param a_FormatTagDetails will be filled with all the corresponding data
571 */
OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails,const LPARAM a_Query)572 inline DWORD ACM::OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails, const LPARAM a_Query)
573 {
574 	DWORD Result;
575 	DWORD the_format = WAVE_FORMAT_UNKNOWN; // the format to give details
576 
577 	if (a_FormatTagDetails->cbStruct >= sizeof(*a_FormatTagDetails)) {
578 
579 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACMDM_FORMATTAG_DETAILS, a_Query = 0x%08X",a_Query);
580 		switch(a_Query & ACM_FORMATTAGDETAILSF_QUERYMASK) {
581 
582 			case ACM_FORMATTAGDETAILSF_INDEX:
583 			// Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex
584 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_INDEX for index %03d",a_FormatTagDetails->dwFormatTagIndex);
585 
586 				if (a_FormatTagDetails->dwFormatTagIndex < FORMAT_TAG_MAX_NB) {
587 					switch (a_FormatTagDetails->dwFormatTagIndex)
588 					{
589 					case 0:
590 						the_format = PERSONAL_FORMAT;
591 						break;
592 					default :
593 						the_format = WAVE_FORMAT_PCM;
594 						break;
595 					}
596 				}
597 				else
598 				{
599 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_INDEX for unsupported index %03d",a_FormatTagDetails->dwFormatTagIndex);
600 					Result = ACMERR_NOTPOSSIBLE;
601 				}
602 				break;
603 
604 			case ACM_FORMATTAGDETAILSF_FORMATTAG:
605 			// Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex and hdrvr given
606 				switch (a_FormatTagDetails->dwFormatTag)
607 				{
608 				case WAVE_FORMAT_PCM:
609 					the_format = WAVE_FORMAT_PCM;
610 					break;
611 				case PERSONAL_FORMAT:
612 					the_format = PERSONAL_FORMAT;
613 					break;
614 				default:
615                     return (ACMERR_NOTPOSSIBLE);
616 				}
617 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_FORMATTAG for index 0x%02X, cStandardFormats = %d",a_FormatTagDetails->dwFormatTagIndex,a_FormatTagDetails->cStandardFormats);
618 				break;
619 			case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
620 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_LARGESTSIZE not used");
621 				Result = 0L;
622 				break;
623 			default:
624 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown Format tag query");
625 				Result = MMSYSERR_NOTSUPPORTED;
626 				break;
627 		}
628 
629 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails the_format = 0x%08X",the_format);
630 		switch(the_format)
631 		{
632 			case WAVE_FORMAT_PCM:
633 				a_FormatTagDetails->dwFormatTag      = WAVE_FORMAT_PCM;
634 				a_FormatTagDetails->dwFormatTagIndex = 0;
635 				a_FormatTagDetails->cbFormatSize     = sizeof(PCMWAVEFORMAT);
636 				/// \note 0 may mean we don't know how to decode
637 				a_FormatTagDetails->fdwSupport       = ACMDRIVERDETAILS_SUPPORTF_CODEC;
638 				a_FormatTagDetails->cStandardFormats = FORMAT_MAX_NB_PCM;
639 				// should be filled by Windows				a_FormatTagDetails->szFormatTag[0] = '\0';
640 				Result = MMSYSERR_NOERROR;
641 				break;
642 			case PERSONAL_FORMAT:
643 				a_FormatTagDetails->dwFormatTag      = PERSONAL_FORMAT;
644 				a_FormatTagDetails->dwFormatTagIndex = 1;
645 				a_FormatTagDetails->cbFormatSize     = SIZE_FORMAT_STRUCT;
646 				a_FormatTagDetails->fdwSupport       = ACMDRIVERDETAILS_SUPPORTF_CODEC;
647 				a_FormatTagDetails->cStandardFormats = GetNumberEncodingFormats();
648 				lstrcpyW( a_FormatTagDetails->szFormatTag, L"Lame MP3" );
649 				Result = MMSYSERR_NOERROR;
650 				break;
651 			default:
652 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown format 0x%08X",the_format);
653 				return (ACMERR_NOTPOSSIBLE);
654 		}
655 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails %d possibilities for format 0x%08X",a_FormatTagDetails->cStandardFormats,the_format);
656 	}
657 	else
658 	{
659 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "a_FormatTagDetails->cbStruct < sizeof(*a_FormatDetails)");
660 		Result = ACMERR_NOTPOSSIBLE;
661 	}
662 
663 	return Result;
664 }
665 
666 /*!
667 	Retreive the global details of this ACM driver
668 
669 	\param a_DriverDetail will be filled with all the corresponding data
670 */
OnDriverDetails(const HDRVR hdrvr,LPACMDRIVERDETAILS a_DriverDetail)671 inline DWORD ACM::OnDriverDetails(const HDRVR hdrvr, LPACMDRIVERDETAILS a_DriverDetail)
672 {
673 	if (my_hIcon == NULL)
674 		my_hIcon = LoadIcon(GetDriverModuleHandle(hdrvr), MAKEINTRESOURCE(IDI_ICON));
675 	a_DriverDetail->hicon       = my_hIcon;
676 
677 	a_DriverDetail->fccType     = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
678 	a_DriverDetail->fccComp     = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
679 
680 	/// \note this is an explicit hack of the FhG values
681 	/// \note later it could be a new value when the decoding is done
682 	a_DriverDetail->wMid        = MM_FRAUNHOFER_IIS;
683 	a_DriverDetail->wPid        = MM_FHGIIS_MPEGLAYER3;
684 
685 	a_DriverDetail->vdwACM      = VERSION_MSACM;
686 	a_DriverDetail->vdwDriver   = VERSION_ACM_DRIVER;
687 	a_DriverDetail->fdwSupport  = ACMDRIVERDETAILS_SUPPORTF_CODEC;
688 	a_DriverDetail->cFormatTags = FORMAT_TAG_MAX_NB; // 2 : MP3 and PCM
689 //	a_DriverDetail->cFormatTags = 1; // 2 : MP3 and PCM
690 	a_DriverDetail->cFilterTags = FILTER_TAG_MAX_NB;
691 
692 	lstrcpyW( a_DriverDetail->szShortName, L"LAME MP3" );
693 	char tmpStr[128];
694 	wsprintf(tmpStr, "LAME MP3 Codec v%s", GetVersionString());
695 	int u = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, 0);
696 	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, u);
697 	lstrcpyW( a_DriverDetail->szCopyright, L"2002 Steve Lhomme" );
698 	lstrcpyW( a_DriverDetail->szLicensing, L"LGPL (see gnu.org)" );
699 	/// \todo update this part when the code changes
700 	lstrcpyW( a_DriverDetail->szFeatures , L"only CBR implementation" );
701 
702     return MMSYSERR_NOERROR;  // Can also return DRVCNF_CANCEL
703 }
704 
705 /*!
706 	Suggest an output format for the specified input format
707 
708 	\param a_FormatSuggest will be filled with all the corresponding data
709 */
OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)710 inline DWORD ACM::OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)
711 {
712 	DWORD Result = MMSYSERR_NOTSUPPORTED;
713     DWORD fdwSuggest = (ACM_FORMATSUGGESTF_TYPEMASK & a_FormatSuggest->fdwSuggest);
714 
715 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest %s%s%s%s (0x%08X)",
716 				 (fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS) ? "channels, ":"",
717 				 (fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC) ? "samples/sec, ":"",
718 				 (fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE) ? "bits/sample, ":"",
719 				 (fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG) ? "format, ":"",
720 				 fdwSuggest);
721 
722 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for source format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
723 				 a_FormatSuggest->pwfxSrc->wFormatTag,
724 				 a_FormatSuggest->pwfxSrc->nChannels,
725 				 a_FormatSuggest->pwfxSrc->nSamplesPerSec,
726 				 a_FormatSuggest->pwfxSrc->nAvgBytesPerSec,
727 				 a_FormatSuggest->pwfxSrc->nBlockAlign,
728 				 a_FormatSuggest->pwfxSrc->wBitsPerSample);
729 
730 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggested destination format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
731 			 a_FormatSuggest->pwfxDst->wFormatTag,
732 			 a_FormatSuggest->pwfxDst->nChannels,
733 			 a_FormatSuggest->pwfxDst->nSamplesPerSec,
734 			 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
735 			 a_FormatSuggest->pwfxDst->nBlockAlign,
736 			 a_FormatSuggest->pwfxDst->wBitsPerSample);
737 
738 	switch (a_FormatSuggest->pwfxSrc->wFormatTag)
739 	{
740         case WAVE_FORMAT_PCM:
741 			/// \todo handle here the decoding ?
742 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PCM source");
743             //
744 			//  if the destination format tag is restricted, verify that
745 			//  it is within our capabilities...
746 			//
747 			//  this driver is able to decode to PCM
748 			//
749 			if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
750             {
751                 if (PERSONAL_FORMAT != a_FormatSuggest->pwfxDst->wFormatTag)
752                     return (ACMERR_NOTPOSSIBLE);
753             }
754             else
755 			{
756                 a_FormatSuggest->pwfxDst->wFormatTag = PERSONAL_FORMAT;
757             }
758 
759 
760 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed A");
761             //
762 			//  if the destination channel count is restricted, verify that
763 			//  it is within our capabilities...
764 			//
765 			//  this driver is not able to change the number of channels
766 			//
767 			if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
768             {
769                 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
770                     return (ACMERR_NOTPOSSIBLE);
771             }
772             else
773 			{
774                 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
775             }
776 
777 			if (a_FormatSuggest->pwfxSrc->nChannels != 1 && a_FormatSuggest->pwfxSrc->nChannels != 2)
778 				return MMSYSERR_INVALPARAM;
779 
780 
781 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed B");
782             //
783 			//  if the destination samples per second is restricted, verify
784 			//  that it is within our capabilities...
785 			//
786 			//  this driver is not able to change the sample rate
787 			//
788 			if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
789             {
790                 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
791                     return (ACMERR_NOTPOSSIBLE);
792             }
793             else
794 			{
795                 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
796             }
797 
798 
799 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed C");
800             //
801 			//  if the destination bits per sample is restricted, verify
802 			//  that it is within our capabilities...
803 			//
804 			//  We prefer decoding to 16-bit PCM.
805 			//
806 			if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
807             {
808                 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
809                     return (ACMERR_NOTPOSSIBLE);
810             }
811             else
812 			{
813                 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
814             }
815 
816 			//			a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
817 			a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
818 
819 			a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nChannels * 64000 / 8;
820 
821 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
822 			Result = MMSYSERR_NOERROR;
823 
824 
825 			break;
826 		case PERSONAL_FORMAT:
827 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PERSONAL source");
828             //
829 			//  if the destination format tag is restricted, verify that
830 			//  it is within our capabilities...
831 			//
832 			//  this driver is able to decode to PCM
833 			//
834 			if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
835             {
836                 if (WAVE_FORMAT_PCM != a_FormatSuggest->pwfxDst->wFormatTag)
837                     return (ACMERR_NOTPOSSIBLE);
838             }
839             else
840 			{
841                 a_FormatSuggest->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
842             }
843 
844 
845             //
846 			//  if the destination channel count is restricted, verify that
847 			//  it is within our capabilities...
848 			//
849 			//  this driver is not able to change the number of channels
850 			//
851 			if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
852             {
853                 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
854                     return (ACMERR_NOTPOSSIBLE);
855             }
856             else
857 			{
858                 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
859             }
860 
861 
862             //
863 			//  if the destination samples per second is restricted, verify
864 			//  that it is within our capabilities...
865 			//
866 			//  this driver is not able to change the sample rate
867 			//
868 			if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
869             {
870                 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
871                     return (ACMERR_NOTPOSSIBLE);
872             }
873             else
874 			{
875                 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
876             }
877 
878 
879             //
880 			//  if the destination bits per sample is restricted, verify
881 			//  that it is within our capabilities...
882 			//
883 			//  We prefer decoding to 16-bit PCM.
884 			//
885 			if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
886             {
887                 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
888                     return (ACMERR_NOTPOSSIBLE);
889             }
890             else
891 			{
892                 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
893             }
894 
895 			//			a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
896 			a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
897 
898 			/// \todo this value must be a correct one !
899 			a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nSamplesPerSec * a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
900 
901 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
902 			Result = MMSYSERR_NOERROR;
903 
904 
905 			break;
906 	}
907 
908 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggested destination format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
909 				 a_FormatSuggest->pwfxDst->wFormatTag,
910 				 a_FormatSuggest->pwfxDst->nChannels,
911 				 a_FormatSuggest->pwfxDst->nSamplesPerSec,
912 				 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
913 				 a_FormatSuggest->pwfxDst->nBlockAlign,
914 				 a_FormatSuggest->pwfxDst->wBitsPerSample);
915 
916 	return Result;
917 }
918 
919 /*!
920 	Create a stream instance for decoding/encoding
921 
922 	\param a_StreamInstance contain information about the stream desired
923 */
OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)924 inline DWORD ACM::OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)
925 {
926 	DWORD Result = ACMERR_NOTPOSSIBLE;
927 
928 	//
929 	//  the most important condition to check before doing anything else
930 	//  is that this ACM driver can actually perform the conversion we are
931 	//  being opened for. this check should fail as quickly as possible
932 	//  if the conversion is not possible by this driver.
933 	//
934 	//  it is VERY important to fail quickly so the ACM can attempt to
935 	//  find a driver that is suitable for the conversion. also note that
936 	//  the ACM may call this driver several times with slightly different
937 	//  format specifications before giving up.
938 	//
939 	//  this driver first verifies that the source and destination formats
940 	//  are acceptable...
941 	//
942 	switch (a_StreamInstance->pwfxSrc->wFormatTag)
943 	{
944         case WAVE_FORMAT_PCM:
945 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PCM source (%05d samples %d channels %d bits/sample)",a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxSrc->nChannels,a_StreamInstance->pwfxSrc->wBitsPerSample);
946 			if (a_StreamInstance->pwfxDst->wFormatTag == PERSONAL_FORMAT)
947 			{
948 				unsigned int OutputFrequency;
949 
950 				/// \todo Smart mode
951 				if (my_EncodingProperties.GetSmartOutputMode())
952 					OutputFrequency = ACMStream::GetOutputSampleRate(a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxDst->nAvgBytesPerSec,a_StreamInstance->pwfxDst->nChannels);
953 				else
954 					OutputFrequency = a_StreamInstance->pwfxSrc->nSamplesPerSec;
955 
956 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PERSONAL output (%05d samples %d channels %d bits/sample %d kbps)",a_StreamInstance->pwfxDst->nSamplesPerSec,a_StreamInstance->pwfxDst->nChannels,a_StreamInstance->pwfxDst->wBitsPerSample,8 * a_StreamInstance->pwfxDst->nAvgBytesPerSec);
957 
958 				/// \todo add the possibility to have channel resampling (mono to stereo / stereo to mono)
959 				/// \todo support resampling ?
960 				/// \todo only do the test on OutputFrequency in "Smart Output" mode
961 				if (a_StreamInstance->pwfxDst->nSamplesPerSec != OutputFrequency ||
962 //					a_StreamInstance->pwfxSrc->nSamplesPerSec != a_StreamInstance->pwfxDst->nSamplesPerSec ||
963 					a_StreamInstance->pwfxSrc->nChannels != a_StreamInstance->pwfxDst->nChannels ||
964 					a_StreamInstance->pwfxSrc->wBitsPerSample != 16)
965 				{
966 					Result = ACMERR_NOTPOSSIBLE;
967 				} else {
968 					if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
969 					{
970 						ACMStream * the_stream = ACMStream::Create();
971 						a_StreamInstance->dwInstance = (DWORD) the_stream;
972 
973 						if (the_stream != NULL)
974 						{
975 							MPEGLAYER3WAVEFORMAT * casted = (MPEGLAYER3WAVEFORMAT *) a_StreamInstance->pwfxDst;
976 							vbr_mode a_mode = (casted->fdwFlags-2 == 0)?vbr_abr:vbr_off;
977 							if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
978 												 OutputFrequency,
979 												 a_StreamInstance->pwfxDst->nChannels,
980 												 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
981 												 a_mode))
982 								Result = MMSYSERR_NOERROR;
983 							else
984 								ACMStream::Erase( the_stream );
985 						}
986 					}
987 					else
988 					{
989 						Result = MMSYSERR_NOERROR;
990 					}
991 				}
992 			}
993 			break;
994 		case PERSONAL_FORMAT:
995 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PERSONAL source (%05d samples %d channels %d bits/sample %d kbps)",a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxSrc->nChannels,a_StreamInstance->pwfxSrc->wBitsPerSample,8 * a_StreamInstance->pwfxSrc->nAvgBytesPerSec);
996 			if (a_StreamInstance->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
997 			{
998 #ifdef ENABLE_DECODING
999 				if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
1000 				{
1001 					/// \todo create the decoding stream
1002 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PCM output (%05d samples %d channels %d bits/sample %d B/s)",a_StreamInstance->pwfxDst->nSamplesPerSec,a_StreamInstance->pwfxDst->nChannels,a_StreamInstance->pwfxDst->wBitsPerSample,a_StreamInstance->pwfxDst->nAvgBytesPerSec);
1003 
1004 					DecodeStream * the_stream = DecodeStream::Create();
1005 					a_StreamInstance->dwInstance = (DWORD) the_stream;
1006 
1007 					if (the_stream != NULL)
1008 					{
1009 						if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
1010 											 a_StreamInstance->pwfxDst->nChannels,
1011 											 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
1012 											 a_StreamInstance->pwfxSrc->nAvgBytesPerSec))
1013 							Result = MMSYSERR_NOERROR;
1014 						else
1015 							DecodeStream::Erase( the_stream );
1016 					}
1017 				}
1018 				else
1019 				{
1020 					/// \todo decoding verification
1021 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream is valid");
1022 					Result = MMSYSERR_NOERROR;
1023 				}
1024 #endif // ENABLE_DECODING
1025 			}
1026 			break;
1027 	}
1028 
1029 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream Result = %d",Result);
1030 	return Result;
1031 }
1032 
OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMSIZE the_StreamSize)1033 inline DWORD ACM::OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMSIZE the_StreamSize)
1034 {
1035 	DWORD Result = ACMERR_NOTPOSSIBLE;
1036 
1037     switch (ACM_STREAMSIZEF_QUERYMASK & the_StreamSize->fdwSize)
1038     {
1039 	case ACM_STREAMSIZEF_DESTINATION:
1040 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get source buffer size for destination size = %d",the_StreamSize->cbDstLength);
1041 		break;
1042 	case ACM_STREAMSIZEF_SOURCE:
1043 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get destination buffer size for source size = %d",the_StreamSize->cbSrcLength);
1044         if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1045 			PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1046         {
1047 			ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1048 			if (the_stream != NULL)
1049 			{
1050 				the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1051 				Result = MMSYSERR_NOERROR;
1052 			}
1053 		}
1054         else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1055 			 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1056 		{
1057 #ifdef ENABLE_DECODING
1058 			DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1059 			if (the_stream != NULL)
1060 			{
1061 				the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1062 				Result = MMSYSERR_NOERROR;
1063 			}
1064 #endif // ENABLE_DECODING
1065 		}
1066 		break;
1067 	default:
1068 		Result = MMSYSERR_INVALFLAG;
1069 		break;
1070 	}
1071 
1072 	return Result;
1073 }
1074 
OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)1075 inline DWORD ACM::OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)
1076 {
1077 	DWORD Result = ACMERR_NOTPOSSIBLE;
1078 
1079 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamClose the stream 0x%X",a_StreamInstance->dwInstance);
1080     if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1081 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1082     {
1083 	ACMStream::Erase( (ACMStream *) a_StreamInstance->dwInstance );
1084 	}
1085     else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1086 		 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1087     {
1088 #ifdef ENABLE_DECODING
1089 		DecodeStream::Erase( (DecodeStream *) a_StreamInstance->dwInstance );
1090 #endif // ENABLE_DECODING
1091 	}
1092 
1093 	// nothing to do yet
1094 	Result = MMSYSERR_NOERROR;
1095 
1096 	return Result;
1097 }
1098 
OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1099 inline DWORD ACM::OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1100 {
1101 	DWORD Result = ACMERR_NOTPOSSIBLE;
1102 
1103 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "  prepare : Src : %d (0x%08X) / %d - Dst : %d (0x%08X) / %d"
1104 												, a_StreamHeader->cbSrcLength
1105 												, a_StreamHeader->pbSrc
1106 												, a_StreamHeader->cbSrcLengthUsed
1107 												, a_StreamHeader->cbDstLength
1108 												, a_StreamHeader->pbDst
1109 												, a_StreamHeader->cbDstLengthUsed
1110 											  );
1111 
1112 	if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1113 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1114 	{
1115 		ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1116 
1117 		if (the_stream->open(my_EncodingProperties))
1118 			Result = MMSYSERR_NOERROR;
1119 	}
1120 	else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1121 		     WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1122 	{
1123 #ifdef ENABLE_DECODING
1124 		DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1125 
1126 		if (the_stream->open())
1127 			Result = MMSYSERR_NOERROR;
1128 #endif // ENABLE_DECODING
1129 	}
1130 
1131 	return Result;
1132 }
1133 
OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1134 inline DWORD ACM::OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1135 {
1136 	DWORD Result = ACMERR_NOTPOSSIBLE;
1137 
1138 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "unprepare : Src : %d / %d - Dst : %d / %d"
1139 											, a_StreamHeader->cbSrcLength
1140 											, a_StreamHeader->cbSrcLengthUsed
1141 											, a_StreamHeader->cbDstLength
1142 											, a_StreamHeader->cbDstLengthUsed
1143 											);
1144     if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1145 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1146     {
1147 	ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1148 	DWORD OutputSize = a_StreamHeader->cbDstLength;
1149 
1150 	if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1151 	{
1152 		a_StreamHeader->cbDstLengthUsed = OutputSize;
1153 			Result = MMSYSERR_NOERROR;
1154 		}
1155 	}
1156     else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1157 		 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1158     {
1159 #ifdef ENABLE_DECODING
1160 		DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1161 		DWORD OutputSize = a_StreamHeader->cbDstLength;
1162 
1163 		if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1164 		{
1165 			a_StreamHeader->cbDstLengthUsed = OutputSize;
1166 			Result = MMSYSERR_NOERROR;
1167 	}
1168 #endif // ENABLE_DECODING
1169 	}
1170 
1171 	return Result;
1172 }
1173 
OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMHEADER a_StreamHeader)1174 inline DWORD ACM::OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMHEADER a_StreamHeader)
1175 {
1176 	DWORD Result = ACMERR_NOTPOSSIBLE;
1177 
1178 	if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1179 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1180 	{
1181 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = PCM (encode)");
1182 
1183 		ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1184 		if (the_stream != NULL)
1185 		{
1186 			if (the_stream->ConvertBuffer( a_StreamHeader ))
1187 				Result = MMSYSERR_NOERROR;
1188 		}
1189 	}
1190 	else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1191 		     WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1192 	{
1193 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = MP3 (decode)");
1194 
1195 #ifdef ENABLE_DECODING
1196 		DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1197 		if (the_stream != NULL)
1198 		{
1199 			if (the_stream->ConvertBuffer( a_StreamHeader ))
1200 				Result = MMSYSERR_NOERROR;
1201 		}
1202 #endif // ENABLE_DECODING
1203 	}
1204 	else
1205 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert unsupported conversion");
1206 
1207 	return Result;
1208 }
1209 
1210 
GetMP3FormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1211 void ACM::GetMP3FormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1212 {
1213 	int Block_size;
1214     char temp[ACMFORMATDETAILS_FORMAT_CHARS];
1215 
1216 
1217 	if (the_Index < bitrate_table.size())
1218 	{
1219 	//	the_Format.wBitsPerSample = 16;
1220 		the_Format.wBitsPerSample = 0;
1221 
1222 		/// \todo handle more channel modes (mono, stereo, joint-stereo, dual-channel)
1223 	//	the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1224 
1225 		the_Format.nBlockAlign = 1;
1226 
1227 		the_Format.nSamplesPerSec = bitrate_table[the_Index].frequency;
1228 		the_Format.nAvgBytesPerSec = bitrate_table[the_Index].bitrate * 1000 / 8;
1229 		if (bitrate_table[the_Index].frequency >= mpeg1_freq[SIZE_FREQ_MPEG1-1])
1230 			Block_size = 1152;
1231 		else
1232 			Block_size = 576;
1233 
1234 		the_Format.nChannels = bitrate_table[the_Index].channels;
1235 
1236 		the_Format.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
1237 		MPEGLAYER3WAVEFORMAT * tmpFormat = (MPEGLAYER3WAVEFORMAT *) &the_Format;
1238 		tmpFormat->wID             = 1;
1239 		// this is the only way I found to know if we do CBR or ABR
1240 		tmpFormat->fdwFlags        = 2 + ((bitrate_table[the_Index].mode == vbr_abr)?0:2);
1241 		tmpFormat->nBlockSize      = Block_size * the_Format.nAvgBytesPerSec / the_Format.nSamplesPerSec;
1242 		tmpFormat->nFramesPerBlock = 1;
1243 		tmpFormat->nCodecDelay     = 0; // 0x0571 on FHG
1244 
1245          /// \todo : generate the string with the appropriate stereo mode
1246          if (bitrate_table[the_Index].mode == vbr_abr)
1247              wsprintfA( temp, "%d Hz, %d kbps ABR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1248          else
1249              wsprintfA( temp, "%d Hz, %d kbps CBR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1250 
1251          MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, the_String, ACMFORMATDETAILS_FORMAT_CHARS);
1252      }
1253  }
1254 
GetPCMFormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1255 void ACM::GetPCMFormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1256 {
1257 	the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1258 	the_Format.wBitsPerSample = 16;
1259 	the_Format.nBlockAlign = the_Format.nChannels * the_Format.wBitsPerSample / 8;
1260 
1261 
1262 	DWORD a_Channel_Independent = the_Index / SIZE_CHANNEL_MODE;
1263 
1264 	// first MPEG1 frequencies
1265 	if (a_Channel_Independent < SIZE_FREQ_MPEG1)
1266 	{
1267 		the_Format.nSamplesPerSec = mpeg1_freq[a_Channel_Independent];
1268 	}
1269 	else
1270 	{
1271 		a_Channel_Independent -= SIZE_FREQ_MPEG1;
1272 		the_Format.nSamplesPerSec = mpeg2_freq[a_Channel_Independent];
1273 	}
1274 
1275 	the_Format.nAvgBytesPerSec = the_Format.nSamplesPerSec * the_Format.nChannels * the_Format.wBitsPerSample / 8;
1276 }
1277 
GetNumberEncodingFormats() const1278 DWORD ACM::GetNumberEncodingFormats() const
1279 {
1280 	return bitrate_table.size();
1281 }
1282 
IsSmartOutput(const int frequency,const int bitrate,const int channels) const1283 bool ACM::IsSmartOutput(const int frequency, const int bitrate, const int channels) const
1284 {
1285 	double compression_ratio = double(frequency * 2 * channels) / double(bitrate * 100);
1286 
1287 //my_debug.OutPut(DEBUG_LEVEL_FUNC_DEBUG, "compression_ratio %f, freq %d, bitrate %d, channels %d", compression_ratio, frequency, bitrate, channels);
1288 
1289 	if(my_EncodingProperties.GetSmartOutputMode())
1290 		return (compression_ratio <= my_EncodingProperties.GetSmartRatio());
1291 	else return true;
1292 }
1293 
BuildBitrateTable()1294 void ACM::BuildBitrateTable()
1295 {
1296 	my_debug.OutPut("entering BuildBitrateTable");
1297 
1298 	// fill the table
1299 	unsigned int channel,bitrate,freq;
1300 
1301 	bitrate_table.clear();
1302 
1303 	// CBR bitrates
1304 	for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1305 	{
1306 		// MPEG I
1307 		for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1308 		{
1309 			for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG1;bitrate++)
1310 			{
1311 
1312 				if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], mpeg1_bitrate[bitrate], channel+1))
1313 				{
1314 					bitrate_item bitrate_table_tmp;
1315 
1316 					bitrate_table_tmp.frequency = mpeg1_freq[freq];
1317 					bitrate_table_tmp.bitrate = mpeg1_bitrate[bitrate];
1318 					bitrate_table_tmp.channels = channel+1;
1319 					bitrate_table_tmp.mode = vbr_off;
1320 					bitrate_table.push_back(bitrate_table_tmp);
1321 				}
1322 			}
1323 		}
1324 		// MPEG II / II.5
1325 		for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1326 		{
1327 			for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG2;bitrate++)
1328 			{
1329 				if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], mpeg2_bitrate[bitrate], channel+1))
1330 				{
1331 					bitrate_item bitrate_table_tmp;
1332 
1333                                         bitrate_table_tmp.frequency = mpeg2_freq[freq];
1334 					bitrate_table_tmp.bitrate = mpeg2_bitrate[bitrate];
1335 					bitrate_table_tmp.channels = channel+1;
1336 					bitrate_table_tmp.mode = vbr_abr;
1337 					bitrate_table.push_back(bitrate_table_tmp);
1338 				}
1339 			}
1340 		}
1341 	}
1342 
1343 	if (my_EncodingProperties.GetAbrOutputMode())
1344 	// ABR bitrates
1345 	{
1346 		for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1347 		{
1348 			// MPEG I
1349 			for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1350 			{
1351 				for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1352 					   bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1353 				     bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1354 				{
1355 					if (bitrate >= mpeg1_bitrate[SIZE_BITRATE_MPEG1-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], bitrate, channel+1)))
1356 					{
1357 						bitrate_item bitrate_table_tmp;
1358 
1359 						bitrate_table_tmp.frequency = mpeg1_freq[freq];
1360 						bitrate_table_tmp.bitrate = bitrate;
1361 						bitrate_table_tmp.channels = channel+1;
1362 						bitrate_table_tmp.mode = vbr_abr;
1363 						bitrate_table.push_back(bitrate_table_tmp);
1364 					}
1365 				}
1366 			}
1367 			// MPEG II / II.5
1368 			for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1369 			{
1370 				for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1371 					   bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1372 				     bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1373 				{
1374 					if (bitrate >= mpeg2_bitrate[SIZE_BITRATE_MPEG2-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], bitrate, channel+1)))
1375 					{
1376 						bitrate_item bitrate_table_tmp;
1377 
1378 						bitrate_table_tmp.frequency = mpeg2_freq[freq];
1379 						bitrate_table_tmp.bitrate = bitrate;
1380 						bitrate_table_tmp.channels = channel+1;
1381 						bitrate_table_tmp.mode = vbr_abr;
1382 						bitrate_table.push_back(bitrate_table_tmp);
1383 					}
1384 				}
1385 			}
1386 		}
1387 	}
1388 
1389 	// sorting by frequency/bitrate/channel
1390 	std::sort(bitrate_table.begin(), bitrate_table.end());
1391 
1392 /*	{
1393 		// display test
1394 		int i=0;
1395 		for (i=0; i<bitrate_table.size();i++)
1396 		{
1397 			my_debug.OutPut("bitrate_table[%d].frequency = %d",i,bitrate_table[i].frequency);
1398 			my_debug.OutPut("bitrate_table[%d].bitrate = %d",i,bitrate_table[i].bitrate);
1399 			my_debug.OutPut("bitrate_table[%d].channel = %d",i,bitrate_table[i].channels);
1400 			my_debug.OutPut("bitrate_table[%d].ABR = %s\n",i,(bitrate_table[i].mode == vbr_abr)?"ABR":"CBR");
1401 		}
1402 	}*/
1403 
1404 	my_debug.OutPut("leaving BuildBitrateTable");
1405 }
1406