/* Mikmod for Winamp By Jake Stine and Justin Frankel. Really. Done in 1998, 1999. The millenium cometh! Done more in 2000. The millenium passeth by! Redone lots in 2001. The REAL millenium cometh! haha. */ #include "api.h" extern "C" { #include "main.h" } #include #include #include "../../winamp/wa_ipc.h" #include #include "../nu/AutoWide.h" #define TabCtrl_InsertItemW(hwnd, iItem, pitem) \ (int)SNDMSG((hwnd), TCM_INSERTITEMW, (WPARAM)(int)(iItem), (LPARAM)(const TC_ITEMW *)(pitem)) #define C_PAGES 4 #define CFG_UNCHANGED (-1) #define EFFECT_8XX (1ul<<0) #define EFFECT_ZXX (1ul<<1) #define CPUTBL_COUNT 23 #define MIXTBL_COUNT 7 #define VOICETBL_COUNT 8 #define DEF_SRATE 44100 typedef struct tag_cdlghdr { HWND hwndTab; // tab control HWND hwndDisplay; // current child dialog box int left,top; HWND apRes[C_PAGES]; } CFG_DLGHDR; // Winamp Stuff UBYTE config_savestr = 0; // save stream to disk // Output Settings UBYTE config_nch = 2; UBYTE config_cpu; // Player Settings... // ------------------ int config_loopcount = 0; // Auto-looping count, if the song has a natural loop. uint config_playflag = 0; // See CPLAYFLG_* defines above for flags int config_pansep = 128; // master panning separation (0 == mono, 128 == stereo, 512 = way-separate) UBYTE config_resonance = 1; int config_fadeout = 1000; // fadeout when the song is ending last loop (in ms) // Mixer Settings... // ----------------- UBYTE config_panrev = 0, // Reverse panning (left<->right) config_interp = 3; // interpolation (bit 0) / noclick (bit 1) / cubic (bit 2) uint config_srate = DEF_SRATE; uint config_voices = 96; // maximum voices player can use. // Local Crud... // ------------- static const char *INI_FILE; static const char app_name[] = "Nullsoft Module Decoder"; static int l_quality, l_srate, // l_quality indexes mixertbl. l_srate is the actual number. l_voices; static BOOL l_useres, l_nch, l_iflags; int config_tsel = 0; static uint voicetable[VOICETBL_COUNT] = { 24, 32, 48, 64, 96, 128, 256, 512 }; static uint mixertbl[MIXTBL_COUNT] = { 48000, 44100, 33075, 22050, 16000, 11025, 8000, }; // Define Extended Loader Details/Options // -------------------------------------- typedef struct _MLCONF { CHAR *cfgname; // configuration name prefix. INT desc_id; // long-style multi-line description! CHAR *exts; MLOADER *loader; // mikmod loader to register BOOL enabled; uint defpan, // default panning separation \ range 0 - 128 pan; // current panning separation / (mono to stereo) uint optavail, // available advanced effects options optset; // current settings for those options. } MLCONF; static MLCONF c_mod[] = { "mod", IDS_PROTRACKER_AND_CLONES, "mod;mdz;nst", &load_mod, TRUE, 0,0, EFFECT_8XX, 0, "m15", IDS_OLD_SKOOL_AMIGA_MODULES, "mod;mdz", &load_m15, TRUE, 0,0, EFFECT_8XX, 0, "stm", IDS_SCREAM_TRACKER_2XX, "stm;stz", &load_stm, TRUE, 0,0, EFFECT_8XX | EFFECT_ZXX, 0, "st3", IDS_SCREAM_TRACKER_3XX, "s3m;s3z", &load_s3m, TRUE, 32,32, EFFECT_8XX | EFFECT_ZXX, 0, "it", IDS_IMPULSE_TRACKER, "it;itz", &load_it, TRUE, 0,0, EFFECT_ZXX, 0, "ft2", IDS_FASTTRACKER_2XX, "xm;xmz", &load_xm, TRUE, 0,0, 0, 0, "mtm", IDS_MULTITRACKER, "mtm", &load_mtm, TRUE, 0,0, EFFECT_8XX, 0, "ult", IDS_ULTRA_TRACKER, "ult", &load_ult, TRUE, 0,0, EFFECT_8XX, 0, "669", IDS_COMPOSER_669, "669", &load_669, TRUE, 0,0, 0, 0, "far", IDS_FARANDOLE_COMPOSER, "far", &load_far, TRUE, 0,0, 0, 0, "amf", IDS_DIGITAL_SOUND_AND_MUSIC_INTERFACE, "amf", &load_amf, TRUE, 0,0, 0, 0, "okt", IDS_AMIGA_OKTALYZER, "okt", &load_okt, TRUE, 0, 0, 0, 0, "ptm", IDS_POLYTRACKER, "ptm", &load_ptm, TRUE, 0, 0, EFFECT_8XX, 0, }; #define C_NUMLOADERS (sizeof(c_mod)/sizeof(c_mod[0])) static MLCONF l_mod[C_NUMLOADERS]; // local copy, for cancelability // ===================================================================================== static int _r_i(char *name, int def) // ===================================================================================== { name += 7; return GetPrivateProfileInt(app_name,name,def,INI_FILE); } #define RI(x) (( x ) = _r_i(#x,( x ))) // ===================================================================================== static void _w_i(char *name, int d) // ===================================================================================== { char str[120] = {0}; StringCchPrintf(str,100,"%d",d); name += 7; WritePrivateProfileString(app_name,name,str,INI_FILE); } #define WI(x) _w_i(#x,( x )) // ===================================================================================== static void config_buildbindings(CHAR *datext) // ===================================================================================== // Creates the binding string. { #define SEP_CHAR ';' uint i; char *base = datext; base[0] = 0; for (i=0; i base) { *(datext-1) = 0; StringCchCopy(datext,4096,WASABI_API_LNGSTRING(IDS_MUSIC_MODULES)); } } // ===================================================================================== static void config_init(void) // ===================================================================================== { INI_FILE = (const char *)SendMessage(mikmod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE); } // ===================================================================================== void config_read(void) // ===================================================================================== { uint t; config_init(); RI(config_savestr); RI(config_nch); RI(config_srate); RI(config_interp); RI(config_voices); RI(config_loopcount); RI(config_playflag); RI(config_resonance); RI(config_fadeout); RI(config_pansep); RI(config_panrev); RI(config_info_x); RI(config_info_y); RI(config_track); RI(config_tsel); config_cpu = _mm_cpudetect(); // Load settings for each of the individual loaders // ------------------------------------------------ for(t=0; tenabled = c_mod[t].enabled; c_mod[t].loader->defpan = c_mod[t].pan; c_mod[t].loader->nopaneff = (c_mod[t].optset | EFFECT_8XX) ? FALSE : TRUE; c_mod[t].loader->noreseff = (c_mod[t].optset | EFFECT_ZXX) ? FALSE : TRUE; } config_buildbindings(mikmod.FileExtensions); // Bounds checking! // ---------------- // This is important to ensure stability of the product in case some // doof goes and starts hacking the ini values carelessly - or if some sort // of version conflict or corruption causes skewed readings. config_pansep = _mm_boundscheck(config_pansep, 0, 512); config_voices = _mm_boundscheck(config_voices, 2, 1024); config_fadeout = _mm_boundscheck(config_fadeout, 0, 1000l*1000l); config_loopcount = _mm_boundscheck(config_loopcount, -1, 63); } // ===================================================================================== void config_write(void) // ===================================================================================== { uint t = 0; WI(config_savestr); WI(config_nch); WI(config_srate); WI(config_interp); WI(config_voices); WI(config_loopcount); WI(config_playflag); WI(config_resonance); WI(config_fadeout); WI(config_pansep); WI(config_panrev); WI(config_info_x); WI(config_info_y); WI(config_track); WI(config_tsel); // Save settings for each of the individual loaders // ------------------------------------------------ for(; t < C_NUMLOADERS; t++) { CHAR stmp[72] = {0}, sint[12] = {0}; StringCchPrintf(stmp,72,"%s%s",c_mod[t].cfgname,"enabled"); StringCchPrintf(sint,12,"%d",c_mod[t].enabled); WritePrivateProfileString(app_name,stmp,sint,INI_FILE); StringCchPrintf(stmp,72,"%s%s",c_mod[t].cfgname,"panning"); StringCchPrintf(sint,12,"%d",c_mod[t].pan); WritePrivateProfileString(app_name,stmp,sint,INI_FILE); StringCchPrintf(stmp,72,"%s%s",c_mod[t].cfgname,"effects"); StringCchPrintf(sint,12,"%d",c_mod[t].optset); WritePrivateProfileString(app_name,stmp,sint,INI_FILE); // configure the loaders c_mod[t].loader->enabled = c_mod[t].enabled; c_mod[t].loader->nopaneff = (c_mod[t].optset | EFFECT_8XX) ? FALSE : TRUE; c_mod[t].loader->noreseff = (c_mod[t].optset | EFFECT_ZXX) ? FALSE : TRUE; } config_buildbindings(mikmod.FileExtensions); } static BOOL CALLBACK prefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); // ===================================================================================== void __cdecl config(HWND hwndParent) // ===================================================================================== { WASABI_API_DIALOGBOXW(IDD_PREFS,hwndParent,prefsProc); config_write(); } static BOOL CALLBACK tabProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK mixerProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK loaderProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static void OnSelChanged(HWND hwndDlg, int initonly); // ===================================================================================== static void prefsTabInit(HWND hwndDlg, CFG_DLGHDR *pHdr) // ===================================================================================== { DWORD dwDlgBase = GetDialogBaseUnits(); int cxMargin = LOWORD(dwDlgBase) / 4, cyMargin = HIWORD(dwDlgBase) / 8; TC_ITEMW tie; int tabCounter; tie.mask = TCIF_TEXT | TCIF_IMAGE; tie.iImage = -1; tabCounter = 0; SendMessage(mikmod.hMainWindow,WM_WA_IPC,(WPARAM)pHdr->hwndTab,IPC_USE_UXTHEME_FUNC); tie.pszText = WASABI_API_LNGSTRINGW(IDS_MIXER); TabCtrl_InsertItemW(pHdr->hwndTab, tabCounter, &tie); pHdr->apRes[tabCounter] = WASABI_API_CREATEDIALOGPARAMW(IDD_PREFTAB_MIXER, hwndDlg, mixerProc, IDD_PREFTAB_MIXER); SetWindowPos(pHdr->apRes[tabCounter], HWND_TOP, pHdr->left, pHdr->top, 0, 0, SWP_NOSIZE); SendMessage(mikmod.hMainWindow,WM_WA_IPC,(WPARAM)pHdr->apRes[tabCounter],IPC_USE_UXTHEME_FUNC); ShowWindow(pHdr->apRes[tabCounter++], SW_HIDE); tie.pszText = WASABI_API_LNGSTRINGW(IDS_PLAYER); TabCtrl_InsertItemW(pHdr->hwndTab, tabCounter, &tie); pHdr->apRes[tabCounter] = WASABI_API_CREATEDIALOGPARAMW(IDD_PREFTAB_DECODER, hwndDlg, tabProc, IDD_PREFTAB_DECODER); SetWindowPos(pHdr->apRes[tabCounter], HWND_TOP, pHdr->left, pHdr->top, 0, 0, SWP_NOSIZE); SendMessage(mikmod.hMainWindow,WM_WA_IPC,(WPARAM)pHdr->apRes[tabCounter],IPC_USE_UXTHEME_FUNC); ShowWindow(pHdr->apRes[tabCounter++], SW_HIDE); tie.pszText = WASABI_API_LNGSTRINGW(IDS_LOADERS); TabCtrl_InsertItemW(pHdr->hwndTab, tabCounter, &tie); pHdr->apRes[tabCounter] = WASABI_API_CREATEDIALOGPARAMW(IDD_PREFTAB_LOADER, hwndDlg, loaderProc, IDD_PREFTAB_LOADER); SetWindowPos(pHdr->apRes[tabCounter], HWND_TOP, pHdr->left, pHdr->top, 0, 0, SWP_NOSIZE); SendMessage(mikmod.hMainWindow,WM_WA_IPC,(WPARAM)pHdr->apRes[tabCounter],IPC_USE_UXTHEME_FUNC); ShowWindow(pHdr->apRes[tabCounter++], SW_HIDE); // Simulate selection of the first item. OnSelChanged(hwndDlg,1); } // ===================================================================================== static void OnSelChanged(HWND hwndDlg, int initonly) // ===================================================================================== { CFG_DLGHDR *pHdr = (CFG_DLGHDR *) GetWindowLong(hwndDlg, GWL_USERDATA); if(!initonly) config_tsel = TabCtrl_GetCurSel(pHdr->hwndTab); else TabCtrl_SetCurSel(pHdr->hwndTab,config_tsel); if(pHdr->hwndDisplay) ShowWindow(pHdr->hwndDisplay,SW_HIDE); ShowWindow(pHdr->apRes[config_tsel],SW_SHOW); pHdr->hwndDisplay = pHdr->apRes[config_tsel]; } // ===================================================================================== static void FadeOutSetup(HWND hwndDlg, BOOL enabled) // ===================================================================================== { EnableWindow(GetDlgItem(hwndDlg, IDC_FADEOUT), enabled); EnableWindow(GetDlgItem(hwndDlg, IDC_FADESEC), enabled); } // ===================================================================================== static void Stereo_Dependencies(HWND hwndDlg) // ===================================================================================== // Enable or Disable the options which are dependant on stereo being enabled { BOOL val = (l_nch==1) ? 0 : 1; EnableWindow(GetDlgItem(hwndDlg,OUTMODE_REVERSE), val); EnableWindow(GetDlgItem(hwndDlg,OUTMODE_SURROUND),val); } // ===================================================================================== static void SetVoiceList(HWND hwndMisc) // ===================================================================================== // erg is the current quality mode (indexes mixertbl). { uint i,k; BOOL picked = FALSE; uint cfgv; cfgv = (l_voices==CFG_UNCHANGED) ? config_voices : voicetable[l_voices]; SendMessage(hwndMisc,CB_RESETCONTENT,0,0); for(i=0; i= cfgv)) { k = i; picked = TRUE; } } // If picked is false, then set to 96 (default) if(!picked) k = 4; SendMessage(hwndMisc,CB_SETCURSEL,k,0); } // ===================================================================================== static BOOL cmod_and_the_moo(HWND dagnergit, int *moo, int count, uint flag) // ===================================================================================== { int l; BOOL oneway, otherway, thisway, thatway; oneway = otherway = thisway = thatway = FALSE; // Set oneway/otherway true for selected/unselected options. // Set thisway/thatway true for avail/nonawail options. for(l=0; lDescStrID)); } SendMessage(hwndMisc, LB_SETCURSEL, 0, 0); loaderProc(hwndDlg, WM_COMMAND, (WPARAM)((LBN_SELCHANGE << 16) + IDLDR_LIST), (LPARAM)hwndMisc); if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(hwndMisc, TRUE); } return TRUE; case WM_DESTROY: { HWND hwndMisc = GetDlgItem(hwndDlg, IDLDR_LIST); if (NULL != WASABI_API_APP) WASABI_API_APP->DirectMouseWheel_EnableConvertToMouseWheel(hwndMisc, FALSE); } break; // ============================================================================= case WM_COMMAND: // ============================================================================= // Process commands and notification messages recieved from our child controls. switch(LOWORD(wParam)) { case IDOK: { uint i; for (i=0; idefpan = c_mod[i].pan; } } break; case IDLDR_LIST: // The Loader Box Update Balloofie // ------------------------------- // Updates the various controls on the 'loader tab' dialog box. Involves // enabling/disabling advanced-effects boxes, checking the Enabled box, and // setting the panning position. Also: extra care is taken to allow proper // and intuitive support for multiple selections! if(HIWORD(wParam) == LBN_SELCHANGE) { int moo[C_NUMLOADERS], count,l; BOOL oneway, otherway, opt1, opt2; HWND beiownd; // Fetch the array of selected items! count = SendMessage((HWND)lParam, LB_GETSELITEMS, C_NUMLOADERS, (LPARAM)moo); if(!count || (count == LB_ERR)) { // Something's not right, so just disable all the controls. SetWindowTextW(GetDlgItem(hwndDlg, IDLDR_DESCRIPTION), WASABI_API_LNGSTRINGW(IDS_SELECT_ANY_LOADER)); EnableWindow(beiownd = GetDlgItem(hwndDlg, IDLDR_PANPOS), FALSE); EnableWindow(beiownd = GetDlgItem(hwndDlg, IDLDR_ENABLED), FALSE); SendMessage(hwndDlg, BM_GETCHECK, BST_UNCHECKED,0); EnableWindow(beiownd = GetDlgItem(hwndDlg, IDLDR_EFFOPT1), FALSE); SendMessage(hwndDlg, BM_GETCHECK, BST_UNCHECKED,0); EnableWindow(beiownd = GetDlgItem(hwndDlg, IDLDR_EFFOPT2), FALSE); SendMessage(hwndDlg, BM_GETCHECK, BST_UNCHECKED,0); EnableWindow(beiownd = GetDlgItem(hwndDlg, IDC_DEFPAN), FALSE); break; } SetWindowTextW(GetDlgItem(hwndDlg, IDLDR_DESCRIPTION), WASABI_API_LNGSTRINGW( (count==1) ? l_mod[moo[0]].desc_id : IDS_MULTIPLE_ITEMS_SELECTED)); // Enabled Box : First of Many // --------------------------- oneway = otherway = FALSE; for(l=0; l>3)); // 8xx Panning Disable: Third of Four // Zxx Resonance: All the Duckies are in a Row! // -------------------------------------------- opt1 = cmod_and_the_moo(GetDlgItem(hwndDlg, IDLDR_EFFOPT1), moo, count, EFFECT_8XX); opt2 = cmod_and_the_moo(GetDlgItem(hwndDlg, IDLDR_EFFOPT2), moo, count, EFFECT_ZXX); EnableWindow(GetDlgItem(hwndDlg, IDC_ADV_TEXT_INFO), opt1 || opt2); } break; case IDLDR_ENABLED: case IDC_DEFPAN: case IDLDR_EFFOPT1: case IDLDR_EFFOPT2: if(HIWORD(wParam) == BN_CLICKED) { int moo[C_NUMLOADERS],count; int res = SendMessage((HWND)lParam,BM_GETCHECK,0,0); count = SendMessage(GetDlgItem(hwndDlg, IDLDR_LIST), LB_GETSELITEMS, C_NUMLOADERS, (LPARAM)moo); switch(res) { case BST_CHECKED: SendMessage((HWND)lParam,BM_SETCHECK,BST_UNCHECKED,0); res = 0; break; case BST_INDETERMINATE: case BST_UNCHECKED: SendMessage((HWND)lParam,BM_SETCHECK,BST_CHECKED,0); res = 1; break; } if (LOWORD(wParam) == IDLDR_ENABLED) { int l; for(l=0; l>3)); } else { uint flag = (LOWORD(wParam) == IDLDR_EFFOPT1) ? EFFECT_8XX : EFFECT_ZXX; int l; for(l=0; lDirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls))) { return TRUE; } return 0; } // ===================================================================================== static void FadeoutSetText(HWND hwndDlg) // ===================================================================================== { CHAR work[32] = {0}; StringCchPrintf(work, 32, "%.02f",config_fadeout/1000.0f); SetDlgItemText(hwndDlg, IDC_FADEOUT, work); } // ===================================================================================== static BOOL CALLBACK tabProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) // ===================================================================================== { switch (uMsg) { // ============================================================================= case WM_INITDIALOG: // ============================================================================= // Windows dialog box startup message. This is messaged for each tab form created. // Initialize all of the controls on each of those forms! { HWND hwndMisc; CFG_DLGHDR *pHdr = (CFG_DLGHDR *)GetWindowLong(GetParent(hwndDlg), GWL_USERDATA); SetWindowLong(hwndDlg,DWL_USER,lParam); switch(lParam) { case IDD_PREFTAB_DECODER: SendMessage(GetDlgItem(hwndDlg,IDC_FADEOUT), EM_SETLIMITTEXT, 10,0); FadeoutSetText(hwndDlg); hwndMisc = GetDlgItem(hwndDlg,IDC_PANSEP); SendMessage(hwndMisc,TBM_SETRANGEMIN,0,0); SendMessage(hwndMisc,TBM_SETRANGEMAX,0,32); { int erg = config_pansep; if (erg <= 128) erg *= 2; else erg = 256 + ((erg - 128) * 256) / 384; SendMessage(hwndMisc,TBM_SETPOS,1, (erg>>4)&31); } hwndMisc = GetDlgItem(hwndDlg, IDC_LOOPS); SendMessage(hwndMisc, TBM_SETRANGEMIN, 0, 0); SendMessage(hwndMisc, TBM_SETRANGEMAX, 0, 64); SendMessage(hwndMisc, TBM_SETTICFREQ, 4, 0); SendMessage(hwndMisc, TBM_SETPOS, 1, config_loopcount>=0 ? config_loopcount : 64); SendMessage(hwndDlg, WM_HSCROLL, 0, (LPARAM)hwndMisc); CheckDlgButton(hwndDlg,IDC_LOOPALL, (config_playflag & CPLAYFLG_LOOPALL) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_CONT_LOOP, (config_playflag & CPLAYFLG_CONT_LOOP) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_PLAYALL, (config_playflag & CPLAYFLG_PLAYALL) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_FADECHECK, (config_playflag & CPLAYFLG_FADEOUT) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_STRIPSILENCE,(config_playflag & CPLAYFLG_STRIPSILENCE) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_SEEKBYORDERS,(config_playflag & CPLAYFLG_SEEKBYORDERS) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg,IDC_RESONANCE,config_resonance ? BST_CHECKED : BST_UNCHECKED); FadeOutSetup(hwndDlg, config_playflag & CPLAYFLG_FADEOUT); return TRUE; } } break; // ============================================================================= case WM_COMMAND: // ============================================================================= // Process commands and notification messages recieved from our child controls. switch(LOWORD(wParam)) { case IDOK: { switch(lParam) { case IDD_PREFTAB_DECODER: { CHAR stmp[32] = {0}; double ftmp; config_loopcount = SendMessage(GetDlgItem(hwndDlg, IDC_LOOPS), TBM_GETPOS, 0, 0); if (config_loopcount == 64) config_loopcount = -1; GetDlgItemText(hwndDlg, IDC_FADEOUT, stmp, 12); ftmp = atof(stmp); config_fadeout = (int)(ftmp * 1000l); config_fadeout = _mm_boundscheck(config_fadeout, 0, 1000l*1000l); // bound to 1000 seconds. { int erg = SendMessage(GetDlgItem(hwndDlg,IDC_PANSEP),TBM_GETPOS,0,0)<<4; if (erg <= 256) erg /= 2; else erg = 128 + ((erg - 256) * 384) / 256; config_pansep = erg; } config_playflag = IsDlgButtonChecked(hwndDlg,IDC_LOOPALL) ? CPLAYFLG_LOOPALL : 0; config_playflag |= IsDlgButtonChecked(hwndDlg,IDC_CONT_LOOP) ? CPLAYFLG_CONT_LOOP : 0; config_playflag |= IsDlgButtonChecked(hwndDlg,IDC_PLAYALL) ? CPLAYFLG_PLAYALL : 0; config_playflag |= IsDlgButtonChecked(hwndDlg,IDC_FADECHECK) ? CPLAYFLG_FADEOUT : 0; config_playflag |= IsDlgButtonChecked(hwndDlg,IDC_STRIPSILENCE) ? CPLAYFLG_STRIPSILENCE : 0; config_playflag |= IsDlgButtonChecked(hwndDlg,IDC_SEEKBYORDERS) ? CPLAYFLG_SEEKBYORDERS : 0; config_resonance = IsDlgButtonChecked(hwndDlg,IDC_RESONANCE) ? 1 : 0; } break; } } break; case IDC_FADECHECK: // hide/unhide fadeout controls if(HIWORD(wParam) == BN_CLICKED) { int res = SendMessage((HWND)lParam,BM_GETCHECK,0,0); FadeOutSetup(hwndDlg, res); } break; } break; // ============================================================================= case WM_HSCROLL: // ============================================================================= switch (GetDlgCtrlID((HWND)lParam)) { case IDC_LOOPS: { wchar_t foo[64] = {0}; int pos = SendMessage((HWND)lParam, TBM_GETPOS, 0, 0); HWND hText = GetDlgItem(hwndDlg, IDC_LOOPTEXT); if (!pos) WASABI_API_LNGSTRINGW_BUF(IDS_DO_NOT_LOOP,foo,64); else if (pos == 64) WASABI_API_LNGSTRINGW_BUF(IDS_LOOP_FOREVER,foo,64); else StringCchPrintfW(foo, 64, WASABI_API_LNGSTRINGW(IDS_LOOP_X_TIMES), pos + 1); SetWindowTextW(hText, foo); } break; } break; // ============================================================================= case WM_NOTIFY: // ============================================================================= switch(LOWORD(wParam)) { case IDC_FADESPIN: { NMUPDOWN *mud = (NMUPDOWN *) lParam; if(mud->hdr.code == UDN_DELTAPOS) { // bounds check things between 0-1000secs (added in 2.2.6) if(mud->iDelta > 0) { if(config_fadeout > 0) config_fadeout -= 250; } else { if(config_fadeout < 1000l*1000l) config_fadeout += 250; } FadeoutSetText(hwndDlg); } } return TRUE; } break; } const int controls[] = { IDC_LOOPS, IDC_PANSEP, IDLDR_PANPOS, }; if (FALSE != WASABI_API_APP->DirectMouseWheel_ProcessDialogMessage(hwndDlg, uMsg, wParam, lParam, controls, ARRAYSIZE(controls))) { return TRUE; } return 0; } // ===================================================================================== static BOOL CALLBACK prefsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) // ===================================================================================== // This is the procedure which initializes the various forms that make up the tabs in // our preferences box! This also contains the message handler for the OK and Cancel // buttons. After that, all messaging is handled by the tab forms themselves in tabProc(); { switch (uMsg) { case WM_INITDIALOG: { CFG_DLGHDR *pHdr = (CFG_DLGHDR*)calloc(1, sizeof(CFG_DLGHDR)); SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pHdr); pHdr->hwndTab = GetDlgItem(hwndDlg,MM_PREFTAB); pHdr->left = 8; pHdr->top = 30; prefsTabInit(hwndDlg, pHdr); { wchar_t title[128] = {0}, temp[128] = {0}; StringCchPrintfW(title, 128, WASABI_API_LNGSTRINGW(IDS_PREFERENCES_TITLE),WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_MODULE_DECODER_OLD,temp,128)); SetWindowTextW(hwndDlg,title); } } return FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: { // Send an IDOK command to both tabcontrol children to let them know // that the world is about to end! CFG_DLGHDR *pHdr = (CFG_DLGHDR*)GetWindowLong(hwndDlg, GWL_USERDATA); SendMessage(pHdr->apRes[0], WM_COMMAND, (WPARAM)IDOK, (LPARAM)IDD_PREFTAB_MIXER); SendMessage(pHdr->apRes[1], WM_COMMAND, (WPARAM)IDOK, (LPARAM)IDD_PREFTAB_DECODER); SendMessage(pHdr->apRes[2], WM_COMMAND, (WPARAM)IDOK, (LPARAM)IDD_PREFTAB_LOADER); EndDialog(hwndDlg,0); return 0; } case IDCANCEL: EndDialog(hwndDlg,0); return FALSE; case OQ_QUALITY: uMsg = 8; break; } break; case WM_NOTIFY: { NMHDR *notice = (NMHDR *) lParam; NMHDR *ack; uint k; ack = (NMHDR *)lParam; if(ack->hwndFrom == GetDlgItem(hwndDlg,OQ_QUALITY)) { switch(ack->code) { case CBEN_GETDISPINFO: k = 1; break; } } switch(notice->code) { case TCN_SELCHANGE: OnSelChanged(hwndDlg,0); return TRUE; } } return FALSE; case WM_DESTROY: { // free local data free((CFG_DLGHDR*)GetWindowLong(hwndDlg, GWL_USERDATA)); } break; } return FALSE; } static int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message) { MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0}; msgbx.lpszText = message; msgbx.lpszCaption = title; msgbx.lpszIcon = MAKEINTRESOURCEW(102); msgbx.hInstance = GetModuleHandle(0); msgbx.dwStyle = MB_USERICON; msgbx.hwndOwner = parent; return MessageBoxIndirectW(&msgbx); } // ===================================================================================== void __cdecl about(HWND hwndParent) // ===================================================================================== { wchar_t message[1024] = {0}, text[1024] = {0}; WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_MODULE_DECODER_OLD,text,1024); StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT), mikmod.description, TEXT(__DATE__)); DoAboutMessageBox(hwndParent,text,message); } static const wchar_t *pExtCompress[] = { L"ITZ", L"MDZ", L"S3Z", L"STZ", L"XMZ" }; static const wchar_t *pExtReplace[] = { L"IT", L"MOD", L"S3M", L"STM", L"XM" }; BOOL GetTypeInfo(LPCWSTR pszType, LPWSTR pszDest, INT cchDest) // return TRUE if typ was found ok { DWORD lcid; LPCWSTR p(NULL); wchar_t buf[128]={0}; int i; BOOL bCompressed(FALSE); lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); for (i = sizeof(pExtCompress)/sizeof(wchar_t*) - 1; i >= 0 && CSTR_EQUAL != CompareStringW(lcid, NORM_IGNORECASE, pszType, -1,pExtCompress[i], -1); i--); if (-1 != i) { pszType = pExtReplace[i]; bCompressed = TRUE; } for (i = 0; i < C_NUMLOADERS && !p; i++) { if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszType, -1, AutoWide(c_mod[i].loader->Type), -1)) { p = WASABI_API_LNGSTRINGW_BUF(c_mod[i].loader->DescStrID, buf, 128); } } if (!p) { if (CSTR_EQUAL == CompareStringW(lcid, NORM_IGNORECASE, pszType, -1, L"NST", -1)) { p = WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_NOISETRACKER, buf, 128); } } if (p) return (S_OK == StringCchPrintfW(pszDest, cchDest, WASABI_API_LNGSTRINGW((bCompressed?IDS_X_COMPRESSED_MODULE:IDS_X_MODULE)), p)); return FALSE; }