1/* in_flac - Winamp2 FLAC input plugin 2 * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#if HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <windows.h> 24#include <commctrl.h> 25#include <stdio.h> 26#include "configure.h" 27#include "tagz.h" 28#include "resource.h" 29#include "share/alloc.h" 30 31 32static char buffer[256]; 33static char ini_name[MAX_PATH]; 34 35/* 36 * Read/write config 37 */ 38 39#define RI(x, def) (x = GetPrivateProfileInt("FLAC", #x, def, ini_name)) 40#define WI(x) WritePrivateProfileString("FLAC", #x, itoa(x, buffer, 10), ini_name) 41#define RS(x, n, def) GetPrivateProfileString("FLAC", #x, def, x, n, ini_name) 42#define WS(x) WritePrivateProfileString("FLAC", #x, x, ini_name) 43 44static const char default_format[] = "[%artist% - ]$if2(%title%,%filename%)"; 45static const char default_sep[] = ", "; 46 47static wchar_t *convert_ansi_to_wide_(const char *src) 48{ 49 int len; 50 wchar_t *dest; 51 52 FLAC__ASSERT(0 != src); 53 54 len = strlen(src) + 1; 55 /* copy */ 56 dest = safe_malloc_mul_2op_(len, /*times*/sizeof(wchar_t)); 57 if (dest) mbstowcs(dest, src, len); 58 return dest; 59} 60 61void InitConfig() 62{ 63 char *p; 64 65 GetModuleFileName(NULL, ini_name, sizeof(ini_name)); 66 p = strrchr(ini_name, '.'); 67 if (!p) p = ini_name + strlen(ini_name); 68 strcpy(p, ".ini"); 69 70 flac_cfg.title.tag_format_w = NULL; 71} 72 73void ReadConfig() 74{ 75 RS(flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format), default_format); 76 if (flac_cfg.title.tag_format_w) 77 free(flac_cfg.title.tag_format_w); 78 flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format); 79 /* @@@ FIXME: trailing spaces */ 80 RS(flac_cfg.title.sep, sizeof(flac_cfg.title.sep), default_sep); 81 RI(flac_cfg.tag.reserve_space, 1); 82 83 RI(flac_cfg.display.show_bps, 1); 84 RI(flac_cfg.output.misc.stop_err, 0); 85 RI(flac_cfg.output.replaygain.enable, 1); 86 RI(flac_cfg.output.replaygain.album_mode, 0); 87 RI(flac_cfg.output.replaygain.hard_limit, 0); 88 RI(flac_cfg.output.replaygain.preamp, 0); 89 RI(flac_cfg.output.resolution.normal.dither_24_to_16, 0); 90 RI(flac_cfg.output.resolution.replaygain.dither, 0); 91 RI(flac_cfg.output.resolution.replaygain.noise_shaping, 1); 92 RI(flac_cfg.output.resolution.replaygain.bps_out, 16); 93} 94 95void WriteConfig() 96{ 97 WS(flac_cfg.title.tag_format); 98 WI(flac_cfg.tag.reserve_space); 99 WS(flac_cfg.title.sep); 100 101 WI(flac_cfg.display.show_bps); 102 WI(flac_cfg.output.misc.stop_err); 103 WI(flac_cfg.output.replaygain.enable); 104 WI(flac_cfg.output.replaygain.album_mode); 105 WI(flac_cfg.output.replaygain.hard_limit); 106 WI(flac_cfg.output.replaygain.preamp); 107 WI(flac_cfg.output.resolution.normal.dither_24_to_16); 108 WI(flac_cfg.output.resolution.replaygain.dither); 109 WI(flac_cfg.output.resolution.replaygain.noise_shaping); 110 WI(flac_cfg.output.resolution.replaygain.bps_out); 111} 112 113/* 114 * Dialog 115 */ 116 117#define PREAMP_RANGE 24 118 119#define Check(x,y) CheckDlgButton(hwnd, x, y ? BST_CHECKED : BST_UNCHECKED) 120#define GetCheck(x) (IsDlgButtonChecked(hwnd, x)==BST_CHECKED) 121#define GetSel(x) SendDlgItemMessage(hwnd, x, CB_GETCURSEL, 0, 0) 122#define GetPos(x) SendDlgItemMessage(hwnd, x, TBM_GETPOS, 0, 0) 123#define Enable(x,y) EnableWindow(GetDlgItem(hwnd, x), y) 124 125static INT_PTR CALLBACK GeneralProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 126{ 127 switch (msg) 128 { 129 /* init */ 130 case WM_INITDIALOG: 131 SendDlgItemMessage(hwnd, IDC_TITLE, EM_LIMITTEXT, 255, 0); 132 SendDlgItemMessage(hwnd, IDC_SEP, EM_LIMITTEXT, 15, 0); 133 134 SetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format); 135 SetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep); 136 Check(IDC_ID3V1, 0); 137/*! Check(IDC_RESERVE, flac_cfg.tag.reserve_space); */ 138 Check(IDC_BPS, flac_cfg.display.show_bps); 139 Check(IDC_ERRORS, flac_cfg.output.misc.stop_err); 140 return TRUE; 141 /* commands */ 142 case WM_COMMAND: 143 switch (LOWORD(wParam)) 144 { 145 /* ok */ 146 case IDOK: 147 GetDlgItemText(hwnd, IDC_TITLE, flac_cfg.title.tag_format, sizeof(flac_cfg.title.tag_format)); 148 if (flac_cfg.title.tag_format_w) 149 free(flac_cfg.title.tag_format_w); 150 GetDlgItemText(hwnd, IDC_SEP, flac_cfg.title.sep, sizeof(flac_cfg.title.sep)); 151 flac_cfg.title.tag_format_w = convert_ansi_to_wide_(flac_cfg.title.tag_format); 152 153/*! flac_cfg.tag.reserve_space = GetCheck(IDC_RESERVE); */ 154 flac_cfg.display.show_bps = GetCheck(IDC_BPS); 155 flac_cfg.output.misc.stop_err = GetCheck(IDC_ERRORS); 156 break; 157 /* reset */ 158 case IDC_RESET: 159 Check(IDC_ID3V1, 0); 160 Check(IDC_RESERVE, 1); 161 Check(IDC_BPS, 1); 162 Check(IDC_ERRORS, 0); 163 /* fall throught */ 164 /* default */ 165 case IDC_TAGZ_DEFAULT: 166 SetDlgItemText(hwnd, IDC_TITLE, default_format); 167 break; 168 /* help */ 169 case IDC_TAGZ_HELP: 170 MessageBox(hwnd, tagz_manual, "Help", 0); 171 break; 172 } 173 break; 174 } 175 176 return 0; 177} 178 179 180static void UpdatePreamp(HWND hwnd, HWND hamp) 181{ 182 int pos = SendMessage(hamp, TBM_GETPOS, 0, 0) - PREAMP_RANGE; 183 sprintf(buffer, "%d dB", pos); 184 SetDlgItemText(hwnd, IDC_PA, buffer); 185} 186 187static void UpdateRG(HWND hwnd) 188{ 189 int on = GetCheck(IDC_ENABLE); 190 Enable(IDC_ALBUM, on); 191 Enable(IDC_LIMITER, on); 192 Enable(IDC_PREAMP, on); 193 Enable(IDC_PA, on); 194} 195 196static void UpdateDither(HWND hwnd) 197{ 198 int on = GetCheck(IDC_DITHERRG); 199 Enable(IDC_SHAPE, on); 200} 201 202static INT_PTR CALLBACK OutputProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 203{ 204 switch (msg) 205 { 206 /* init */ 207 case WM_INITDIALOG: 208 Check(IDC_ENABLE, flac_cfg.output.replaygain.enable); 209 Check(IDC_ALBUM, flac_cfg.output.replaygain.album_mode); 210 Check(IDC_LIMITER, flac_cfg.output.replaygain.hard_limit); 211 Check(IDC_DITHER, flac_cfg.output.resolution.normal.dither_24_to_16); 212 Check(IDC_DITHERRG, flac_cfg.output.resolution.replaygain.dither); 213 /* prepare preamp slider */ 214 { 215 HWND hamp = GetDlgItem(hwnd, IDC_PREAMP); 216 SendMessage(hamp, TBM_SETRANGE, 1, MAKELONG(0, PREAMP_RANGE*2)); 217 SendMessage(hamp, TBM_SETPOS, 1, flac_cfg.output.replaygain.preamp+PREAMP_RANGE); 218 UpdatePreamp(hwnd, hamp); 219 } 220 /* fill comboboxes */ 221 { 222 HWND hlist = GetDlgItem(hwnd, IDC_TO); 223 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"16 bps"); 224 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"24 bps"); 225 SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.bps_out/8 - 2, 0); 226 227 hlist = GetDlgItem(hwnd, IDC_SHAPE); 228 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"None"); 229 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Low"); 230 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"Medium"); 231 SendMessage(hlist, CB_ADDSTRING, 0, (LPARAM)"High"); 232 SendMessage(hlist, CB_SETCURSEL, flac_cfg.output.resolution.replaygain.noise_shaping, 0); 233 } 234 UpdateRG(hwnd); 235 UpdateDither(hwnd); 236 return TRUE; 237 /* commands */ 238 case WM_COMMAND: 239 switch (LOWORD(wParam)) 240 { 241 /* ok */ 242 case IDOK: 243 flac_cfg.output.replaygain.enable = GetCheck(IDC_ENABLE); 244 flac_cfg.output.replaygain.album_mode = GetCheck(IDC_ALBUM); 245 flac_cfg.output.replaygain.hard_limit = GetCheck(IDC_LIMITER); 246 flac_cfg.output.replaygain.preamp = GetPos(IDC_PREAMP) - PREAMP_RANGE; 247 flac_cfg.output.resolution.normal.dither_24_to_16 = GetCheck(IDC_DITHER); 248 flac_cfg.output.resolution.replaygain.dither = GetCheck(IDC_DITHERRG); 249 flac_cfg.output.resolution.replaygain.noise_shaping = GetSel(IDC_SHAPE); 250 flac_cfg.output.resolution.replaygain.bps_out = (GetSel(IDC_TO)+2)*8; 251 break; 252 /* reset */ 253 case IDC_RESET: 254 Check(IDC_ENABLE, 1); 255 Check(IDC_ALBUM, 0); 256 Check(IDC_LIMITER, 0); 257 Check(IDC_DITHER, 0); 258 Check(IDC_DITHERRG, 0); 259 260 SendDlgItemMessage(hwnd, IDC_PREAMP, TBM_SETPOS, 1, PREAMP_RANGE); 261 SendDlgItemMessage(hwnd, IDC_TO, CB_SETCURSEL, 0, 0); 262 SendDlgItemMessage(hwnd, IDC_SHAPE, CB_SETCURSEL, 1, 0); 263 264 UpdatePreamp(hwnd, GetDlgItem(hwnd, IDC_PREAMP)); 265 UpdateRG(hwnd); 266 UpdateDither(hwnd); 267 break; 268 /* active check-boxes */ 269 case IDC_ENABLE: 270 UpdateRG(hwnd); 271 break; 272 case IDC_DITHERRG: 273 UpdateDither(hwnd); 274 break; 275 } 276 break; 277 /* scroller */ 278 case WM_HSCROLL: 279 if (GetDlgCtrlID((HWND)lParam)==IDC_PREAMP) 280 UpdatePreamp(hwnd, (HWND)lParam); 281 return 0; 282 } 283 284 return 0; 285} 286 287#define NUM_PAGES 2 288 289typedef struct 290{ 291 HWND htab; 292 HWND hdlg; 293 RECT r; 294 HWND all[NUM_PAGES]; 295} LOCALDATA; 296 297static void ScreenToClientRect(HWND hwnd, RECT *rect) 298{ 299 POINT pt = { rect->left, rect->top }; 300 ScreenToClient(hwnd, &pt); 301 rect->left = pt.x; 302 rect->top = pt.y; 303 304 pt.x = rect->right; 305 pt.y = rect->bottom; 306 ScreenToClient(hwnd, &pt); 307 rect->right = pt.x; 308 rect->bottom = pt.y; 309} 310 311static void SendCommand(HWND hwnd, int command) 312{ 313 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA); 314 SendMessage(data->hdlg, WM_COMMAND, command, 0); 315} 316 317static void BroadcastCommand(HWND hwnd, int command) 318{ 319 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA); 320 int i; 321 322 for (i=0; i<NUM_PAGES; i++) 323 SendMessage(data->all[i], WM_COMMAND, command, 0); 324} 325 326static void OnSelChange(HWND hwnd) 327{ 328 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA); 329 int index = TabCtrl_GetCurSel(data->htab); 330 if (index < 0) return; 331 /* hide previous */ 332 if (data->hdlg) 333 ShowWindow(data->hdlg, SW_HIDE); 334 /* display */ 335 data->hdlg = data->all[index]; 336 SetWindowPos(data->hdlg, HWND_TOP, data->r.left, data->r.top, data->r.right-data->r.left, data->r.bottom-data->r.top, SWP_SHOWWINDOW); 337 SetFocus(hwnd); 338} 339 340static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 341{ 342 static activePage = 0; 343 344 switch (msg) 345 { 346 /* init */ 347 case WM_INITDIALOG: 348 { 349 LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA)); 350 HINSTANCE inst = (HINSTANCE)lParam; 351 TCITEM item; 352 353 /* init */ 354 SetWindowLong(hwnd, GWL_USERDATA, (LONG)data); 355 data->htab = GetDlgItem(hwnd, IDC_TABS); 356 data->hdlg = NULL; 357 /* add pages */ 358 item.mask = TCIF_TEXT; 359 data->all[0] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_GENERAL), hwnd, GeneralProc); 360 item.pszText = "General"; 361 TabCtrl_InsertItem(data->htab, 0, &item); 362 363 data->all[1] = CreateDialog(inst, MAKEINTRESOURCE(IDD_CONFIG_OUTPUT), hwnd, OutputProc); 364 item.pszText = "Output"; 365 TabCtrl_InsertItem(data->htab, 1, &item); 366 /* get rect (after adding pages) */ 367 GetWindowRect(data->htab, &data->r); 368 ScreenToClientRect(hwnd, &data->r); 369 TabCtrl_AdjustRect(data->htab, 0, &data->r); 370 /* simulate item change */ 371 TabCtrl_SetCurSel(data->htab, activePage); 372 OnSelChange(hwnd); 373 } 374 return TRUE; 375 /* destory */ 376 case WM_DESTROY: 377 { 378 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA); 379 int i; 380 381 activePage = TabCtrl_GetCurSel(data->htab); 382 383 for (i=0; i<NUM_PAGES; i++) 384 DestroyWindow(data->all[i]); 385 386 LocalFree(data); 387 } 388 break; 389 /* commands */ 390 case WM_COMMAND: 391 switch (LOWORD(wParam)) 392 { 393 /* ok/cancel */ 394 case IDOK: 395 BroadcastCommand(hwnd, IDOK); 396 /* fall through */ 397 case IDCANCEL: 398 EndDialog(hwnd, LOWORD(wParam)); 399 return TRUE; 400 case IDC_RESET: 401 SendCommand(hwnd, IDC_RESET); 402 break; 403 } 404 break; 405 /* notification */ 406 case WM_NOTIFY: 407 if (LOWORD(wParam) == IDC_TABS) 408 { 409 NMHDR *hdr = (NMHDR*)lParam; 410 411 switch (hdr->code) 412 { 413 case TCN_SELCHANGE: 414 OnSelChange(hwnd); 415 break; 416 } 417 } 418 break; 419 } 420 421 return 0; 422} 423 424 425int DoConfig(HINSTANCE inst, HWND parent) 426{ 427 return DialogBoxParam(inst, MAKEINTRESOURCE(IDD_CONFIG), parent, DialogProc, (LONG)inst) == IDOK; 428} 429