• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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$
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 = FALSE;
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 					::ShellExecute(hwndDlg,"open",Url,NULL,"",SW_SHOWMAXIMIZED );
253 				}
254 
255 			}
256 			break;
257 
258 		case WM_COMMAND:
259 			UINT command;
260 			command = GET_WM_COMMAND_ID(wParam, lParam);
261             if (IDOK == command)
262             {
263                 EndDialog(hwndDlg, TRUE);
264             }
265             bResult = FALSE;
266 			break;
267 
268 		case IDC_STATIC_ABOUT_URL:
269 			break;
270 		default:
271 			bResult = FALSE; // will be treated by DefWindowProc
272 }
273 	return bResult;
274 }
275 
About(HWND hParentWindow)276 inline DWORD ACM::About(HWND hParentWindow)
277 {
278 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM : About (Parent Window = 0x%08X)",hParentWindow);
279 
280 	DialogBoxParam( my_hModule, MAKEINTRESOURCE(IDD_ABOUT), hParentWindow, ::AboutProc , (LPARAM)this);
281 
282 	return DRVCNF_OK; // Can also return
283 // DRVCNF_CANCEL
284 // and DRVCNF_RESTART
285 }
286 
287 
288 //////////////////////////////////////////////////////////////////////
289 // Construction/Destruction
290 //////////////////////////////////////////////////////////////////////
291 
ACM(HMODULE hModule)292 ACM::ACM( HMODULE hModule )
293  :my_hModule(hModule),
294   my_hIcon(NULL),
295   my_debug(ADbg(DEBUG_LEVEL_CREATION)),
296   my_EncodingProperties(hModule)
297 {
298 	my_EncodingProperties.ParamsRestore();
299 
300 	/// \todo get the debug level from the registry
301 	unsigned char DebugFileName[512];
302 
303 	char tmp[128];
304 	wsprintf(tmp,"LAMEacm 0x%08X",this);
305 	my_debug.setPrefix(tmp); /// \todo get it from the registry
306 	my_debug.setIncludeTime(true);  /// \todo get it from the registry
307 
308 	// Check in the registry if we have to Output Debug information
309 	DebugFileName[0] = '\0';
310 
311 	HKEY OssKey;
312 	if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\MUKOLI", 0, KEY_READ , &OssKey ) == ERROR_SUCCESS) {
313 		DWORD DataType;
314 		DWORD DebugFileNameSize = 512;
315 		if (RegQueryValueEx( OssKey, "DebugFile", NULL, &DataType, DebugFileName, &DebugFileNameSize ) == ERROR_SUCCESS) {
316 			if (DataType == REG_SZ) {
317 				my_debug.setUseFile(true);
318 				my_debug.setDebugFile((char *)DebugFileName);
319 				my_debug.OutPut("Debug file is %s",(char *)DebugFileName);
320 			}
321 		}
322 	}
323         wsprintf(VersionString,"%s - %s", ACM_VERSION, get_lame_version() );
324 	BuildBitrateTable();
325 
326 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "New ACM Creation (0x%08X)",this);
327 }
328 
~ACM()329 ACM::~ACM()
330 {
331 // not used, it's done automatically when closing the driver	if (my_hIcon != NULL)
332 //		CloseHandle(my_hIcon);
333 
334 	bitrate_table.clear();
335 
336 	my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM Deleted (0x%08X)",this);
337 }
338 
339 //////////////////////////////////////////////////////////////////////
340 // Main message handler
341 //////////////////////////////////////////////////////////////////////
342 
DriverProcedure(const HDRVR hdrvr,const UINT msg,LONG lParam1,LONG lParam2)343 LONG ACM::DriverProcedure(const HDRVR hdrvr, const UINT msg, LONG lParam1, LONG lParam2)
344 {
345     DWORD dwRes = 0L;
346 
347 //my_debug.OutPut(DEBUG_LEVEL_MSG, "message 0x%08X for ThisACM 0x%08X", msg, this);
348 
349 switch (msg) {
350     case DRV_INSTALL:
351 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_INSTALL");
352 		// Sent when the driver is installed.
353 		dwRes = DRVCNF_OK;  // Can also return
354 		break;              // DRVCNF_CANCEL
355 							// and DRV_RESTART
356 
357 	case DRV_REMOVE:
358 		// Sent when the driver is removed.
359 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_REMOVE");
360 		dwRes = 1L;  // return value ignored
361 		break;
362 
363     case DRV_QUERYCONFIGURE:
364 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_QUERYCONFIGURE");
365 		// Sent to determine if the driver can be
366 		// configured.
367 		dwRes = 1L;  // Zero indicates configuration
368 		break;       // NOT supported
369 
370 	case DRV_CONFIGURE:
371 		my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_CONFIGURE");
372 		// Sent to display the configuration
373 		// dialog box for the driver.
374 //		dwRes = Configure( (HWND) lParam1, (LPDRVCONFIGINFO) lParam2 );
375 		if (my_EncodingProperties.Config(my_hModule, (HWND) lParam1))
376 		{
377 			dwRes = DRVCNF_OK; // Can also return
378 					// DRVCNF_CANCEL
379 					// and DRVCNF_RESTART
380 		} else {
381 			dwRes = DRVCNF_CANCEL;
382 		}
383 		break;
384 
385 	/**************************************
386 	// ACM additional messages
387 	***************************************/
388 
389 	case ACMDM_DRIVER_ABOUT:
390 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_ABOUT");
391 
392 		dwRes = About( (HWND) lParam1 );
393 
394         break;
395 
396 	case ACMDM_DRIVER_DETAILS: // acmDriverDetails
397 		// Fill-in general informations about the driver/codec
398 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_DETAILS");
399 
400 		dwRes = OnDriverDetails(hdrvr, (LPACMDRIVERDETAILS) lParam1);
401 
402 		break;
403 
404 	case ACMDM_FORMATTAG_DETAILS: // acmFormatTagDetails
405 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMATTAG_DETAILS");
406 
407 		dwRes = OnFormatTagDetails((LPACMFORMATTAGDETAILS) lParam1, lParam2);
408 
409         break;
410 
411 	case ACMDM_FORMAT_DETAILS: // acmFormatDetails
412 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_DETAILS");
413 
414 		dwRes = OnFormatDetails((LPACMFORMATDETAILS) lParam1, lParam2);
415 
416         break;
417 
418     case ACMDM_FORMAT_SUGGEST: // acmFormatSuggest
419 		// Sent to determine if the driver can be
420 		// configured.
421 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_SUGGEST");
422 		dwRes = OnFormatSuggest((LPACMDRVFORMATSUGGEST) lParam1);
423         break;
424 
425 	/**************************************
426 	// ACM stream messages
427 	***************************************/
428 
429 	case ACMDM_STREAM_OPEN:
430 	// Sent to determine if the driver can be
431 	// configured.
432 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_OPEN");
433 		dwRes = OnStreamOpen((LPACMDRVSTREAMINSTANCE) lParam1);
434         break;
435 
436 	case ACMDM_STREAM_SIZE:
437 	// returns a recommended size for a source
438 	// or destination buffer on an ACM stream
439 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_SIZE");
440 		dwRes = OnStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
441         break;
442 
443 	case ACMDM_STREAM_PREPARE:
444 	// prepares an ACMSTREAMHEADER structure for
445 	// an ACM stream conversion
446 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_PREPARE");
447 		dwRes = OnStreamPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
448         break;
449 
450 	case ACMDM_STREAM_UNPREPARE:
451 	// cleans up the preparation performed by
452 	// the ACMDM_STREAM_PREPARE message for an ACM stream
453 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_UNPREPARE");
454 		dwRes = OnStreamUnPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
455         break;
456 
457 	case ACMDM_STREAM_CONVERT:
458 	// perform a conversion on the specified conversion stream
459 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CONVERT");
460 		dwRes = OnStreamConvert((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMHEADER) lParam2);
461 
462         break;
463 
464 	case ACMDM_STREAM_CLOSE:
465 	// closes an ACM conversion stream
466 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CLOSE");
467 		dwRes = OnStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
468         break;
469 
470 	/**************************************
471 	// Unknown message
472 	***************************************/
473 
474 	default:
475 	// Process any other messages.
476 		my_debug.OutPut(DEBUG_LEVEL_MSG, "ACM::DriverProc unknown message (0x%08X), lParam1 = 0x%08X, lParam2 = 0x%08X", msg, lParam1, lParam2);
477 		return DefDriverProc ((DWORD)this, hdrvr, msg, lParam1, lParam2);
478     }
479 
480     return dwRes;
481 }
482 
483 //////////////////////////////////////////////////////////////////////
484 // Special message handlers
485 //////////////////////////////////////////////////////////////////////
486 /*!
487 	Retreive the config details of this ACM driver
488 	The index represent the specified format
489 
490 	\param a_FormatDetails will be filled with all the corresponding data
491 */
OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails,const LPARAM a_Query)492 inline DWORD ACM::OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails, const LPARAM a_Query)
493 {
494 	DWORD Result = ACMERR_NOTPOSSIBLE;
495 
496 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILS a_Query = 0x%08X",a_Query);
497 	switch (a_Query & ACM_FORMATDETAILSF_QUERYMASK) {
498 
499 		// Fill-in the informations corresponding to the FormatDetails->dwFormatTagIndex
500 		case ACM_FORMATDETAILSF_INDEX :
501 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "enter ACM_FORMATDETAILSF_INDEX for index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
502 			if (a_FormatDetails->dwFormatTag == PERSONAL_FORMAT) {
503 				if (a_FormatDetails->dwFormatIndex < GetNumberEncodingFormats()) {
504 					LPWAVEFORMATEX WaveExt;
505 					WaveExt = a_FormatDetails->pwfx;
506 
507 					WaveExt->wFormatTag = PERSONAL_FORMAT;
508 
509 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in  : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
510 					GetMP3FormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
511 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
512 					Result = MMSYSERR_NOERROR;
513 				}
514 				else
515 				{
516 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
517 				}
518 			}
519 			else if (a_FormatDetails->dwFormatTag == WAVE_FORMAT_PCM) {
520 				if (a_FormatDetails->dwFormatIndex < FORMAT_MAX_NB_PCM) {
521 					LPWAVEFORMATEX WaveExt;
522 					WaveExt = a_FormatDetails->pwfx;
523 
524 					WaveExt->wFormatTag = WAVE_FORMAT_PCM;
525 
526 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in  : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
527 					GetPCMFormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
528 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
529 					Result = MMSYSERR_NOERROR;
530 				}
531 				else
532 				{
533 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
534 				}
535 			}
536 			else
537 			{
538 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Unknown a_FormatDetails->dwFormatTag = 0x%08X",a_FormatDetails->dwFormatTag);
539 			}
540 
541 		case ACM_FORMATDETAILSF_FORMAT :
542 			/// \todo we may output the corresponding strong (only for personal format)
543 			LPWAVEFORMATEX WaveExt;
544 			WaveExt = a_FormatDetails->pwfx;
545 
546 			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);
547 
548 			Result = MMSYSERR_NOERROR;
549 			break;
550 
551 		default:
552 			Result = ACMERR_NOTPOSSIBLE;
553 			break;
554 	}
555 
556 	a_FormatDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
557 
558 	return Result;
559 }
560 
561 /*!
562 	Retreive the details of each known format by this ACM driver
563 	The index represent the specified format (0 = MP3 / 1 = PCM)
564 
565 	\param a_FormatTagDetails will be filled with all the corresponding data
566 */
OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails,const LPARAM a_Query)567 inline DWORD ACM::OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails, const LPARAM a_Query)
568 {
569 	DWORD Result;
570 	DWORD the_format = WAVE_FORMAT_UNKNOWN; // the format to give details
571 
572 	if (a_FormatTagDetails->cbStruct >= sizeof(*a_FormatTagDetails)) {
573 
574 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACMDM_FORMATTAG_DETAILS, a_Query = 0x%08X",a_Query);
575 		switch(a_Query & ACM_FORMATTAGDETAILSF_QUERYMASK) {
576 
577 			case ACM_FORMATTAGDETAILSF_INDEX:
578 			// Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex
579 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_INDEX for index %03d",a_FormatTagDetails->dwFormatTagIndex);
580 
581 				if (a_FormatTagDetails->dwFormatTagIndex < FORMAT_TAG_MAX_NB) {
582 					switch (a_FormatTagDetails->dwFormatTagIndex)
583 					{
584 					case 0:
585 						the_format = PERSONAL_FORMAT;
586 						break;
587 					default :
588 						the_format = WAVE_FORMAT_PCM;
589 						break;
590 					}
591 				}
592 				else
593 				{
594 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_INDEX for unsupported index %03d",a_FormatTagDetails->dwFormatTagIndex);
595 					Result = ACMERR_NOTPOSSIBLE;
596 				}
597 				break;
598 
599 			case ACM_FORMATTAGDETAILSF_FORMATTAG:
600 			// Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex and hdrvr given
601 				switch (a_FormatTagDetails->dwFormatTag)
602 				{
603 				case WAVE_FORMAT_PCM:
604 					the_format = WAVE_FORMAT_PCM;
605 					break;
606 				case PERSONAL_FORMAT:
607 					the_format = PERSONAL_FORMAT;
608 					break;
609 				default:
610                     return (ACMERR_NOTPOSSIBLE);
611 				}
612 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_FORMATTAG for index 0x%02X, cStandardFormats = %d",a_FormatTagDetails->dwFormatTagIndex,a_FormatTagDetails->cStandardFormats);
613 				break;
614 			case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
615 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_LARGESTSIZE not used");
616 				Result = 0L;
617 				break;
618 			default:
619 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown Format tag query");
620 				Result = MMSYSERR_NOTSUPPORTED;
621 				break;
622 		}
623 
624 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails the_format = 0x%08X",the_format);
625 		switch(the_format)
626 		{
627 			case WAVE_FORMAT_PCM:
628 				a_FormatTagDetails->dwFormatTag      = WAVE_FORMAT_PCM;
629 				a_FormatTagDetails->dwFormatTagIndex = 0;
630 				a_FormatTagDetails->cbFormatSize     = sizeof(PCMWAVEFORMAT);
631 				/// \note 0 may mean we don't know how to decode
632 				a_FormatTagDetails->fdwSupport       = ACMDRIVERDETAILS_SUPPORTF_CODEC;
633 				a_FormatTagDetails->cStandardFormats = FORMAT_MAX_NB_PCM;
634 				// should be filled by Windows				a_FormatTagDetails->szFormatTag[0] = '\0';
635 				Result = MMSYSERR_NOERROR;
636 				break;
637 			case PERSONAL_FORMAT:
638 				a_FormatTagDetails->dwFormatTag      = PERSONAL_FORMAT;
639 				a_FormatTagDetails->dwFormatTagIndex = 1;
640 				a_FormatTagDetails->cbFormatSize     = SIZE_FORMAT_STRUCT;
641 				a_FormatTagDetails->fdwSupport       = ACMDRIVERDETAILS_SUPPORTF_CODEC;
642 				a_FormatTagDetails->cStandardFormats = GetNumberEncodingFormats();
643 				lstrcpyW( a_FormatTagDetails->szFormatTag, L"Lame MP3" );
644 				Result = MMSYSERR_NOERROR;
645 				break;
646 			default:
647 				my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown format 0x%08X",the_format);
648 				return (ACMERR_NOTPOSSIBLE);
649 		}
650 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails %d possibilities for format 0x%08X",a_FormatTagDetails->cStandardFormats,the_format);
651 	}
652 	else
653 	{
654 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "a_FormatTagDetails->cbStruct < sizeof(*a_FormatDetails)");
655 		Result = ACMERR_NOTPOSSIBLE;
656 	}
657 
658 	return Result;
659 }
660 
661 /*!
662 	Retreive the global details of this ACM driver
663 
664 	\param a_DriverDetail will be filled with all the corresponding data
665 */
OnDriverDetails(const HDRVR hdrvr,LPACMDRIVERDETAILS a_DriverDetail)666 inline DWORD ACM::OnDriverDetails(const HDRVR hdrvr, LPACMDRIVERDETAILS a_DriverDetail)
667 {
668 	if (my_hIcon == NULL)
669 		my_hIcon = LoadIcon(GetDriverModuleHandle(hdrvr), MAKEINTRESOURCE(IDI_ICON));
670 	a_DriverDetail->hicon       = my_hIcon;
671 
672 	a_DriverDetail->fccType     = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
673 	a_DriverDetail->fccComp     = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
674 
675 	/// \note this is an explicit hack of the FhG values
676 	/// \note later it could be a new value when the decoding is done
677 	a_DriverDetail->wMid        = MM_FRAUNHOFER_IIS;
678 	a_DriverDetail->wPid        = MM_FHGIIS_MPEGLAYER3;
679 
680 	a_DriverDetail->vdwACM      = VERSION_MSACM;
681 	a_DriverDetail->vdwDriver   = VERSION_ACM_DRIVER;
682 	a_DriverDetail->fdwSupport  = ACMDRIVERDETAILS_SUPPORTF_CODEC;
683 	a_DriverDetail->cFormatTags = FORMAT_TAG_MAX_NB; // 2 : MP3 and PCM
684 //	a_DriverDetail->cFormatTags = 1; // 2 : MP3 and PCM
685 	a_DriverDetail->cFilterTags = FILTER_TAG_MAX_NB;
686 
687 	lstrcpyW( a_DriverDetail->szShortName, L"LAME MP3" );
688 	char tmpStr[128];
689 	wsprintf(tmpStr, "LAME MP3 Codec v%s", GetVersionString());
690 	int u = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, 0);
691 	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, u);
692 	lstrcpyW( a_DriverDetail->szCopyright, L"2002 Steve Lhomme" );
693 	lstrcpyW( a_DriverDetail->szLicensing, L"LGPL (see gnu.org)" );
694 	/// \todo update this part when the code changes
695 	lstrcpyW( a_DriverDetail->szFeatures , L"only CBR implementation" );
696 
697     return MMSYSERR_NOERROR;  // Can also return DRVCNF_CANCEL
698 }
699 
700 /*!
701 	Suggest an output format for the specified input format
702 
703 	\param a_FormatSuggest will be filled with all the corresponding data
704 */
OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)705 inline DWORD ACM::OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)
706 {
707 	DWORD Result = MMSYSERR_NOTSUPPORTED;
708     DWORD fdwSuggest = (ACM_FORMATSUGGESTF_TYPEMASK & a_FormatSuggest->fdwSuggest);
709 
710 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest %s%s%s%s (0x%08X)",
711 				 (fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS) ? "channels, ":"",
712 				 (fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC) ? "samples/sec, ":"",
713 				 (fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE) ? "bits/sample, ":"",
714 				 (fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG) ? "format, ":"",
715 				 fdwSuggest);
716 
717 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",
718 				 a_FormatSuggest->pwfxSrc->wFormatTag,
719 				 a_FormatSuggest->pwfxSrc->nChannels,
720 				 a_FormatSuggest->pwfxSrc->nSamplesPerSec,
721 				 a_FormatSuggest->pwfxSrc->nAvgBytesPerSec,
722 				 a_FormatSuggest->pwfxSrc->nBlockAlign,
723 				 a_FormatSuggest->pwfxSrc->wBitsPerSample);
724 
725 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",
726 			 a_FormatSuggest->pwfxDst->wFormatTag,
727 			 a_FormatSuggest->pwfxDst->nChannels,
728 			 a_FormatSuggest->pwfxDst->nSamplesPerSec,
729 			 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
730 			 a_FormatSuggest->pwfxDst->nBlockAlign,
731 			 a_FormatSuggest->pwfxDst->wBitsPerSample);
732 
733 	switch (a_FormatSuggest->pwfxSrc->wFormatTag)
734 	{
735         case WAVE_FORMAT_PCM:
736 			/// \todo handle here the decoding ?
737 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PCM source");
738             //
739 			//  if the destination format tag is restricted, verify that
740 			//  it is within our capabilities...
741 			//
742 			//  this driver is able to decode to PCM
743 			//
744 			if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
745             {
746                 if (PERSONAL_FORMAT != a_FormatSuggest->pwfxDst->wFormatTag)
747                     return (ACMERR_NOTPOSSIBLE);
748             }
749             else
750 			{
751                 a_FormatSuggest->pwfxDst->wFormatTag = PERSONAL_FORMAT;
752             }
753 
754 
755 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed A");
756             //
757 			//  if the destination channel count is restricted, verify that
758 			//  it is within our capabilities...
759 			//
760 			//  this driver is not able to change the number of channels
761 			//
762 			if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
763             {
764                 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
765                     return (ACMERR_NOTPOSSIBLE);
766             }
767             else
768 			{
769                 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
770             }
771 
772 			if (a_FormatSuggest->pwfxSrc->nChannels != 1 && a_FormatSuggest->pwfxSrc->nChannels != 2)
773 				return MMSYSERR_INVALPARAM;
774 
775 
776 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed B");
777             //
778 			//  if the destination samples per second is restricted, verify
779 			//  that it is within our capabilities...
780 			//
781 			//  this driver is not able to change the sample rate
782 			//
783 			if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
784             {
785                 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
786                     return (ACMERR_NOTPOSSIBLE);
787             }
788             else
789 			{
790                 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
791             }
792 
793 
794 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed C");
795             //
796 			//  if the destination bits per sample is restricted, verify
797 			//  that it is within our capabilities...
798 			//
799 			//  We prefer decoding to 16-bit PCM.
800 			//
801 			if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
802             {
803                 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
804                     return (ACMERR_NOTPOSSIBLE);
805             }
806             else
807 			{
808                 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
809             }
810 
811 			//			a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
812 			a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
813 
814 			a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nChannels * 64000 / 8;
815 
816 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
817 			Result = MMSYSERR_NOERROR;
818 
819 
820 			break;
821 		case PERSONAL_FORMAT:
822 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PERSONAL source");
823             //
824 			//  if the destination format tag is restricted, verify that
825 			//  it is within our capabilities...
826 			//
827 			//  this driver is able to decode to PCM
828 			//
829 			if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
830             {
831                 if (WAVE_FORMAT_PCM != a_FormatSuggest->pwfxDst->wFormatTag)
832                     return (ACMERR_NOTPOSSIBLE);
833             }
834             else
835 			{
836                 a_FormatSuggest->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
837             }
838 
839 
840             //
841 			//  if the destination channel count is restricted, verify that
842 			//  it is within our capabilities...
843 			//
844 			//  this driver is not able to change the number of channels
845 			//
846 			if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
847             {
848                 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
849                     return (ACMERR_NOTPOSSIBLE);
850             }
851             else
852 			{
853                 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
854             }
855 
856 
857             //
858 			//  if the destination samples per second is restricted, verify
859 			//  that it is within our capabilities...
860 			//
861 			//  this driver is not able to change the sample rate
862 			//
863 			if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
864             {
865                 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
866                     return (ACMERR_NOTPOSSIBLE);
867             }
868             else
869 			{
870                 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
871             }
872 
873 
874             //
875 			//  if the destination bits per sample is restricted, verify
876 			//  that it is within our capabilities...
877 			//
878 			//  We prefer decoding to 16-bit PCM.
879 			//
880 			if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
881             {
882                 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
883                     return (ACMERR_NOTPOSSIBLE);
884             }
885             else
886 			{
887                 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
888             }
889 
890 			//			a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
891 			a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
892 
893 			/// \todo this value must be a correct one !
894 			a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nSamplesPerSec * a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
895 
896 			my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
897 			Result = MMSYSERR_NOERROR;
898 
899 
900 			break;
901 	}
902 
903 	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",
904 				 a_FormatSuggest->pwfxDst->wFormatTag,
905 				 a_FormatSuggest->pwfxDst->nChannels,
906 				 a_FormatSuggest->pwfxDst->nSamplesPerSec,
907 				 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
908 				 a_FormatSuggest->pwfxDst->nBlockAlign,
909 				 a_FormatSuggest->pwfxDst->wBitsPerSample);
910 
911 	return Result;
912 }
913 
914 /*!
915 	Create a stream instance for decoding/encoding
916 
917 	\param a_StreamInstance contain information about the stream desired
918 */
OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)919 inline DWORD ACM::OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)
920 {
921 	DWORD Result = ACMERR_NOTPOSSIBLE;
922 
923 	//
924 	//  the most important condition to check before doing anything else
925 	//  is that this ACM driver can actually perform the conversion we are
926 	//  being opened for. this check should fail as quickly as possible
927 	//  if the conversion is not possible by this driver.
928 	//
929 	//  it is VERY important to fail quickly so the ACM can attempt to
930 	//  find a driver that is suitable for the conversion. also note that
931 	//  the ACM may call this driver several times with slightly different
932 	//  format specifications before giving up.
933 	//
934 	//  this driver first verifies that the source and destination formats
935 	//  are acceptable...
936 	//
937 	switch (a_StreamInstance->pwfxSrc->wFormatTag)
938 	{
939         case WAVE_FORMAT_PCM:
940 			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);
941 			if (a_StreamInstance->pwfxDst->wFormatTag == PERSONAL_FORMAT)
942 			{
943 				unsigned int OutputFrequency;
944 
945 				/// \todo Smart mode
946 				if (my_EncodingProperties.GetSmartOutputMode())
947 					OutputFrequency = ACMStream::GetOutputSampleRate(a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxDst->nAvgBytesPerSec,a_StreamInstance->pwfxDst->nChannels);
948 				else
949 					OutputFrequency = a_StreamInstance->pwfxSrc->nSamplesPerSec;
950 
951 				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);
952 
953 				/// \todo add the possibility to have channel resampling (mono to stereo / stereo to mono)
954 				/// \todo support resampling ?
955 				/// \todo only do the test on OutputFrequency in "Smart Output" mode
956 				if (a_StreamInstance->pwfxDst->nSamplesPerSec != OutputFrequency ||
957 //					a_StreamInstance->pwfxSrc->nSamplesPerSec != a_StreamInstance->pwfxDst->nSamplesPerSec ||
958 					a_StreamInstance->pwfxSrc->nChannels != a_StreamInstance->pwfxDst->nChannels ||
959 					a_StreamInstance->pwfxSrc->wBitsPerSample != 16)
960 				{
961 					Result = ACMERR_NOTPOSSIBLE;
962 				} else {
963 					if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
964 					{
965 						ACMStream * the_stream = ACMStream::Create();
966 						a_StreamInstance->dwInstance = (DWORD) the_stream;
967 
968 						if (the_stream != NULL)
969 						{
970 							MPEGLAYER3WAVEFORMAT * casted = (MPEGLAYER3WAVEFORMAT *) a_StreamInstance->pwfxDst;
971 							vbr_mode a_mode = (casted->fdwFlags-2 == 0)?vbr_abr:vbr_off;
972 							if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
973 												 OutputFrequency,
974 												 a_StreamInstance->pwfxDst->nChannels,
975 												 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
976 												 a_mode))
977 								Result = MMSYSERR_NOERROR;
978 							else
979 								ACMStream::Erase( the_stream );
980 						}
981 					}
982 					else
983 					{
984 						Result = MMSYSERR_NOERROR;
985 					}
986 				}
987 			}
988 			break;
989 		case PERSONAL_FORMAT:
990 			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);
991 			if (a_StreamInstance->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
992 			{
993 #ifdef ENABLE_DECODING
994 				if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
995 				{
996 					/// \todo create the decoding stream
997 					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);
998 
999 					DecodeStream * the_stream = DecodeStream::Create();
1000 					a_StreamInstance->dwInstance = (DWORD) the_stream;
1001 
1002 					if (the_stream != NULL)
1003 					{
1004 						if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
1005 											 a_StreamInstance->pwfxDst->nChannels,
1006 											 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
1007 											 a_StreamInstance->pwfxSrc->nAvgBytesPerSec))
1008 							Result = MMSYSERR_NOERROR;
1009 						else
1010 							DecodeStream::Erase( the_stream );
1011 					}
1012 				}
1013 				else
1014 				{
1015 					/// \todo decoding verification
1016 					my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream is valid");
1017 					Result = MMSYSERR_NOERROR;
1018 				}
1019 #endif // ENABLE_DECODING
1020 			}
1021 			break;
1022 	}
1023 
1024 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream Result = %d",Result);
1025 	return Result;
1026 }
1027 
OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMSIZE the_StreamSize)1028 inline DWORD ACM::OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMSIZE the_StreamSize)
1029 {
1030 	DWORD Result = ACMERR_NOTPOSSIBLE;
1031 
1032     switch (ACM_STREAMSIZEF_QUERYMASK & the_StreamSize->fdwSize)
1033     {
1034 	case ACM_STREAMSIZEF_DESTINATION:
1035 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get source buffer size for destination size = %d",the_StreamSize->cbDstLength);
1036 		break;
1037 	case ACM_STREAMSIZEF_SOURCE:
1038 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get destination buffer size for source size = %d",the_StreamSize->cbSrcLength);
1039         if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1040 			PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1041         {
1042 			ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1043 			if (the_stream != NULL)
1044 			{
1045 				the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1046 				Result = MMSYSERR_NOERROR;
1047 			}
1048 		}
1049         else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1050 			 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1051 		{
1052 #ifdef ENABLE_DECODING
1053 			DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1054 			if (the_stream != NULL)
1055 			{
1056 				the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1057 				Result = MMSYSERR_NOERROR;
1058 			}
1059 #endif // ENABLE_DECODING
1060 		}
1061 		break;
1062 	default:
1063 		Result = MMSYSERR_INVALFLAG;
1064 		break;
1065 	}
1066 
1067 	return Result;
1068 }
1069 
OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)1070 inline DWORD ACM::OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)
1071 {
1072 	DWORD Result = ACMERR_NOTPOSSIBLE;
1073 
1074 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamClose the stream 0x%X",a_StreamInstance->dwInstance);
1075     if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1076 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1077     {
1078 	ACMStream::Erase( (ACMStream *) a_StreamInstance->dwInstance );
1079 	}
1080     else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1081 		 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1082     {
1083 #ifdef ENABLE_DECODING
1084 		DecodeStream::Erase( (DecodeStream *) a_StreamInstance->dwInstance );
1085 #endif // ENABLE_DECODING
1086 	}
1087 
1088 	// nothing to do yet
1089 	Result = MMSYSERR_NOERROR;
1090 
1091 	return Result;
1092 }
1093 
OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1094 inline DWORD ACM::OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1095 {
1096 	DWORD Result = ACMERR_NOTPOSSIBLE;
1097 
1098 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "  prepare : Src : %d (0x%08X) / %d - Dst : %d (0x%08X) / %d"
1099 												, a_StreamHeader->cbSrcLength
1100 												, a_StreamHeader->pbSrc
1101 												, a_StreamHeader->cbSrcLengthUsed
1102 												, a_StreamHeader->cbDstLength
1103 												, a_StreamHeader->pbDst
1104 												, a_StreamHeader->cbDstLengthUsed
1105 											  );
1106 
1107 	if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1108 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1109 	{
1110 		ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1111 
1112 		if (the_stream->open(my_EncodingProperties))
1113 			Result = MMSYSERR_NOERROR;
1114 	}
1115 	else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1116 		     WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1117 	{
1118 #ifdef ENABLE_DECODING
1119 		DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1120 
1121 		if (the_stream->open())
1122 			Result = MMSYSERR_NOERROR;
1123 #endif // ENABLE_DECODING
1124 	}
1125 
1126 	return Result;
1127 }
1128 
OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1129 inline DWORD ACM::OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1130 {
1131 	DWORD Result = ACMERR_NOTPOSSIBLE;
1132 
1133 	my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "unprepare : Src : %d / %d - Dst : %d / %d"
1134 											, a_StreamHeader->cbSrcLength
1135 											, a_StreamHeader->cbSrcLengthUsed
1136 											, a_StreamHeader->cbDstLength
1137 											, a_StreamHeader->cbDstLengthUsed
1138 											);
1139     if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1140 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1141     {
1142 	ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1143 	DWORD OutputSize = a_StreamHeader->cbDstLength;
1144 
1145 	if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1146 	{
1147 		a_StreamHeader->cbDstLengthUsed = OutputSize;
1148 			Result = MMSYSERR_NOERROR;
1149 		}
1150 	}
1151     else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1152 		 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1153     {
1154 #ifdef ENABLE_DECODING
1155 		DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1156 		DWORD OutputSize = a_StreamHeader->cbDstLength;
1157 
1158 		if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1159 		{
1160 			a_StreamHeader->cbDstLengthUsed = OutputSize;
1161 			Result = MMSYSERR_NOERROR;
1162 	}
1163 #endif // ENABLE_DECODING
1164 	}
1165 
1166 	return Result;
1167 }
1168 
OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMHEADER a_StreamHeader)1169 inline DWORD ACM::OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMHEADER a_StreamHeader)
1170 {
1171 	DWORD Result = ACMERR_NOTPOSSIBLE;
1172 
1173 	if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1174 		PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1175 	{
1176 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = PCM (encode)");
1177 
1178 		ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1179 		if (the_stream != NULL)
1180 		{
1181 			if (the_stream->ConvertBuffer( a_StreamHeader ))
1182 				Result = MMSYSERR_NOERROR;
1183 		}
1184 	}
1185 	else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1186 		     WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1187 	{
1188 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = MP3 (decode)");
1189 
1190 #ifdef ENABLE_DECODING
1191 		DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1192 		if (the_stream != NULL)
1193 		{
1194 			if (the_stream->ConvertBuffer( a_StreamHeader ))
1195 				Result = MMSYSERR_NOERROR;
1196 		}
1197 #endif // ENABLE_DECODING
1198 	}
1199 	else
1200 		my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert unsupported conversion");
1201 
1202 	return Result;
1203 }
1204 
1205 
GetMP3FormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1206 void ACM::GetMP3FormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1207 {
1208 	int Block_size;
1209     char temp[ACMFORMATDETAILS_FORMAT_CHARS];
1210 
1211 
1212 	if (the_Index < bitrate_table.size())
1213 	{
1214 	//	the_Format.wBitsPerSample = 16;
1215 		the_Format.wBitsPerSample = 0;
1216 
1217 		/// \todo handle more channel modes (mono, stereo, joint-stereo, dual-channel)
1218 	//	the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1219 
1220 		the_Format.nBlockAlign = 1;
1221 
1222 		the_Format.nSamplesPerSec = bitrate_table[the_Index].frequency;
1223 		the_Format.nAvgBytesPerSec = bitrate_table[the_Index].bitrate * 1000 / 8;
1224 		if (bitrate_table[the_Index].frequency >= mpeg1_freq[SIZE_FREQ_MPEG1-1])
1225 			Block_size = 1152;
1226 		else
1227 			Block_size = 576;
1228 
1229 		the_Format.nChannels = bitrate_table[the_Index].channels;
1230 
1231 		the_Format.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
1232 		MPEGLAYER3WAVEFORMAT * tmpFormat = (MPEGLAYER3WAVEFORMAT *) &the_Format;
1233 		tmpFormat->wID             = 1;
1234 		// this is the only way I found to know if we do CBR or ABR
1235 		tmpFormat->fdwFlags        = 2 + ((bitrate_table[the_Index].mode == vbr_abr)?0:2);
1236 		tmpFormat->nBlockSize      = Block_size * the_Format.nAvgBytesPerSec / the_Format.nSamplesPerSec;
1237 		tmpFormat->nFramesPerBlock = 1;
1238 		tmpFormat->nCodecDelay     = 0; // 0x0571 on FHG
1239 
1240          /// \todo : generate the string with the appropriate stereo mode
1241          if (bitrate_table[the_Index].mode == vbr_abr)
1242              wsprintfA( temp, "%d Hz, %d kbps ABR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1243          else
1244              wsprintfA( temp, "%d Hz, %d kbps CBR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1245 
1246          MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, the_String, ACMFORMATDETAILS_FORMAT_CHARS);
1247      }
1248  }
1249 
GetPCMFormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1250 void ACM::GetPCMFormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1251 {
1252 	the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1253 	the_Format.wBitsPerSample = 16;
1254 	the_Format.nBlockAlign = the_Format.nChannels * the_Format.wBitsPerSample / 8;
1255 
1256 
1257 	DWORD a_Channel_Independent = the_Index / SIZE_CHANNEL_MODE;
1258 
1259 	// first MPEG1 frequencies
1260 	if (a_Channel_Independent < SIZE_FREQ_MPEG1)
1261 	{
1262 		the_Format.nSamplesPerSec = mpeg1_freq[a_Channel_Independent];
1263 	}
1264 	else
1265 	{
1266 		a_Channel_Independent -= SIZE_FREQ_MPEG1;
1267 		the_Format.nSamplesPerSec = mpeg2_freq[a_Channel_Independent];
1268 	}
1269 
1270 	the_Format.nAvgBytesPerSec = the_Format.nSamplesPerSec * the_Format.nChannels * the_Format.wBitsPerSample / 8;
1271 }
1272 
GetNumberEncodingFormats() const1273 DWORD ACM::GetNumberEncodingFormats() const
1274 {
1275 	return bitrate_table.size();
1276 }
1277 
IsSmartOutput(const int frequency,const int bitrate,const int channels) const1278 bool ACM::IsSmartOutput(const int frequency, const int bitrate, const int channels) const
1279 {
1280 	double compression_ratio = double(frequency * 2 * channels) / double(bitrate * 100);
1281 
1282 //my_debug.OutPut(DEBUG_LEVEL_FUNC_DEBUG, "compression_ratio %f, freq %d, bitrate %d, channels %d", compression_ratio, frequency, bitrate, channels);
1283 
1284 	if(my_EncodingProperties.GetSmartOutputMode())
1285 		return (compression_ratio <= my_EncodingProperties.GetSmartRatio());
1286 	else return true;
1287 }
1288 
BuildBitrateTable()1289 void ACM::BuildBitrateTable()
1290 {
1291 	my_debug.OutPut("entering BuildBitrateTable");
1292 
1293 	// fill the table
1294 	unsigned int channel,bitrate,freq;
1295 
1296 	bitrate_table.clear();
1297 
1298 	// CBR bitrates
1299 	for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1300 	{
1301 		// MPEG I
1302 		for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1303 		{
1304 			for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG1;bitrate++)
1305 			{
1306 
1307 				if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], mpeg1_bitrate[bitrate], channel+1))
1308 				{
1309 					bitrate_item bitrate_table_tmp;
1310 
1311 					bitrate_table_tmp.frequency = mpeg1_freq[freq];
1312 					bitrate_table_tmp.bitrate = mpeg1_bitrate[bitrate];
1313 					bitrate_table_tmp.channels = channel+1;
1314 					bitrate_table_tmp.mode = vbr_off;
1315 					bitrate_table.push_back(bitrate_table_tmp);
1316 				}
1317 			}
1318 		}
1319 		// MPEG II / II.5
1320 		for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1321 		{
1322 			for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG2;bitrate++)
1323 			{
1324 				if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], mpeg2_bitrate[bitrate], channel+1))
1325 				{
1326 					bitrate_item bitrate_table_tmp;
1327 
1328                                         bitrate_table_tmp.frequency = mpeg2_freq[freq];
1329 					bitrate_table_tmp.bitrate = mpeg2_bitrate[bitrate];
1330 					bitrate_table_tmp.channels = channel+1;
1331 					bitrate_table_tmp.mode = vbr_abr;
1332 					bitrate_table.push_back(bitrate_table_tmp);
1333 				}
1334 			}
1335 		}
1336 	}
1337 
1338 	if (my_EncodingProperties.GetAbrOutputMode())
1339 	// ABR bitrates
1340 	{
1341 		for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1342 		{
1343 			// MPEG I
1344 			for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1345 			{
1346 				for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1347 					   bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1348 				     bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1349 				{
1350 					if (bitrate >= mpeg1_bitrate[SIZE_BITRATE_MPEG1-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], bitrate, channel+1)))
1351 					{
1352 						bitrate_item bitrate_table_tmp;
1353 
1354 						bitrate_table_tmp.frequency = mpeg1_freq[freq];
1355 						bitrate_table_tmp.bitrate = bitrate;
1356 						bitrate_table_tmp.channels = channel+1;
1357 						bitrate_table_tmp.mode = vbr_abr;
1358 						bitrate_table.push_back(bitrate_table_tmp);
1359 					}
1360 				}
1361 			}
1362 			// MPEG II / II.5
1363 			for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1364 			{
1365 				for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1366 					   bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1367 				     bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1368 				{
1369 					if (bitrate >= mpeg2_bitrate[SIZE_BITRATE_MPEG2-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], bitrate, channel+1)))
1370 					{
1371 						bitrate_item bitrate_table_tmp;
1372 
1373 						bitrate_table_tmp.frequency = mpeg2_freq[freq];
1374 						bitrate_table_tmp.bitrate = bitrate;
1375 						bitrate_table_tmp.channels = channel+1;
1376 						bitrate_table_tmp.mode = vbr_abr;
1377 						bitrate_table.push_back(bitrate_table_tmp);
1378 					}
1379 				}
1380 			}
1381 		}
1382 	}
1383 
1384 	// sorting by frequency/bitrate/channel
1385 	std::sort(bitrate_table.begin(), bitrate_table.end());
1386 
1387 /*	{
1388 		// display test
1389 		int i=0;
1390 		for (i=0; i<bitrate_table.size();i++)
1391 		{
1392 			my_debug.OutPut("bitrate_table[%d].frequency = %d",i,bitrate_table[i].frequency);
1393 			my_debug.OutPut("bitrate_table[%d].bitrate = %d",i,bitrate_table[i].bitrate);
1394 			my_debug.OutPut("bitrate_table[%d].channel = %d",i,bitrate_table[i].channels);
1395 			my_debug.OutPut("bitrate_table[%d].ABR = %s\n",i,(bitrate_table[i].mode == vbr_abr)?"ABR":"CBR");
1396 		}
1397 	}*/
1398 
1399 	my_debug.OutPut("leaving BuildBitrateTable");
1400 }
1401