From: <sag...@us...> - 2012-03-08 00:13:17
|
Revision: 1210 http://modplug.svn.sourceforge.net/modplug/?rev=1210&view=rev Author: saga-games Date: 2012-03-08 00:13:11 +0000 (Thu, 08 Mar 2012) Log Message: ----------- [Fix] VST: MIDI Portamentos on muted channels should now *really* be ignored in all cases (revision 1181 only partly fixed the issue). [Mod] OpenMPT: Version is now 1.20.00.76 Revision Links: -------------- http://modplug.svn.sourceforge.net/modplug/?rev=1181&view=rev Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Snd_fx.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-07 23:51:23 UTC (rev 1209) +++ trunk/OpenMPT/mptrack/version.h 2012-03-08 00:13:11 UTC (rev 1210) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 75 +#define VER_MINORMINOR 76 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-07 23:51:23 UTC (rev 1209) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-08 00:13:11 UTC (rev 1210) @@ -563,11 +563,12 @@ ////////////////////////////////////////////////////////////////////////////////////////////////// // Effects +// Change sample or instrument number. void CSoundFile::InstrumentChange(ModChannel *pChn, UINT instr, bool bPorta, bool bUpdVol, bool bResetEnv) //-------------------------------------------------------------------------------------------------------- { if (instr >= MAX_INSTRUMENTS) return; - ModInstrument *pIns = Instruments[instr]; + ModInstrument *pIns = (instr < MAX_INSTRUMENTS) ? Instruments[instr] : nullptr; ModSample *pSmp = &Samples[instr]; UINT note = pChn->nNewNote; @@ -615,8 +616,8 @@ } const bool bNewTuning = (GetType() == MOD_TYPE_MPT && pIns && pIns->pTuning); - //Playback behavior change for MPT: With portamento don't change sample if it is in - //the same instrument as previous sample. + // Playback behavior change for MPT: With portamento don't change sample if it is in + // the same instrument as previous sample. if(bPorta && bNewTuning && pIns == pChn->pModInstrument) return; @@ -738,7 +739,7 @@ } // Tone-Portamento doesn't reset the pingpong direction flag - if ((bPorta) && (pSmp == pChn->pModSample)) + if (bPorta && pSmp == pChn->pModSample) { // If channel length is 0, we cut a previous sample using SCx. In that case, we have to update sample length, loop points, etc... if(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT) && pChn->nLength != 0) return; @@ -748,8 +749,8 @@ { pChn->dwFlags &= ~(CHN_KEYOFF|CHN_NOTEFADE); - //IT compatibility tentative fix: Don't change bidi loop direction when - //no sample nor instrument is changed. + // IT compatibility tentative fix: Don't change bidi loop direction when + // no sample nor instrument is changed. if(IsCompatibleMode(TRK_ALLTRACKERS) && pSmp == pChn->pModSample && !instrumentChanged) pChn->dwFlags = (pChn->dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)) | (pSmp->uFlags & CHN_SAMPLEFLAGS); else @@ -1002,8 +1003,10 @@ } if (pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart; } - else + else + { bPorta = false; + } if ((!bPorta) || (!(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))) || ((pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol)) @@ -2483,7 +2486,7 @@ void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param) //----------------------------------------------------------- { - if((Chn[nChn].dwFlags & CHN_MUTE) != 0) + if((Chn[nChn].dwFlags & (CHN_MUTE | CHN_SYNCMUTE)) != 0) { // Don't process portamento on muted channels. Note that this might have a side-effect // on other channels which trigger notes on the same MIDI channel of the same plugin, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-08 01:39:35
|
Revision: 1211 http://modplug.svn.sourceforge.net/modplug/?rev=1211&view=rev Author: saga-games Date: 2012-03-08 01:39:23 +0000 (Thu, 08 Mar 2012) Log Message: ----------- [Imp] Keyboard Settings: Added a search box, so finding a shortcut by name should be much easier now. [Mod] Updated my keymap a bit. Modified Paths: -------------- trunk/OpenMPT/mptrack/KeyConfigDlg.cpp trunk/OpenMPT/mptrack/KeyConfigDlg.h trunk/OpenMPT/mptrack/mptrack.rc trunk/OpenMPT/mptrack/resource.h trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb Modified: trunk/OpenMPT/mptrack/KeyConfigDlg.cpp =================================================================== --- trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2012-03-08 00:13:11 UTC (rev 1210) +++ trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2012-03-08 01:39:23 UTC (rev 1211) @@ -111,6 +111,7 @@ ON_COMMAND(IDC_EFFECTLETTERSIT, OnSetITEffects) ON_COMMAND(IDC_CLEARLOG, OnClearLog) ON_COMMAND(IDC_RESTORE_KEYMAP, OnRestoreDefaultKeymap) + ON_EN_CHANGE(IDC_FIND, OnSearchTermChanged) ON_WM_DESTROY() END_MESSAGE_MAP() @@ -127,6 +128,7 @@ DDX_Control(pDX, IDC_CHECKKEYDOWN, m_bKeyDown); DDX_Control(pDX, IDC_CHECKKEYHOLD, m_bKeyHold); DDX_Control(pDX, IDC_CHECKKEYUP, m_bKeyUp); + DDX_Control(pDX, IDC_FIND, m_eFind); } @@ -177,7 +179,7 @@ // Filter commands: We only need user to see a select set off commands // for each category void COptionsKeyboard::DefineCommandCategories() - +//---------------------------------------------- { CommandCategory *newCat; @@ -359,36 +361,90 @@ } -// Fills command list and automatically selects first command. void COptionsKeyboard::OnCategorySelChanged() //------------------------------------------- { - //CommandID nCmd = (CommandID)m_lbnCommandKeys.GetItemData( m_lbnCommandKeys.GetCurSel() ); - int nCat = m_cmbCategory.GetItemData( m_cmbCategory.GetCurSel() ); + int cat = m_cmbCategory.GetItemData(m_cmbCategory.GetCurSel()); - //Fill Command list - if ((nCat >= 0) && (nCat != m_nCurCategory)) //have we changed category? + if(cat >= 0 && cat != m_nCurCategory) { - CommandID com; - m_nCurCategory = nCat; - m_lbnCommandKeys.ResetContent(); - for (int c=0; c<commandCategories[nCat].commands.GetSize(); c++) + // Changed category + UpdateShortcutList(cat); + } +} + + +void COptionsKeyboard::OnSearchTermChanged() +//------------------------------------------ +{ + UpdateShortcutList(); +} + + +// Fills command list and automatically selects first command. +void COptionsKeyboard::UpdateShortcutList(int category) +//----------------------------------------------------- +{ + CString findString; + m_eFind.GetWindowText(findString); + findString.MakeLower(); + + const bool doSearch = !findString.IsEmpty(); + + m_nCurCategory = category; + + int firstCat = category, lastCat = category; + if(category == -1) + { + // We will search in all categories + firstCat = 0; + lastCat = commandCategories.GetSize() - 1; + } + + m_lbnCommandKeys.ResetContent(); + + for(int cat = firstCat; cat <= lastCat; cat++) + { + // When searching, we also add the category names to the list. + bool addCategoryName = (firstCat != lastCat); + + for(int cmd = 0; cmd < commandCategories[cat].commands.GetSize(); cmd++) { - com = (CommandID)commandCategories[nCat].commands[c]; - if (plocalCmdSet->GetCommandText(com)) + CommandID com = (CommandID)commandCategories[cat].commands[cmd]; + + CString cmdText = plocalCmdSet->GetCommandText(com); + bool addString = true; + if(doSearch) { - if (!plocalCmdSet->isHidden(com)) + addString = (cmdText.MakeLower().Find(findString) >= 0); + } + + if(addString) + { + if(!plocalCmdSet->isHidden(com)) + { + if(doSearch && addCategoryName) + { + const CString catName = "------ " + commandCategories[cat].name.Trim() + " ------"; + m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString(catName), DWORD_PTR(-1)); + addCategoryName = false; + } + m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString(plocalCmdSet->GetCommandText(com)), com); - - if (commandCategories[nCat].separatorAt(com)) + } + + if(commandCategories[cat].separatorAt(com)) m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString("------------------------------------------------------"), DWORD_PTR(-1)); } } - m_lbnCommandKeys.SetCurSel(0); - OnCommandKeySelChanged(); + } + + m_lbnCommandKeys.SetCurSel(0); + OnCommandKeySelChanged(); } + // Fills key choice list and automatically selects first key choice void COptionsKeyboard::OnCommandKeySelChanged() //--------------------------------------------- @@ -424,12 +480,13 @@ m_bKeyUp.EnableWindow(TRUE); m_nCurHotKey = nCmd; + m_nCurCategory = GetCategoryFromCommandID(nCmd); char s[20]; m_cmbKeyChoice.ResetContent(); int numChoices=plocalCmdSet->GetKeyListSize(nCmd); if ((nCmd<kcNumCommands) && (numChoices>0)) - { + { for (int i=0; i<numChoices; i++) { wsprintf(s, "Choice %d (of %d)", i+1, numChoices); @@ -482,6 +539,7 @@ //rewbs.autochord void COptionsKeyboard::OnChordWaitTimeChanged() +//--------------------------------------------- { CString s; UINT val; @@ -530,6 +588,7 @@ void COptionsKeyboard::OnRestoreKeyChoice() +//----------------------------------------- { KeyCombination kc; CommandID cmd = (CommandID)m_nCurHotKey; @@ -555,6 +614,7 @@ } void COptionsKeyboard::OnDeleteKeyChoice() +//---------------------------------------- { CommandID cmd = (CommandID)m_nCurHotKey; @@ -576,6 +636,7 @@ void COptionsKeyboard::OnSetKeyChoice() +//------------------------------------- { CString report, reportHistory; KeyCombination kc; @@ -591,9 +652,9 @@ kc.mod = m_eCustHotKey.mod; kc.code = m_eCustHotKey.code; kc.ctx = (commandCategories[m_nCurCategory]).id; - temp |= m_bKeyDown.GetCheck()?kKeyEventDown:0; - temp |= m_bKeyHold.GetCheck()?kKeyEventRepeat:0; - temp |= m_bKeyUp.GetCheck()?kKeyEventUp:0; + temp |= m_bKeyDown.GetCheck() ? kKeyEventDown : 0; + temp |= m_bKeyHold.GetCheck() ? kKeyEventRepeat : 0; + temp |= m_bKeyUp.GetCheck() ? kKeyEventUp : 0; kc.event =(KeyEventType)temp; //kc.event =(KeyEventType)((UINT)kKeyEventDown|(UINT)kKeyEventRepeat); //detect invalid input @@ -627,6 +688,7 @@ return; } + void COptionsKeyboard::OnOK() //--------------------------- { @@ -641,12 +703,15 @@ void COptionsKeyboard::OnDestroy() +//-------------------------------- { CPropertyPage::OnDestroy(); delete plocalCmdSet; } + void COptionsKeyboard::OnLoad() +//----------------------------- { std::string filename = m_sFullPathName; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "mkb", filename, @@ -660,7 +725,9 @@ //TentativeSetToDefaultFile(m_sFullPathName); } + void COptionsKeyboard::OnSave() +//----------------------------- { std::string filename = m_sFullPathName; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, "mkb", filename, @@ -673,31 +740,41 @@ //TentativeSetToDefaultFile(m_sFullPathName); } + void COptionsKeyboard::OnNotesRepeat() +//------------------------------------ { plocalCmdSet->QuickChange_NotesRepeat(); ForceUpdateGUI(); } + void COptionsKeyboard::OnNoNotesRepeat() +//-------------------------------------- { plocalCmdSet->QuickChange_NoNotesRepeat(); ForceUpdateGUI(); } + void COptionsKeyboard::OnSetITEffects() +//------------------------------------- { plocalCmdSet->QuickChange_SetEffectsIT(); ForceUpdateGUI(); } + void COptionsKeyboard::OnSetXMEffects() +//------------------------------------- { plocalCmdSet->QuickChange_SetEffectsXM(); ForceUpdateGUI(); } + void COptionsKeyboard::ForceUpdateGUI() +//------------------------------------- { //update gui m_bForceUpdate=true; // m_nCurKeyChoice and m_nCurHotKey haven't changed, yet we still want to update. @@ -708,7 +785,9 @@ OnSettingsChanged(); // Enable "apply" button } + void COptionsKeyboard::OnClearLog() +//--------------------------------- { m_eReport.SetWindowText(""); ForceUpdateGUI(); @@ -723,4 +802,21 @@ plocalCmdSet->LoadDefaultKeymap(); ForceUpdateGUI(); } -} \ No newline at end of file +} + + +int COptionsKeyboard::GetCategoryFromCommandID(CommandID command) const +//--------------------------------------------------------------------- +{ + for(int cat = 0; cat < commandCategories.GetSize(); cat++) + { + for(int cmd = 0; cmd < commandCategories[cat].commands.GetSize(); cmd++) + { + if(commandCategories[cat].commands[cmd] == command) + { + return cat; + } + } + } + return -1; +} Modified: trunk/OpenMPT/mptrack/KeyConfigDlg.h =================================================================== --- trunk/OpenMPT/mptrack/KeyConfigDlg.h 2012-03-08 00:13:11 UTC (rev 1210) +++ trunk/OpenMPT/mptrack/KeyConfigDlg.h 2012-03-08 01:39:23 UTC (rev 1211) @@ -49,7 +49,7 @@ for (int p=0; p<separators.GetSize(); p++) { if (separators[p]==c) - return true; + return true; } return false; } @@ -100,6 +100,7 @@ CButton m_bKeyDown, m_bKeyHold, m_bKeyUp; CButton m_bnReset; CCustEdit m_eCustHotKey; + CEdit m_eFind; CEdit m_eReport, m_eChordWaitTime; UINT m_nKeyboardCfg; int m_nCurHotKey, m_nCurCategory, m_nCurKeyChoice; @@ -110,6 +111,8 @@ bool m_bChoiceModified; void ForceUpdateGUI(); + void UpdateShortcutList(int category = -1); + int GetCategoryFromCommandID(CommandID command) const; public: COptionsKeyboard():CPropertyPage(IDD_OPTIONS_KEYBOARD) { m_nKeyboardCfg = 0; } @@ -131,6 +134,7 @@ afx_msg void OnKeyChoiceSelect(); afx_msg void OnCommandKeySelChanged(); afx_msg void OnCategorySelChanged(); + afx_msg void OnSearchTermChanged(); afx_msg void OnChordWaitTimeChanged(); //rewbs.autochord afx_msg void OnHotKeyChanged(); afx_msg void OnSettingsChanged() { SetModified(TRUE); } Modified: trunk/OpenMPT/mptrack/mptrack.rc =================================================================== --- trunk/OpenMPT/mptrack/mptrack.rc 2012-03-08 00:13:11 UTC (rev 1210) +++ trunk/OpenMPT/mptrack/mptrack.rc 2012-03-08 01:39:23 UTC (rev 1211) @@ -466,7 +466,7 @@ BEGIN LTEXT "Select category:",IDC_STATIC,7,5,131,11 COMBOBOX IDC_KEYCATEGORY,5,16,133,204,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_COMMAND_LIST,5,32,133,244,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + LISTBOX IDC_COMMAND_LIST,5,32,133,228,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_CHOICECOMBO,150,18,72,51,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP LTEXT "Key:",IDC_STATIC,150,38,16,8 EDITTEXT IDC_CUSTHOTKEY,168,36,54,13,ES_AUTOHSCROLL @@ -489,10 +489,12 @@ GROUPBOX "Key setup for this command ",IDC_STATIC,144,6,126,84 GROUPBOX "Misc",IDC_STATIC,144,96,126,40 GROUPBOX "Multi Config Handling",IDC_STATIC,144,144,126,48 - PUSHBUTTON "it",IDC_EFFECTLETTERSIT,98,252,12,9,NOT WS_VISIBLE - PUSHBUTTON "xm",IDC_EFFECTLETTERSXM,114,252,12,9,NOT WS_VISIBLE - LTEXT "Effect letters like:",IDC_STATIC,6,254,73,11,NOT WS_VISIBLE + PUSHBUTTON "it",IDC_EFFECTLETTERSIT,103,223,12,9,NOT WS_VISIBLE + PUSHBUTTON "xm",IDC_EFFECTLETTERSXM,119,223,12,9,NOT WS_VISIBLE + LTEXT "Effect letters like:",IDC_STATIC,11,225,73,11,NOT WS_VISIBLE PUSHBUTTON "Restore default configuration",IDC_RESTORE_KEYMAP,150,174,114,12 + EDITTEXT IDC_FIND,30,264,108,12,ES_AUTOHSCROLL + LTEXT "Find:",IDC_STATIC,6,266,24,8 END IDD_OPTIONS_COLORS DIALOGEX 0, 0, 272, 281 @@ -1086,7 +1088,7 @@ END IDD_PAGEEDITEFFECT DIALOGEX 0, 0, 220, 35 -STYLE DS_SETFONT | WS_CHILD | WS_CAPTION +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION CAPTION "Effect" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN Modified: trunk/OpenMPT/mptrack/resource.h =================================================================== --- trunk/OpenMPT/mptrack/resource.h 2012-03-08 00:13:11 UTC (rev 1210) +++ trunk/OpenMPT/mptrack/resource.h 2012-03-08 01:39:23 UTC (rev 1211) @@ -944,6 +944,7 @@ #define IDC_LASTUPDATE 2435 #define IDC_RESTORE_KEYMAP 2436 #define IDC_SAMPLE_AUTOTUNE 2437 +#define IDC_FIND 2438 #define ID_FILE_NEWMOD 32771 #define ID_FILE_NEWXM 32772 #define ID_FILE_NEWS3M 32773 @@ -1220,7 +1221,7 @@ #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 535 #define _APS_NEXT_COMMAND_VALUE 44602 -#define _APS_NEXT_CONTROL_VALUE 2448 +#define _APS_NEXT_CONTROL_VALUE 2439 #define _APS_NEXT_SYMED_VALUE 901 #endif #endif Modified: trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb =================================================================== --- trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-08 00:13:11 UTC (rev 1210) +++ trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-08 01:39:23 UTC (rev 1211) @@ -28,10 +28,10 @@ 0:1362:2:86:1 //Paste: Ctrl+V (KeyDown) 0:1363:3:86:1 //Mix Paste: Shift+Ctrl+V (KeyDown) 0:1793:1:86:1 //Paste Flood: Shift+V (KeyDown) -0:1820:6:86:1 //Push Forward Paste (Insert): Ctrl+Alt+V (KeyDown) +0:1820:6:86:5 //Push Forward Paste (Insert): Ctrl+Alt+V (KeyDown|KeyHold) 0:1364:2:53:1 //Select All: Ctrl+5 (KeyDown) 0:1365:2:70:1 //Find / Replace: Ctrl+F (KeyDown) -0:1366:0:114:1 //Find Next: F3 (KeyDown) +0:1366:0:114:5 //Find Next: F3 (KeyDown|KeyHold) 0:1021:4:71:1 //View General: Alt+G (KeyDown) 0:1021:0:112:1 //View General: F1 (KeyDown) 0:1022:4:80:1 //View Pattern: Alt+P (KeyDown) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-09 23:38:50
|
Revision: 1212 http://modplug.svn.sourceforge.net/modplug/?rev=1212&view=rev Author: saga-games Date: 2012-03-09 23:38:42 +0000 (Fri, 09 Mar 2012) Log Message: ----------- [Fix] Revision 1203 broke IT / MPTM extended settings loading if the last sample slot was empty. [Mod] Updated MTPM loader test. [Mod] Default ramp up setting is now 16 samples. [Imp] Instrument Editor: Also added tooltips for resonance / cutoff sliders. [Imp] Keyboard Settings: Improved shortcut search behaviour a bit. [Mod] OpenMPT: Version is now 1.20.00.77 Revision Links: -------------- http://modplug.svn.sourceforge.net/modplug/?rev=1203&view=rev Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/KeyConfigDlg.cpp trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/mptrack.rc trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/mptrack/test/test.mptm trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/Load_it.cpp Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -1607,6 +1607,14 @@ wsprintf(pszText, "\xB1%d panning variation", pIns->nPanSwing); return TRUE; + case IDC_SLIDER3: + wsprintf(pszText, "%d", pIns->GetCutoff()); + return TRUE; + + case IDC_SLIDER4: + wsprintf(pszText, "%d", pIns->GetResonance()); + return TRUE; + case IDC_SLIDER6: wsprintf(pszText, "\xB1%d cutoff variation", pIns->nCutSwing); return TRUE; Modified: trunk/OpenMPT/mptrack/KeyConfigDlg.cpp =================================================================== --- trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/KeyConfigDlg.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -181,163 +181,195 @@ void COptionsKeyboard::DefineCommandCategories() //---------------------------------------------- { - CommandCategory *newCat; + { + CommandCategory newCat("Global keys", kCtxAllContexts); - newCat = new CommandCategory("Global keys", kCtxAllContexts); - for (int c=kcStartFile; c<=kcEndFile; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndFile); //-------------------------------------- - for (int c=kcStartPlayCommands; c<=kcEndPlayCommands; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndPlayCommands); //-------------------------------------- - for (int c=kcStartEditCommands; c<=kcEndEditCommands; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndEditCommands); //-------------------------------------- - for (int c=kcStartView; c<=kcEndView; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndView); //-------------------------------------- - for (int c=kcStartMisc; c<=kcEndMisc; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndMisc); //-------------------------------------- + for(int c = kcStartFile; c <= kcEndFile; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndFile); //-------------------------------------- + for(int c = kcStartPlayCommands; c <= kcEndPlayCommands; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndPlayCommands); //-------------------------------------- + for(int c = kcStartEditCommands; c <= kcEndEditCommands; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndEditCommands); //-------------------------------------- + for(int c = kcStartView; c <= kcEndView; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndView); //-------------------------------------- + for(int c = kcStartMisc; c <= kcEndMisc; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndMisc); //-------------------------------------- - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" General [Top]", kCtxCtrlGeneral); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" General [Top]", kCtxCtrlGeneral); + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" General [Bottom]", kCtxViewGeneral); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" General [Bottom]", kCtxViewGeneral); + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Pattern Editor [Top]", kCtxCtrlPatterns); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" Pattern Editor [Top]", kCtxCtrlPatterns); + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Pattern Editor - Order List", kCtxCtrlOrderlist); + { + CommandCategory newCat(" Pattern Editor - Order List", kCtxCtrlOrderlist); - for (int c=kcStartOrderlistCommands; c<=kcEndOrderlistCommands; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndOrderlistNavigation); //-------------------------------------- - newCat->separators.Add(kcEndOrderlistEdit); //-------------------------------------- + for(int c = kcStartOrderlistCommands; c <= kcEndOrderlistCommands; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndOrderlistNavigation); //-------------------------------------- + newCat.separators.Add(kcEndOrderlistEdit); //-------------------------------------- - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Pattern Editor - General", kCtxViewPatterns); - - for (int c=kcStartPlainNavigate; c<=kcEndPlainNavigate; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndPlainNavigate); //-------------------------------------- - for (int c=kcStartJumpSnap; c<=kcEndJumpSnap; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndJumpSnap); //-------------------------------------- - for (int c=kcStartHomeEnd; c<=kcEndHomeEnd; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndHomeEnd); //-------------------------------------- - for (int c=kcPrevPattern; c<=kcNextPattern; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcNextPattern); //-------------------------------------- - for (int c=kcStartSelect; c<=kcEndSelect; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndSelect); //-------------------------------------- - newCat->commands.Add(kcCopyAndLoseSelection); - for (int c=kcClearRow; c<=kcInsertAllRows; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcInsertAllRows); //-------------------------------------- - for (int c=kcChannelMute; c<=kcChannelReset; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcChannelReset); //-------------------------------------- - for (int c=kcTransposeUp; c<=kcTransposeOctDown; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcTransposeOctDown); //-------------------------------------- - for (int c=kcPatternAmplify; c<=kcPatternShrinkSelection; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcPatternShrinkSelection); //-------------------------------------- - for (int c=kcStartPatternEditMisc; c<=kcEndPatternEditMisc; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndPatternEditMisc); //-------------------------------------- + { + CommandCategory newCat(" Pattern Editor - General", kCtxViewPatterns); - commandCategories.Add(*newCat); - delete newCat; + for(int c = kcStartPlainNavigate; c <= kcEndPlainNavigate; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndPlainNavigate); //-------------------------------------- + for(int c = kcStartJumpSnap; c <= kcEndJumpSnap; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndJumpSnap); //-------------------------------------- + for(int c = kcStartHomeEnd; c <= kcEndHomeEnd; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndHomeEnd); //-------------------------------------- + for(int c = kcPrevPattern; c <= kcNextPattern; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcNextPattern); //-------------------------------------- + for(int c = kcStartSelect; c <= kcEndSelect; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndSelect); //-------------------------------------- + newCat.commands.Add(kcCopyAndLoseSelection); + for(int c = kcClearRow; c <= kcInsertAllRows; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcInsertAllRows); //-------------------------------------- + for(int c = kcChannelMute; c <= kcChannelReset; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcChannelReset); //-------------------------------------- + for(int c = kcTransposeUp; c <= kcTransposeOctDown; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcTransposeOctDown); //-------------------------------------- + for(int c = kcPatternAmplify; c <= kcPatternShrinkSelection; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcPatternShrinkSelection); //-------------------------------------- + for(int c = kcStartPatternEditMisc; c <= kcEndPatternEditMisc; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndPatternEditMisc); //-------------------------------------- - newCat = new CommandCategory(" Pattern Editor - Note Column", kCtxViewPatternsNote); - for (int c=kcVPStartNotes; c<=kcVPEndNotes; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcVPEndNotes); //-------------------------------------- - for (int c=kcSetOctave0; c<=kcSetOctave9; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcVPEndNotes); //-------------------------------------- - for (int c=kcStartNoteMisc; c<=kcEndNoteMisc; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Pattern Editor - Instrument Column", kCtxViewPatternsIns); - for (int c=kcSetIns0; c<=kcSetIns9; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" Pattern Editor - Note Column", kCtxViewPatternsNote); - newCat = new CommandCategory(" Pattern Editor - Volume Column", kCtxViewPatternsVol); - for (int c=kcSetVolumeStart; c<=kcSetVolumeEnd; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + for(int c = kcVPStartNotes; c <= kcVPEndNotes; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcVPEndNotes); //-------------------------------------- + for(int c = kcSetOctave0; c <= kcSetOctave9; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcVPEndNotes); //-------------------------------------- + for(int c = kcStartNoteMisc; c <= kcEndNoteMisc; c++) + newCat.commands.Add(c); - newCat = new CommandCategory(" Pattern Editor - Effect Column", kCtxViewPatternsFX); - for (int c=kcSetFXStart; c<=kcSetFXEnd; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Pattern Editor - Effect Parameter Column", kCtxViewPatternsFXparam); - for (int c=kcSetFXParam0; c<=kcSetFXParamF; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" Pattern Editor - Instrument Column", kCtxViewPatternsIns); - newCat = new CommandCategory(" Sample [Top]", kCtxCtrlSamples); - commandCategories.Add(*newCat); - delete newCat; + for(int c = kcSetIns0; c <= kcSetIns9; c++) + newCat.commands.Add(c); - newCat = new CommandCategory(" Sample Editor", kCtxViewSamples); - for (int c=kcStartSampleEditing; c<=kcEndSampleEditing; c++) - newCat->commands.Add(c); - newCat->separators.Add(kcEndSampleEditing); //-------------------------------------- - for (int c=kcStartSampleMisc; c<=kcEndSampleMisc; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Instrument Editor", kCtxCtrlInstruments); - for (int c=kcStartInstrumentCtrlMisc; c<=kcEndInstrumentCtrlMisc; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" Pattern Editor - Volume Column", kCtxViewPatternsVol); - newCat = new CommandCategory(" Envelope Editor", kCtxViewInstruments); - for (int c=kcStartInstrumentMisc; c<=kcEndInstrumentMisc; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + for(int c = kcSetVolumeStart; c <= kcSetVolumeEnd; c++) + newCat.commands.Add(c); - newCat = new CommandCategory(" Comments [Top]", kCtxCtrlComments); - commandCategories.Add(*newCat); - delete newCat; + commandCategories.Add(newCat); + } - newCat = new CommandCategory(" Comments [Bottom]", kCtxViewComments); - commandCategories.Add(*newCat); - delete newCat; + { + CommandCategory newCat(" Pattern Editor - Effect Column", kCtxViewPatternsFX); - newCat = new CommandCategory(" Plugin Editor", kCtxVSTGUI); - for (int c=kcStartVSTGUICommands; c<=kcEndVSTGUICommands; c++) - newCat->commands.Add(c); - commandCategories.Add(*newCat); - delete newCat; + for(int c = kcSetFXStart; c <= kcSetFXEnd; c++) + newCat.commands.Add(c); + commandCategories.Add(newCat); + } + { + CommandCategory newCat(" Pattern Editor - Effect Parameter Column", kCtxViewPatternsFXparam); + for(int c = kcSetFXParam0; c <= kcSetFXParamF; c++) + newCat.commands.Add(c); + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Sample [Top]", kCtxCtrlSamples); + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Sample Editor", kCtxViewSamples); + + for(int c = kcStartSampleEditing; c <= kcEndSampleEditing; c++) + newCat.commands.Add(c); + newCat.separators.Add(kcEndSampleEditing); //-------------------------------------- + for(int c = kcStartSampleMisc; c <= kcEndSampleMisc; c++) + newCat.commands.Add(c); + + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Instrument Editor", kCtxCtrlInstruments); + + for(int c = kcStartInstrumentCtrlMisc; c <= kcEndInstrumentCtrlMisc; c++) + newCat.commands.Add(c); + + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Envelope Editor", kCtxViewInstruments); + + for(int c = kcStartInstrumentMisc; c <= kcEndInstrumentMisc; c++) + newCat.commands.Add(c); + + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Comments [Top]", kCtxCtrlComments); + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Comments [Bottom]", kCtxViewComments); + commandCategories.Add(newCat); + } + + { + CommandCategory newCat(" Plugin Editor", kCtxVSTGUI); + + for(int c = kcStartVSTGUICommands; c <= kcEndVSTGUICommands; c++) + newCat.commands.Add(c); + + commandCategories.Add(newCat); + } + } @@ -377,7 +409,22 @@ void COptionsKeyboard::OnSearchTermChanged() //------------------------------------------ { - UpdateShortcutList(); + CString findString; + m_eFind.GetWindowText(findString); + + if(findString.IsEmpty()) + { + // Go back to last found category + for(int i = 0; i < m_cmbCategory.GetCount(); i++) + { + if((int)m_cmbCategory.GetItemData(i) == m_nCurCategory) + { + m_cmbCategory.SetCurSel(i); + break; + } + } + } + UpdateShortcutList(findString.IsEmpty() ? m_nCurCategory : -1); } @@ -391,8 +438,6 @@ const bool doSearch = !findString.IsEmpty(); - m_nCurCategory = category; - int firstCat = category, lastCat = category; if(category == -1) { @@ -401,6 +446,7 @@ lastCat = commandCategories.GetSize() - 1; } + CommandID curCommand = static_cast<CommandID>(m_lbnCommandKeys.GetItemData( m_lbnCommandKeys.GetCurSel())); m_lbnCommandKeys.ResetContent(); for(int cat = firstCat; cat <= lastCat; cat++) @@ -421,6 +467,8 @@ if(addString) { + m_nCurCategory = cat; + if(!plocalCmdSet->isHidden(com)) { if(doSearch && addCategoryName) @@ -430,7 +478,14 @@ addCategoryName = false; } - m_lbnCommandKeys.SetItemData(m_lbnCommandKeys.AddString(plocalCmdSet->GetCommandText(com)), com); + int item = m_lbnCommandKeys.AddString(plocalCmdSet->GetCommandText(com)); + m_lbnCommandKeys.SetItemData(item, com); + + if(curCommand == com) + { + // Keep selection on previously selected string + m_lbnCommandKeys.SetCurSel(item); + } } if(commandCategories[cat].separatorAt(com)) @@ -440,7 +495,10 @@ } - m_lbnCommandKeys.SetCurSel(0); + if(m_lbnCommandKeys.GetCurSel() == -1) + { + m_lbnCommandKeys.SetCurSel(0); + } OnCommandKeySelChanged(); } @@ -449,7 +507,7 @@ void COptionsKeyboard::OnCommandKeySelChanged() //--------------------------------------------- { - CommandID nCmd = (CommandID)m_lbnCommandKeys.GetItemData( m_lbnCommandKeys.GetCurSel() ); + CommandID nCmd = static_cast<CommandID>(m_lbnCommandKeys.GetItemData( m_lbnCommandKeys.GetCurSel())); CString str; //Separator Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -50,7 +50,7 @@ gcsInstallGUID = ""; // Audio Setup //rewbs.resamplerConf - glVolumeRampUpSamples = 42; + glVolumeRampUpSamples = 16; glVolumeRampDownSamples = 42; gdWFIRCutoff = 0.97; gbWFIRType = 7; //WFIR_KAISER4T; Modified: trunk/OpenMPT/mptrack/mptrack.rc =================================================================== --- trunk/OpenMPT/mptrack/mptrack.rc 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/mptrack.rc 2012-03-09 23:38:42 UTC (rev 1212) @@ -766,9 +766,9 @@ CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,116,133,8,12 COMBOBOX IDC_COMBO9,50,151,71,81,CBS_DROPDOWNLIST | WS_TABSTOP CONTROL "Reso",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | BS_FLAT | WS_TABSTOP,136,37,33,10 - CONTROL "Slider2",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_DISABLED | WS_TABSTOP,168,37,64,10 + CONTROL "Slider2",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_DISABLED | WS_TABSTOP,168,37,64,10 CONTROL "Cutoff",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | BS_FLAT | WS_TABSTOP,136,52,35,10 - CONTROL "Slider2",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_DISABLED | WS_TABSTOP,168,53,64,10 + CONTROL "Slider2",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_DISABLED | WS_TABSTOP,168,53,64,10 COMBOBOX IDC_FILTERMODE,163,70,69,42,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP CONTROL "Slider1",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,172,101,60,10 CONTROL "Slider1",IDC_SLIDER2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,172,118,60,10 Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -323,6 +323,16 @@ VERIFY_EQUAL_NONCONT(sample.nVibRate, 4); VERIFY_EQUAL_NONCONT(sample.nVibDepth, 5); + // Sample Data + for(size_t i = 0; i < 6; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], 18); + } + for(size_t i = 6; i < 16; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], 0); + } + // Instruments VERIFY_EQUAL_NONCONT(pSndFile->GetNumInstruments(), 1); const ModInstrument *pIns = pSndFile->Instruments[1]; @@ -364,14 +374,7 @@ for(size_t i = pSndFile->GetModSpecifications().noteMin; i < pSndFile->GetModSpecifications().noteMax; i++) { - if(i == NOTE_MIDDLEC - 1) - { - VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], 2); - } - else - { - VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], 1); - } + VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 2 : 1); } VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_SUSTAIN); @@ -486,6 +489,7 @@ // Macros VERIFY_EQUAL_NONCONT(pSndFile->m_MidiCfg.GetParameteredMacroType(0), sfx_reso); VERIFY_EQUAL_NONCONT(pSndFile->m_MidiCfg.GetParameteredMacroType(1), sfx_drywet); + VERIFY_EQUAL_NONCONT(pSndFile->m_MidiCfg.GetParameteredMacroType(2), sfx_polyAT); VERIFY_EQUAL_NONCONT(pSndFile->m_MidiCfg.GetFixedMacroType(), zxx_resomode); // Channels @@ -503,28 +507,57 @@ VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].nMixPlugin, 1); // Samples - VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 1); - const ModSample &sample = pSndFile->GetSample(1); - VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1); - VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1); - VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1); - VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16); - VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 9001); - VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4); - VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 16); - VERIFY_EQUAL_NONCONT(sample.nPan, 160); - VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_PANNING | CHN_LOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); + VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 3); + { + const ModSample &sample = pSndFile->GetSample(1); + VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1); + VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1); + VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1); + VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16); + VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 9001); + VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4); + VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 16); + VERIFY_EQUAL_NONCONT(sample.nPan, 160); + VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_PANNING | CHN_LOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN); - VERIFY_EQUAL_NONCONT(sample.nLoopStart, 1); - VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 8); - VERIFY_EQUAL_NONCONT(sample.nSustainStart, 1); - VERIFY_EQUAL_NONCONT(sample.nSustainEnd, 7); + VERIFY_EQUAL_NONCONT(sample.nLoopStart, 1); + VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 8); + VERIFY_EQUAL_NONCONT(sample.nSustainStart, 1); + VERIFY_EQUAL_NONCONT(sample.nSustainEnd, 7); - VERIFY_EQUAL_NONCONT(sample.nVibType, VIB_SQUARE); - VERIFY_EQUAL_NONCONT(sample.nVibSweep, 3); - VERIFY_EQUAL_NONCONT(sample.nVibRate, 4); - VERIFY_EQUAL_NONCONT(sample.nVibDepth, 5); + VERIFY_EQUAL_NONCONT(sample.nVibType, VIB_SQUARE); + VERIFY_EQUAL_NONCONT(sample.nVibSweep, 3); + VERIFY_EQUAL_NONCONT(sample.nVibRate, 4); + VERIFY_EQUAL_NONCONT(sample.nVibDepth, 5); + // Sample Data + for(size_t i = 0; i < 6; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], 18); + } + for(size_t i = 6; i < 16; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], 0); + } + } + + { + const ModSample &sample = pSndFile->GetSample(2); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[2], "Stereo / 16-Bit"), 0); + VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 4); + VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 2); + VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 2); + VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16 * 4); + VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 16000); + VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_16BIT | CHN_STEREO | CHN_LOOP); + + // Sample Data (Stereo Interleaved) + for(size_t i = 0; i < 7; i++) + { + VERIFY_EQUAL_NONCONT(reinterpret_cast<int16 *>(sample.pSample)[4 + i], int16(-32768)); + } + } + // Instruments VERIFY_EQUAL_NONCONT(pSndFile->GetNumInstruments(), 1); const ModInstrument *pIns = pSndFile->Instruments[1]; @@ -534,7 +567,7 @@ VERIFY_EQUAL_NONCONT(pIns->dwFlags, INS_SETPANNING); VERIFY_EQUAL_NONCONT(pIns->nPPS, 16); - VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - 1) + 6); // F#5 + VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6); // F#5 VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200); VERIFY_EQUAL_NONCONT(pIns->nResampling, SRCMODE_POLYPHASE); @@ -568,16 +601,8 @@ for(size_t i = 0; i < NOTE_MAX; i++) { - if(i == NOTE_MIDDLEC - 1) - { - VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], 99); - VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], i + 13); - } - else - { - VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], 1); - VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], i + 1); - } + VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 99 : 1); + VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], (i == NOTE_MIDDLEC - 1) ? (i + 13) : (i + 1)); } VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_CARRY); @@ -788,7 +813,7 @@ pat[1].resize(numCommands[1]); pat[2].resize(numCommands[2]); - for(size_t i = 0; i<3; i++) // Copy pattern data for comparison. + for(size_t i = 0; i < 3; i++) // Copy pattern data for comparison. { CPattern::const_iterator iter = pSndFile->Patterns[i].Begin(); for(size_t j = 0; j < numCommands[i]; j++, iter++) pat[i][j] = *iter; Modified: trunk/OpenMPT/mptrack/test/test.mptm =================================================================== (Binary files differ) Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/mptrack/version.h 2012-03-09 23:38:42 UTC (rev 1212) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 76 +#define VER_MINORMINOR 77 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -546,7 +546,7 @@ mptSmp.nVibDepth = vid & 0x7F; mptSmp.nVibSweep = vir; - return mptSmp.nLength ? LittleEndian(samplepointer) : 0; + return LittleEndian(samplepointer); } Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-03-08 01:39:23 UTC (rev 1211) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-03-09 23:38:42 UTC (rev 1212) @@ -766,7 +766,7 @@ memcpy(m_szNames[nsmp + 1], pis->name, 26); StringFixer::SpaceToNullStringFixed<25>(m_szNames[nsmp + 1]); - lastSampleOffset = sampleOffset + ReadSample(&Samples[nsmp + 1], pis->GetSampleFormat(itHeader.cwtv), (LPSTR)(lpStream + sampleOffset), dwMemLength - sampleOffset); + lastSampleOffset = Util::Max(lastSampleOffset, sampleOffset + ReadSample(&Samples[nsmp + 1], pis->GetSampleFormat(itHeader.cwtv), (LPSTR)(lpStream + sampleOffset), dwMemLength - sampleOffset)); } } m_nSamples = max(1, m_nSamples); @@ -1822,7 +1822,7 @@ UINT nTotalSize = 0; UINT nChInfo = 0; - for(UINT i=0; i<MAX_MIXPLUGINS; i++) + for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++) { const SNDMIXPLUGIN &plugin = m_MixPlugins[i]; if(plugin.IsValidPlugin()) @@ -1944,7 +1944,7 @@ nPlugin = (p[nPos + 2] - '0') * 10 + (p[nPos + 3] - '0'); //calculate plug-in number. - if ((nPlugin < MAX_MIXPLUGINS) && (nPluginSize >= sizeof(SNDMIXPLUGININFO)+4)) + if ((nPlugin < MAX_MIXPLUGINS) && (nPluginSize >= sizeof(SNDMIXPLUGININFO) + 4)) { // MPT's standard plugin data. Size not specified in file.. grrr.. m_MixPlugins[nPlugin].Info = *(const SNDMIXPLUGININFO *)( p +nPos + 8); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-09 23:48:39
|
Revision: 1213 http://modplug.svn.sourceforge.net/modplug/?rev=1213&view=rev Author: saga-games Date: 2012-03-09 23:48:33 +0000 (Fri, 09 Mar 2012) Log Message: ----------- [Fix] FT2 Compatibility: Also using IT envelope style processing fot XM files now, to fix EnvLoops.xm Modified Paths: -------------- trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2012-03-09 23:38:42 UTC (rev 1212) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2012-03-09 23:48:33 UTC (rev 1213) @@ -1094,9 +1094,9 @@ if (chnEnv.flags & ENV_ENABLED) { DWORD pos = chnEnv.nEnvPosition; - if(m_pSndFile->IsCompatibleMode(TRK_IMPULSETRACKER)) + if(m_pSndFile->IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) { - // Impulse Tracker envelope handling (see SndMix.cpp for details) + // Impulse Tracker / Fasttracker 2 envelope handling (see SndMix.cpp for details) if(pos > 0) pos--; else Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2012-03-09 23:38:42 UTC (rev 1212) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2012-03-09 23:48:33 UTC (rev 1213) @@ -1074,7 +1074,8 @@ const InstrumentEnvelope &insEnv = pChn->pModInstrument->GetEnvelope(env); // IT Compatibility: S77/S79/S7B do not disable the envelope, they just pause the counter - return (((pChn->GetEnvelope(env).flags & ENV_ENABLED) || ((insEnv.dwFlags & ENV_ENABLED) && IsCompatibleMode(TRK_IMPULSETRACKER))) + // Test cases: s77.it, EnvLoops.xm + return (((pChn->GetEnvelope(env).flags & ENV_ENABLED) || ((insEnv.dwFlags & ENV_ENABLED) && IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2))) && insEnv.nNodes != 0); } @@ -1086,12 +1087,12 @@ { const ModInstrument *pIns = pChn->pModInstrument; - if(IsCompatibleMode(TRK_IMPULSETRACKER) && pChn->VolEnv.nEnvPosition == 0) + if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) && pChn->VolEnv.nEnvPosition == 0) { // If the envelope is disabled at the very same moment as it is triggered, we do not process anything. return; } - const int envpos = pChn->VolEnv.nEnvPosition - (IsCompatibleMode(TRK_IMPULSETRACKER) ? 1 : 0); + const int envpos = pChn->VolEnv.nEnvPosition - (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 1 : 0); // Get values in [0, 256] int envval = Util::Round<int>(pIns->VolEnv.GetValueFromPosition(envpos) * 256.0f); @@ -1216,7 +1217,7 @@ } // Increase position - UINT position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 0 : 1); + UINT position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 0 : 1); const InstrumentEnvelope &insEnv = pChn->pModInstrument->GetEnvelope(envType); @@ -1230,7 +1231,12 @@ // Normal loop active UINT end = insEnv.Ticks[insEnv.nLoopEnd]; if(GetType() != MOD_TYPE_XM) end++; - if(position == end) + + // FT2 compatibility: If the sustain point is at the loop end and the sustain loop has been released, don't loop anymore. + // Test case: EnvLoops.xm + const bool escapeLoop = (insEnv.nLoopEnd == insEnv.nSustainEnd && (pChn->dwFlags & CHN_KEYOFF) && IsCompatibleMode(TRK_FASTTRACKER2)); + + if(position == end && !escapeLoop) { position = insEnv.Ticks[insEnv.nLoopStart]; @@ -1312,7 +1318,7 @@ } } - chnEnv.nEnvPosition = position + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 1 : 0); + chnEnv.nEnvPosition = position + (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 1 : 0); } @@ -1909,7 +1915,7 @@ ModChannel *pChn = Chn; for (CHANNELINDEX nChn = 0; nChn < MAX_CHANNELS; nChn++, pChn++) { - // XM Compatibility: Prevent notes to be stopped after a fadeout. This way, a portamento effect can pick up a faded instrument which is long enough. + // FT2 Compatibility: Prevent notes to be stopped after a fadeout. This way, a portamento effect can pick up a faded instrument which is long enough. // This occours for example in the bassline (channel 11) of jt_burn.xm. I hope this won't break anything else... // I also suppose this could decrease mixing performance a bit, but hey, which CPU can't handle 32 muted channels these days... :-) if ((pChn->dwFlags & CHN_NOTEFADE) && (!(pChn->nFadeOutVol|pChn->nRightVol|pChn->nLeftVol)) && (!IsCompatibleMode(TRK_FASTTRACKER2))) @@ -1972,13 +1978,13 @@ // Process Envelopes if (pIns) { - if(IsCompatibleMode(TRK_IMPULSETRACKER)) + if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) { - // In IT compatible mode, envelope position indices are shifted by one for proper envelope pausing, + // In IT and FT2 compatible mode, envelope position indices are shifted by one for proper envelope pausing, // so we have to update the position before we actually process the envelopes. // When using MPT behaviour, we get the envelope position for the next tick while we are still calculating the current tick, // which then results in wrong position information when the envelope is paused on the next row. - // Test case: s77.it + // Test cases: s77.it, EnvLoops.xm IncrementEnvelopePositions(pChn); } ProcessVolumeEnvelope(pChn, vol); @@ -2130,10 +2136,10 @@ } // Increment envelope positions - if (pIns != nullptr && !IsCompatibleMode(TRK_IMPULSETRACKER)) + if (pIns != nullptr && !IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) { - // In IT compatible mode, envelope positions are updated above. - // Test case: s77.it + // In IT and FT2 compatible mode, envelope positions are updated above. + // Test cases: s77.it, EnvLoops.xm IncrementEnvelopePositions(pChn); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-10 18:19:53
|
Revision: 1215 http://modplug.svn.sourceforge.net/modplug/?rev=1215&view=rev Author: saga-games Date: 2012-03-10 18:19:44 +0000 (Sat, 10 Mar 2012) Log Message: ----------- Another refactoring weekend! [Ref] Moved visited rows stuff to separate files. [Ref] Moved conversion functions relevant to ModCommand from CSoundFile to ModCommand. [Ref] Moved conversion functions relevant to ModChannel from CSoundFile to ModChannel. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/PatternClipboard.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/mptrack.vcproj trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/LOAD_DBM.CPP trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/Load_ptm.cpp trunk/OpenMPT/soundlib/Load_ult.cpp trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp trunk/OpenMPT/soundlib/load_j2b.cpp trunk/OpenMPT/soundlib/modcommand.cpp trunk/OpenMPT/soundlib/modcommand.h Added Paths: ----------- trunk/OpenMPT/soundlib/ModChannel.cpp trunk/OpenMPT/soundlib/RowVisitor.cpp trunk/OpenMPT/soundlib/RowVisitor.h Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -1060,7 +1060,9 @@ CSoundFile::InitPlayer(TRUE); CSoundFile::gdwSoundSetup |= SNDMIX_DIRECTTODISK; if ((!m_dwFileLimit) && (!m_dwSongLimit)) CSoundFile::gdwSoundSetup |= SNDMIX_NOBACKWARDJUMPS; - m_pSndFile->InitializeVisitedRows(true); + + m_pSndFile->visitedSongRows.Initialize(true); + // Setting up file limits and progress range if ((!m_dwFileLimit) || (m_dwFileLimit > 512000)) m_dwFileLimit = 512000; m_dwFileLimit <<= 10; @@ -1151,8 +1153,9 @@ CSoundFile::gdwSoundSetup &= ~(SNDMIX_DIRECTTODISK|SNDMIX_NOBACKWARDJUMPS); m_pSndFile->SetRepeatCount(oldrepeat); m_pSndFile->m_nMaxOrderPosition = 0; - m_pSndFile->InitializeVisitedRows(true); + m_pSndFile->visitedSongRows.Initialize(true); CMainFrame::UpdateAudioParameters(TRUE); + // Success if (bSaveWave) { Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -185,7 +185,7 @@ { nChannel = (nChannel + 1) % GetNumChannels(); // 0...Channels - 1 - m_SndFile.ConvertCommand(m, nOldType, nNewType); + m->Convert(nOldType, nNewType); // Deal with effect memory for MOD/XM arpeggio if (oldTypeIsS3M_IT_MPT && newTypeIsMOD_XM) Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -959,7 +959,7 @@ if (nins) // Set instrument { - m_SndFile.ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); m_SndFile.InstrumentChange(pChn, nins); pChn->nFadeOutVol = 0x10000; // Needed for XM files, as the nRowInstr check in NoteChange() will fail. } else if ((nsmp) && (nsmp < MAX_SAMPLES)) // Or set sample @@ -1693,7 +1693,7 @@ } // Render song (or current channel, or current sample/instrument) - m_SndFile.InitializeVisitedRows(true); + m_SndFile.visitedSongRows.Initialize(true); m_SndFile.SetCurrentPos(0); m_SndFile.m_dwSongFlags &= ~SONG_PATTERNLOOP; if (wsdlg.m_bSelectPlay) @@ -1998,7 +1998,7 @@ //m_SndFile.m_dwSongFlags &= ~SONG_STEP; m_SndFile.m_dwSongFlags &= ~(SONG_STEP|SONG_PATTERNLOOP); m_SndFile.SetCurrentPos(0); - m_SndFile.InitializeVisitedRows(true); + m_SndFile.visitedSongRows.Initialize(true); pMainFrm->ResetElapsedTime(); CriticalSection cs; Modified: trunk/OpenMPT/mptrack/PatternClipboard.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternClipboard.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/PatternClipboard.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -515,7 +515,7 @@ // of the old modcommand would falsely be interpreted being of type // origFormat and ConvertCommand could change them. if (pasteFormat != sndFile.GetType() && (!doMixPaste || origModCmd.IsEmpty(false))) - sndFile.ConvertCommand(&m[col], pasteFormat, sndFile.GetType()); + m[col].Convert(pasteFormat, sndFile.GetType()); } pos += 11; Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -1631,7 +1631,7 @@ const bool bIsMuted = pModDoc->IsChannelMuted(nChn); if(!bIsMuted) pModDoc->MuteChannel(nChn, true); - pSndFile->ResetChannelState(nChn, CHNRESET_TOTAL); + pSndFile->Chn[nChn].Reset(ModChannel::resetTotal, *pSndFile, nChn); if(!bIsMuted) pModDoc->MuteChannel(nChn, false); } Modified: trunk/OpenMPT/mptrack/mptrack.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack.vcproj 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/mptrack.vcproj 2012-03-10 18:19:44 UTC (rev 1215) @@ -310,6 +310,9 @@ RelativePath="..\soundlib\mod_specifications.cpp"> </File> <File + RelativePath="..\soundlib\ModChannel.cpp"> + </File> + <File RelativePath="..\soundlib\modcommand.cpp"> </File> <File @@ -379,6 +382,9 @@ RelativePath="..\common\Reporting.cpp"> </File> <File + RelativePath="..\soundlib\RowVisitor.cpp"> + </File> + <File RelativePath=".\SampleEditorDialogs.cpp"> </File> <File @@ -858,6 +864,9 @@ RelativePath=".\soundlib\PlugInterface.h"> </File> <File + RelativePath=".\soundlib\RowVisitor.h"> + </File> + <File RelativePath="..\common\Reporting.h"> </File> <File Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-10 18:19:44 UTC (rev 1215) @@ -417,6 +417,10 @@ > </File> <File + RelativePath="..\soundlib\ModChannel.cpp" + > + </File> + <File RelativePath="..\soundlib\modcommand.cpp" > </File> @@ -509,6 +513,10 @@ > </File> <File + RelativePath="..\soundlib\RowVisitor.cpp" + > + </File> + <File RelativePath=".\SampleEditorDialogs.cpp" > </File> @@ -1139,6 +1147,10 @@ > </File> <File + RelativePath=".\soundlib\RowVisitor.h" + > + </File> + <File RelativePath="..\common\Reporting.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-10 18:19:44 UTC (rev 1215) @@ -171,8 +171,10 @@ <ClCompile Include="..\common\Reporting.cpp" /> <ClCompile Include="..\soundlib\ITTools.cpp" /> <ClCompile Include="..\soundlib\MIDIMacros.cpp" /> + <ClCompile Include="..\soundlib\ModChannel.cpp" /> <ClCompile Include="..\soundlib\ModInstrument.cpp" /> <ClCompile Include="..\soundlib\ModSample.cpp" /> + <ClCompile Include="..\soundlib\RowVisitor.cpp" /> <ClCompile Include="AbstractVstEditor.cpp" /> <ClCompile Include="ACMConvert.cpp" /> <ClCompile Include="ArrayUtils.cpp" /> @@ -336,6 +338,7 @@ <ClInclude Include="..\soundlib\PluginEventQueue.h" /> <ClInclude Include="..\soundlib\PluginMixBuffer.h" /> <ClInclude Include="..\soundlib\PlugInterface.h" /> + <ClInclude Include="..\soundlib\RowVisitor.h" /> <ClInclude Include="ACMConvert.h" /> <ClInclude Include="Autotune.h" /> <ClInclude Include="EffectInfo.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-03-10 18:19:44 UTC (rev 1215) @@ -442,6 +442,12 @@ <ClCompile Include="PatternClipboard.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\soundlib\RowVisitor.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\soundlib\ModChannel.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -786,6 +792,9 @@ <ClInclude Include="..\soundlib\PluginEventQueue.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\soundlib\RowVisitor.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-10 18:19:44 UTC (rev 1215) @@ -382,7 +382,7 @@ int n; for (n = 0; n < 4; n++) { - if(CSoundFile::ConvertVolEffect(&cmd1, ¶m1, (n >> 1) != 0)) + if(ModCommand::ConvertVolEffect(cmd1, param1, (n >> 1) != 0)) { n = 5; break; @@ -392,7 +392,7 @@ } if (n < 5) { - if (CSoundFile::GetEffectWeight((ModCommand::COMMAND)cmd1) > CSoundFile::GetEffectWeight((ModCommand::COMMAND)cmd2)) + if (ModCommand::GetEffectWeight((ModCommand::COMMAND)cmd1) > ModCommand::GetEffectWeight((ModCommand::COMMAND)cmd2)) { std::swap(cmd1, cmd2); std::swap(param1, param2); @@ -408,7 +408,7 @@ m[ch].vol = param1; m[ch].command = cmd2; m[ch].param = param2; - MODExx2S3MSxx(&m[ch]); + m[ch].ExtendedMODtoS3MEffect(); } } else { Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-03-10 18:19:44 UTC (rev 1215) @@ -669,7 +669,7 @@ int n; for (n = 0; n < 4; n++) { - if(CSoundFile::ConvertVolEffect(&effect2, &effectParam2, (n >> 1) != 0)) + if(ModCommand::ConvertVolEffect(effect2, effectParam2, (n >> 1) != 0)) { n = 5; break; @@ -679,7 +679,7 @@ } if (n < 5) { - if (CSoundFile::GetEffectWeight((ModCommand::COMMAND)effect2) > CSoundFile::GetEffectWeight((ModCommand::COMMAND)effect3)) + if (ModCommand::GetEffectWeight((ModCommand::COMMAND)effect2) > ModCommand::GetEffectWeight((ModCommand::COMMAND)effect3)) { std::swap(effect2, effect3); std::swap(effectParam2, effectParam3); Modified: trunk/OpenMPT/soundlib/Load_mt2.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mt2.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Load_mt2.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -183,7 +183,7 @@ m->command = p->fxparam2; m->param = p->fxparam1; that->ConvertModCommand(m); - that->MODExx2S3MSxx(m); + m->ExtendedMODtoS3MEffect(); } else { // TODO: MT2 Effects Modified: trunk/OpenMPT/soundlib/Load_mtm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mtm.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Load_mtm.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -132,7 +132,7 @@ if ((cmd) || (param)) { ConvertModCommand(m); - ConvertCommand(m, MOD_TYPE_MOD, MOD_TYPE_S3M); + m->Convert(MOD_TYPE_MOD, MOD_TYPE_S3M); } } } Modified: trunk/OpenMPT/soundlib/Load_ptm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ptm.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Load_ptm.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -171,7 +171,7 @@ if (m[nChn].command < 0x10) { ConvertModCommand(&m[nChn]); - MODExx2S3MSxx(&m[nChn]); + m[nChn].ExtendedMODtoS3MEffect(); // Note cut does just mute the sample, not cut it. We have to fix that, if possible. if(m[nChn].command == CMD_S3MCMDEX && (m[nChn].param & 0xF0) == 0xC0 && m[nChn].volcmd == VOLCMD_NONE) { Modified: trunk/OpenMPT/soundlib/Load_ult.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ult.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Load_ult.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -204,7 +204,7 @@ int n; for (n = 0; n < 4; n++) { - if(CSoundFile::ConvertVolEffect(&cmd1, ¶m1, (n >> 1) != 0)) + if(ModCommand::ConvertVolEffect(cmd1, param1, (n >> 1) != 0)) { n = 5; break; @@ -214,7 +214,7 @@ } if (n < 5) { - if (CSoundFile::GetEffectWeight((ModCommand::COMMAND)cmd1) > CSoundFile::GetEffectWeight((ModCommand::COMMAND)cmd2)) + if (ModCommand::GetEffectWeight((ModCommand::COMMAND)cmd1) > ModCommand::GetEffectWeight((ModCommand::COMMAND)cmd2)) { std::swap(cmd1, cmd2); std::swap(param1, param2); Added: trunk/OpenMPT/soundlib/ModChannel.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModChannel.cpp (rev 0) +++ trunk/OpenMPT/soundlib/ModChannel.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -0,0 +1,87 @@ +/* + * ModChannel.cpp + * -------------- + * Purpose: Module Channel header class and helpers + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Sndfile.h" +#include "ModChannel.h" + +void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel) +//------------------------------------------------------------------------------------------------- +{ + if(resetMask & resetSetPosBasic) + { + nNote = nNewNote = nNewIns = 0; + pModSample = nullptr; + pModInstrument = nullptr; + nPortamentoDest = 0; + nCommand = 0; + nPatternLoopCount = 0; + nPatternLoop = 0; + nFadeOutVol = 0; + dwFlags |= CHN_KEYOFF|CHN_NOTEFADE; + //IT compatibility 15. Retrigger + if(sndFile.IsCompatibleMode(TRK_IMPULSETRACKER)) + { + nRetrigParam = 1; + nRetrigCount = 0; + } + nTremorCount = 0; + nEFxSpeed = 0; + } + + if(resetMask & resetSetPosAdvanced) + { + nPeriod = 0; + nPos = nLength = 0; + nLoopStart = 0; + nLoopEnd = 0; + nROfs = nLOfs = 0; + pSample = nullptr; + pModSample = nullptr; + pModInstrument = nullptr; + nCutOff = 0x7F; + nResonance = 0; + nFilterMode = 0; + nLeftVol = nRightVol = 0; + nNewLeftVol = nNewRightVol = 0; + nLeftRamp = nRightRamp = 0; + nVolume = 256; + nVibratoPos = nTremoloPos = nPanbrelloPos = 0; + + //-->Custom tuning related + m_ReCalculateFreqOnFirstTick = false; + m_CalculateFreq = false; + m_PortamentoFineSteps = 0; + m_PortamentoTickSlide = 0; + m_Freq = 0; + m_VibratoDepth = 0; + //<--Custom tuning related. + } + + if(resetMask & resetChannelSettings) + { + if(sourceChannel < MAX_BASECHANNELS) + { + dwFlags = sndFile.ChnSettings[sourceChannel].dwFlags; + nPan = sndFile.ChnSettings[sourceChannel].nPan; + nGlobalVol = sndFile.ChnSettings[sourceChannel].nVolume; + } + else + { + dwFlags = 0; + nPan = 128; + nGlobalVol = 64; + } + nRestorePanOnNewNote = 0; + nRestoreCutoffOnNewNote = 0; + nRestoreResonanceOnNewNote = 0; + + } +} Modified: trunk/OpenMPT/soundlib/ModChannel.h =================================================================== --- trunk/OpenMPT/soundlib/ModChannel.h 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/ModChannel.h 2012-03-10 18:19:44 UTC (rev 1215) @@ -36,43 +36,43 @@ LPSTR pCurrentSample; // Currently playing sample (nullptr if no sample is playing) DWORD nPos; DWORD nPosLo; // actually 16-bit (fractional part) - LONG nInc; // 16.16 fixed point - LONG nRightVol; - LONG nLeftVol; - LONG nRightRamp; - LONG nLeftRamp; + int32 nInc; // 16.16 fixed point + int nRightVol; + int nLeftVol; + int nRightRamp; + int nLeftRamp; // 2nd cache line DWORD nLength; DWORD dwFlags; DWORD nLoopStart; DWORD nLoopEnd; - LONG nRampRightVol; - LONG nRampLeftVol; + int nRampRightVol; + int nRampLeftVol; float nFilter_Y1, nFilter_Y2, nFilter_Y3, nFilter_Y4; float nFilter_A0, nFilter_B0, nFilter_B1; int nFilter_HP; - LONG nROfs, nLOfs; - LONG nRampLength; + int nROfs, nLOfs; + int nRampLength; // Information not used in the mixer LPSTR pSample; // Currently playing sample, or previously played sample if no sample is playing. - LONG nNewRightVol, nNewLeftVol; - LONG nRealVolume, nRealPan; - LONG nVolume, nPan, nFadeOutVol; - LONG nPeriod, nC5Speed, nPortamentoDest; + int nNewRightVol, nNewLeftVol; + int nRealVolume, nRealPan; + int nVolume, nPan, nFadeOutVol; + int nPeriod, nC5Speed, nPortamentoDest; int nCalcVolume; // Calculated channel volume, 14-Bit (without global volume, pre-amp etc applied) - for MIDI macros ModInstrument *pModInstrument; // Currently assigned instrument slot ModChannelEnvInfo VolEnv, PanEnv, PitchEnv; // Envelope playback info ModSample *pModSample; // Currently assigned sample slot CHANNELINDEX nMasterChn; DWORD nVUMeter; - LONG nGlobalVol; // Channel volume (CV in ITTECH.TXT) - LONG nInsVol; // Sample / Instrument volume (SV * IV in ITTECH.TXT) - LONG nFineTune, nTranspose; - LONG nPortamentoSlide, nAutoVibDepth; + int nGlobalVol; // Channel volume (CV in ITTECH.TXT) + int nInsVol; // Sample / Instrument volume (SV * IV in ITTECH.TXT) + int nFineTune, nTranspose; + int nPortamentoSlide, nAutoVibDepth; UINT nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos; - LONG nVolSwing, nPanSwing; - LONG nCutSwing, nResSwing; - LONG nRestorePanOnNewNote; //If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from panswing. + int nVolSwing, nPanSwing; + int nCutSwing, nResSwing; + int nRestorePanOnNewNote; //If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from panswing. UINT nOldGlobalVolSlide; DWORD nEFxOffset; // offset memory for Invert Loop (EFx, .MOD only) int nRetrigCount, nRetrigParam; @@ -128,6 +128,25 @@ return const_cast<ModChannelEnvInfo &>(static_cast<const ModChannel &>(*this).GetEnvelope(envType)); } + void ResetEnvelopes() + { + VolEnv.Reset(); + PanEnv.Reset(); + PitchEnv.Reset(); + } + + enum ResetFlags + { + resetChannelSettings = 1, // Reload initial channel settings + resetSetPosBasic = 2, // Reset basic runtime channel attributes + resetSetPosAdvanced = 4, // Reset more runtime channel attributes + resetSetPosFull = resetSetPosBasic | resetSetPosAdvanced | resetChannelSettings, // Reset all runtime channel attributes + resetTotal = resetSetPosFull, + + }; + + void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel); + typedef UINT VOLUME; VOLUME GetVSTVolume() {return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume;} @@ -148,12 +167,7 @@ //<---- } ModChannel; -#define CHNRESET_CHNSETTINGS 1 // 1 b -#define CHNRESET_SETPOS_BASIC 2 // 10 b -#define CHNRESET_SETPOS_FULL 7 // 111 b -#define CHNRESET_TOTAL 255 // 11111111b - // Default pattern channel settings struct ModChannelSettings { Added: trunk/OpenMPT/soundlib/RowVisitor.cpp =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.cpp (rev 0) +++ trunk/OpenMPT/soundlib/RowVisitor.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -0,0 +1,160 @@ +/* + * RowVisitor.cpp + * -------------- + * Purpose: Class for managing which rows of a song has already been visited. Useful for detecting backwards jumps, loops, etc. + * Notes : The class keepts track of rows that have been visited by the player before. + * This way, we can tell when the module starts to loop, i.e. we can determine the song length, + * or find out that a given point of the module can never be reached. + * + * Specific implementations: + * + * Length detection code: + * As the ModPlug engine already deals with pattern loops sufficiently (though not always correctly), + * there's no problem with (infinite) pattern loops in this code. + * + * Normal player code: + * Bare in mind that rows inside pattern loops should only be evaluated once, or else the algorithm will cancel too early! + * So in that case, the pattern loop rows have to be reset when looping back. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Sndfile.h" +#include "RowVisitor.h" + +// Resize / Clear the row vector. +// If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). +void RowVisitor::Initialize(bool reset) +//------------------------------------- +{ + const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + visitedRows.resize(endOrder); + + for(ORDERINDEX order = 0; order < endOrder; order++) + { + VisitedRowsBaseType &row = visitedRows[order]; + // If we want to reset the vectors completely, we overwrite existing items with false. + if(reset) + { + row.assign(row.size(), false); + } + row.resize(GetVisitedRowsVectorSize(sndFile.Order[order]), false); + } +} + + +// (Un)sets a given row as visited. +// order, row - which row should be (un)set +// If visited is true, the row will be set as visited. +void RowVisitor::SetVisited(ORDERINDEX order, ROWINDEX row, bool visited) +//----------------------------------------------------------------------- +{ + const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + if(order >= endOrder || row >= GetVisitedRowsVectorSize(sndFile.Order[order])) + { + return; + } + + // The module might have been edited in the meantime - so we have to extend this a bit. + if(order >= visitedRows.size() || row >= visitedRows[order].size()) + { + Initialize(false); + } + + visitedRows[order][row] = visited; +} + + +// Returns whether a given row has been visited yet. +// If autoSet is true, the queried row will automatically be marked as visited. +// Use this parameter instead of consecutive IsRowVisited / SetRowVisited calls. +bool RowVisitor::IsVisited(ORDERINDEX order, ROWINDEX row, bool autoSet) +//---------------------------------------------------------------------- +{ + const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + if(order >= endOrder) + { + return false; + } + + // The row slot for this row has not been assigned yet - Just return false, as this means that the program has not played the row yet. + if(order >= visitedRows.size() || row >= visitedRows[order].size()) + { + if(autoSet) + { + SetVisited(order, row, true); + } + return false; + } + + if(visitedRows[order][row]) + { + // We visited this row already - this module must be looping. + return true; + } + + if(autoSet) + { + visitedRows[order][row] = true; + } + + return false; +} + + +// Get the needed vector size for pattern nPat. +size_t RowVisitor::GetVisitedRowsVectorSize(PATTERNINDEX pattern) const +//--------------------------------------------------------------------- +{ + if(sndFile.Patterns.IsValidPat(pattern)) + { + return static_cast<size_t>(sndFile.Patterns[pattern].GetNumRows()); + } + else + { + // Invalid patterns consist of a "fake" row. + return 1; + } +} + + +// Find the first row that has not been played yet. +// The order and row is stored in the order and row variables on success, on failure they contain invalid values. +// If fastSearch is true (default), only the first row of each pattern is looked at, otherwise every row is examined. +// Function returns true on success. +bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch) const +//-------------------------------------------------------------------------------------------- +{ + const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + for(order = 0; order < endOrder; order++) + { + const PATTERNINDEX pattern = sndFile.Order[order]; + if(!sndFile.Patterns.IsValidPat(pattern)) + { + continue; + } + + if(order >= visitedRows.size()) + { + // Not yet initialized => unvisited + return true; + } + + const ROWINDEX endRow = (fastSearch ? 1 : sndFile.Patterns[pattern].GetNumRows()); + for(row = 0; row < endRow; row++) + { + if(row >= visitedRows[order].size() || visitedRows[order][row] == false) + { + // Not yet initialized, or unvisited + return true; + } + } + } + + // Didn't find anything :( + order = ORDERINDEX_INVALID; + row = ROWINDEX_INVALID; + return false; +} Added: trunk/OpenMPT/soundlib/RowVisitor.h =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.h (rev 0) +++ trunk/OpenMPT/soundlib/RowVisitor.h 2012-03-10 18:19:44 UTC (rev 1215) @@ -0,0 +1,82 @@ +/* + * RowVisitor.h + * ------------ + * Purpose: Class for managing which rows of a song has already been visited. Useful for detecting backwards jumps, loops, etc. + * Notes : See implementation file. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include <vector> +#include "Snd_defs.h" +class CSoundFile; + +//============== +class RowVisitor +//============== +{ +protected: + + // Data type for the visited rows. + typedef std::vector<bool> VisitedRowsBaseType; + typedef std::vector<VisitedRowsBaseType> VisitedRowsType; + + VisitedRowsType visitedRows; + const CSoundFile &sndFile; + +public: + + RowVisitor(const CSoundFile &sf) : sndFile(sf) + { + Initialize(true); + }; + + RowVisitor(const RowVisitor &other) : sndFile(other.sndFile), visitedRows(other.visitedRows) { }; + + // Resize / Clear the row vector. + // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). + void Initialize(bool reset); + + // Mark a row as visited. + void Visit(ORDERINDEX order, ROWINDEX row) + { + SetVisited(order, row, true); + }; + + // Mark a row as not visited. + void Unvisit(ORDERINDEX order, ROWINDEX row) + { + SetVisited(order, row, false); + }; + + // Returns whether a given row has been visited yet. + // If autoSet is true, the queried row will automatically be marked as visited. + // Use this parameter instead of consecutive IsRowVisited / SetRowVisited calls. + bool IsVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool autoSet); + + // Get the needed vector size for a given pattern. + size_t GetVisitedRowsVectorSize(PATTERNINDEX pattern) const; + + // Find the first row that has not been played yet. + // The order and row is stored in the order and row variables on success, on failure they contain invalid values. + // If fastSearch is true (default), only the first row of each pattern is looked at, otherwise every row is examined. + // Function returns true on success. + bool GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch) const; + + // Retrieve visited rows vector from another RowVisitor object. + void Set(const RowVisitor &other) + { + visitedRows = other.visitedRows; + } + +protected: + + // (Un)sets a given row as visited. + // order, row - which row should be (un)set + // If visited is true, the row will be set as visited. + void SetVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool visited); + +}; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -158,10 +158,9 @@ PATTERNINDEX nPattern = Order[0]; GetLengthMemory memory(*this); - VisitedRowsType visitedRows; // temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time) + // Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time) + RowVisitor visitedRows(*this); - InitializeVisitedRows(true, &visitedRows); - for (;;) { UINT nSpeedCount = 0; @@ -191,9 +190,9 @@ } nPattern = (nCurrentOrder < Order.size()) ? Order[nCurrentOrder] : Order.GetInvalidPatIndex(); nNextOrder = nCurrentOrder; - if((!Patterns.IsValidPat(nPattern)) && IsRowVisited(nCurrentOrder, 0, true, &visitedRows)) + if((!Patterns.IsValidPat(nPattern)) && visitedRows.IsVisited(nCurrentOrder, 0, true)) { - if(!hasSearchTarget || !GetFirstUnvisitedRow(nNextOrder, nNextRow, true, &visitedRows)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -211,7 +210,7 @@ // If there isn't even a tune, we should probably stop here. if(nCurrentOrder == m_nRestartPos) { - if(!hasSearchTarget || !GetFirstUnvisitedRow(nNextOrder, nNextRow, true, &visitedRows)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -236,9 +235,9 @@ break; } - if(IsRowVisited(nCurrentOrder, nRow, true, &visitedRows)) + if(visitedRows.IsVisited(nCurrentOrder, nRow, true)) { - if(!hasSearchTarget || !GetFirstUnvisitedRow(nNextOrder, nNextRow, true, &visitedRows)) + if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(nNextOrder, nNextRow, true)) { // We aren't searching for a specific row, or we couldn't find any more unvisited rows. break; @@ -552,7 +551,7 @@ m_nGlobalVolume = m_nDefaultGlobalVolume; } // When adjusting the playback status, we will also want to update the visited rows vector according to the current position. - m_VisitedRows = visitedRows; + visitedSongRows.Set(visitedRows); } return retval; @@ -711,7 +710,7 @@ if (!(pIns->PitchEnv.dwFlags & ENV_CARRY)) pChn->PitchEnv.Reset(); } else { - ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); } // IT Compatibility: Autovibrato reset if(!IsCompatibleMode(TRK_IMPULSETRACKER)) @@ -726,7 +725,7 @@ pChn->VolEnv.Reset(); } else { - ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); } } } @@ -1014,7 +1013,7 @@ { if ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && (pChn->dwFlags & CHN_NOTEFADE) && (!pChn->nFadeOutVol)) { - ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); // IT Compatibility: Autovibrato reset if(!IsCompatibleMode(TRK_IMPULSETRACKER)) { @@ -1698,7 +1697,7 @@ if (GetNumInstruments() && (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) { pChn->dwFlags |= CHN_FASTVOLRAMP; - ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); pChn->nAutoVibDepth = 0; pChn->nAutoVibPos = 0; pChn->dwFlags &= ~CHN_NOTEFADE; @@ -1768,7 +1767,7 @@ if ((bPorta) && (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr)) { pChn->dwFlags |= CHN_FASTVOLRAMP; - ResetChannelEnvelopes(pChn); + pChn->ResetEnvelopes(); pChn->nAutoVibDepth = 0; pChn->nAutoVibPos = 0; } @@ -2333,7 +2332,7 @@ // As long as the pattern loop is running, mark the looped rows as not visited yet for(ROWINDEX nRow = nPatLoopRow; nRow <= m_nRow; nRow++) { - SetRowVisited(m_nCurrentOrder, nRow, false); + visitedSongRows.Unvisit(m_nCurrentOrder, nRow); } } @@ -2371,15 +2370,6 @@ } -void CSoundFile::ResetChannelEnvelopes(ModChannel *pChn) const -//------------------------------------------------------------ -{ - pChn->VolEnv.Reset(); - pChn->PanEnv.Reset(); - pChn->PitchEnv.Reset(); -} - - //////////////////////////////////////////////////////////// // Channels effects @@ -4470,178 +4460,3 @@ pChn->m_CalculateFreq = true; } - - -/* Now, some fun code begins: This will determine if a specific row in a pattern (orderlist item) - has been visited before. This way, we can tell when the module starts to loop, i.e. when we have determined - the song length (or found out that a given point of the module cannot be reached). - The concept is actually very simple: Store a boolean value for every row for every possible orderlist item. - - Specific implementations: - - Length detection code: - As the ModPlug engine already deals with pattern loops sufficiently (though not always correctly), - there's no problem with (infinite) pattern loops in this code. - - Normal player code: - Bare in mind that rows inside pattern loops should only be evaluated once, or else the algorithm will cancel too early! - So in that case, the pattern loop rows have to be reset when looping back. -*/ - - -// Resize / Clear the row vector. -// If bReset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). -// If pRowVector is specified, an alternative row vector instead of the module's global one will be used (f.e. when using GetLength()). -void CSoundFile::InitializeVisitedRows(bool bReset, VisitedRowsType *pRowVector) -//------------------------------------------------------------------------------ -{ - const ORDERINDEX nMaxOrd = Order.GetLengthTailTrimmed(); - if(pRowVector == nullptr) - { - pRowVector = &m_VisitedRows; - } - pRowVector->resize(nMaxOrd); - - for(ORDERINDEX nOrd = 0; nOrd < nMaxOrd; nOrd++) - { - VisitedRowsBaseType &row = pRowVector->at(nOrd); - // If we want to reset the vectors completely, we overwrite existing items with false. - if(bReset) - { - row.assign(row.size(), false); - } - row.resize(GetVisitedRowsVectorSize(Order[nOrd]), false); - } -} - - -// (Un)sets a given row as visited. -// nOrd, nRow - which row should be (un)set -// If bVisited is true, the row will be set as visited. -// If pRowVector is specified, an alternative row vector instead of the module's global one will be used (f.e. when using GetLength()). -void CSoundFile::SetRowVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool bVisited, VisitedRowsType *pRowVector) -//-------------------------------------------------------------------------------------------------------- -{ - const ORDERINDEX nMaxOrd = Order.GetLengthTailTrimmed(); - if(nOrd >= nMaxOrd || nRow >= GetVisitedRowsVectorSize(Order[nOrd])) - { - return; - } - - if(pRowVector == nullptr) - { - pRowVector = &m_VisitedRows; - } - - // The module might have been edited in the meantime - so we have to extend this a bit. - if(nOrd >= pRowVector->size() || nRow >= pRowVector->at(nOrd).size()) - { - InitializeVisitedRows(false, pRowVector); - } - - pRowVector->at(nOrd).at(nRow) = bVisited; -} - - -// Returns if a given row has been visited yet. -// If bAutoSet is true, the queried row will automatically be marked as visited. -// Use this parameter instead of consecutive IsRowVisited/SetRowVisited calls. -// If pRowVector is specified, an alternative row vector instead of the module's global one will be used (f.e. when using GetLength()). -bool CSoundFile::IsRowVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool bAutoSet, VisitedRowsType *pRowVector) -//------------------------------------------------------------------------------------------------------- -{ - const ORDERINDEX nMaxOrd = Order.GetLengthTailTrimmed(); - if(nOrd >= nMaxOrd) - { - return false; - } - - if(pRowVector == nullptr) - { - pRowVector = &m_VisitedRows; - } - - // The row slot for this row has not been assigned yet - Just return false, as this means that the program has not played the row yet. - if(nOrd >= pRowVector->size() || nRow >= pRowVector->at(nOrd).size()) - { - if(bAutoSet) - { - SetRowVisited(nOrd, nRow, true, pRowVector); - } - return false; - } - - if(pRowVector->at(nOrd).at(nRow)) - { - // we visited this row already - this module must be looping. - return true; - } - - if(bAutoSet) - { - pRowVector->at(nOrd).at(nRow) = true; - } - - return false; -} - - -// Get the needed vector size for pattern nPat. -size_t CSoundFile::GetVisitedRowsVectorSize(PATTERNINDEX nPat) const -//------------------------------------------------------------------ -{ - if(Patterns.IsValidPat(nPat)) - { - return (size_t)(Patterns[nPat].GetNumRows()); - } - else - { - // invalid patterns consist of a "fake" row. - return 1; - } -} - - -// Find the first row that has not been played yet. -// The order and row is stored in the order and row variables on success, on failure they contain invalid values. -// If fastSearch is true (default), only the first row of each pattern is looked at, otherwise every row is examined. -// Function returns true on success. -bool CSoundFile::GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch, const VisitedRowsType *pRowVector) const -//------------------------------------------------------------------------------------------------------------------------------- -{ - if(pRowVector == nullptr) - { - pRowVector = &m_VisitedRows; - } - - const ORDERINDEX endOrder = Order.GetLengthTailTrimmed(); - for(order = 0; order < endOrder; order++) - { - const PATTERNINDEX pattern = Order[order]; - if(!Patterns.IsValidPat(pattern)) - { - continue; - } - - if(order >= pRowVector->size()) - { - // Not yet initialized => unvisited - return true; - } - - const ROWINDEX endRow = (fastSearch ? 1 : Patterns[pattern].GetNumRows()); - for(row = 0; row < endRow; row++) - { - if(row >= pRowVector->at(order).size() || pRowVector->at(order).at(row) == false) - { - // Not yet initialized, or unvisited - return true; - } - } - } - - // Didn't find anything :( - order = ORDERINDEX_INVALID; - row = ROWINDEX_INVALID; - return false; -} Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -448,7 +448,8 @@ Order(*this), m_PlaybackEventer(*this), m_pModSpecs(&ModSpecs::itEx), - m_MIDIMapper(*this) + m_MIDIMapper(*this), + visitedSongRows(*this) #pragma warning(default : 4355) // "'this' : used in base member initializer list" //---------------------- { @@ -742,8 +743,6 @@ m_nNextRow = 0; m_nRow = 0; - InitializeVisitedRows(true); - RecalculateSamplesPerTick(); if ((m_nRestartPos >= Order.size()) || (Order[m_nRestartPos] >= Patterns.Size())) m_nRestartPos = 0; @@ -1023,10 +1022,10 @@ //--------------------------------------- { ORDERINDEX nPattern; - BYTE resetMask = (!nPos) ? CHNRESET_SETPOS_FULL : CHNRESET_SETPOS_BASIC; + ModChannel::ResetFlags resetMask = (!nPos) ? ModChannel::resetSetPosFull : ModChannel::resetSetPosBasic; - for (CHANNELINDEX i=0; i<MAX_CHANNELS; i++) - ResetChannelState(i, resetMask); + for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + Chn[i].Reset(resetMask, *this, i); if (!nPos) { @@ -1324,7 +1323,7 @@ ChnSettings[nChn].nMixPlugin = 0; strcpy(ChnSettings[nChn].szName, ""); - ResetChannelState(nChn, CHNRESET_TOTAL); + Chn[nChn].Reset(ModChannel::resetTotal, *this, nChn); if(m_pModDoc) { @@ -1336,83 +1335,7 @@ return false; } -void CSoundFile::ResetChannelState(CHANNELINDEX i, BYTE resetMask) -//---------------------------------------------------------------- -{ - if(i >= MAX_CHANNELS) return; - if(resetMask & 2) - { - Chn[i].nNote = Chn[i].nNewNote = Chn[i].nNewIns = 0; - Chn[i].pModSample = nullptr; - Chn[i].pModInstrument = nullptr; - Chn[i].nPortamentoDest = 0; - Chn[i].nCommand = 0; - Chn[i].nPatternLoopCount = 0; - Chn[i].nPatternLoop = 0; - Chn[i].nFadeOutVol = 0; - Chn[i].dwFlags |= CHN_KEYOFF|CHN_NOTEFADE; - //IT compatibility 15. Retrigger - if(IsCompatibleMode(TRK_IMPULSETRACKER)) - { - Chn[i].nRetrigParam = 1; - Chn[i].nRetrigCount = 0; - } - Chn[i].nTremorCount = 0; - Chn[i].nEFxSpeed = 0; - } - - if(resetMask & 4) - { - Chn[i].nPeriod = 0; - Chn[i].nPos = Chn[i].nLength = 0; - Chn[i].nLoopStart = 0; - Chn[i].nLoopEnd = 0; - Chn[i].nROfs = Chn[i].nLOfs = 0; - Chn[i].pSample = nullptr; - Chn[i].pModSample = nullptr; - Chn[i].pModInstrument = nullptr; - Chn[i].nCutOff = 0x7F; - Chn[i].nResonance = 0; - Chn[i].nFilterMode = 0; - Chn[i].nLeftVol = Chn[i].nRightVol = 0; - Chn[i].nNewLeftVol = Chn[i].nNewRightVol = 0; - Chn[i].nLeftRamp = Chn[i].nRightRamp = 0; - Chn[i].nVolume = 256; - Chn[i].nVibratoPos = Chn[i].nTremoloPos = Chn[i].nPanbrelloPos = 0; - - //-->Custom tuning related - Chn[i].m_ReCalculateFreqOnFirstTick = false; - Chn[i].m_CalculateFreq = false; - Chn[i].m_PortamentoFineSteps = 0; - Chn[i].m_PortamentoTickSlide = 0; - Chn[i].m_Freq = 0; - Chn[i].m_VibratoDepth = 0; - //<--Custom tuning related. - } - - if(resetMask & 1) - { - if(i < MAX_BASECHANNELS) - { - Chn[i].dwFlags = ChnSettings[i].dwFlags; - Chn[i].nPan = ChnSettings[i].nPan; - Chn[i].nGlobalVol = ChnSettings[i].nVolume; - } - else - { - Chn[i].dwFlags = 0; - Chn[i].nPan = 128; - Chn[i].nGlobalVol = 64; - } - Chn[i].nRestorePanOnNewNote = 0; - Chn[i].nRestoreCutoffOnNewNote = 0; - Chn[i].nRestoreResonanceOnNewNote = 0; - - } -} - - #ifndef NO_PACKING UINT CSoundFile::PackSample(int &sample, int next) //------------------------------------------------ Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-03-10 18:19:44 UTC (rev 1215) @@ -28,6 +28,7 @@ #include "ModChannel.h" #include "modcommand.h" #include "PlugInterface.h" +#include "RowVisitor.h" // ----------------------------------------------------------------------------------------- // MODULAR ModInstrument FIELD ACCESS : body content at the (near) top of Sndfile.cpp !!! @@ -93,11 +94,7 @@ ORDERINDEX order; // which order is this? }; -// Data type for the visited rows routines. -typedef vector<bool> VisitedRowsBaseType; -typedef vector<VisitedRowsBaseType> VisitedRowsType; - // Return values for GetLength() struct GetLengthType { @@ -109,6 +106,7 @@ ROWINDEX endRow; // last row before module loops (dito) }; + // Reset mode for GetLength() enum enmGetLengthResetMode { @@ -223,10 +221,6 @@ const CModSpecifications* m_pModSpecs; bool m_bITBidiMode; // Process bidi loops like Impulse Tracker (see Fastmix.cpp for an explanation) - // For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. - VisitedRowsType m_VisitedRows; - - public: // Static Members static UINT m_nXBassDepth, m_nXBassRange; static UINT m_nReverbDepth, gnReverbType; @@ -262,7 +256,7 @@ ROWINDEX m_nCurrentRowsPerBeat, m_nCurrentRowsPerMeasure; // current rows per beat and measure for this module BYTE m_nTempoMode; // rewbs.betterBPM BYTE m_nMixLevels; - UINT m_nMusicSpeed, m_nMusicTempo; // Current speed and tempo + UINT m_nMusicSpeed, m_nMusicTempo; // Current speed and tempo ROWINDEX m_nNextRow, m_nRow; ROWINDEX m_nNextPatStartRow; // for FT2's E60 bug PATTERNINDEX m_nPattern; @@ -298,6 +292,9 @@ vector<PatternCuePoint> m_PatternCuePoints; // For WAV export (writing pattern positions to file) + // For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. + RowVisitor visitedSongRows; + // -> CODE#0023 // -> DESC="IT project files (.itp)" CHAR m_szInstrumentPath[MAX_INSTRUMENTS][_MAX_PATH]; @@ -363,7 +360,6 @@ void SetupITBidiMode(); bool InitChannel(CHANNELINDEX nChn); - void ResetChannelState(CHANNELINDEX chn, BYTE resetStyle); // Module Loaders bool ReadXM(const LPCBYTE lpStream, const DWORD dwMemLength); @@ -431,9 +427,6 @@ void S3MSaveConvert(UINT *pcmd, UINT *pprm, bool bIT, bool bCompatibilityExport = false) const; WORD ModSaveCommand(const ModCommand *m, const bool bXM, const bool bCompatibilityExport = false) const; - static void ConvertCommand(ModCommand *m, MODTYPE nOldType, MODTYPE nNewType); // Convert a complete ModCommand item from one format to another - static void MODExx2S3MSxx(ModCommand *m); // Convert Exx to Sxx - static void S3MSxx2MODExx(ModCommand *m); // Convert Sxx to Exx void SetupMODPanning(bool bForceSetup = false); // Setup LRRL panning, max channel volume public: @@ -706,9 +699,6 @@ // [out] returns true on success. bool ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &) = nullptr); -public: - void ResetChannelEnvelopes(ModChannel *pChn) const; - private: PLUGINDEX __cdecl GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const; PLUGINDEX __cdecl GetActiveInstrumentPlugin(CHANNELINDEX, PluginMutePriority respectMutes) const; @@ -720,21 +710,6 @@ PLUGINDEX GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const; UINT GetBestMidiChannel(CHANNELINDEX nChn) const; -// A couple of functions for handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. -public: - void InitializeVisitedRows(const bool bReset = true, VisitedRowsType *pRowVector = nullptr); -private: - void SetRowVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool bVisited = true, VisitedRowsType *pRowVector = nullptr); - bool IsRowVisited(ORDERINDEX nOrd, ROWINDEX nRow, bool bAutoSet = true, VisitedRowsType *pRowVector = nullptr); - size_t GetVisitedRowsVectorSize(PATTERNINDEX nPat) const; - bool GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch = true, const VisitedRowsType *pRowVector = nullptr) const; - -public: - // "importance" of every FX command. Table is used for importing from formats with multiple effect columns - // and is approximately the same as in SchismTracker. - static size_t GetEffectWeight(ModCommand::COMMAND cmd); - // try to convert a an effect into a volume column effect. - static bool ConvertVolEffect(uint8 *e, uint8 *p, bool bForce); }; #pragma warning(default : 4324) //structure was padded due to __declspec(align()) Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -776,7 +776,7 @@ || (Order[m_nCurrentOrder] >= Patterns.Size()) || (!Patterns[Order[m_nCurrentOrder]]) ) { - InitializeVisitedRows(true); + visitedSongRows.Initialize(true); return FALSE; } @@ -810,7 +810,7 @@ // the pattern loop (editor flag, not to be confused with the pattern loop effect) // flag is set - because in that case, the module would stop after the first pattern loop... const bool overrideLoopCheck = (m_nRepeatCount != -1) && (m_dwSongFlags & SONG_PATTERNLOOP); - if(!overrideLoopCheck && IsRowVisited(m_nCurrentOrder, m_nRow, true)) + if(!overrideLoopCheck && visitedSongRows.IsVisited(m_nCurrentOrder, m_nRow, true)) { if(m_nRepeatCount) { @@ -820,8 +820,8 @@ m_nRepeatCount--; } // Forget all but the current row. - InitializeVisitedRows(true); - SetRowVisited(m_nCurrentOrder, m_nRow); + visitedSongRows.Initialize(true); + visitedSongRows.Visit(m_nCurrentOrder, m_nRow); } else { #ifdef MODPLUG_TRACKER @@ -835,7 +835,7 @@ #endif // MODPLUG_TRACKER { // This is really the song's end! - InitializeVisitedRows(true); + visitedSongRows.Initialize(true); return FALSE; } else { Modified: trunk/OpenMPT/soundlib/load_j2b.cpp =================================================================== --- trunk/OpenMPT/soundlib/load_j2b.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/load_j2b.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -292,7 +292,7 @@ m->param = ((m->param >> 4) * 10) + (m->param & 0x0F); break; case CMD_MODCMDEX: - CSoundFile::MODExx2S3MSxx(m); + m->ExtendedMODtoS3MEffect(); break; case CMD_TEMPO: if(m->param <= 0x1F) m->command = CMD_SPEED; Modified: trunk/OpenMPT/soundlib/modcommand.cpp =================================================================== --- trunk/OpenMPT/soundlib/modcommand.cpp 2012-03-10 15:51:28 UTC (rev 1214) +++ trunk/OpenMPT/soundlib/modcommand.cpp 2012-03-10 18:19:44 UTC (rev 1215) @@ -15,132 +15,141 @@ // Convert an Exx command (MOD) to Sxx command (S3M) -void CSoundFile::MODExx2S3MSxx(ModCommand *m) -//------------------------------------------- +void ModCommand::ExtendedMODtoS3MEffect() +//--------------------------------------- { - if(m->command != CMD_MODCMDEX) return; - m->command = CMD_S3MCMDEX; - switch(m->param & 0xF0) + if(command != CMD_MODCMDEX) + return; + + command = CMD_S3MCMDEX; + switch(param & 0xF0) { - case 0x10: m->command = CMD_PORTAMENTOUP; m->param |= 0xF0; break; - case 0x20: m->command = CMD_PORTAMENTODOWN; m->param |= 0xF0; break; - case 0x30: m->param = (m->param & 0x0F) | 0x10; break; - case 0x40: m->param = (m->param & 0x03) | 0x30; break; - case 0x50: m->param = (m->param & 0x0F) | 0x20; break; - case 0x60: m->param = (m->param & 0x0F) | 0xB0; break; - case 0x70: m->param = (m->param & 0x03) | 0x40; break; - case 0x90: m->command = CMD_RETRIG; m->param = (m->param & 0x0F); break; - case 0xA0: if (m->param & 0x0F) { m->command = CMD_VOLUMESLIDE; m->param = (m->param << 4) | 0x0F; } else m->command = 0; break; - case 0xB0: if (m->param & 0x0F) { m->command = CMD_VOLUMESLIDE; m->param |= 0xF0; } else m->command = 0; break; - case 0xC0: if (m->param == 0xC0) { m->command = CMD_NONE; m->note = NOTE_NOTECUT; } // this does different things in IT and ST3 - case 0xD0: if (m->param == 0xD0) { m->command = CMD_NONE; } // dito + case 0x10: command = CMD_PORTAMENTOUP; param |= 0xF0; break; + case 0x20: command = CMD_PORTAMENTODOWN; param |= 0xF0; break; + case 0x30: param = (param & 0x0F) | 0x10; break; + case 0x40: param = (param & 0x03) | 0x30; break; + case 0x50: param = (param & 0x0F) | 0x20; break; + case 0x60: param = (param & 0x0F) | 0xB0; break; + case 0x70: param = (param & 0x03) | 0x40; break; + case 0x90: command = CMD_RETRIG; param = (param & 0x0F); break; + case 0xA0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command = 0; break; + case 0xB0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command = 0; break; + case 0xC0: if (param == 0xC0) { command = CMD_NONE; note = NOTE_NOTECUT; } // this does different things in IT and ST3 + case 0xD0: if (param == 0xD0) { command = CMD_NONE; } // dito // rest are the same } } // Convert an Sxx command (S3M) to Exx command (MOD) -void CSoundFile::S3MSxx2MODExx(ModCommand *m) -//------------------------------------------- +void ModCommand::ExtendedS3MtoMODEffect() +//--------------------------------------- { - if(m->command != CMD_S3MCMDEX) return; - m->command = CMD_MODCMDEX; - switch(m->param & 0xF0) + if(command != CMD_S3MCMDEX) + return; + + command = CMD_MODCMDEX; + switch(param & 0xF0) { - case 0x10: m->param = (m->param & 0x0F) | 0x30; break; - case 0x20: m->param = (m->param & 0x0F) | 0x50; break; - case 0x30: m->param = (m->param & 0x0F) | 0x40; break; - case 0x40: m->param = (m->param & 0x0F) | 0x70; break; + case 0x10: param = (param & 0x0F) | 0x30; break; + case 0x20: param = (param & 0x0F) | 0x50; break; + case 0x30: param = (param & 0x0F) | 0x40; break; + case 0x40: param = (param & 0x0F) | 0x70; break; case 0x50: case 0x60: case 0x90: - case 0xA0: m->command = CMD_XFINEPORTAUPDOWN; break; - case 0xB0: m->param = (m->param & 0x0F) | 0x60; break; - case 0x70: m->command = CMD_NONE; // No NNA / envelope control in MOD/XM format + case 0xA0: command = CMD_XFINEPORTAUPDOWN; break; + case 0xB0: param = (param & 0x0F) | 0x60; break; + case 0x70: command = CMD_NONE; // No NNA / envelope control in MOD/XM format // rest are the same } } // Convert a mod command from one format to another. -void CSoundFile::ConvertCommand(ModCommand *m, MODTYPE nOldType, MODTYPE nNewType) -//-------------------------------------------------------------------------------- +void ModCommand::Convert(MODTYPE fromType, MODTYPE toType) +//-------------------------------------------------------- { + if(fromType == toType) + { + return; + } + // helper variables - const bool oldTypeIsMOD = (nOldType == MOD_TYPE_MOD), oldTypeIsXM = (nOldType == MOD_TYPE_XM), - oldTypeIsS3M = (nOldType == MOD_TYPE_S3M), oldTypeIsIT = (nOldType == MOD_TYPE_IT), - oldTypeIsMPT = (nOldType == MOD_TYPE_MPT), oldTypeIsMOD_XM = (oldTypeIsMOD || oldTypeIsXM), + const bool oldTypeIsMOD = (fromType == MOD_TYPE_MOD), oldTypeIsXM = (fromType == MOD_TYPE_XM), + oldTypeIsS3M = (fromType == MOD_TYPE_S3M), oldTypeIsIT = (fromType == MOD_TYPE_IT), + oldTypeIsMPT = (fromType == MOD_TYPE_MPT), oldTypeIsMOD_XM = (oldTypeIsMOD || oldTypeIsXM), oldTypeIsS3M_IT_MPT = (oldTypeIsS3M || oldTypeIsIT || oldTypeIsMPT), oldTypeIsIT_MPT = (oldTypeIsIT || oldTypeIsMPT); - const bool newTypeIsMOD = (nNewType == MOD_TYPE_MOD), newTypeIsXM = (nNewType == MOD_TYPE_XM), - newTypeIsS3M = (nNewType == MOD_TYPE_S3M), newTypeIsIT = (nNewType == MOD_TYPE_IT), - newTypeIsMPT = (nNewType == MOD_TYPE_MPT), newTypeIsMOD_XM = (newTypeIsMOD || newTypeIsXM), + const bool newTypeIsMOD = (toType == MOD_TYPE_MOD), newTypeIsXM = (toType == MOD_TYPE_XM), + newTypeIsS3M = (toType == MOD_TYPE_S3M), newTypeIsIT = (toType == MOD_TYPE_IT), + newTypeIsMPT = (toType == MOD_TYPE_MPT), newTypeIsMOD_XM = (newTypeIsMOD || newTypeIsXM), newTypeIsS3M_IT_MPT = (newTypeIsS3M || newTypeIsIT || newTypeIsMPT), newTypeIsIT_MPT = (newTypeIsIT || newTypeIsMPT); ////////////////////////// // Convert 8-bit Panning - if(m->command == CMD_PANNING8) + if(command == CMD_PANNING8) { if(newTypeIsS3M) { - m->param = (m->param + 1) >> 1; + param = (param + 1) >> 1; } else if(oldTypeIsS3M) { - if(m->param == 0xA4) + if(param == 0xA4) { // surround remap - m->command = (nNewType & (MOD_TYPE_IT|MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN; - m->param = 0x91; + command = (toType & (MOD_TYPE_IT|MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN; + param = 0x91; } else { - m->param = min(m->param << 1, 0xFF); + param = min(param << 1, 0xFF); } } - } // End if(m->command == CMD_PANNING8) + } // End if(command == CMD_PANNING8) // Re-map \xx to Zxx if the new format only knows the latter command. - if(m->command == CMD_SMOOTHMIDI && !GetModSpecifications(nNewType).HasCommand(CMD_SMOOTHMIDI) && GetModSpecifications(nNewType).HasCommand(CMD_MIDI)) + if(command == CMD_SMOOTHMIDI && !CSoundFile::GetModSpecifications(toType).HasCommand(CMD_SMOOTHMIDI) && CSoundFile::GetModSpecifications(toType).HasCommand(CMD_MIDI)) { - m->command = CMD_MIDI; + command = CMD_MIDI; } /////////////////////////////////////////////////////////////////////////////////////// // MPTM to anything: Convert param control, extended envelope control, note delay+cut if(oldTypeIsMPT) { - if(m->IsPcNote()) + if(IsPcNote()) { - ModCommand::COMMAND newcommand = (m->note == NOTE_PC) ? CMD_MIDI : CMD_SMOOTHMIDI; - if(!GetModSpecifications(nNewType).HasCommand(newcommand)) + ModCommand::COMMAND newcommand = (note == NOTE_PC) ? CMD_MIDI : CMD_SMOOTHMIDI; + if(!CSoundFile::GetModSpecifications(toType).HasCommand(newcommand)) { newcommand = CMD_MIDI; // assuming that this was CMD_SMOOTHMIDI } - if(!GetModSpecifications(nNewType).HasCommand(newcommand)) + if(!CSoundFile::GetModSpecifications(toType).HasCommand(newcommand)) { newcommand = CMD_NONE; } - m->param = (BYTE)(min(ModCommand::maxColumnValue, m->GetValueEffectCol()) * 0x7F / ModCommand::maxColumnValue); - m->command = newcommand; // might be removed later - m->volcmd = VOLCMD_NONE; - m->note = NOTE_NONE; - m->instr = 0; + param = (BYTE)(min(ModCommand::maxColumnValue, GetValueEffectCol()) * 0x7F / ModCommand::maxColumnValue); + command = newcommand; // might be removed later + volcmd = VOLCMD_NONE; + note = NOTE_NONE; + instr = 0; } // adjust extended envelope control commands - if((m->command == CMD_S3MCMDEX) && ((m->param & 0xF0) == 0x70) && ((m->param & 0x0F) > 0x0C)) + if((command == CMD_S3MCMDEX) && ((param & 0xF0) == 0x70) && ((param & 0x0F) > 0x0C)) { - m->param = 0x7C; + param = 0x7C; } - if(m->command == CMD_DELAYCUT) + if(command == CMD_DELAYCUT) { - m->command = CMD_S3MCMDEX; // when converting to MOD/XM, this will be converted to CMD_MODCMDEX later - m->param = 0xD0 | (m->param >> 4); // preserve delay nibble. + command = CMD_S3MCMDEX; // when converting to MOD/XM, this will be converted to CMD_MODCMDEX later + param = 0xD0 | (param >> 4); // preserve delay nibble. } } // End if(oldTypeIsMPT) @@ -148,78 +157,78 @@ // Convert MOD / XM to S3M / IT / MPTM if(oldTypeIsMOD_XM && newTypeIsS3M_IT_MPT) { - switch(m->command) + switch(command) { case CMD_MODCMDEX: - MODExx2S3MSxx(m); + ExtendedMODtoS3MEffect(); break; case CMD_VOLUME: // Effect column volume command overrides the volume column in XM. - if (m->volcmd == VOLCMD_NONE || m->volcmd == VOLCMD_VOLUME) + if (volcmd == VOLCMD_NONE || volcmd == VOLCMD_VOLUME) { - m->volcmd = VOLCMD_VOLUME; - m->vol = m->param; - if(m->vol > 64) m->vol = 64; - m->command = m->param = 0; - } else if(m->volcmd == VOLCMD_PANNING) + volcmd = VOLCMD_VOLUME; + vol = param; + if(vol > 64) vol = 64; + command = param = 0; + } else if(volcmd == VOLCMD_PANNING) { - m->SwapEffects(); - m->volcmd = VOLCMD_VOLUME; - if(m->vol > 64) m->vol = 64; - m->command = CMD_S3MCMDEX; - m->param = 0x80 | ((m->param * 15 + 32) / 64); // XM volcol panning is 4-Bit, so we can use 4-Bit panning here. + SwapEffects(); + volcmd = VOLCMD_VOLUME; + if(vol > 64) vol = 64; + command = CMD_S3MCMDEX; + param = 0x80 | ((param * 15 + 32) / 64); // XM volcol panning is 4-Bit, so we can use 4-Bit panning here. } break; case CMD_PORTAMENTOUP: - if (m->param > 0xDF) m->param = 0xDF; + if (param > 0xDF) param = 0xDF; break; case CMD_PORTAMENTODOWN: - if (m->param > 0xDF) m->param = 0xDF; + if (param > 0xDF) param = 0xDF; break; case CMD_XFINEPORTAUPDOWN: - switch(m->param & 0xF0) + switch(param & 0xF0) { - case 0x10: m->command = CMD_PORTAMENTOUP; m->param = (m->param & 0x0F) | 0xE0; break; - case 0x20: m->command = CMD_PORTAMENTODOWN; m->param = (m->param & 0x0F) | 0xE0; break; + case 0x10: command = CMD_PORTAMENTOUP; param = (param & 0x0F) | 0xE0; break; + case 0x20: command = CMD_PORTAMENTODOWN; param = (param & 0x0F) | 0xE0; break; case 0x50: case 0x60: case 0x70: case 0x90: case 0xA0: - m->command = CMD_S3MCMDEX; + command = CMD_S3MC... [truncated message content] |
From: <sag...@us...> - 2012-03-12 22:41:27
|
Revision: 1216 http://modplug.svn.sourceforge.net/modplug/?rev=1216&view=rev Author: saga-games Date: 2012-03-12 22:41:17 +0000 (Mon, 12 Mar 2012) Log Message: ----------- [Ref] NOTE: ASIO and VST SDK paths have been relocated. Please read include/readme.txt for more details. [Ref] Removed unused files. [Ref] Removed VS2003 project. [New] OpenMPT ships with a MIDI Input / Output plugin now. It is meant as a substitute for VST2MID, which is only freeware, not free software. Modified Paths: -------------- trunk/OpenMPT/include/readme.txt trunk/OpenMPT/installer/install.iss trunk/OpenMPT/installer/packageTemplate/readme.txt trunk/OpenMPT/mptrack/ACMConvert.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/packageTemplate/readme.txt trunk/OpenMPT/soundlib/PlugInterface.h Added Paths: ----------- trunk/OpenMPT/include/ASIOSDK2/ trunk/OpenMPT/include/bladeenc/ trunk/OpenMPT/include/bladeenc/bladedll.h trunk/OpenMPT/include/portmidi/ trunk/OpenMPT/include/vstsdk2.4/ trunk/OpenMPT/installer/plugins.iss trunk/OpenMPT/plugins/ trunk/OpenMPT/plugins/MIDI Tools.sln trunk/OpenMPT/plugins/MidiInOut/ trunk/OpenMPT/plugins/MidiInOut/MidiInOut.cpp trunk/OpenMPT/plugins/MidiInOut/MidiInOut.h trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj.filters trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.cpp trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.h trunk/OpenMPT/plugins/bin/ trunk/OpenMPT/plugins/common/ trunk/OpenMPT/plugins/common/ComboBox.h trunk/OpenMPT/plugins/common/Label.h trunk/OpenMPT/plugins/common/Window.h Removed Paths: ------------- trunk/OpenMPT/include/bladedll.h trunk/OpenMPT/installer/VST2MID.iss trunk/OpenMPT/mptrack/MAKEHELP.BAT trunk/OpenMPT/mptrack/MPTRACK.REG trunk/OpenMPT/mptrack/MPTRACK.sln trunk/OpenMPT/mptrack/mptrack.vcproj Property changes on: trunk/OpenMPT/include/ASIOSDK2 ___________________________________________________________________ Added: tsvn:logminsize + 10 Deleted: trunk/OpenMPT/include/bladedll.h =================================================================== --- trunk/OpenMPT/include/bladedll.h 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/include/bladedll.h 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,145 +0,0 @@ -/* - - bladedll.h - - +++++++++++++++++++++++++++ - + Blade's Encoder DLL + - +++++++++++++++++++++++++++ - - ------------------------------------------------------ - - Version 1.00 (7 November 1998) - Jukka Poikolainen - - ------------------------------------------------------ - - Initial version - - ------------------------------------------------------ - - Version x.xx (x xxxxxxxx xxxx) - xxxxx xxxxxxxxxxx - - ------------------------------------------------------ - -*/ - -#ifndef ___BLADEDLL_H_INCLUDED___ - -#define ___BLADEDLL_H_INCLUDED___ - -#pragma pack(push) -#pragma pack(1) - -/* encoding formats */ - -#define BE_CONFIG_MP3 0 - -/* type definitions */ - -typedef unsigned long HBE_STREAM; -typedef HBE_STREAM *PHBE_STREAM; -typedef unsigned long BE_ERR; - -/* error codes */ - -#define BE_ERR_SUCCESSFUL 0x00000000 -#define BE_ERR_INVALID_FORMAT 0x00000001 -#define BE_ERR_INVALID_FORMAT_PARAMETERS 0x00000002 -#define BE_ERR_NO_MORE_HANDLES 0x00000003 -#define BE_ERR_INVALID_HANDLE 0x00000004 - -/* other constants */ - -#define BE_MAX_HOMEPAGE 256 - -/* format specific variables */ - -#define BE_MP3_MODE_STEREO 0 -#define BE_MP3_MODE_DUALCHANNEL 2 -#define BE_MP3_MODE_MONO 3 - -typedef struct { - - DWORD dwConfig; // BE_CONFIG_XXXXX - // Currently only BE_CONFIG_MP3 is supported - union { - - struct { - - DWORD dwSampleRate; // 48000, 44100 and 32000 allowed - BYTE byMode; // BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO - WORD wBitrate; // 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320 allowed - BOOL bPrivate; - BOOL bCRC; - BOOL bCopyright; - BOOL bOriginal; - - } mp3; // BE_CONFIG_MP3 - - struct { - - DWORD dwSampleRate; - BYTE byMode; - WORD wBitrate; - BYTE byEncodingMethod; - - } aac; - - } format; - -} BE_CONFIG, *PBE_CONFIG; - -typedef struct { - - // BladeEnc DLL Version number - - BYTE byDLLMajorVersion; - BYTE byDLLMinorVersion; - - // BladeEnc Engine Version Number - - BYTE byMajorVersion; - BYTE byMinorVersion; - - // DLL Release date - - BYTE byDay; - BYTE byMonth; - WORD wYear; - - // BladeEnc Homepage URL - - CHAR zHomepage[BE_MAX_HOMEPAGE + 1]; - -} BE_VERSION, *PBE_VERSION; - -#ifndef _BLADEDLL - -typedef BE_ERR (*BEINITSTREAM) (PBE_CONFIG, PDWORD, PDWORD, PHBE_STREAM); -typedef BE_ERR (*BEENCODECHUNK) (HBE_STREAM, DWORD, PSHORT, PBYTE, PDWORD); -typedef BE_ERR (*BEDEINITSTREAM) (HBE_STREAM, PBYTE, PDWORD); -typedef BE_ERR (*BECLOSESTREAM) (HBE_STREAM); -typedef VOID (*BEVERSION) (PBE_VERSION); - -#define TEXT_BEINITSTREAM "beInitStream" -#define TEXT_BEENCODECHUNK "beEncodeChunk" -#define TEXT_BEDEINITSTREAM "beDeinitStream" -#define TEXT_BECLOSESTREAM "beCloseStream" -#define TEXT_BEVERSION "beVersion" - -/* - BE_ERR beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream); - BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples, PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput); - BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput); - BE_ERR beCloseStream(HBE_STREAM hbeStream); - VOID beVersion(PBE_VERSION pbeVersion); -*/ - -#else - -__declspec(dllexport) BE_ERR beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream); -__declspec(dllexport) BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples, PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput); -__declspec(dllexport) BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput); -__declspec(dllexport) BE_ERR beCloseStream(HBE_STREAM hbeStream); -__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion); - -#endif - -#pragma pack(pop) - -#endif Property changes on: trunk/OpenMPT/include/bladeenc ___________________________________________________________________ Added: tsvn:logminsize + 10 Copied: trunk/OpenMPT/include/bladeenc/bladedll.h (from rev 1204, trunk/OpenMPT/include/bladedll.h) =================================================================== --- trunk/OpenMPT/include/bladeenc/bladedll.h (rev 0) +++ trunk/OpenMPT/include/bladeenc/bladedll.h 2012-03-12 22:41:17 UTC (rev 1216) @@ -0,0 +1,145 @@ +/* + + bladedll.h + + +++++++++++++++++++++++++++ + + Blade's Encoder DLL + + +++++++++++++++++++++++++++ + + ------------------------------------------------------ + - Version 1.00 (7 November 1998) - Jukka Poikolainen - + ------------------------------------------------------ + + Initial version + + ------------------------------------------------------ + - Version x.xx (x xxxxxxxx xxxx) - xxxxx xxxxxxxxxxx - + ------------------------------------------------------ + +*/ + +#ifndef ___BLADEDLL_H_INCLUDED___ + +#define ___BLADEDLL_H_INCLUDED___ + +#pragma pack(push) +#pragma pack(1) + +/* encoding formats */ + +#define BE_CONFIG_MP3 0 + +/* type definitions */ + +typedef unsigned long HBE_STREAM; +typedef HBE_STREAM *PHBE_STREAM; +typedef unsigned long BE_ERR; + +/* error codes */ + +#define BE_ERR_SUCCESSFUL 0x00000000 +#define BE_ERR_INVALID_FORMAT 0x00000001 +#define BE_ERR_INVALID_FORMAT_PARAMETERS 0x00000002 +#define BE_ERR_NO_MORE_HANDLES 0x00000003 +#define BE_ERR_INVALID_HANDLE 0x00000004 + +/* other constants */ + +#define BE_MAX_HOMEPAGE 256 + +/* format specific variables */ + +#define BE_MP3_MODE_STEREO 0 +#define BE_MP3_MODE_DUALCHANNEL 2 +#define BE_MP3_MODE_MONO 3 + +typedef struct { + + DWORD dwConfig; // BE_CONFIG_XXXXX + // Currently only BE_CONFIG_MP3 is supported + union { + + struct { + + DWORD dwSampleRate; // 48000, 44100 and 32000 allowed + BYTE byMode; // BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO + WORD wBitrate; // 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320 allowed + BOOL bPrivate; + BOOL bCRC; + BOOL bCopyright; + BOOL bOriginal; + + } mp3; // BE_CONFIG_MP3 + + struct { + + DWORD dwSampleRate; + BYTE byMode; + WORD wBitrate; + BYTE byEncodingMethod; + + } aac; + + } format; + +} BE_CONFIG, *PBE_CONFIG; + +typedef struct { + + // BladeEnc DLL Version number + + BYTE byDLLMajorVersion; + BYTE byDLLMinorVersion; + + // BladeEnc Engine Version Number + + BYTE byMajorVersion; + BYTE byMinorVersion; + + // DLL Release date + + BYTE byDay; + BYTE byMonth; + WORD wYear; + + // BladeEnc Homepage URL + + CHAR zHomepage[BE_MAX_HOMEPAGE + 1]; + +} BE_VERSION, *PBE_VERSION; + +#ifndef _BLADEDLL + +typedef BE_ERR (*BEINITSTREAM) (PBE_CONFIG, PDWORD, PDWORD, PHBE_STREAM); +typedef BE_ERR (*BEENCODECHUNK) (HBE_STREAM, DWORD, PSHORT, PBYTE, PDWORD); +typedef BE_ERR (*BEDEINITSTREAM) (HBE_STREAM, PBYTE, PDWORD); +typedef BE_ERR (*BECLOSESTREAM) (HBE_STREAM); +typedef VOID (*BEVERSION) (PBE_VERSION); + +#define TEXT_BEINITSTREAM "beInitStream" +#define TEXT_BEENCODECHUNK "beEncodeChunk" +#define TEXT_BEDEINITSTREAM "beDeinitStream" +#define TEXT_BECLOSESTREAM "beCloseStream" +#define TEXT_BEVERSION "beVersion" + +/* + BE_ERR beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream); + BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples, PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput); + BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput); + BE_ERR beCloseStream(HBE_STREAM hbeStream); + VOID beVersion(PBE_VERSION pbeVersion); +*/ + +#else + +__declspec(dllexport) BE_ERR beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream); +__declspec(dllexport) BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples, PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput); +__declspec(dllexport) BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput); +__declspec(dllexport) BE_ERR beCloseStream(HBE_STREAM hbeStream); +__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion); + +#endif + +#pragma pack(pop) + +#endif Property changes on: trunk/OpenMPT/include/portmidi ___________________________________________________________________ Added: tsvn:logminsize + 10 Modified: trunk/OpenMPT/include/readme.txt =================================================================== --- trunk/OpenMPT/include/readme.txt 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/include/readme.txt 2012-03-12 22:41:17 UTC (rev 1216) @@ -2,21 +2,31 @@ VST 2.4 SDK =========== -If you don't use #define NO_VST, you will need to place the following files -from Steinberg's VST 2.4 SDK in this folder: -aeffect.h -aeffectx.h -vstfxstore.h -You can find them in the "vstsdk2.4/pluginterfaces/vst2.x" folder. +If you don't use #define NO_VST, you will need to put the VST 2.4 SDK in the +"vstsdk2.4" folder. The top level directory of the SDK is already named +"vstsdk2.4", so simply move that directory in the include folder. +Please visit http://www.steinberg.net/en/company/developer.html +to download the SDK. + ASIO SDK ======== -If you don't use #define NO_ASIO, you will need to place the following files -from Steinberg's ASIO SDK in this folder: -asio.h -asiosys.h -iasiodrv.h -You can find them in the "ASIOSDK2/common" directory. +If you don't use #define NO_ASIO, you will need to put the ASIO SDK in the +"ASIOSDK2" folder. The top level directory of the SDK is already named +"ASIOSDK2", so simply move that directory in the include folder. -Please visit http://www.steinberg.net/en/company/developer.html to download -these SDKs. \ No newline at end of file +Please visit http://www.steinberg.net/en/company/developer.html +to download the SDK. + +PortMidi +======== +PortMidi is only required if you wish to compile the MIDI plugins that ship with +OpenMPT. Put the PortMidi source in the the "portmidi" folder. The top level +directory of the PortMidi code archive is already named "portmidi", so simply +move that directory in the include folder. +NOTE: The static PortMidi library has to be built before the MIDI plugins can +be built; PortMidi comes with a VisualStudio solution, though, so building the +library should be easy. + +Please visit https://sourceforge.net/projects/portmedia/files/portmidi/ +to download the SDK. \ No newline at end of file Property changes on: trunk/OpenMPT/include/vstsdk2.4 ___________________________________________________________________ Added: tsvn:logminsize + 10 Deleted: trunk/OpenMPT/installer/VST2MID.iss =================================================================== --- trunk/OpenMPT/installer/VST2MID.iss 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/installer/VST2MID.iss 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,40 +0,0 @@ -[Code] - -// Helper code for installing the VST2MID plugin. - -// Register VST2MID in OpenMPT's plugin settings -procedure RegisterVST2MID(); -var - totalNum : Integer; - i : Integer; - INIFile : String; - plugPath: String; -begin - - INIFile := GetINIPath(); - totalNum := GetIniInt('VST Plugins', 'NumPlugins', 0, 0, 0, INIFile); - - // Check if the plugin has already been registered with OpenMPT. - for i := 0 to totalNum - 1 do - begin - plugPath := GetIniString('VST Plugins', Format('Plugin%d', [i]), '', INIFile); - if CompareFilename(plugPath, 'vst2mid.dll') then - begin - // The plugin is already registered, so don't add it again. - Exit; - end; - end; - - // In portable mode, write a relative path into the config file. - if(IsTaskSelected('portable')) then - begin - plugPath := '.'; - end else - begin - plugPath := ExpandConstant('{app}'); - end; - SetIniString('VST Plugins', Format('Plugin%d', [totalNum]), plugPath + '\Plugins\VST2MID.dll', INIFile); - - SetIniInt('VST Plugins', 'NumPlugins', totalNum + 1, INIFile); - -end; Modified: trunk/OpenMPT/installer/install.iss =================================================================== --- trunk/OpenMPT/installer/install.iss 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/installer/install.iss 2012-03-12 22:41:17 UTC (rev 1216) @@ -66,8 +66,8 @@ Source: ..\mptrack\bin\unmo3.dll; DestDir: {app}; Flags: ignoreversion #endif -; VST2MID Plugin -Source: ..\packageTemplate\Plugins\VST2MID.dll; DestDir: {app}\Plugins\; Flags: ignoreversion +; Plugins +Source: ..\packageTemplate\Plugins\*.*; DestDir: {app}\Plugins\; Flags: ignoreversion recursesubdirs createallsubdirs Source: ..\packageTemplate\ExampleSongs\*.*; DestDir: {app}\ExampleSongs\; Flags: ignoreversion sortfilesbyextension @@ -139,7 +139,7 @@ #include "utilities.iss" #include "vst_scan.iss" -#include "VST2MID.iss" +#include "plugins.iss" [Code] @@ -200,7 +200,7 @@ VerifyUNMO3Checksum(); #endif - RegisterVST2MID(); + RegisterPlugin('MIDI\MIDI Input Output.dll'); // Copy old config files from app's directory, if possible and necessary. CopyConfigsToAppDataDir(); Modified: trunk/OpenMPT/installer/packageTemplate/readme.txt =================================================================== --- trunk/OpenMPT/installer/packageTemplate/readme.txt 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/installer/packageTemplate/readme.txt 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,5 +1,5 @@ ****************** -* OpenMPT 1.19 * +* OpenMPT 1.20 * ****************** @@ -7,7 +7,7 @@ --------------------------- Unless you install OpenMPT in portable mode, all settings are now stored in -%appdata%\OpenMPT. The installer will automatically try to move all settings +%APPDATA%\OpenMPT. The installer will automatically try to move all settings to the new folder - Migration is done automatically. @@ -39,6 +39,8 @@ Impulse Tracker) and country-specific layouts. SoundTouch (folder): SoundTouch readme and license ReleaseNotesImages (folder): Files used in the release notes document. +Plugins (folder): Contains standard audio and MIDI processing plugins that ship + with OpenMPT. ExampleSongs (folder): A set of module files which should give an impression of what can be done in OpenMPT with only a few kilobytes. History.txt: Version history. @@ -54,7 +56,7 @@ OpenMPT is partially under the following license: -> Copyright (c) 2004-2011, OpenMPT contributors +> Copyright (c) 2004-2012, OpenMPT contributors > Copyright (c) 1997-2003, Olivier Lapicque > All rights reserved. > @@ -86,6 +88,10 @@ For more information about SoundTouch, see folder SoundTouch. +OpenMPT's MIDI plugins make use of the PortMidi library, which is released under +the MIT license. +Visit https://sourceforge.net/projects/portmedia/ for more information. + unmo3.dll --------- Copyright (c) 2001-2011 Ian Luck. All rights reserved Copied: trunk/OpenMPT/installer/plugins.iss (from rev 1204, trunk/OpenMPT/installer/VST2MID.iss) =================================================================== --- trunk/OpenMPT/installer/plugins.iss (rev 0) +++ trunk/OpenMPT/installer/plugins.iss 2012-03-12 22:41:17 UTC (rev 1216) @@ -0,0 +1,40 @@ +[Code] + +// Helper code for installing the plugins that are shipped with OpenMPT. + +// Register plugins in OpenMPT's plugin settings +procedure RegisterPlugin(plugName : String); +var + totalNum : Integer; + i : Integer; + INIFile : String; + plugPath: String; +begin + + INIFile := GetINIPath(); + totalNum := GetIniInt('VST Plugins', 'NumPlugins', 0, 0, 0, INIFile); + + // Check if the plugin has already been registered with OpenMPT. + for i := 0 to totalNum - 1 do + begin + plugPath := GetIniString('VST Plugins', Format('Plugin%d', [i]), '', INIFile); + if(CompareFilename(plugPath, plugName)) then + begin + // The plugin is already registered, so don't add it again. + Exit; + end; + end; + + // In portable mode, write a relative path into the config file. + if(IsTaskSelected('portable')) then + begin + plugPath := '.'; + end else + begin + plugPath := ExpandConstant('{app}'); + end; + SetIniString('VST Plugins', Format('Plugin%d', [totalNum]), plugPath + '\Plugins\' + plugName, INIFile); + + SetIniInt('VST Plugins', 'NumPlugins', totalNum + 1, INIFile); + +end; Modified: trunk/OpenMPT/mptrack/ACMConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ACMConvert.cpp 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/ACMConvert.cpp 2012-03-12 22:41:17 UTC (rev 1216) @@ -10,7 +10,7 @@ #include "stdafx.h" -#include "bladedll.h" +#include <bladeenc/bladedll.h> #include "Mptrack.h" #include "ACMConvert.h" Deleted: trunk/OpenMPT/mptrack/MAKEHELP.BAT =================================================================== --- trunk/OpenMPT/mptrack/MAKEHELP.BAT 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/MAKEHELP.BAT 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,50 +0,0 @@ -@echo off -REM -- First make map file from Microsoft Visual C++ generated resource.h -echo // MAKEHELP.BAT generated Help Map file. Used by MPTRACK.HPJ. >"hlp\mptrack.hm" -echo. >>"hlp\mptrack.hm" -echo // Commands (ID_* and IDM_*) >>"hlp\mptrack.hm" -makehm ID_,HID_,0x10000 IDM_,HIDM_,0x10000 resource.h >>"hlp\mptrack.hm" -makehm IDC_,HIDC_,0x10000 resource.h >>"hlp\mptrack.hm" -echo. >>"hlp\mptrack.hm" -echo // Prompts (IDP_*) >>"hlp\mptrack.hm" -makehm IDP_,HIDP_,0x30000 resource.h >>"hlp\mptrack.hm" -echo. >>"hlp\mptrack.hm" -echo // Resources (IDR_*) >>"hlp\mptrack.hm" -makehm IDR_,HIDR_,0x20000 resource.h >>"hlp\mptrack.hm" -echo. >>"hlp\mptrack.hm" -echo // Dialogs (IDD_*) >>"hlp\mptrack.hm" -makehm IDD_,HIDD_,0x20000 resource.h >>"hlp\mptrack.hm" -echo. >>"hlp\mptrack.hm" -echo // Frame Controls (IDW_*) >>"hlp\mptrack.hm" -makehm IDW_,HIDW_,0x50000 resource.h >>"hlp\mptrack.hm" -REM -- Make help for Project MPTRACK - - -echo Converting HTML to RTF -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\index.rtf html\index.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\file.rtf html\file.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\player.rtf html\player.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\edit.rtf html\edit.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\view.rtf html\view.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\window.rtf html\window.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\help.rtf html\help.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\faq.rtf html\faq.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\formats.rtf html\formats.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\keyboard.rtf html\keyboard.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\mainbar.rtf html\mainbar.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\patterns.rtf html\patterns.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\samples.rtf html\samples.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\instrums.rtf html\instrums.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\intro.rtf html\intro.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\setup.rtf html\setup.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\effects.rtf html\effects.htm -html2rtf -pc:\temp\tmp.$$$ -dhlp\sizes.def -rhlp\starting.rtf html\starting.htm -if exist c:\temp\tmp.$$$ del c:\temp\tmp.$$$ - -echo Building Win32 Help files -start /wait hcrtf -x "hlp\mptrack.hpj" -echo. -if exist bin\nul copy "hlp\mptrack.hlp" bin\mptrack.hlp -if exist bin\nul copy "hlp\mptrack.cnt" bin\mptrack.cnt -echo. - Deleted: trunk/OpenMPT/mptrack/MPTRACK.REG =================================================================== --- trunk/OpenMPT/mptrack/MPTRACK.REG 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/MPTRACK.REG 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,14 +0,0 @@ -REGEDIT -; This .REG file may be used by your SETUP program. -; If a SETUP program is not available, the entries below will be -; registered in your InitInstance automatically with a call to -; CWinApp::RegisterShellFileTypes and COleObjectFactory::UpdateRegistryAll. - -HKEY_CLASSES_ROOT\.mod = ModplugTracker.Document -HKEY_CLASSES_ROOT\ModplugTracker.Document\shell\open\command = MPTRACK.EXE %1 -HKEY_CLASSES_ROOT\ModplugTracker.Document\shell\open\ddeexec = [open("%1")] -HKEY_CLASSES_ROOT\ModplugTracker.Document\shell\open\ddeexec\application = MPTRACK - ; note: the application is optional - ; (it defaults to the app name in "command") - -HKEY_CLASSES_ROOT\ModplugTracker.Document = Music Module Deleted: trunk/OpenMPT/mptrack/MPTRACK.sln =================================================================== --- trunk/OpenMPT/mptrack/MPTRACK.sln 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/MPTRACK.sln 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,120 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mptrack", "mptrack.vcproj", "{DB18719C-9177-4632-A9E0-7E72E2E6B05E}" - ProjectSection(ProjectDependencies) = postProject - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4} = {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4} - {3F7D3110-B3DD-4DE1-B608-C3F491009625} = {3F7D3110-B3DD-4DE1-B608-C3F491009625} - {71531076-78C7-488D-8FD6-9D841F20AADE} = {71531076-78C7-488D-8FD6-9D841F20AADE} - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896} = {CF3C2CA5-5D45-4635-BBA4-C1F435E10896} - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7} = {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7} - {20BF96C8-0202-4251-80C9-6C62BE845DAE} = {20BF96C8-0202-4251-80C9-6C62BE845DAE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unlha", "..\unlha\unlha.vcproj", "{71531076-78C7-488D-8FD6-9D841F20AADE}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unrar", "..\UNRAR\UNRAR.vcproj", "{3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unzip", "..\UNZIP\unzip.vcproj", "{1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xsoundlib", "..\xsoundlib\xsoundlib.vcproj", "{DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\soundtouch\soundtouch.vcproj", "{CF3C2CA5-5D45-4635-BBA4-C1F435E10896}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "..\zlib\contrib\vstudio\vc7\zlibstat.vcproj", "{3F7D3110-B3DD-4DE1-B608-C3F491009625}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ungzip", "..\ungzip\ungzip.vcproj", "{20BF96C8-0202-4251-80C9-6C62BE845DAE}" - ProjectSection(ProjectDependencies) = postProject - {3F7D3110-B3DD-4DE1-B608-C3F491009625} = {3F7D3110-B3DD-4DE1-B608-C3F491009625} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - ReleaseAxp = ReleaseAxp - ReleaseWithoutAsm = ReleaseWithoutAsm - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.Debug.ActiveCfg = Debug|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.Debug.Build.0 = Debug|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.Release.ActiveCfg = Release|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.Release.Build.0 = Release|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.ReleaseAxp.ActiveCfg = Release|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.ReleaseAxp.Build.0 = Release|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {DB18719C-9177-4632-A9E0-7E72E2E6B05E}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.Debug.ActiveCfg = Debug|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.Debug.Build.0 = Debug|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.Release.ActiveCfg = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.Release.Build.0 = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.ReleaseAxp.ActiveCfg = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.ReleaseAxp.Build.0 = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {71531076-78C7-488D-8FD6-9D841F20AADE}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.Debug.ActiveCfg = Debug|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.Debug.Build.0 = Debug|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.Release.ActiveCfg = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.Release.Build.0 = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.ReleaseAxp.ActiveCfg = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.ReleaseAxp.Build.0 = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {3C7281B0-D0E2-48ED-AE4D-A181FC77D8F7}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.Debug.ActiveCfg = Debug|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.Debug.Build.0 = Debug|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.Release.ActiveCfg = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.Release.Build.0 = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.ReleaseAxp.ActiveCfg = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.ReleaseAxp.Build.0 = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {1FF4AB04-B22F-4CB8-AA2A-0C5095B5FEE4}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.Debug.ActiveCfg = Debug|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.Debug.Build.0 = Debug|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.Release.ActiveCfg = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.Release.Build.0 = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.ReleaseAxp.ActiveCfg = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.ReleaseAxp.Build.0 = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {DCC2BB2F-6778-4FD3-9C00-D6CD8DC917B8}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.Debug.ActiveCfg = Debug|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.Debug.Build.0 = Debug|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.Release.ActiveCfg = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.Release.Build.0 = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.ReleaseAxp.ActiveCfg = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.ReleaseAxp.Build.0 = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {CF3C2CA5-5D45-4635-BBA4-C1F435E10896}.ReleaseWithoutAsm.Build.0 = Release|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.Debug.ActiveCfg = Debug|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.Debug.Build.0 = Debug|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.Release.ActiveCfg = ReleaseWithoutAsm|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.Release.Build.0 = ReleaseWithoutAsm|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.ReleaseAxp.ActiveCfg = ReleaseAxp|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.ReleaseAxp.Build.0 = ReleaseAxp|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.ReleaseWithoutAsm.ActiveCfg = ReleaseWithoutAsm|Win32 - {3F7D3110-B3DD-4DE1-B608-C3F491009625}.ReleaseWithoutAsm.Build.0 = ReleaseWithoutAsm|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.Debug.ActiveCfg = Debug|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.Debug.Build.0 = Debug|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.Release.ActiveCfg = Release|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.Release.Build.0 = Release|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.ReleaseAxp.ActiveCfg = Release|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.ReleaseAxp.Build.0 = Release|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.ReleaseWithoutAsm.ActiveCfg = Release|Win32 - {20BF96C8-0202-4251-80C9-6C62BE845DAE}.ReleaseWithoutAsm.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-03-12 22:41:17 UTC (rev 1216) @@ -12,8 +12,8 @@ #ifndef NO_VST #define VST_FORCE_DEPRECATED 0 - #include <aeffectx.h> // VST - #include <vstfxstore.h> + #include <pluginterfaces/vst2.x/aeffectx.h> // VST + #include <pluginterfaces/vst2.x/vstfxstore.h> #endif #include "../soundlib/Snd_defs.h" Deleted: trunk/OpenMPT/mptrack/mptrack.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack.vcproj 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/mptrack.vcproj 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,1098 +0,0 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="7.10" - Name="mptrack" - RootNamespace="mptrack" - SccProjectName="" - SccLocalPath="" - Keyword="MFCProj"> - <Platforms> - <Platform - Name="Win32"/> - </Platforms> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory=".\Debug" - IntermediateDirectory=".\Debug" - ConfigurationType="1" - UseOfMFC="2" - ATLMinimizesCRunTimeLibraryUsage="FALSE"> - <Tool - Name="VCCLCompilerTool" - AdditionalOptions="/EHsc" - Optimization="0" - OptimizeForProcessor="1" - AdditionalIncludeDirectories="..\unlha,..\unzip,..\unrar,..\soundlib,..\include,..\xsoundlib,..\" - PreprocessorDefinitions="_DEBUG,WIN32,_WINDOWS,ENABLE_EQ,MODPLUG_TRACKER,NO_PACKING,HAVE_DOT_NET,ENABLE_AMD,ENABLE_SSE,ENABLE_AMDNOW,ENABLE_MMX" - StringPooling="TRUE" - BasicRuntimeChecks="3" - RuntimeLibrary="3" - BufferSecurityCheck="TRUE" - EnableFunctionLevelLinking="TRUE" - ForceConformanceInForLoopScope="TRUE" - UsePrecompiledHeader="3" - PrecompiledHeaderThrough="stdafx.h" - PrecompiledHeaderFile=".\Debug/mptrack.pch" - AssemblerListingLocation=".\Debug/" - ObjectFile=".\Debug/" - ProgramDataBaseFileName=".\Debug/" - BrowseInformation="1" - WarningLevel="4" - SuppressStartupBanner="FALSE" - DebugInformationFormat="4" - CompileAs="0"/> - <Tool - Name="VCCustomBuildTool"/> - <Tool - Name="VCLinkerTool" - AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="winmm.lib strmiids.lib dmoguids.lib version.lib Rpcrt4.lib delayimp.lib wininet.lib" - OutputFile=".\Debug/mptrack.exe" - Version="5.0" - LinkIncremental="2" - SuppressStartupBanner="TRUE" - AdditionalLibraryDirectories="" - DelayLoadDLLs="OpenMPT_SoundTouch_i16.dll" - GenerateDebugInformation="TRUE" - AssemblyDebug="1" - ProgramDatabaseFile=".\Debug/mptrack.pdb" - GenerateMapFile="TRUE" - MapFileName=".\Debug/mptrack.map" - SubSystem="2"/> - <Tool - Name="VCMIDLTool" - PreprocessorDefinitions="_DEBUG" - MkTypLibCompatible="TRUE" - SuppressStartupBanner="TRUE" - TargetEnvironment="1" - TypeLibraryName=".\Debug/mptrack.tlb"/> - <Tool - Name="VCPostBuildEventTool"/> - <Tool - Name="VCPreBuildEventTool"/> - <Tool - Name="VCPreLinkEventTool"/> - <Tool - Name="VCResourceCompilerTool" - PreprocessorDefinitions="_DEBUG" - Culture="1033"/> - <Tool - Name="VCWebServiceProxyGeneratorTool"/> - <Tool - Name="VCXMLDataGeneratorTool"/> - <Tool - Name="VCWebDeploymentTool"/> - <Tool - Name="VCManagedWrapperGeneratorTool"/> - <Tool - Name="VCAuxiliaryManagedWrapperGeneratorTool"/> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" - ConfigurationType="1" - UseOfMFC="1" - ATLMinimizesCRunTimeLibraryUsage="FALSE" - WholeProgramOptimization="TRUE"> - <Tool - Name="VCCLCompilerTool" - AdditionalOptions="/EHsc /O2" - Optimization="2" - GlobalOptimizations="TRUE" - InlineFunctionExpansion="2" - OptimizeForWindowsApplication="TRUE" - AdditionalIncludeDirectories="..\unlha,..\unzip,..\unrar,..\soundlib,..\include,..\xsoundlib,..\" - PreprocessorDefinitions="NDEBUG,WIN32,_WINDOWS,ENABLE_MMX,ENABLE_EQ,MODPLUG_TRACKER,NO_PACKING,HAVE_DOT_NET,ENABLE_AMD,ENABLE_SSE,ENABLE_AMDNOW" - StringPooling="TRUE" - RuntimeLibrary="0" - BufferSecurityCheck="TRUE" - EnableFunctionLevelLinking="FALSE" - ForceConformanceInForLoopScope="TRUE" - UsePrecompiledHeader="3" - PrecompiledHeaderThrough="stdafx.h" - PrecompiledHeaderFile=".\Release/mptrack.pch" - AssemblerListingLocation=".\Release/" - ObjectFile=".\Release/" - ProgramDataBaseFileName=".\Release/" - WarningLevel="3" - SuppressStartupBanner="FALSE" - DebugInformationFormat="3" - CompileAs="0"/> - <Tool - Name="VCCustomBuildTool"/> - <Tool - Name="VCLinkerTool" - AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="winmm.lib strmiids.lib dmoguids.lib version.lib Rpcrt4.lib delayimp.lib wininet.lib" - OutputFile=".\Bin/mptrack.exe" - Version="5.0" - LinkIncremental="1" - SuppressStartupBanner="TRUE" - AdditionalLibraryDirectories="" - DelayLoadDLLs="OpenMPT_SoundTouch_i16.dll" - GenerateDebugInformation="TRUE" - GenerateMapFile="FALSE" - MapFileName=".\Release/mptrack.map" - SubSystem="2" - OptimizeReferences="2" - EnableCOMDATFolding="2"/> - <Tool - Name="VCMIDLTool" - PreprocessorDefinitions="NDEBUG" - MkTypLibCompatible="TRUE" - SuppressStartupBanner="TRUE" - TargetEnvironment="1" - TypeLibraryName=".\Bin/mptrack.tlb"/> - <Tool - Name="VCPostBuildEventTool"/> - <Tool - Name="VCPreBuildEventTool"/> - <Tool - Name="VCPreLinkEventTool"/> - <Tool - Name="VCResourceCompilerTool" - PreprocessorDefinitions="NDEBUG" - Culture="1033"/> - <Tool - Name="VCWebServiceProxyGeneratorTool"/> - <Tool - Name="VCXMLDataGeneratorTool"/> - <Tool - Name="VCWebDeploymentTool"/> - <Tool - Name="VCManagedWrapperGeneratorTool"/> - <Tool - Name="VCAuxiliaryManagedWrapperGeneratorTool"/> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Source Files" - Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"> - <File - RelativePath=".\AbstractVstEditor.cpp"> - </File> - <File - RelativePath=".\ACMConvert.cpp"> - </File> - <File - RelativePath=".\ArrayUtils.cpp"> - </File> - <File - RelativePath=".\AutoSaver.cpp"> - </File> - <File - RelativePath=".\Autotune.cpp"> - </File> - <File - RelativePath=".\ChannelManagerDlg.cpp"> - </File> - <File - RelativePath=".\ChildFrm.cpp"> - </File> - <File - RelativePath=".\CleanupSong.cpp"> - </File> - <File - RelativePath=".\CloseMainDialog.cpp"> - </File> - <File - RelativePath=".\ColourEdit.cpp"> - </File> - <File - RelativePath=".\CommandSet.cpp"> - </File> - <File - RelativePath=".\CreditStatic.cpp"> - </File> - <File - RelativePath=".\ctrl_com.cpp"> - </File> - <File - RelativePath=".\ctrl_gen.cpp"> - </File> - <File - RelativePath=".\ctrl_ins.cpp"> - </File> - <File - RelativePath=".\ctrl_pat.cpp"> - </File> - <File - RelativePath=".\ctrl_seq.cpp"> - </File> - <File - RelativePath=".\ctrl_smp.cpp"> - </File> - <File - RelativePath=".\DefaultVstEditor.cpp"> - </File> - <File - RelativePath=".\dlg_misc.cpp"> - </File> - <File - RelativePath="..\soundlib\dlsbank.cpp"> - </File> - <File - RelativePath=".\draw_pat.cpp"> - </File> - <File - RelativePath=".\EffectInfo.cpp"> - </File> - <File - RelativePath=".\EffectVis.cpp"> - </File> - <File - RelativePath=".\ExceptionHandler.cpp"> - </File> - <File - RelativePath="..\soundlib\Fastmix.cpp"> - </File> - <File - RelativePath=".\fxp.cpp"> - </File> - <File - RelativePath=".\globals.cpp"> - </File> - <File - RelativePath=".\HyperEdit.cpp"> - </File> - <File - RelativePath=".\HyperEdit2.cpp"> - </File> - <File - RelativePath=".\HyperEdit3.cpp"> - </File> - <File - RelativePath="InputHandler.cpp"> - </File> - <File - RelativePath=".\KeyConfigDlg.cpp"> - </File> - <File - RelativePath=".\mainbar.cpp"> - </File> - <File - RelativePath=".\MainFrm.cpp"> - </File> - <File - RelativePath="..\soundlib\Message.cpp"> - </File> - <File - RelativePath=".\MIDIMacroDialog.cpp"> - </File> - <File - RelativePath=".\soundlib\MIDIMacros.cpp"> - </File> - <File - RelativePath=".\MIDIMappingDialog.cpp"> - </File> - <File - RelativePath="..\common\misc_util.cpp"> - </File> - <File - RelativePath="..\soundlib\mmcmp.cpp"> - </File> - <File - RelativePath="..\soundlib\Mmx_mix.cpp"> - </File> - <File - RelativePath=".\mod2midi.cpp"> - </File> - <File - RelativePath=".\Mod2wave.cpp"> - </File> - <File - RelativePath="..\soundlib\mod_specifications.cpp"> - </File> - <File - RelativePath="..\soundlib\ModChannel.cpp"> - </File> - <File - RelativePath="..\soundlib\modcommand.cpp"> - </File> - <File - RelativePath="..\soundlib\ModInstrument.cpp"> - </File> - <File - RelativePath="..\soundlib\ModSample.cpp"> - </File> - <File - RelativePath=".\ModConvert.cpp"> - </File> - <File - RelativePath=".\Moddoc.cpp"> - </File> - <File - RelativePath=".\Modedit.cpp"> - </File> - <File - RelativePath="..\soundlib\ModSequence.cpp"> - </File> - <File - RelativePath="..\soundlib\modsmp_ctrl.cpp"> - </File> - <File - RelativePath=".\Moptions.cpp"> - </File> - <File - RelativePath=".\MoveFXSlotDialog.cpp"> - </File> - <File - RelativePath=".\Mpdlgs.cpp"> - </File> - <File - RelativePath=".\mpt_midi.cpp"> - </File> - <File - RelativePath=".\MPTHacks.cpp"> - </File> - <File - RelativePath=".\mptrack.cpp"> - </File> - <File - RelativePath=".\mptrack.rc"> - </File> - <File - RelativePath="..\soundlib\pattern.cpp"> - </File> - <File - RelativePath=".\PatternClipboard.cpp"> - </File> - <File - RelativePath="..\soundlib\patternContainer.cpp"> - </File> - <File - RelativePath=".\PatternEditorDialogs.cpp"> - </File> - <File - RelativePath=".\PatternGotoDialog.cpp"> - </File> - <File - RelativePath="..\soundlib\PlaybackEventer.cpp"> - </File> - <File - RelativePath=".\PSRatioCalc.cpp"> - </File> - <File - RelativePath="..\common\Reporting.cpp"> - </File> - <File - RelativePath="..\soundlib\RowVisitor.cpp"> - </File> - <File - RelativePath=".\SampleEditorDialogs.cpp"> - </File> - <File - RelativePath="..\soundlib\Sampleio.cpp"> - </File> - <File - RelativePath=".\ScaleEnvPointsDlg.cpp"> - </File> - <File - RelativePath=".\SelectPluginDialog.cpp"> - </File> - <File - RelativePath=".\serialization_utils.cpp"> - </File> - <File - RelativePath="..\soundlib\snd_dsp.cpp"> - </File> - <File - RelativePath="..\soundlib\snd_eq.cpp"> - </File> - <File - RelativePath="..\soundlib\snd_flt.cpp"> - </File> - <File - RelativePath="..\soundlib\Snd_fx.cpp"> - </File> - <File - RelativePath="..\Soundlib\Snd_rvb.cpp"> - <FileConfiguration - Name="Release|Win32"> - <Tool - Name="VCCLCompilerTool" - AssemblerOutput="4"/> - </FileConfiguration> - </File> - <File - RelativePath="..\Soundlib\snddev.cpp"> - </File> - <File - RelativePath="..\soundlib\Sndfile.cpp"> - </File> - <File - RelativePath="..\soundlib\Sndmix.cpp"> - </File> - <File - RelativePath=".\SoundFilePlayConfig.cpp"> - </File> - <File - RelativePath=".\StdAfx.cpp"> - <FileConfiguration - Name="Debug|Win32"> - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1"/> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32"> - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1"/> - </FileConfiguration> - </File> - <File - RelativePath="..\soundlib\Tables.cpp"> - </File> - <File - RelativePath=".\tagging.cpp"> - </File> - <File - RelativePath=".\TrackerSettings.cpp"> - </File> - <File - RelativePath=".\Undo.cpp"> - </File> - <File - RelativePath=".\UpdateCheck.cpp"> - </File> - <File - RelativePath=".\view_com.cpp"> - </File> - <File - RelativePath=".\view_gen.cpp"> - </File> - <File - RelativePath=".\view_ins.cpp"> - </File> - <File - RelativePath=".\view_pat.cpp"> - </File> - <File - RelativePath=".\view_smp.cpp"> - </File> - <File - RelativePath=".\view_tre.cpp"> - </File> - <File - RelativePath=".\VSTEditor.cpp"> - </File> - <File - RelativePath=".\vstplug.cpp"> - </File> - <File - RelativePath="..\soundlib\Waveform.cpp"> - </File> - <File - RelativePath="..\soundlib\WindowedFIR.cpp"> - </File> - <Filter - Name="PatternRandomizer" - Filter=""> - <File - RelativePath=".\PatternRandomizer.cpp"> - </File> - <File - RelativePath=".\PatternRandomizer.h"> - </File> - <File - RelativePath=".\PatternRandomizerGUI.cpp"> - </File> - <File - RelativePath=".\PatternRandomizerGUI.h"> - </File> - <File - RelativePath=".\PatternRandomizerGUIEffect.cpp"> - </File> - <File - RelativePath=".\PatternRandomizerGUIEffect.h"> - </File> - <File - RelativePath=".\PatternRandomizerGUIInstrument.cpp"> - </File> - <File - RelativePath=".\PatternRandomizerGUIInstrument.h"> - </File> - <File - RelativePath=".\PatternRandomizerGUINote.cpp"> - </File> - <File - RelativePath=".\PatternRandomizerGUINote.h"> - </File> - <File - RelativePath=".\PatternRandomizerGUIVolCmd.cpp"> - </File> - <File - RelativePath=".\PatternRandomizerGUIVolCmd.h"> - </File> - </Filter> - <Filter - Name="MixGraph" - Filter=""> - <File - RelativePath=".\ChannelNode.cpp"> - </File> - <File - RelativePath=".\ChannelNode.h"> - </File> - <File - RelativePath=".\ctrl_graph.cpp"> - </File> - <File - RelativePath=".\ctrl_graph.h"> - </File> - <File - RelativePath=".\EffectNode.cpp"> - </File> - <File - RelativePath=".\EffectNode.h"> - </File> - <File - RelativePath=".\FinalNode.cpp"> - </File> - <File - RelativePath=".\FinalNode.h"> - </File> - <File - RelativePath=".\Graph.cpp"> - </File> - <File - RelativePath=".\Graph.h"> - </File> - <File - RelativePath=".\InstrumentNode.cpp"> - </File> - <File - RelativePath=".\InstrumentNode.h"> - </File> - <File - RelativePath=".\Node.cpp"> - </File> - <File - RelativePath=".\Node.h"> - </File> - <File - RelativePath=".\Vertex.cpp"> - </File> - <File - RelativePath=".\Vertex.h"> - </File> - <File - RelativePath=".\view_graph.cpp"> - </File> - <File - RelativePath=".\view_graph.h"> - </File> - </Filter> - <Filter - Name="Tuning" - Filter=""> - <File - RelativePath="..\soundlib\tuning.cpp"> - </File> - <File - RelativePath="..\soundlib\tuningbase.cpp"> - </File> - <File - RelativePath="..\soundlib\tuningCollection.cpp"> - </File> - <File - RelativePath=".\TuningDialog.cpp"> - </File> - <File - RelativePath=".\tuningRatioMapWnd.cpp"> - </File> - </Filter> - </Filter> - <Filter - Name="Resource Files" - Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"> - <File - RelativePath="res\bitmap1.bmp"> - </File> - <File - RelativePath=".\res\built-inTunings.tc"> - </File> - <File - RelativePath=".\res\colors.bmp"> - </File> - <File - RelativePath=".\res\defaultKeyBindings.mkb"> - </File> - <File - RelativePath=".\res\dragging.cur"> - </File> - <File - RelativePath=".\Res\envbar.bmp"> - </File> - <File - RelativePath=".\res\img_list.bmp"> - </File> - <File - RelativePath=".\res\mainbar.bmp"> - </File> - <File - RelativePath=".\res\moddoc.ico"> - </File> - <File - RelativePath=".\res\MPTRACK.bmp"> - </File> - <File - RelativePath=".\res\mptrack.ico"> - </File> - <File - RelativePath=".\res\mptrack.rc2"> - </File> - <File - RelativePath=".\Res\nodrag.cur"> - </File> - <File - RelativePath=".\res\nodrop.cur"> - </File> - <File - RelativePath=".\res\patterns.bmp"> - </File> - <File - RelativePath=".\res\rt_manif.bin"> - </File> - <File - RelativePath=".\Res\smptoolb.bmp"> - </File> - <File - RelativePath=".\res\splashno.bmp"> - </File> - <File - RelativePath=".\res\view_pat.bmp"> - </File> - <File - RelativePath=".\res\vispcnode.bmp"> - </File> - <File - RelativePath=".\res\vumeters.bmp"> - </File> - </Filter> - <Filter - Name="Header Files" - Filter="h;hpp;hxx;hm;inl"> - <File - RelativePath=".\AbstractVstEditor.h"> - </File> - <File - RelativePath=".\ACMConvert.h"> - </File> - <File - RelativePath=".\ArrayUtils.h"> - </File> - <File - RelativePath=".\AutoSaver.h"> - </File> - <File - RelativePath=".\Autotune.h"> - </File> - <File - RelativePath=".\ChannelManagerDlg.h"> - </File> - <File - RelativePath=".\ChildFrm.h"> - </File> - <File - RelativePath=".\CleanupSong.h"> - </File> - <File - RelativePath=".\CloseMainDialog.h"> - </File> - <File - RelativePath=".\ColourEdit.h"> - </File> - <File - RelativePath=".\CommandSet.h"> - </File> - <File - RelativePath=".\CreditStatic.h"> - </File> - <File - RelativePath=".\ctrl_com.h"> - </File> - <File - RelativePath=".\ctrl_gen.h"> - </File> - <File - RelativePath=".\ctrl_ins.h"> - </File> - <File - RelativePath=".\ctrl_pat.h"> - </File> - <File - RelativePath=".\ctrl_smp.h"> - </File> - <File - RelativePath=".\DefaultVstEditor.h"> - </File> - <File - RelativePath=".\dlg_misc.h"> - </File> - <File - RelativePath="..\Soundlib\Dlsbank.h"> - </File> - <File - RelativePath=".\EffectInfo.h"> - </File> - <File - RelativePath=".\EffectVis.h"> - </File> - <File - RelativePath="..\soundlib\Endianness.h"> - </File> - <File - RelativePath=".\ExceptionHandler.h"> - </File> - <File - RelativePath=".\fxp.h"> - </File> - <File - RelativePath=".\globals.h"> - </File> - <File - RelativePath="InputHandler.h"> - </File> - <File - RelativePath=".\KeyConfigDlg.h"> - </File> - <File - RelativePath=".\mainbar.h"> - </File> - <File - RelativePath=".\MainFrm.h"> - </File> - <File - RelativePath="..\soundlib\midi.h"> - </File> - <File - RelativePath=".\MIDIMacroDialog.h"> - </File> - <File - RelativePath=".\soundlib\MIDIMacros.h"> - </File> - <File - RelativePath=".\MIDIMappingDialog.h"> - </File> - <File - RelativePath="..\common\misc_util.h"> - </File> - <File - RelativePath=".\mod2midi.h"> - </File> - <File - RelativePath=".\mod2wave.h"> - </File> - <File - RelativePath="..\soundlib\mod_specifications.h"> - </File> - <File - RelativePath="..\soundlib\ModChannel.h"> - </File> - <File - RelativePath="..\soundlib\modcommand.h"> - </File> - <File - RelativePath="..\soundlib\ModInstrument.h"> - </File> - <File - RelativePath="..\soundlib\ModSample.h"> - </File> - <File - RelativePath=".\ModConvert.h"> - </File> - <File - RelativePath=".\moddoc.h"> - </File> - <File - RelativePath="..\soundlib\ModSequence.h"> - </File> - <File - RelativePath="..\soundlib\modsmp_ctrl.h"> - </File> - <File - RelativePath=".\Moptions.h"> - </File> - <File - RelativePath=".\MoveFXSlotDialog.h"> - </File> - <File - RelativePath=".\Mpdlgs.h"> - </File> - <File - RelativePath=".\mptrack.h"> - </File> - <File - RelativePath="..\soundlib\pattern.h"> - </File> - <File - RelativePath=".\PatternClipboard.h"> - </File> - <File - RelativePath="..\soundlib\patternContainer.h"> - </File> - <File - RelativePath=".\PatternCursor.h"> - </File> - <File - RelativePath=".\PatternEditorDialogs.h"> - </File> - <File - RelativePath=".\PatternGotoDialog.h"> - </File> - <File - RelativePath="..\soundlib\PlaybackEventer.h"> - </File> - <File - RelativePath=".\PSRatioCalc.h"> - </File> - <File - RelativePath=".\soundlib\PluginEventQueue.h"> - </File> - <File - RelativePath=".\soundlib\PluginMixBuffer.h"> - </File> - <File - RelativePath=".\soundlib\PlugInterface.h"> - </File> - <File - RelativePath=".\soundlib\RowVisitor.h"> - </File> - <File - RelativePath="..\common\Reporting.h"> - </File> - <File - RelativePath=".\Resource.h"> - </File> - <File - RelativePath=".\SampleEditorDialogs.h"> - </File> - <File - RelativePath=".\ScaleEnvPointsDlg.h"> - </File> - <File - RelativePath=".\SelectPluginDialog.h"> - </File> - <File - RelativePath=".\serialization_utils.h"> - </File> - <File - RelativePath="..\soundlib\Snd_defs.h"> - </File> - <File - RelativePath="..\Soundlib\snddev.h"> - </File> - <File - RelativePath="..\Soundlib\snddevx.h"> - </File> - <File - RelativePath="..\Soundlib\Sndfile.h"> - </File> - <File - RelativePath=".\SoundFilePlayConfig.h"> - </File> - <File - RelativePath=".\StdAfx.h"> - </File> - <File - RelativePath="..\common\StringFixer.h"> - </File> - <File - RelativePath=".\tagging.h"> - </File> - <File - RelativePath=".\TrackerSettings.h"> - </File> - <File - RelativePath="..\common\typedefs.h"> - </File> - <File - RelativePath=".\Undo.h"> - </File> - <File - RelativePath=".\UpdateCheck.h"> - </File> - <File - RelativePath=".\version.h"> - </File> - <File - RelativePath=".\view_com.h"> - </File> - <File - RelativePath=".\view_gen.h"> - </File> - <File - RelativePath=".\view_ins.h"> - </File> - <File - RelativePath=".\view_pat.h"> - </File> - <File - RelativePath=".\view_smp.h"> - </File> - <File - RelativePath=".\view_tre.h"> - </File> - <File - RelativePath=".\VSTEditor.h"> - </File> - <File - RelativePath=".\vstplug.h"> - </File> - <File - RelativePath="..\soundlib\Wav.h"> - </File> - <File - RelativePath="..\soundlib\wavConverter.h"> - </File> - <File - RelativePath="..\soundlib\WindowedFIR.h"> - </File> - <Filter - Name="tuning" - Filter=""> - <File - RelativePath="..\soundlib\tuning.h"> - </File> - <File - RelativePath="..\soundlib\tuningbase.h"> - </File> - <File - RelativePath="..\soundlib\tuningcollection.h"> - </File> - <File - RelativePath=".\TuningDialog.h"> - </File> - <File - RelativePath=".\tuningRatioMapWnd.h"> - </File> - </Filter> - </Filter> - <Filter - Name="test" - Filter=""> - <File - RelativePath=".\test\test.cpp"> - </File> - <File - RelativePath=".\test\test.h"> - </File> - </Filter> - <Filter - Name="Module Loaders" - Filter=""> - <File - RelativePath="..\soundlib\ITTools.h"> - </File> - <File - RelativePath="..\soundlib\ITTools.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_669.cpp"> - </File> - <File - RelativePath="..\Soundlib\load_amf.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_ams.cpp"> - </File> - <File - RelativePath="..\soundlib\load_dbm.cpp"> - </File> - <File - RelativePath="..\soundlib\load_dmf.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_dsm.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_far.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_gdm.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_imf.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_it.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_itp.cpp"> - </File> - <File - RelativePath="..\soundlib\load_j2b.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_mdl.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_med.cpp"> - </File> - <File - RelativePath="..\soundlib\load_mid.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_mo3.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_mod.cpp"> - </File> - <File - RelativePath="..\Soundlib\load_mt2.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_mtm.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_okt.cpp"> - </File> - <File - RelativePath="..\Soundlib\load_psm.cpp"> - </File> - <File - RelativePath="..\soundlib\load_ptm.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_s3m.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_stm.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_ult.cpp"> - </File> - <File - RelativePath="..\Soundlib\Load_umx.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_wav.cpp"> - </File> - <File - RelativePath="..\soundlib\Load_xm.cpp"> - </File> - <File - RelativePath="..\soundlib\Loaders.h"> - </File> - </Filter> - <File - RelativePath=".\mptrack.reg"> - </File> - <File - RelativePath=".\VTune\mptrack.vpj"> - </File> - </Files> - <Globals> - <Global - Name="RESOURCE_FILE" - Value="mptrack.rc"/> - </Globals> -</VisualStudioProject> Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-12 22:41:17 UTC (rev 1216) @@ -49,7 +49,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/EHsc" Optimization="0" - AdditionalIncludeDirectories="..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\xsoundlib;..\" + AdditionalIncludeDirectories="..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\include\vstsdk2.4\;..\include\ASIOSDK2\common\;..\xsoundlib;..\" PreprocessorDefinitions="_DEBUG,WIN32,_WINDOWS,ENABLE_EQ,MODPLUG_TRACKER,NO_PACKING,HAVE_DOT_NET,ENABLE_AMD,ENABLE_SSE,ENABLE_AMDNOW,ENABLE_MMX" StringPooling="true" BasicRuntimeChecks="3" @@ -157,7 +157,7 @@ AdditionalOptions="/EHsc /O2" Optimization="2" InlineFunctionExpansion="2" - AdditionalIncludeDirectories="..\unlha,..\unzip,..\unrar,..\soundlib,..\include,..\xsoundlib,..\" + AdditionalIncludeDirectories="..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\include\vstsdk2.4\;..\include\ASIOSDK2\common\;..\xsoundlib;..\" PreprocessorDefinitions="NDEBUG,WIN32,_WINDOWS,ENABLE_MMX,ENABLE_EQ,MODPLUG_TRACKER,NO_PACKING,HAVE_DOT_NET,ENABLE_AMD,ENABLE_SSE,ENABLE_AMDNOW" StringPooling="true" RuntimeLibrary="0" Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-12 22:41:17 UTC (rev 1216) @@ -62,7 +62,7 @@ <ClCompile> <AdditionalOptions>/EHsc %(AdditionalOptions)</AdditionalOptions> <Optimization>Disabled</Optimization> - <AdditionalIncludeDirectories>..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\xsoundlib;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\include\vstsdk2.4\;..\include\ASIOSDK2\common\;..\xsoundlib;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;ENABLE_EQ;MODPLUG_TRACKER;NO_PACKING;HAVE_DOT_NET;ENABLE_AMD;ENABLE_SSE;ENABLE_AMDNOW;ENABLE_MMX;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> @@ -119,7 +119,7 @@ <ClCompile> <Optimization>MaxSpeed</Optimization> <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> - <AdditionalIncludeDirectories>..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\xsoundlib;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\unlha;..\unzip;..\unrar;..\soundlib;..\include;..\include\vstsdk2.4\;..\include\ASIOSDK2\common\;..\xsoundlib;..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;ENABLE_MMX;ENABLE_EQ;MODPLUG_TRACKER;NO_PACKING;HAVE_DOT_NET;ENABLE_AMD;ENABLE_SSE;ENABLE_AMDNOW;%(PreprocessorDefinitions)</PreprocessorDefinitions> <StringPooling>true</StringPooling> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> Modified: trunk/OpenMPT/packageTemplate/readme.txt =================================================================== --- trunk/OpenMPT/packageTemplate/readme.txt 2012-03-10 18:19:44 UTC (rev 1215) +++ trunk/OpenMPT/packageTemplate/readme.txt 2012-03-12 22:41:17 UTC (rev 1216) @@ -1,15 +1,1... [truncated message content] |
From: <sag...@us...> - 2012-03-12 22:59:32
|
Revision: 1217 http://modplug.svn.sourceforge.net/modplug/?rev=1217&view=rev Author: saga-games Date: 2012-03-12 22:59:25 +0000 (Mon, 12 Mar 2012) Log Message: ----------- [Fix] VST: Current program name was not read properly for plugins that don't support GetProgramNameIndexed. [Fix] Mod Conversion: When fixing envelopes when converting from XM to IT, a sustain point behind a normal loop wasn't handled correctly. Modified Paths: -------------- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/soundlib/ModInstrument.cpp trunk/OpenMPT/soundlib/PluginEventQueue.h Modified: trunk/OpenMPT/mptrack/AbstractVstEditor.cpp =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2012-03-12 22:59:25 UTC (rev 1217) @@ -444,7 +444,7 @@ for (long p = 0; p < numProgs; p++) { - CString programName = m_pVstPlugin->GetFormattedProgramName(p); + CString programName = m_pVstPlugin->GetFormattedProgramName(p, p == curProg); UINT splitMenuFlag = 0; if(entryInThisMenu++ == PRESETS_PER_GROUP) Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2012-03-12 22:59:25 UTC (rev 1217) @@ -1528,13 +1528,14 @@ CVstPlugin *pVstPlugin = dynamic_cast<CVstPlugin *>(pSndFile->m_MixPlugins[m_nCurrentPlugin].pMixPlugin); if(pVstPlugin == nullptr) return; - UINT nProg = pVstPlugin->GetNumPrograms(); + UINT nProg = pVstPlugin->GetNumPrograms(); + UINT curProg = pVstPlugin->GetCurrentProgram(); m_CbnPreset.SetRedraw(FALSE); m_CbnPreset.ResetContent(); m_CbnPreset.SetItemData(m_CbnPreset.AddString(_T("current")), 0); for (UINT i = 0; i < nProg; i++) { - m_CbnPreset.SetItemData(m_CbnPreset.AddString(pVstPlugin->GetFormattedProgramName(i)), i + 1); + m_CbnPreset.SetItemData(m_CbnPreset.AddString(pVstPlugin->GetFormattedProgramName(i, i == curProg)), i + 1); } m_nCurrentPreset = 0; m_CbnPreset.SetRedraw(TRUE); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-12 22:59:25 UTC (rev 1217) @@ -15,6 +15,7 @@ #include <medparam.h> #include "mainfrm.h" #include "vstplug.h" +#include <pluginterfaces/vst2.x/vstfxstore.h> // VST Presets #include "moddoc.h" #include "sndfile.h" #include "fxp.h" //rewbs.VSTpresets @@ -1512,6 +1513,8 @@ #ifdef VST_LOG Log("~CVstPlugin: m_nRefCount=%d\n", m_nRefCount); #endif + CriticalSection cs; + // First thing to do, if we don't want to hang in a loop if ((m_pFactory) && (m_pFactory->pPluginsList == this)) m_pFactory->pPluginsList = m_pNext; if (m_pMixStruct) @@ -1799,9 +1802,10 @@ if(!GetProgramNameIndexed(index, -1, rawname)) { // Fallback: Try to get current program name. - if(!allowFallback || Dispatch(effGetProgramName, 0, 0, rawname, 0) != 1) + strcpy(rawname, ""); + if(allowFallback) { - strcpy(rawname, ""); + Dispatch(effGetProgramName, 0, 0, rawname, 0); } } StringFixer::SetNullTerminator(rawname); Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-03-12 22:59:25 UTC (rev 1217) @@ -13,7 +13,6 @@ #ifndef NO_VST #define VST_FORCE_DEPRECATED 0 #include <pluginterfaces/vst2.x/aeffectx.h> // VST - #include <pluginterfaces/vst2.x/vstfxstore.h> #endif #include "../soundlib/Snd_defs.h" @@ -117,7 +116,7 @@ PluginMixBuffer<float, MIXBUFFERSIZE> mixBuffer; // Float buffers (input and output) for plugins int m_MixBuffer[MIXBUFFERSIZE * 2 + 2]; // Stereo interleaved - PluginEventQueue<VstEventQueueLength> vstEvents; // MIDI events that should be sent to the plugin + PluginEventQueue<VstEventQueueLength> vstEvents; // MIDI events that should be sent to the plugin public: CVstPlugin(HINSTANCE hLibrary, VSTPLUGINLIB *pFactory, SNDMIXPLUGIN *pMixPlugin, AEffect *pEffect); Modified: trunk/OpenMPT/soundlib/ModInstrument.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModInstrument.cpp 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/soundlib/ModInstrument.cpp 2012-03-12 22:59:25 UTC (rev 1217) @@ -32,6 +32,14 @@ } } else if((fromType & MOD_TYPE_XM) && !(toType & MOD_TYPE_XM)) { + if(nSustainStart > nLoopEnd && (dwFlags & ENV_LOOP)) + { + // In the IT format, the sustain loop is always considered before the envelope loop. + // In the XM format, whichever of the two is encountered first is considered. + // So we have to disable the sustain loop if it was behind the normal loop. + dwFlags &= ~ENV_SUSTAIN; + } + // XM -> IT / MPTM: Shorten loop by one tick by inserting bogus point if(nLoopEnd > nLoopStart && (dwFlags & ENV_LOOP)) { Modified: trunk/OpenMPT/soundlib/PluginEventQueue.h =================================================================== --- trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-12 22:41:17 UTC (rev 1216) +++ trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-12 22:59:25 UTC (rev 1217) @@ -30,7 +30,9 @@ // Alternative, easy to use implementation of VstEvents struct. template <size_t N> +//==================== class PluginEventQueue +//==================== { protected: @@ -40,10 +42,14 @@ && sizeof(BiggestVstEvent) >= sizeof(VstMidiSysexEvent), "Check typedef above, BiggestVstEvent must be the biggest VstEvent struct."); + // The first three member variables of this class mustn't be changed, to be compatible with the original VSTEvents struct. VstInt32 numEvents; ///< number of Events in array VstIntPtr reserved; ///< zero (Reserved for future use) VstEvent *events[N]; ///< event pointer array - std::deque<BiggestVstEvent> eventQueue; // Here we store our events. + // Here we store our events. + std::deque<BiggestVstEvent> eventQueue; + // Since plugins can also add events to the queue (even from a different thread than the processing thread), + // we need to ensure that reading and writing is never done in parallel. CRITICAL_SECTION criticalSection; public: @@ -62,12 +68,15 @@ DeleteCriticalSection(&criticalSection); } + // Get the number of events that are currently in the output buffer. + // It is possible that there are more events left in the queue if the output buffer is full. size_t GetNumEvents() { return numEvents; } // Add a VST event to the queue. Returns true on success. + // Set insertFront to true to prioritise this event (i.e. add it at the front of the queue instead of the back) bool Enqueue(const VstEvent &event, bool insertFront = false) { VstMidiEvent midiEvent; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-13 22:15:35
|
Revision: 1220 http://modplug.svn.sourceforge.net/modplug/?rev=1220&view=rev Author: saga-games Date: 2012-03-13 22:15:28 +0000 (Tue, 13 Mar 2012) Log Message: ----------- [Fix] Pattern Editor: Reset Channel shortcut never worked. [Imp] VST: Implemented (deprecated) GetPreviousPlug / GetNextPlug opcodes. [Mod] Plugins: When using Randomise Params, only automatable parameters are now randomised. [Mod] OpenMPT: Version is now 1.20.00.78 Modified Paths: -------------- trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_pat.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/PluginEventQueue.h Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-13 22:15:28 UTC (rev 1220) @@ -1624,15 +1624,22 @@ void CViewPattern::OnChannelReset() //--------------------------------- { - const CHANNELINDEX nChn = m_MenuCursor.GetChannel(); + ResetChannel(m_MenuCursor.GetChannel()); +} + + +// Reset all channel variables +void CViewPattern::ResetChannel(CHANNELINDEX chn) +//----------------------------------------------- +{ CModDoc *pModDoc = GetDocument(); CSoundFile *pSndFile; if(pModDoc == nullptr || (pSndFile = pModDoc->GetSoundFile()) == nullptr) return; - const bool bIsMuted = pModDoc->IsChannelMuted(nChn); - if(!bIsMuted) pModDoc->MuteChannel(nChn, true); - pSndFile->Chn[nChn].Reset(ModChannel::resetTotal, *pSndFile, nChn); - if(!bIsMuted) pModDoc->MuteChannel(nChn, false); + const bool isMuted = pModDoc->IsChannelMuted(chn); + if(!isMuted) pModDoc->MuteChannel(chn, true); + pSndFile->Chn[chn].Reset(ModChannel::resetTotal, *pSndFile, chn); + if(!isMuted) pModDoc->MuteChannel(chn, false); } @@ -3958,7 +3965,7 @@ case kcChannelUnmuteAll: OnUnmuteAll(); return wParam; case kcToggleChanMuteOnPatTransition: TogglePendingMute(GetCurrentChannel()); return wParam; case kcUnmuteAllChnOnPatTransition: OnPendingUnmuteAllChnFromClick(); return wParam; - case kcChannelReset: OnChannelReset(); return wParam; + case kcChannelReset: ResetChannel(m_Cursor.GetChannel()); return wParam; case kcTimeAtRow: OnShowTimeAtRow(); return wParam; case kcSoloChnOnPatTransition: PendingSoloChn(GetCurrentChannel()); return wParam; case kcTransposeUp: OnTransposeUp(); return wParam; Modified: trunk/OpenMPT/mptrack/View_pat.h =================================================================== --- trunk/OpenMPT/mptrack/View_pat.h 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/mptrack/View_pat.h 2012-03-13 22:15:28 UTC (rev 1220) @@ -280,6 +280,9 @@ void ExecutePaste(PatternClipboard::PasteModes mode); + // Reset all channel variables + void ResetChannel(CHANNELINDEX chn); + public: //{{AFX_VIRTUAL(CViewPattern) virtual void OnDraw(CDC *); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-13 22:15:28 UTC (rev 1220) @@ -728,7 +728,7 @@ { // Called when plugin param is changed via gui case audioMasterAutomate: - if (pVstPlugin != nullptr && pVstPlugin->Dispatch(effCanBeAutomated, index, nullptr, nullptr, 0.0f) != 0) + if (pVstPlugin != nullptr && pVstPlugin->CanAutomateParameter(index)) { // This parameter can be automated. Ugo Motion constantly sends automation callback events for parameters that cannot be automated... pVstPlugin->AutomateParameter((PlugParamIndex)index); @@ -927,12 +927,24 @@ // input pin in <value> (-1: first to come), returns cEffect* - DEPRECATED in VST 2.4 case audioMasterGetPreviousPlug: - Log("VST plugin to host: Get Previous Plug\n"); + if(pVstPlugin != nullptr) + { + CArray<CVstPlugin *, CVstPlugin *> list; + pVstPlugin->GetInputPlugList(list); + // We don't assign plugins to pins... + return ToVstPtr(list[0]); + } break; // output pin in <value> (-1: first to come), returns cEffect* - DEPRECATED in VST 2.4 case audioMasterGetNextPlug: - Log("VST plugin to host: Get Next Plug\n"); + if(pVstPlugin != nullptr) + { + CArray<CVstPlugin *, CVstPlugin *> list; + pVstPlugin->GetOutputPlugList(list); + // We don't assign plugins to pins... + return ToVstPtr(list[0]); + } break; // realtime info @@ -1589,14 +1601,10 @@ } -BOOL CVstPlugin::HasEditor() +bool CVstPlugin::HasEditor() //-------------------------- { - if ((m_pEffect) && (m_pEffect->flags & effFlagsHasEditor)) - { - return TRUE; - } - return FALSE; + return (m_pEffect != nullptr) && (m_pEffect->flags & effFlagsHasEditor); } //rewbs.VSTcompliance: changed from BOOL to long @@ -1622,6 +1630,14 @@ } +// Check whether a VST parameter can be automated +bool CVstPlugin::CanAutomateParameter(PlugParamIndex index) +//--------------------------------------------------------- +{ + return (Dispatch(effCanBeAutomated, index, nullptr, nullptr, 0.0f) != 0); +} + + VstInt32 CVstPlugin::GetUID() //--------------------------- { @@ -1671,7 +1687,12 @@ LimitMax(maxParam, PlugParamIndex(m_pEffect->numParams)); for(PlugParamIndex p = minParam; p < maxParam; p++) - SetParameter(p, (float(rand()) / float(RAND_MAX))); + { + if(CanAutomateParameter(p)) + { + SetParameter(p, (float(rand()) / float(RAND_MAX))); + } + } return true; } @@ -1798,7 +1819,7 @@ CString CVstPlugin::GetFormattedProgramName(VstInt32 index, bool allowFallback) //----------------------------------------------------------------------------- { - char rawname[max(kVstMaxProgNameLen, 256)]; // kVstMaxProgNameLen is 24... + char rawname[max(kVstMaxProgNameLen + 1, 256)]; // kVstMaxProgNameLen is 24... if(!GetProgramNameIndexed(index, -1, rawname)) { // Fallback: Try to get current program name. @@ -1886,7 +1907,7 @@ CString CVstPlugin::GetParamPropertyString(VstInt32 param, VstInt32 opcode) //------------------------------------------------------------------------- { - CHAR s[max(kVstMaxParamStrLen, 64)]; // Increased to 64 bytes since 32 bytes doesn't seem to suffice for all plugs. Kind of ridiculous if you consider that kVstMaxParamStrLen = 8... + CHAR s[max(kVstMaxParamStrLen + 1, 64)]; // Increased to 64 bytes since 32 bytes doesn't seem to suffice for all plugs. Kind of ridiculous if you consider that kVstMaxParamStrLen = 8... s[0] = '\0'; if(m_pEffect != nullptr && m_pEffect->numParams > 0 && param < m_pEffect->numParams) @@ -1933,7 +1954,7 @@ //-------------------------------------------------- { pszName[0] = 0; - if (m_bIsVst2) + if(m_bIsVst2) { Dispatch(effGetEffectName, 0, 0, pszName, 0); return TRUE; @@ -1941,6 +1962,7 @@ return FALSE; } + void CVstPlugin::Init(unsigned long /*nFreq*/, int /*bReset*/) //------------------------------------------------------------ { @@ -2967,7 +2989,7 @@ PLUGINDEX nOutput = m_pMixStruct->GetOutputPlugin(); if(m_pSndFile && nOutput > m_nSlot && nOutput != PLUGINDEX_INVALID) { - pOutputPlug = reinterpret_cast<CVstPlugin *>(m_pSndFile->m_MixPlugins[nOutput].pMixPlugin); + pOutputPlug = dynamic_cast<CVstPlugin *>(m_pSndFile->m_MixPlugins[nOutput].pMixPlugin); } } list.Add(pOutputPlug); @@ -2986,7 +3008,7 @@ for (int nPlug = 0; nPlug < MAX_MIXPLUGINS; nPlug++) { - pCandidatePlug = reinterpret_cast<CVstPlugin *>(m_pSndFile->m_MixPlugins[nPlug].pMixPlugin); + pCandidatePlug = dynamic_cast<CVstPlugin *>(m_pSndFile->m_MixPlugins[nPlug].pMixPlugin); if (pCandidatePlug) { pCandidatePlug->GetOutputPlugList(candidatePlugOutputs); @@ -3317,6 +3339,9 @@ } break; + case effCanBeAutomated: + return (index < m_pMachineInfo->numGlobalParameters); + // Buzz extensions case effBuzzGetNumCommands: { @@ -3676,6 +3701,9 @@ } break; + case effCanBeAutomated: + return (index < m_Effect.numParams); + case effSetSampleRate: m_nSamplesPerSec = (int)opt; break; @@ -3871,9 +3899,10 @@ CString SNDMIXPLUGIN::GetParamName(PlugParamIndex index) const //------------------------------------------------------------ { - if(pMixPlugin) + CVstPlugin *vstPlug = dynamic_cast<CVstPlugin *>(pMixPlugin); + if(vstPlug != nullptr) { - return reinterpret_cast<CVstPlugin *>(pMixPlugin)->GetParamName(index); + return vstPlug->GetParamName(index); } else { return CString(); Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-03-13 22:15:28 UTC (rev 1220) @@ -125,7 +125,7 @@ public: PVSTPLUGINLIB GetPluginFactory() const { return m_pFactory; } - BOOL HasEditor(); + bool HasEditor(); long GetNumPrograms(); PlugParamIndex GetNumParameters(); long GetCurrentProgram(); @@ -206,6 +206,9 @@ void SetDryRatio(UINT param); void AutomateParameter(PlugParamIndex param); + // Check whether a VST parameter can be automated + bool CanAutomateParameter(PlugParamIndex index); + void SetZxxParameter(UINT nParam, UINT nValue); UINT GetZxxParameter(UINT nParam); //rewbs.smoothVST @@ -231,15 +234,17 @@ #else // case: NO_VST public: - PlugParamIndex GetNumParameters() {return 0;} + PlugParamIndex GetNumParameters() { return 0; } void ToggleEditor() {} - BOOL HasEditor() {return FALSE;} - UINT GetNumCommands() {return 0;} + bool HasEditor() { return false; } + UINT GetNumCommands() { return 0; } void GetPluginType(LPSTR) {} - PlugParamIndex GetNumPrograms() {return 0;} + PlugParamIndex GetNumPrograms() { return 0; } bool GetProgramNameIndexed(long, long, char*) { return false; } - CString GetFormattedProgramName(VstInt32, bool = false) { return ""; }; + CString GetFormattedProgramName(VstInt32, bool = false) { return ""; } void SetParameter(PlugParamIndex, PlugParamValue) {} + + bool CanAutomateParameter(PlugParamIndex index) { return false; } CString GetFormattedParamName(PlugParamIndex) { return ""; }; CString GetFormattedParamValue(PlugParamIndex){ return ""; }; Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/mptrack/version.h 2012-03-13 22:15:28 UTC (rev 1220) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 77 +#define VER_MINORMINOR 78 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/PluginEventQueue.h =================================================================== --- trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-13 14:49:58 UTC (rev 1219) +++ trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-13 22:15:28 UTC (rev 1220) @@ -36,7 +36,9 @@ { protected: - typedef VstMidiEvent BiggestVstEvent; + // Although originally all event types were apparently supposed to be of the same size, this is not the case on 64-Bit systems. + // VstMidiSysexEvent contains 3 pointers, so the struct size differs between 32-Bit and 64-Bit systems. + typedef VstMidiSysexEvent BiggestVstEvent; static_assert(sizeof(BiggestVstEvent) >= sizeof(VstEvent) && sizeof(BiggestVstEvent) >= sizeof(VstMidiEvent) && sizeof(BiggestVstEvent) >= sizeof(VstMidiSysexEvent), @@ -79,14 +81,39 @@ // Set insertFront to true to prioritise this event (i.e. add it at the front of the queue instead of the back) bool Enqueue(const VstEvent &event, bool insertFront = false) { - VstMidiEvent midiEvent; - memcpy(&midiEvent, &event, min(event.byteSize, sizeof(event))); ASSERT(event.byteSize == sizeof(event)); - return Enqueue(midiEvent, insertFront); +#if 1 + // True on 32-Bit hosts: No copying is necessary + static_assert(sizeof(VstEvent) == sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); +#else + // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. + static_assert(sizeof(VstEvent) <= sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + VstMidiSysexEvent copyEvent; + memcpy(©Event, &event, min(event.byteSize, sizeof(event))); + return Enqueue(copyEvent, insertFront); +#endif } + bool Enqueue(const VstMidiEvent &event, bool insertFront = false) { - static_assert(sizeof(BiggestVstEvent) <= sizeof(VstMidiEvent), "Also check implementation here."); + ASSERT(event.byteSize == sizeof(event)); +#if 1 + // True on 32-Bit hosts: No copying is necessary + static_assert(sizeof(VstMidiEvent) == sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); +#else + // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. + static_assert(sizeof(VstMidiEvent) <= sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + VstMidiSysexEvent copyEvent; + memcpy(©Event, &event, min(event.byteSize, sizeof(event))); + return Enqueue(copyEvent, insertFront); +#endif + } + + bool Enqueue(const VstMidiSysexEvent &event, bool insertFront = false) + { + static_assert(sizeof(BiggestVstEvent) <= sizeof(VstMidiSysexEvent), "Also check implementation here."); EnterCriticalSection(&criticalSection); if(insertFront) { @@ -98,13 +125,6 @@ LeaveCriticalSection(&criticalSection); return true; } - bool Enqueue(const VstMidiSysexEvent &event, bool insertFront = false) - { - VstMidiEvent midiEvent; - memcpy(&midiEvent, &event, min(event.byteSize, sizeof(event))); - ASSERT(event.byteSize == sizeof(event)); - return Enqueue(midiEvent, insertFront); - } // Set up the queue for transmitting to the plugin. Returns number of elements that are going to be transmitted. VstInt32 Finalise() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-17 19:42:23
|
Revision: 1222 http://modplug.svn.sourceforge.net/modplug/?rev=1222&view=rev Author: saga-games Date: 2012-03-17 19:42:16 +0000 (Sat, 17 Mar 2012) Log Message: ----------- [Fix] Pattern Editor: Tried to fix pattern navigation in low/med detail view. Some of this (home/end keys) was already broken before the "great refactoring commit", some bugs were new. [Fix] VST: Fixed potential problems with multi-threading VSTs when loading a plugin for the first time (tx manx) [Mod] Updated my keymap a bit. [Mod] OpenMPT: Version is now 1.20.00.79 Modified Paths: -------------- trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_pat.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp 2012-03-17 19:42:16 UTC (rev 1222) @@ -260,12 +260,18 @@ POINT pt; int xofs = GetXScrollPos(); int yofs = GetYScrollPos(); - pt.x = (cursor.GetChannel() - xofs) * GetColumnWidth(); PatternCursor::Columns imax = cursor.GetColumnType(); LimitMax(imax, PatternCursor::lastColumn); - LimitMax(imax, static_cast<PatternCursor::Columns>(m_nDetailLevel)); +// if(imax > m_nDetailLevel) +// { +// // Extend to next channel +// imax = PatternCursor::firstColumn; +// cursor.Move(0, 1, 0); +// } + pt.x = (cursor.GetChannel() - xofs) * GetColumnWidth(); + for(int i = 0; i < imax; i++) { pt.x += pfnt->nEltWidths[i]; Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-17 19:42:16 UTC (rev 1222) @@ -4013,23 +4013,14 @@ case kcNavigateUpBySpacing: SetCurrentRow(GetCurrentRow() - m_nSpacing, TRUE); return wParam; case kcNavigateLeftSelect: - case kcNavigateLeft: if ((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_WRAP) && m_Cursor.IsInFirstColumn()) - SetCurrentColumn(pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn); - else - { - m_Cursor.Move(0, 0, -1); - SetCurrentColumn(m_Cursor); - } - return wParam; + case kcNavigateLeft: + MoveCursor(false); + break; case kcNavigateRightSelect: - case kcNavigateRight: if ((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_WRAP) && (m_Cursor.CompareColumn(PatternCursor(0, pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn)) >= 0)) - SetCurrentColumn(0); - else - { - m_Cursor.Move(0, 0, 1); - SetCurrentColumn(m_Cursor); - } - return wParam; + case kcNavigateRight: + MoveCursor(true); + break; + case kcNavigateNextChanSelect: case kcNavigateNextChan: SetCurrentColumn((GetCurrentChannel() + 1) % pSndFile->GetNumChannels(), m_Cursor.GetColumnType()); return wParam; case kcNavigatePrevChanSelect: @@ -4054,20 +4045,20 @@ return wParam; case kcEndHorizontalSelect: - case kcEndHorizontal: if (m_Cursor.CompareColumn(PatternCursor(0, pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn)) < 0) SetCurrentColumn(pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn); + case kcEndHorizontal: if (m_Cursor.CompareColumn(PatternCursor(0, pSndFile->GetNumChannels() - 1, m_nDetailLevel)) < 0) SetCurrentColumn(pSndFile->GetNumChannels() - 1, m_nDetailLevel); else if (GetCurrentRow() < pModDoc->GetPatternSize(m_nPattern) - 1) SetCurrentRow(pModDoc->GetPatternSize(m_nPattern) - 1); return wParam; case kcEndVerticalSelect: case kcEndVertical: if (GetCurrentRow() < pModDoc->GetPatternSize(m_nPattern) - 1) SetCurrentRow(pModDoc->GetPatternSize(m_nPattern) - 1); - else if (m_Cursor.CompareColumn(PatternCursor(0, pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn)) < 0) SetCurrentColumn(pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn); + else if (m_Cursor.CompareColumn(PatternCursor(0, pSndFile->GetNumChannels() - 1, m_nDetailLevel)) < 0) SetCurrentColumn(pSndFile->GetNumChannels() - 1, m_nDetailLevel); return wParam; case kcEndAbsoluteSelect: - case kcEndAbsolute: SetCurrentColumn(pSndFile->GetNumChannels() - 1, PatternCursor::lastColumn); + case kcEndAbsolute: SetCurrentColumn(pSndFile->GetNumChannels() - 1, m_nDetailLevel); if (GetCurrentRow() < pModDoc->GetPatternSize(m_nPattern) - 1) SetCurrentRow(pModDoc->GetPatternSize(m_nPattern) - 1); return wParam; case kcNextPattern: { PATTERNINDEX n = m_nPattern + 1; - while ((n < pSndFile->Patterns.Size()) && !pSndFile->Patterns.IsValidPat(n)) n++; + while ((n < pSndFile->Patterns.Size()) && !pSndFile->Patterns.IsValidPat(n)) n++; SetCurrentPattern((n < pSndFile->Patterns.Size()) ? n : 0); ORDERINDEX currentOrder = SendCtrlMessage(CTRLMSG_GETCURRENTORDER); ORDERINDEX newOrder = pSndFile->Order.FindOrder(m_nPattern, currentOrder, true); @@ -4230,6 +4221,41 @@ return NULL; } + +// Move pattern cursor to left or right, respecting invisible columns. +void CViewPattern::MoveCursor(bool moveRight) +//------------------------------------------- +{ + if(!moveRight) + { + // Move cursor one column to the left + if((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_WRAP) && m_Cursor.IsInFirstColumn()) + { + // Wrap around to last channel + SetCurrentColumn(GetDocument()->GetNumChannels() - 1, m_nDetailLevel); + } else if(!m_Cursor.IsInFirstColumn()) + { + m_Cursor.Move(0, 0, -1); + SetCurrentColumn(m_Cursor); + } + } else + { + // Move cursor one column to the right + if((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_WRAP) && (m_Cursor.CompareColumn(PatternCursor(0, GetDocument()->GetNumChannels() - 1, m_nDetailLevel)) >= 0)) + { + // Wrap around to first channel. + SetCurrentColumn(0); + } else + { + do + { + m_Cursor.Move(0, 0, 1); + } while(m_Cursor.GetColumnType() > m_nDetailLevel); + SetCurrentColumn(m_Cursor); + } + } +} + #define ENTER_PCNOTE_VALUE(v, method) \ { \ if((v >= 0) && (v <= 9)) \ Modified: trunk/OpenMPT/mptrack/View_pat.h =================================================================== --- trunk/OpenMPT/mptrack/View_pat.h 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/mptrack/View_pat.h 2012-03-17 19:42:16 UTC (rev 1222) @@ -235,6 +235,8 @@ bool ShowEditWindow(); UINT GetCurrentInstrument() const; void SelectBeatOrMeasure(bool selectBeat); + // Move pattern cursor to left or right, respecting invisible columns. + void MoveCursor(bool moveRight); bool TransposeSelection(int transp); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-17 19:42:16 UTC (rev 1222) @@ -318,11 +318,11 @@ } if ((hLib) && (hLib != INVALID_HANDLE_VALUE)) { - BOOL bOk = FALSE; - PVSTPLUGENTRY pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "main"); - if(pMainProc == NULL) + bool validPlug = false; + PVSTPLUGENTRY pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "VSTPluginMain"); + if(pMainProc == nullptr) { - pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "VSTPluginMain"); + pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "main"); } #ifdef ENABLE_BUZZ GET_INFO pBuzzGetInfo = (GET_INFO)GetProcAddress(hLib, "GetInfo"); @@ -340,22 +340,22 @@ p->dwPluginId1 = 0; p->dwPluginId2 = 0; p->bIsInstrument = FALSE; - p->pPluginsList = NULL; + p->pPluginsList = nullptr; lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); - _splitpath(pszDllPath, NULL, NULL, p->szLibraryName, NULL); + _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); p->szLibraryName[63] = 0; p->pNext = m_pVstHead; - p->pPrev = NULL; + p->pPrev = nullptr; if (m_pVstHead) m_pVstHead->pPrev = p; m_pVstHead = p; try { AEffect *pEffect = pMainProc(MasterCallBack); - if ((pEffect) && (pEffect->magic == kEffectMagic) - && (pEffect->dispatcher)) + if(pEffect != nullptr && pEffect->magic == kEffectMagic && pEffect->dispatcher != nullptr) { pEffect->dispatcher(pEffect, effOpen, 0, 0, 0, 0); + #ifdef VST_USE_ALTERNATIVE_MAGIC p->dwPluginId1 = CalculateCRC32fromFilename(p->szLibraryName); // Make Plugin ID unique for sure #else @@ -363,6 +363,7 @@ #endif // VST_USE_ALTERNATIVE_MAGIC p->dwPluginId2 = pEffect->uniqueID; if ((pEffect->flags & effFlagsIsSynth) || (!pEffect->numInputs)) p->bIsInstrument = TRUE; + #ifdef VST_LOG int nver = pEffect->dispatcher(pEffect, effGetVstVersion, 0,0, NULL, 0); if (!nver) nver = pEffect->version; @@ -373,7 +374,9 @@ pEffect->flags, pEffect->realQualities, pEffect->offQualities); #endif // VST_LOG - bOk = TRUE; + pEffect->dispatcher(pEffect, effClose, 0, 0, 0, 0); + + validPlug = true; } } catch(...) { @@ -381,7 +384,7 @@ } // If OK, write the information in PluginCache - if (bOk) + if(validPlug) { const CString cacheSection = "PluginCache"; const CString cacheFile = theApp.GetPluginCacheFileName(); @@ -434,7 +437,7 @@ { lstrcpyn(p->szLibraryName, pInfo->Name, CountOf(p->szLibraryName)); } - bOk = TRUE; + validPlug = true; } } catch (...) { @@ -453,7 +456,7 @@ // Now it should be safe to assume that this plugin loaded properly. :) WritePrivateProfileString("VST Plugins", "FailedPlugin", NULL, theApp.GetConfigFileName()); - return (bOk) ? m_pVstHead : nullptr; + return (validPlug ? m_pVstHead : nullptr); } else { #ifdef VST_LOG @@ -1306,6 +1309,7 @@ } } delete[] pFileSel->returnMultiplePaths; + pFileSel->returnMultiplePaths = nullptr; } else { if(pFileSel->reserved == 1 && pFileSel->returnPath != nullptr) Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/mptrack/version.h 2012-03-17 19:42:16 UTC (rev 1222) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 78 +#define VER_MINORMINOR 79 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb =================================================================== --- trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-17 19:06:05 UTC (rev 1221) +++ trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-17 19:42:16 UTC (rev 1222) @@ -24,7 +24,6 @@ 0:1359:2:90:5 //Undo: Ctrl+Z (KeyDown|KeyHold) 0:1360:2:88:1 //Cut: Ctrl+X (KeyDown) 0:1361:2:67:1 //Copy: Ctrl+C (KeyDown) -0:1361:2:45:1 //Copy: Ctrl+EINFG (KeyDown) 0:1362:2:86:1 //Paste: Ctrl+V (KeyDown) 0:1363:3:86:1 //Mix Paste: Shift+Ctrl+V (KeyDown) 0:1793:1:86:1 //Paste Flood: Shift+V (KeyDown) @@ -116,8 +115,8 @@ 2:1665:0:46:1 //Clear field and step (IT Style): ENTF (KeyDown) 2:1061:0:8:5 //Delete rows: R\xDCCK (KeyDown|KeyHold) 2:1377:2:8:5 //Delete all rows: Ctrl+R\xDCCK (KeyDown|KeyHold) -2:1378:0:45:1 //Insert Row: EINFG (KeyDown) -2:1379:2:45:1 //Insert All Rows: Ctrl+EINFG (KeyDown) +2:1378:0:45:5 //Insert Row: EINFG (KeyDown|KeyHold) +2:1379:2:45:5 //Insert All Rows: Ctrl+EINFG (KeyDown|KeyHold) 2:1055:0:109:5 //Previous pattern: - (ZEHNERTASTATUR) (KeyDown|KeyHold) 2:1054:0:107:5 //Next pattern: + (ZEHNERTASTATUR) (KeyDown|KeyHold) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-18 18:02:57
|
Revision: 1224 http://modplug.svn.sourceforge.net/modplug/?rev=1224&view=rev Author: saga-games Date: 2012-03-18 18:02:50 +0000 (Sun, 18 Mar 2012) Log Message: ----------- [Fix] Fixed SE0 effect handling in IT files. Modified Paths: -------------- trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2012-03-18 14:51:52 UTC (rev 1223) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2012-03-18 18:02:50 UTC (rev 1224) @@ -179,11 +179,14 @@ } bool addBreak = false; // When converting to XM, avoid the E60 bug. - CHANNELINDEX nChannel = GetNumChannels() - 1; + CHANNELINDEX channel = 0; - for (UINT len = m_SndFile.Patterns[nPat].GetNumRows() * m_SndFile.m_nChannels; len; m++, len--) + for (UINT len = m_SndFile.Patterns[nPat].GetNumRows() * m_SndFile.GetNumChannels(); len; m++, len--, channel++) { - nChannel = (nChannel + 1) % GetNumChannels(); // 0...Channels - 1 + if(channel >= GetNumChannels()) + { + channel = 0; + } m->Convert(nOldType, nNewType); @@ -197,9 +200,9 @@ case CMD_MODCMDEX: // No effect memory in XM / MOD if(m->param == 0) - m->param = cEffectMemory[nChannel][m->command]; + m->param = cEffectMemory[channel][m->command]; else - cEffectMemory[nChannel][m->command] = m->param; + cEffectMemory[channel][m->command] = m->param; break; } } @@ -216,9 +219,9 @@ case CMD_VOLUMESLIDE: // ProTracker doesn't have effect memory for these commands, so let's try to fix them if(m->param == 0) - m->param = cEffectMemory[nChannel][m->command]; + m->param = cEffectMemory[channel][m->command]; else - cEffectMemory[nChannel][m->command] = m->param; + cEffectMemory[channel][m->command] = m->param; break; } @@ -241,6 +244,40 @@ break; } } + + // Fix Row Delay commands when converting between MOD/XM and S3M/IT. + // FT2 only considers the rightmost command, ST3/IT only the leftmost... + if((nOldType & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) && (nNewType & (MOD_TYPE_MOD | MOD_TYPE_XM)) + && m->command == CMD_MODCMDEX && (m->param & 0xF0) == 0xE0) + { + if(oldTypeIsIT_MPT || m->param != 0xE0) + { + // If the leftmost row delay command is SE0, ST3 ignores it, IT doesn't. + + // Delete all commands right of the first command + ModCommand *p = m + 1; + for(CHANNELINDEX c = channel + 1; c < m_SndFile.GetNumChannels(); c++, p++) + { + if(p->command == CMD_S3MCMDEX && (p->param & 0xF0) == 0xE0) + { + p->command = CMD_NONE; + } + } + } + } else if((nOldType & (MOD_TYPE_MOD | MOD_TYPE_XM)) && (nNewType & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) + && m->command == CMD_S3MCMDEX && (m->param & 0xF0) == 0xE0) + { + // Delete all commands left of the last command + ModCommand *p = m - 1; + for(CHANNELINDEX c = 0; c < channel; c++, p--) + { + if(p->command == CMD_S3MCMDEX && (p->param & 0xF0) == 0xE0) + { + p->command = CMD_NONE; + } + } + } + } if(addBreak) { Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-18 14:51:52 UTC (rev 1223) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-18 18:02:50 UTC (rev 1224) @@ -365,7 +365,12 @@ } else if((param & 0xF0) == 0xE0 && !rowDelay) { // Pattern Delay - rowDelay = (param & 0x0F); + if(!(GetType() & MOD_TYPE_S3M) || (param & 0x0F) != 0) + { + // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right), + // Scream Tracker 3 simply ignores such commands. + rowDelay = 1 + (param & 0x0F); + } } else if((param & 0xF0) == 0xA0) { // High sample offset @@ -388,7 +393,7 @@ if((param & 0xF0) == 0xE0) { // Pattern Delay - rowDelay = (param & 0x0F); + rowDelay = 1 + (param & 0x0F); } else if ((param & 0xF0) == 0x60) { // Pattern Loop @@ -521,7 +526,7 @@ } // XXX this does not take per-pattern time signatures into consideration! - memory.elapsedTime += GetRowDuration(memory.musicTempo, memory.musicSpeed, (memory.musicSpeed + tickDelay) * (1 + rowDelay)); + memory.elapsedTime += GetRowDuration(memory.musicTempo, memory.musicSpeed, (memory.musicSpeed + tickDelay) * max(rowDelay, 1)); } if(retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) @@ -1600,7 +1605,12 @@ // XXX In Scream Tracker 3, the "left" channels are evaluated before the "right" channels, which is not emulated here! if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) || !m_nPatternDelay) { - m_nPatternDelay = param & 0x0F; + if(!(GetType() & (MOD_TYPE_S3M)) || (param & 0x0F) != 0) + { + // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right), + // Scream Tracker 3 simply ignores such commands. + m_nPatternDelay = 1 + (param & 0x0F); + } } } } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-03-18 14:51:52 UTC (rev 1223) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-03-18 18:02:50 UTC (rev 1224) @@ -576,7 +576,7 @@ UINT GetNumTicksOnCurrentRow() const { - return (m_nMusicSpeed + m_nFrameDelay) * (m_nPatternDelay + 1); + return (m_nMusicSpeed + m_nFrameDelay) * max(m_nPatternDelay, 1); } public: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-21 00:36:31
|
Revision: 1226 http://modplug.svn.sourceforge.net/modplug/?rev=1226&view=rev Author: saga-games Date: 2012-03-21 00:36:20 +0000 (Wed, 21 Mar 2012) Log Message: ----------- [Ref] Moved XI / XM instrument / sample handling to XMTools.cpp to avoid duplicate code. Let's see if / when the new code explodes... [Ref] Removed hard to use and hard to understand SpaceToNullStringFixed method and replaced it by easy to understand, easy to use and most importantly safer ReadString / WriteString methods. It's never ever possible to overflow the destination buffer with those, and if source buffer is larger than destination buffer, absolutely no adjustments have to be done (that was previously not the case). [Ref] Removed unused ADPCM packing code (it's not 1997 anymore). Unpacking does still work, though. [Fix] Fixed possible stack corruption when loading instruments into XM files. Modified Paths: -------------- trunk/OpenMPT/common/StringFixer.h trunk/OpenMPT/installer/filetypes.iss trunk/OpenMPT/mptrack/AutoSaver.cpp trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/ITTools.h trunk/OpenMPT/soundlib/LOAD_AMF.CPP trunk/OpenMPT/soundlib/LOAD_DBM.CPP trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/LOAD_DSM.CPP trunk/OpenMPT/soundlib/Load_669.cpp trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/Load_far.cpp trunk/OpenMPT/soundlib/Load_gdm.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_mdl.cpp trunk/OpenMPT/soundlib/Load_med.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/Load_okt.cpp trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Load_ptm.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_stm.cpp trunk/OpenMPT/soundlib/Load_ult.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/load_j2b.cpp Added Paths: ----------- trunk/OpenMPT/soundlib/XMTools.cpp trunk/OpenMPT/soundlib/XMTools.h Removed Paths: ------------- trunk/OpenMPT/unlha/Debug/ trunk/OpenMPT/unrar/Debug/ Modified: trunk/OpenMPT/common/StringFixer.h =================================================================== --- trunk/OpenMPT/common/StringFixer.h 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/common/StringFixer.h 2012-03-21 00:36:20 UTC (rev 1226) @@ -25,40 +25,6 @@ } - // Convert a 0-terminated string to a space-padded string - template <size_t size> - void NullToSpaceString(char (&buffer)[size]) - //------------------------------------------ - { - STATIC_ASSERT(size > 0); - size_t pos = size; - while (pos-- > 0) - if (buffer[pos] == 0) - buffer[pos] = 32; - buffer[size - 1] = 0; - } - - - // Convert a space-padded string to a 0-terminated string - template <size_t size> - void SpaceToNullString(char (&buffer)[size]) - //------------------------------------------ - { - STATIC_ASSERT(size > 0); - // First, remove any Nulls - NullToSpaceString(buffer); - size_t pos = size; - while (pos-- > 0) - { - if (buffer[pos] == 32) - buffer[pos] = 0; - else if(buffer[pos] != 0) - break; - } - buffer[size - 1] = 0; - } - - // Remove any chars after the first null char template <size_t size> void FixNullString(char (&buffer)[size]) @@ -80,41 +46,173 @@ } - // Convert a space-padded string to a 0-terminated string. STATIC VERSION! (use this if the maximum string length is known) - // Additional template parameter to specifify the max length of the final string, - // not including null char (useful for e.g. mod loaders) - template <size_t length, size_t size> - void SpaceToNullStringFixed(char (&buffer)[size]) - //------------------------------------------------ + enum ReadWriteMode { - STATIC_ASSERT(size > 0); - STATIC_ASSERT(length < size); - // Remove Nulls in string - SpaceToNullString(buffer); - // Overwrite trailing chars - for(size_t pos = length; pos < size; pos++) + // Reading / Writing: Standard null-terminated string handling. + nullTerminated, + // Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array). + // Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array). + maybeNullTerminated, + // Reading: String may contain null characters anywhere. They should be treated as spaces. + // Writing: A space-padded string is written. + spacePadded, + // Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0). + // Writing: A space-padded string with a trailing null is written. + spacePaddedNull, + }; + + + // Copy a string from srcBuffer to destBuffer using a given read mode. + // Used for reading strings from files. + // Preferrably use this version of the function, it is safer. + template <ReadWriteMode mode, size_t destSize, size_t srcSize> + void ReadString(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize]) + //----------------------------------------------------------------------------- + { + STATIC_ASSERT(destSize > 0); + STATIC_ASSERT(srcSize > 0); + ReadString<mode, destSize>(destBuffer, srcBuffer, srcSize); + } + + + // Copy a string from srcBuffer to destBuffer using a given read mode. + // Used for reading strings from files. + // Only use this version of the function if the size of the source buffer is variable. + template <ReadWriteMode mode, size_t destSize> + void ReadString(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize) + //---------------------------------------------------------------------------------------- + { + STATIC_ASSERT(destSize > 0); + ASSERT(srcSize > 0); + + const size_t maxSize = min(destSize, srcSize); + char *dst = destBuffer; + const char *src = srcBuffer; + + if(mode == nullTerminated || mode == maybeNullTerminated) { - buffer[pos] = 0; + // Copy null-terminated string and make sure that destination is null-terminated. + size_t pos = maxSize; + while(pos > 0) + { + pos--; + if((*dst++ = *src++) == '\0') + { + break; + } + } + // Fill rest of string with nulls. + memset(dst, '\0', destSize - maxSize + pos); + + if(mode == nullTerminated) + { + // We assume that the last character of the source buffer is null. + destBuffer[maxSize - 1] = '\0'; + } else + { + // Last character of source buffer may actually be a valid character. + destBuffer[min(destSize - 1, srcSize)] = '\0'; + } + + } else if(mode == spacePadded || mode == spacePaddedNull) + { + // Copy string over, but convert null characters to spaces. + size_t pos = maxSize; + while(pos > 0) + { + *dst = *src; + if(*dst == '\0') + { + *dst = ' '; + } + pos--; + dst++; + src++; + } + // Fill rest of string with nulls. + memset(dst, '\0', destSize - maxSize); + + if(mode == spacePaddedNull && srcSize <= destSize) + { + // We assumed that the last character of the source buffer should be ignored, so make sure it's really null. + destBuffer[srcSize - 1] = '\0'; + } + + // Trim trailing spaces. + pos = maxSize; + dst = destBuffer + pos - 1; + while(pos > 0) + { + if(*dst == ' ') + { + *dst = '\0'; + } else if(*dst != '\0') + { + break; + } + pos--; + dst--; + } + + SetNullTerminator(destBuffer); } } - // Convert a space-padded string to a 0-terminated string. DYNAMIC VERSION! - // Additional function parameter to specifify the max length of the final string, - // not including null char (useful for e.g. mod loaders) - template <size_t size> - void SpaceToNullStringFixed(char (&buffer)[size], size_t length) - //-------------------------------------------------------------- + // Copy a string from srcBuffer to destBuffer using a given write mode. + // Used for writing strings to files. + // Preferrably use this version of the function, it is safer. + template <ReadWriteMode mode, size_t destSize, size_t srcSize> + void WriteString(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize]) + //------------------------------------------------------------------------------ { - STATIC_ASSERT(size > 0); - ASSERT(length < size); - // Remove Nulls in string - SpaceToNullString(buffer); - // Overwrite trailing chars - for(size_t pos = length; pos < size; pos++) + STATIC_ASSERT(destSize > 0); + STATIC_ASSERT(srcSize > 0); + WriteString<mode, destSize>(destBuffer, srcBuffer, srcSize); + } + + // Copy a string from srcBuffer to destBuffer using a given write mode. + // Used for writing strings to files. + // Only use this version of the function if the size of the source buffer is variable. + template <ReadWriteMode mode, size_t destSize> + void WriteString(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize) + //----------------------------------------------------------------------------------------- + { + STATIC_ASSERT(destSize > 0); + ASSERT(srcSize > 0); + + const size_t maxSize = min(destSize, srcSize); + char *dst = destBuffer; + const char *src = srcBuffer; + + // First, copy over null-terminated string. + size_t pos = maxSize; + while(pos > 0) { - buffer[pos] = 0; + if((*dst = *src) == '\0') + { + break; + } + pos--; + dst++; + src++; } + + if(mode == nullTerminated || mode == maybeNullTerminated) + { + // Fill rest of string with nulls. + memset(dst, '\0', destSize - maxSize + pos); + } else if(mode == spacePadded || mode == spacePaddedNull) + { + // Fill the rest of the destination string with spaces. + memset(dst, ' ', destSize - maxSize + pos); + } + + if(mode == nullTerminated || mode == spacePaddedNull) + { + // Make sure that destination is really null-terminated. + SetNullTerminator(destBuffer); + } } }; Modified: trunk/OpenMPT/installer/filetypes.iss =================================================================== --- trunk/OpenMPT/installer/filetypes.iss 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/installer/filetypes.iss 2012-03-21 00:36:20 UTC (rev 1226) @@ -29,7 +29,7 @@ Name: "associate_exotic\gdm"; Description: "General Digital Music (GDM)"; Name: "associate_exotic\imf"; Description: "Imago Orpheus (IMF)"; Name: "associate_exotic\j2b"; Description: "Jazz Jackrabbit 2 Music (J2B)"; -Name: "associate_exotic\mdl"; Description: "DigiTracker (MDL)"; +Name: "associate_exotic\mdl"; Description: "DigiTrakker (MDL)"; Name: "associate_exotic\med"; Description: "OctaMED (MED)"; Name: "associate_exotic\mo3"; Description: "MO3 compressed modules (MO3)"; Name: "associate_exotic\mt2"; Description: "MadTracker 2 (MT2)"; Modified: trunk/OpenMPT/mptrack/AutoSaver.cpp =================================================================== --- trunk/OpenMPT/mptrack/AutoSaver.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/AutoSaver.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -277,22 +277,26 @@ switch (pModDoc->GetModType()) { case MOD_TYPE_MOD: - success = pSndFile->SaveMod(fileName, 0); + success = pSndFile->SaveMod(fileName); break; + case MOD_TYPE_S3M: - success = pSndFile->SaveS3M(fileName, 0); + success = pSndFile->SaveS3M(fileName); break; + case MOD_TYPE_XM: - success = pSndFile->SaveXM(fileName, 0); + success = pSndFile->SaveXM(fileName); break; + case MOD_TYPE_IT: success = (pSndFile->m_dwSongFlags & SONG_ITPROJECT) ? - pSndFile->SaveITProject(fileName) : - pSndFile->SaveIT(fileName, 0); + pSndFile->SaveITProject(fileName) : + pSndFile->SaveIT(fileName); break; + case MOD_TYPE_MPT: //Using IT save function also for MPT. - success = pSndFile->SaveIT(fileName, 0); + success = pSndFile->SaveIT(fileName); break; //default: //Do nothing Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -1475,17 +1475,20 @@ _tsplitpath(lpszFileName, nullptr, nullptr, szName, szExt); CMainFrame::GetSettings().SetWorkingDirectory(lpszFileName, DIR_INSTRUMENTS, true); - if (!pIns->name[0]) + if (!pIns->name[0] && m_pSndFile->GetModSpecifications().instrNameLengthMax > 0) { - szName[m_pSndFile->GetModSpecifications().instrNameLengthMax - 1] = 0; - strcpy(pIns->name, szName); + strncpy(pIns->name, szName, CountOf(pIns->name) - 1); + ASSERT(m_pSndFile->GetModSpecifications().instrNameLengthMax < CountOf(pIns->name)); + pIns->name[m_pSndFile->GetModSpecifications().instrNameLengthMax] = '\0'; } - if (!pIns->filename[0]) + if (!pIns->filename[0] && m_pSndFile->GetModSpecifications().instrFilenameLengthMax > 0) { strcat(szName, szExt); - szName[m_pSndFile->GetModSpecifications().instrFilenameLengthMax - 1] = 0; - strcpy(pIns->filename, szName); + strncpy(pIns->filename, szName, CountOf(pIns->filename) - 1); + ASSERT(m_pSndFile->GetModSpecifications().instrFilenameLengthMax < CountOf(pIns->filename)); + pIns->filename[m_pSndFile->GetModSpecifications().instrFilenameLengthMax] = '\0'; } + SetCurrentInstrument(m_nInstrument); if (m_pModDoc) { @@ -1707,7 +1710,7 @@ if (m_pModDoc) { CSoundFile *pSndFile = m_pModDoc->GetSoundFile(); - if ((pSndFile->m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (pSndFile->m_nInstruments > 0)) + if(pSndFile->m_nInstruments > 0) { BOOL bFirst = (pSndFile->m_nInstruments) ? FALSE : TRUE; LONG ins = m_pModDoc->InsertInstrument(INSTRUMENTINDEX_INVALID, m_nInstrument); @@ -1753,7 +1756,7 @@ else m_nInstrument++; - if(m_nInstrument > m_pSndFile->GetNumInstruments()) + if(m_nInstrument > m_pSndFile->GetNumInstruments()) OnInstrumentNew(); } Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -432,7 +432,6 @@ //-------------------------------------------------------------------------- { static int greccount = 0; - UINT dwPacking = 0; BOOL bOk = FALSE; m_SndFile.m_dwLastSavedWithVersion = MptVersion::num; if (!lpszPathName) @@ -444,18 +443,18 @@ greccount++; bOk = DoSave(NULL, TRUE); greccount--; - return bOk; + return bOk; } BeginWaitCursor(); ClearLog(); FixNullStrings(); switch(type) { - case MOD_TYPE_MOD: bOk = m_SndFile.SaveMod(lpszPathName, dwPacking); break; - case MOD_TYPE_S3M: bOk = m_SndFile.SaveS3M(lpszPathName, dwPacking); break; - case MOD_TYPE_XM: bOk = m_SndFile.SaveXM(lpszPathName, dwPacking); break; - case MOD_TYPE_IT: bOk = (m_SndFile.m_dwSongFlags & SONG_ITPROJECT) ? m_SndFile.SaveITProject(lpszPathName) : m_SndFile.SaveIT(lpszPathName, dwPacking); break; - case MOD_TYPE_MPT: bOk = m_SndFile.SaveIT(lpszPathName, dwPacking); break; + case MOD_TYPE_MOD: bOk = m_SndFile.SaveMod(lpszPathName); break; + case MOD_TYPE_S3M: bOk = m_SndFile.SaveS3M(lpszPathName); break; + case MOD_TYPE_XM: bOk = m_SndFile.SaveXM(lpszPathName); break; + case MOD_TYPE_IT: bOk = (m_SndFile.m_dwSongFlags & SONG_ITPROJECT) ? m_SndFile.SaveITProject(lpszPathName) : m_SndFile.SaveIT(lpszPathName); break; + case MOD_TYPE_MPT: bOk = m_SndFile.SaveIT(lpszPathName); break; } EndWaitCursor(); if (bOk) @@ -649,10 +648,6 @@ return TRUE; } else { -// -> CODE#0023 -// -> DESC="IT project files (.itp)" -// ErrorBox(IDS_ERR_SAVESONG, CMainFrame::GetMainFrame()); // done in OnSaveDocument() -// -! NEW_FEATURE#0023 return FALSE; } } @@ -1871,10 +1866,10 @@ switch (type) { case MOD_TYPE_XM: - m_SndFile.SaveXM(files.first_file.c_str(), 0, true); + m_SndFile.SaveXM(files.first_file.c_str(), true); break; case MOD_TYPE_IT: - m_SndFile.SaveIT(files.first_file.c_str(), 0, true); + m_SndFile.SaveIT(files.first_file.c_str(), true); break; } ShowLog(); Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-21 00:36:20 UTC (rev 1226) @@ -517,6 +517,10 @@ > </File> <File + RelativePath="..\soundlib\XMTools.cpp" + > + </File> + <File RelativePath=".\SampleEditorDialogs.cpp" > </File> @@ -1151,6 +1155,10 @@ > </File> <File + RelativePath=".\soundlib\XMTools.h" + > + </File> + <File RelativePath="..\common\Reporting.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-21 00:36:20 UTC (rev 1226) @@ -175,6 +175,7 @@ <ClCompile Include="..\soundlib\ModInstrument.cpp" /> <ClCompile Include="..\soundlib\ModSample.cpp" /> <ClCompile Include="..\soundlib\RowVisitor.cpp" /> + <ClCompile Include="..\soundlib\XMTools.cpp" /> <ClCompile Include="AbstractVstEditor.cpp" /> <ClCompile Include="ACMConvert.cpp" /> <ClCompile Include="ArrayUtils.cpp" /> @@ -339,6 +340,7 @@ <ClInclude Include="..\soundlib\PluginMixBuffer.h" /> <ClInclude Include="..\soundlib\PlugInterface.h" /> <ClInclude Include="..\soundlib\RowVisitor.h" /> + <ClInclude Include="..\soundlib\XMTools.h" /> <ClInclude Include="ACMConvert.h" /> <ClInclude Include="Autotune.h" /> <ClInclude Include="EffectInfo.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-03-21 00:36:20 UTC (rev 1226) @@ -448,6 +448,9 @@ <ClCompile Include="..\soundlib\ModChannel.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\soundlib\XMTools.cpp"> + <Filter>Module Loaders</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -795,6 +798,9 @@ <ClInclude Include="..\soundlib\RowVisitor.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\soundlib\XMTools.h"> + <Filter>Module Loaders</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -17,6 +17,7 @@ #include "../version.h" #include "../../soundlib/MIDIMacros.h" #include "../../common/misc_util.h" +#include "../../common/StringFixer.h" #include "../serialization_utils.h" #include <limits> #include <fstream> @@ -74,6 +75,7 @@ void TestLoadSaveFile(); void TestPCnoteSerialization(); void TestMisc(); +void TestStringIO(); @@ -83,9 +85,10 @@ { DO_TEST(TestVersion); DO_TEST(TestTypes); - //DO_TEST(TestPCnoteSerialization); + DO_TEST(TestPCnoteSerialization); DO_TEST(TestMisc); - DO_TEST(TestLoadSaveFile) + DO_TEST(TestLoadSaveFile); + DO_TEST(TestStringIO); Log(TEXT("Tests were run\n")); } @@ -855,6 +858,125 @@ } +// Test String I/O functionality +void TestStringIO() +//----------------- +{ + char src1[4] = { 'X', ' ', '\0', 'X' }; // Weird buffer (hello Impulse Tracker) + char src2[4] = { 'X', 'Y', 'Z', ' ' }; // Full buffer, last character space + char src3[4] = { 'X', 'Y', 'Z', '!' }; // Full buffer, last character non-space + char dst1[6]; // Destination buffer, larger than source buffer + char dst2[3]; // Destination buffer, smaller than source buffer + +#define ReadTest(mode, dst, src, expectedResult) \ + StringFixer::ReadString<StringFixer::##mode>(dst, src); \ + VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, CountOf(dst)), 0); + +#define WriteTest(mode, dst, src, expectedResult) \ + StringFixer::WriteString<StringFixer::##mode>(dst, src); \ + VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, CountOf(dst)), 0); + + // Check reading of null-terminated string into larger buffer + ReadTest(nullTerminated, dst1, src1, "X "); + ReadTest(nullTerminated, dst1, src2, "XYZ"); + ReadTest(nullTerminated, dst1, src3, "XYZ"); + + // Check reading of string that should be null-terminated, but is maybe too long to still hold the null character. + ReadTest(maybeNullTerminated, dst1, src1, "X "); + ReadTest(maybeNullTerminated, dst1, src2, "XYZ "); + ReadTest(maybeNullTerminated, dst1, src3, "XYZ!"); + + // Check reading of space-padded strings with ignored last character + ReadTest(spacePaddedNull, dst1, src1, "X"); + ReadTest(spacePaddedNull, dst1, src2, "XYZ"); + ReadTest(spacePaddedNull, dst1, src3, "XYZ"); + + // Check reading of space-padded strings + ReadTest(spacePadded, dst1, src1, "X X"); + ReadTest(spacePadded, dst1, src2, "XYZ"); + ReadTest(spacePadded, dst1, src3, "XYZ!"); + + /////////////////////////////// + + // Check reading of null-terminated string into smaller buffer + ReadTest(nullTerminated, dst2, src1, "X "); + ReadTest(nullTerminated, dst2, src2, "XY"); + ReadTest(nullTerminated, dst2, src3, "XY"); + + // Check reading of string that should be null-terminated, but is maybe too long to still hold the null character. + ReadTest(maybeNullTerminated, dst2, src1, "X "); + ReadTest(maybeNullTerminated, dst2, src2, "XY"); + ReadTest(maybeNullTerminated, dst2, src3, "XY"); + + // Check reading of space-padded strings with ignored last character + ReadTest(spacePaddedNull, dst2, src1, "X"); + ReadTest(spacePaddedNull, dst2, src2, "XY"); + ReadTest(spacePaddedNull, dst2, src3, "XY"); + + // Check reading of space-padded strings + ReadTest(spacePadded, dst2, src1, "X"); + ReadTest(spacePadded, dst2, src2, "XY"); + ReadTest(spacePadded, dst2, src3, "XY"); + + /////////////////////////////// + + // Check writing of null-terminated string into larger buffer + WriteTest(nullTerminated, dst1, src1, "X "); + WriteTest(nullTerminated, dst1, src2, "XYZ "); + WriteTest(nullTerminated, dst1, src3, "XYZ!"); + + // Check writing of string that should be null-terminated, but is maybe too long to still hold the null character. + WriteTest(maybeNullTerminated, dst1, src1, "X "); + WriteTest(maybeNullTerminated, dst1, src2, "XYZ "); + WriteTest(maybeNullTerminated, dst1, src3, "XYZ!"); + + // Check writing of space-padded strings with last character set to null + WriteTest(spacePaddedNull, dst1, src1, "X "); + WriteTest(spacePaddedNull, dst1, src2, "XYZ "); + WriteTest(spacePaddedNull, dst1, src3, "XYZ! "); + + // Check writing of space-padded strings + WriteTest(spacePadded, dst1, src1, "X "); + WriteTest(spacePadded, dst1, src2, "XYZ "); + WriteTest(spacePadded, dst1, src3, "XYZ! "); + + /////////////////////////////// + + // Check writing of null-terminated string into smaller buffer + WriteTest(nullTerminated, dst2, src1, "X "); + WriteTest(nullTerminated, dst2, src2, "XY"); + WriteTest(nullTerminated, dst2, src3, "XY"); + + // Check writing of string that should be null-terminated, but is maybe too long to still hold the null character. + WriteTest(maybeNullTerminated, dst2, src1, "X "); + WriteTest(maybeNullTerminated, dst2, src2, "XYZ"); + WriteTest(maybeNullTerminated, dst2, src3, "XYZ"); + + // Check writing of space-padded strings with last character set to null + WriteTest(spacePaddedNull, dst2, src1, "X "); + WriteTest(spacePaddedNull, dst2, src2, "XY"); + WriteTest(spacePaddedNull, dst2, src3, "XY"); + + // Check writing of space-padded strings + WriteTest(spacePadded, dst2, src1, "X "); + WriteTest(spacePadded, dst2, src2, "XYZ"); + WriteTest(spacePadded, dst2, src3, "XYZ"); + + /////////////////////////////// + + // Test FixNullString() + StringFixer::FixNullString(src1); + StringFixer::FixNullString(src2); + StringFixer::FixNullString(src3); + VERIFY_EQUAL_NONCONT(strncmp(src1, "X ", CountOf(src1)), 0); + VERIFY_EQUAL_NONCONT(strncmp(src2, "XYZ", CountOf(src2)), 0); + VERIFY_EQUAL_NONCONT(strncmp(src3, "XYZ", CountOf(src3)), 0); + +#undef ReadTest +#undef WriteTest + +} + }; //Namespace MptTest #else //Case: ENABLE_TESTS is not defined. Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -124,10 +124,8 @@ return; } - memcpy(mptIns.name, name, 26); - StringFixer::SpaceToNullStringFixed<25>(mptIns.name); - memcpy(mptIns.filename, filename, 13); - StringFixer::SpaceToNullStringFixed<12>(mptIns.filename); + StringFixer::ReadString<StringFixer::spacePaddedNull>(mptIns.name, name); + StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.filename, filename); // Volume / Panning mptIns.nFadeOut = LittleEndianW(fadeout) << 6; @@ -195,10 +193,8 @@ id = LittleEndian(ITInstrument::magic); trkvers = LittleEndianW(0x0214); - memcpy(filename, mptIns.filename, 13); - StringFixer::FixNullString(filename); - memcpy(name, mptIns.name, 26); - StringFixer::FixNullString(name); + StringFixer::WriteString<StringFixer::nullTerminated>(filename, mptIns.filename); + StringFixer::WriteString<StringFixer::nullTerminated>(name, mptIns.name); // Volume / Panning fadeout = LittleEndianW(static_cast<uint16>(min(mptIns.nFadeOut >> 5, 256))); @@ -278,10 +274,8 @@ return 0; } - memcpy(mptIns.name, name, 26); - StringFixer::SpaceToNullStringFixed<25>(mptIns.name); - memcpy(mptIns.filename, filename, 13); - StringFixer::SpaceToNullStringFixed<12>(mptIns.filename); + StringFixer::ReadString<StringFixer::spacePaddedNull>(mptIns.name, name); + StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.filename, filename); // Volume / Panning mptIns.nFadeOut = LittleEndianW(fadeout) << 5; @@ -438,10 +432,8 @@ // Header id = LittleEndian(ITSample::magic); - memcpy(filename, mptSmp.filename, 13); - StringFixer::FixNullString(filename); - //memcpy(name, m_szNames[nsmp], 26); - //StringFixer::FixNullString(name); + StringFixer::WriteString<StringFixer::nullTerminated>(filename, mptSmp.filename); + //StringFixer::WriteString<StringFixer::nullTerminated>(name, m_szNames[nsmp]); // Volume / Panning gvl = static_cast<BYTE>(mptSmp.nGlobalVol); @@ -507,8 +499,7 @@ return 0; } - memcpy(mptSmp.filename, filename, 13); - StringFixer::SpaceToNullStringFixed<12>(mptSmp.filename); + StringFixer::ReadString<StringFixer::nullTerminated>(mptSmp.filename, filename); mptSmp.uFlags = 0; Modified: trunk/OpenMPT/soundlib/ITTools.h =================================================================== --- trunk/OpenMPT/soundlib/ITTools.h 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/ITTools.h 2012-03-21 00:36:20 UTC (rev 1226) @@ -47,7 +47,7 @@ }; uint32 id; // Magic Bytes (IMPM) - char songname[26]; // Song Name (duh) + char songname[26]; // Song Name, null-terminated (but may also contain nulls) uint8 highlight_minor; // Rows per Beat highlight uint8 highlight_major; // Rows per Measure highlight uint16 ordnum; // Number of Orders @@ -65,7 +65,7 @@ uint8 sep; // Pan Separation (0...128) uint8 pwd; // Pitch Wheel Depth uint16 msglength; // Length of Song Message - uint32 msgoffset; // Offset of Song Message in File + uint32 msgoffset; // Offset of Song Message in File (IT crops message after first null) uint32 reserved; // ChibiTracker writes "CHBI" here. OpenMPT writes "OMPT" here in some cases, see Load_it.cpp uint8 chnpan[64]; // Initial Channel Panning uint8 chnvol[64]; // Initial Channel Volume @@ -124,7 +124,7 @@ }; uint32 id; // Magic Bytes (IMPI) - char filename[13]; // DOS Filename + char filename[13]; // DOS Filename, null-terminated uint8 flags; // Volume Envelope Flags uint8 vls; // Envelope Loop Start uint8 vle; // Envelope Loop End @@ -137,7 +137,7 @@ uint16 trkvers; // Tracker ID uint8 nos; // Number of embedded samples char reserved2; // Reserved - char name[26]; // Instrument Name + char name[26]; // Instrument Name, null-terminated (but may also contain nulls) char reserved3[6]; // Even more reserved bytes uint8 keyboard[240]; // Sample / Transpose map uint8 volenv[200]; // This appears to be a pre-computed (interpolated) version of the volume envelope data found below. @@ -167,7 +167,7 @@ }; uint32 id; // Magic Bytes (IMPI) - char filename[13]; // DOS Filename + char filename[13]; // DOS Filename, null-terminated uint8 nna; // New Note Action uint8 dct; // Duplicate Note Check Type uint8 dca; // Duplicate Note Check Action @@ -181,7 +181,7 @@ uint16 trkvers; // Tracker ID uint8 nos; // Number of embedded samples char reserved1; // Reserved - char name[26]; // Instrument Name + char name[26]; // Instrument Name, null-terminated (but may also contain nulls) uint8 ifc; // Filter Cutoff uint8 ifr; // Filter Resonance uint8 mch; // MIDI Channel @@ -246,15 +246,15 @@ cvtSignedSample = 0x01, cvtIT215Compression = 0x04, - cvtADPCMSample = 0xFF + cvtADPCMSample = 0xFF, // MODPlugin :( }; uint32 id; // Magic Bytes (IMPS) - char filename[13]; // DOS Filename + char filename[13]; // DOS Filename, null-terminated uint8 gvl; // Global Volume uint8 flags; // Sample Flags uint8 vol; // Default Volume - char name[26]; // Sample Name + char name[26]; // Sample Name, null-terminated (but may also contain nulls) uint8 cvt; // Sample Import Format uint8 dfp; // Sample Panning uint32 length; // Sample Length (in samples) Modified: trunk/OpenMPT/soundlib/LOAD_AMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-03-21 00:36:20 UTC (rev 1226) @@ -193,8 +193,8 @@ for (UINT iSmp=0; iSmp<numsamples; iSmp++) { ModSample *psmp = &Samples[iSmp+1]; - memcpy(m_szNames[iSmp + 1], lpStream+dwMemPos, 22); - StringFixer::SpaceToNullStringFixed<22>(m_szNames[iSmp + 1]); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[iSmp + 1], reinterpret_cast<const char *>(lpStream + dwMemPos), 22); + psmp->nGlobalVol = 64; psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]); psmp->nVolume = lpStream[dwMemPos+23]; @@ -267,8 +267,9 @@ || (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES) || (pfh->numchannels < 1) || (pfh->numchannels > 32)) return false; - memcpy(m_szNames[0], pfh->title, 31); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pfh->title); + dwMemPos = sizeof(AMFFILEHEADER); m_nType = MOD_TYPE_AMF; m_nChannels = pfh->numchannels; @@ -327,10 +328,9 @@ AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos); dwMemPos += sizeof(AMFSAMPLE); - memcpy(m_szNames[iIns+1], psh->samplename, 31); - memcpy(pSmp->filename, psh->filename, 13); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[iIns + 1]); - StringFixer::SpaceToNullStringFixed<13>(pSmp->filename); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[iIns + 1], psh->samplename); + StringFixer::ReadString<StringFixer::nullTerminated>(pSmp->filename, psh->filename); + pSmp->nLength = LittleEndian(psh->length); pSmp->nC5Speed = LittleEndianW(psh->c2spd); pSmp->nGlobalVol = 64; Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-21 00:36:20 UTC (rev 1226) @@ -194,8 +194,16 @@ nPatterns = BigEndianW(pfh->patterns); m_nType = MOD_TYPE_DBM; m_nChannels = CLAMP(BigEndianW(pfh->channels), 1, MAX_BASECHANNELS); // note: MAX_BASECHANNELS is currently 127, but DBM supports up to 128 channels. - memcpy(m_szNames[0], (pfh->songname[0]) ? pfh->songname : pfh->songname2, 32); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + + if(pfh->songname[0]) + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pfh->songname); + } else + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pfh->songname2); + + } + Order.resize(nOrders, Order.GetInvalidPatIndex()); for (UINT iOrd=0; iOrd < nOrders; iOrd++) { @@ -240,12 +248,10 @@ Instruments[iIns + 1] = pIns; - memcpy(pIns->name, pih->name, 30); - StringFixer::SpaceToNullStringFixed<30>(pIns->name); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(pIns->name, pih->name); if (psmp) { - memcpy(m_szNames[nsmp], pih->name, 30); - StringFixer::SpaceToNullStringFixed<30>(m_szNames[nsmp]); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[nsmp], pih->name); } pIns->nFadeOut = 1024; // ??? Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2012-03-21 00:36:20 UTC (rev 1226) @@ -749,11 +749,8 @@ ASSERT_CAN_READ_SAMPLE(1); const size_t lenName = lpStream[dwMemPos++]; - STATIC_ASSERT(MAX_SAMPLENAME > 30); - const size_t lenNameImport = min(30, lenName); ASSERT_CAN_READ_SAMPLE(lenName); - memcpy(pSndFile->m_szNames[nSmp], lpStream + dwMemPos, lenNameImport); - StringFixer::SpaceToNullStringFixed(pSndFile->m_szNames[nSmp], lenNameImport); + StringFixer::ReadString<StringFixer::spacePadded>(pSndFile->m_szNames[nSmp], reinterpret_cast<const char *>(lpStream + dwMemPos), lenName); dwMemPos += lenName; ASSERT_CAN_READ_SAMPLE(sizeof(DMFCHUNK_SAMPLEHEADER)); @@ -797,8 +794,7 @@ { // Read library name in version 8 files ASSERT_CAN_READ_SAMPLE(8); - memcpy(sample.filename, lpStream + dwMemPos, 8); - StringFixer::SpaceToNullStringFixed<8>(sample.filename); + StringFixer::ReadString<StringFixer::spacePadded>(sample.filename, reinterpret_cast<const char *>(lpStream + dwMemPos), 8); dwMemPos += 8; } @@ -828,8 +824,7 @@ } dwMemPos += sizeof(DMFHEADER); - memcpy(m_szNames[0], pHeader->songname, 30); - StringFixer::SpaceToNullStringFixed<30>(m_szNames[0]); + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], pHeader->songname); m_nChannels = 0; #ifdef MODPLUG_TRACKER Modified: trunk/OpenMPT/soundlib/LOAD_DSM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DSM.CPP 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/LOAD_DSM.CPP 2012-03-21 00:36:20 UTC (rev 1226) @@ -120,8 +120,9 @@ ChnSettings[iPan].nPan = psong->panpos[iPan] << 1; } } - memcpy(m_szNames[0], psong->songname, 28); - StringFixer::SpaceToNullStringFixed<28>(m_szNames[0]); + + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], psong->songname); + nPat = 0; nSmp = 1; while (dwMemPos < dwMemLength - 8) @@ -214,11 +215,12 @@ if (dwMemPos + pSmp->inst_len >= dwMemLength - 8) break; DWORD dwPos = dwMemPos + sizeof(DSMSAMPLE); dwMemPos += 8 + pSmp->inst_len; - memcpy(m_szNames[nSmp], pSmp->samplename, 28); - StringFixer::SpaceToNullStringFixed<28>(m_szNames[nSmp]); + ModSample *psmp = &Samples[nSmp]; - memcpy(psmp->filename, pSmp->filename, 13); - StringFixer::SpaceToNullStringFixed<13>(psmp->filename); + + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[nSmp], pSmp->samplename); + StringFixer::ReadString<StringFixer::nullTerminated>(psmp->filename, pSmp->filename); + psmp->nGlobalVol = 64; psmp->nC5Speed = pSmp->c2spd; psmp->uFlags = (WORD)((pSmp->flags & 1) ? CHN_LOOP : 0); Modified: trunk/OpenMPT/soundlib/Load_669.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_669.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_669.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -30,10 +30,10 @@ typedef struct tagSAMPLE669 { - BYTE filename[13]; - BYTE length[4]; // when will somebody think about DWORD align ??? - BYTE loopstart[4]; - BYTE loopend[4]; + char filename[13]; + uint32 length; // when will somebody think about DWORD align ??? + uint32 loopStart; + uint32 loopEnd; } SAMPLE669; @@ -54,7 +54,7 @@ if (dontfuckwithme > dwMemLength) return false; for (UINT ichk=0; ichk<pfh->samples; ichk++) { - DWORD len = LittleEndian(*((DWORD *)(&psmp[ichk].length))); + DWORD len = LittleEndian(psmp[ichk].length); dontfuckwithme += len; } if (dontfuckwithme - 0x1F1 > dwMemLength) return false; @@ -67,15 +67,15 @@ m_nDefaultSpeed = 6; m_nChannels = 8; - memcpy(m_szNames[0], pfh->songmessage, min(MAX_SAMPLENAME - 1, 36)); - StringFixer::SpaceToNullStringFixed<min(MAX_SAMPLENAME - 1, 36)>(m_szNames[0]); + // Copy first song message line into song title + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], reinterpret_cast<const char *>(pfh->songmessage), 36); m_nSamples = pfh->samples; for (SAMPLEINDEX nSmp = 1; nSmp <= m_nSamples; nSmp++, psmp++) { - DWORD len = LittleEndian(*((DWORD *)(&psmp->length))); - DWORD loopstart = LittleEndian(*((DWORD *)(&psmp->loopstart))); - DWORD loopend = LittleEndian(*((DWORD *)(&psmp->loopend))); + DWORD len = LittleEndian(psmp->length); + DWORD loopstart = LittleEndian(psmp->loopStart); + DWORD loopend = LittleEndian(psmp->loopEnd); if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH; if ((loopend > len) && (!loopstart)) loopend = 0; if (loopend > len) loopend = len; @@ -84,8 +84,7 @@ Samples[nSmp].nLoopStart = loopstart; Samples[nSmp].nLoopEnd = loopend; if (loopend) Samples[nSmp].uFlags |= CHN_LOOP; - memcpy(m_szNames[nSmp], psmp->filename, 13); - StringFixer::SpaceToNullStringFixed<13>(m_szNames[nSmp]); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nSmp], psmp->filename); Samples[nSmp].nVolume = 256; Samples[nSmp].nGlobalVol = 64; Samples[nSmp].nPan = 128; Modified: trunk/OpenMPT/soundlib/Load_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -112,34 +112,28 @@ // Read Song Name if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; - if (dwMemPos + tmp + 1 >= dwMemLength) return true; - tmp2 = (tmp < 32) ? tmp : 31; - if (tmp2) memcpy(m_szNames[0], lpStream + dwMemPos, tmp2); - StringFixer::SpaceToNullStringFixed(m_szNames[0], tmp2); - m_szNames[0][tmp2] = 0; + if (dwMemPos + tmp >= dwMemLength) return true; + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); + dwMemPos += tmp; // Read sample names for (UINT sNam=1; sNam<=m_nSamples; sNam++) { - if (dwMemPos + 32 >= dwMemLength) return true; + if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; - tmp2 = (tmp < 32) ? tmp : 31; - if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2); - StringFixer::SpaceToNullStringFixed(m_szNames[sNam], tmp2); + if (dwMemPos + tmp >= dwMemLength) return true; + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[sNam], reinterpret_cast<const char *>(lpStream + dwMemPos), tmp); dwMemPos += tmp; } // Read Channel names for (UINT cNam=0; cNam<m_nChannels; cNam++) { - if (dwMemPos + 32 >= dwMemLength) return true; - BYTE chnnamlen = lpStream[dwMemPos++]; - if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME)) - { - memcpy(ChnSettings[cNam].szName, lpStream + dwMemPos, chnnamlen); - StringFixer::SpaceToNullStringFixed(ChnSettings[cNam].szName, chnnamlen); - } + if (dwMemPos + 1 >= dwMemLength) return true; + uint8 chnnamlen = lpStream[dwMemPos++]; + if (dwMemPos + tmp >= dwMemLength) return true; + StringFixer::ReadString<StringFixer::maybeNullTerminated>(ChnSettings[cNam].szName, reinterpret_cast<const char *>(lpStream + dwMemPos), chnnamlen); dwMemPos += chnnamlen; } Modified: trunk/OpenMPT/soundlib/Load_far.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_far.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_far.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -21,8 +21,9 @@ typedef struct FARHEADER1 { DWORD id; // file magic FAR= - CHAR songname[40]; // songname - CHAR magic2[3]; // 13,10,26 + char songname[32]; // songname + uint8 reserved[8]; + char eofMagic[3]; // 13,10,26 WORD headerlen; // remaining length of header in bytes BYTE version; // 0xD1 BYTE onoff[16]; @@ -71,8 +72,12 @@ UINT headerlen; BYTE samplemap[8]; - if ((!lpStream) || (dwMemLength < 1024) || (LittleEndian(pmh1->id) != FARFILEMAGIC) - || (pmh1->magic2[0] != 13) || (pmh1->magic2[1] != 10) || (pmh1->magic2[2] != 26)) return false; + if ((!lpStream) || (dwMemLength < 1024) || (pmh1->id != LittleEndian(FARFILEMAGIC)) + || (pmh1->eofMagic[0] != 13) || (pmh1->eofMagic[1] != 10) || (pmh1->eofMagic[2] != 26)) + { + return false; + } + headerlen = LittleEndianW(pmh1->headerlen); pmh1->stlen = LittleEndianW( pmh1->stlen ); /* inplace byteswap -- Toad */ if ((headerlen >= dwMemLength) || (dwMemPos + pmh1->stlen + sizeof(FARHEADER2) >= dwMemLength)) return false; @@ -86,8 +91,7 @@ m_nDefaultTempo = 80; m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; - memcpy(m_szNames[0], pmh1->songname, 31); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pmh1->songname); // Channel Setting for (UINT nchpan=0; nchpan<16; nchpan++) @@ -244,9 +248,10 @@ const FARSAMPLE *pfs = reinterpret_cast<const FARSAMPLE*>(lpStream + dwMemPos); dwMemPos += sizeof(FARSAMPLE); m_nSamples = ismp + 1; - memcpy(m_szNames[ismp+1], pfs->samplename, 31); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[ismp + 1]); - const DWORD length = LittleEndian( pfs->length ); + + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[ismp+1], pfs->samplename); + + const DWORD length = LittleEndian(pfs->length); pSmp->nLength = length; pSmp->nLoopStart = LittleEndian(pfs->reppos) ; pSmp->nLoopEnd = LittleEndian(pfs->repend) ; Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -105,8 +105,7 @@ // Song name MemsetZero(m_szNames); - memcpy(m_szNames[0], pHeader->SongTitle, 32); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pHeader->SongTitle); // Read channel pan map... 0...15 = channel panning, 16 = surround channel, 255 = channel does not exist m_nChannels = 32; @@ -166,10 +165,8 @@ // Sample header - memcpy(m_szNames[iSmp], pSample->SamName, 32); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[iSmp]); - memcpy(Samples[iSmp].filename, pSample->FileName, 12); - StringFixer::SpaceToNullStringFixed<12>(Samples[iSmp].filename); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[iSmp], pSample->SamName); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(Samples[iSmp].filename, pSample->FileName); Samples[iSmp].nC5Speed = LittleEndianW(pSample->C4Hertz); Samples[iSmp].nGlobalVol = 256; // not supported in this format Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -293,8 +293,7 @@ // song name MemsetZero(m_szNames); - memcpy(m_szNames[0], hdr.title, 31); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], hdr.title); if(hdr.flags & 1) m_dwSongFlags |= SONG_LINEARSLIDES; @@ -312,8 +311,7 @@ ChnSettings[nChn].nPan = hdr.channels[nChn].panning * 64 / 255; ChnSettings[nChn].nPan *= 4; - memcpy(ChnSettings[nChn].szName, hdr.channels[nChn].name, 12); - StringFixer::SpaceToNullStringFixed<12>(ChnSettings[nChn].szName); + StringFixer::ReadString<StringFixer::nullTerminated>(ChnSettings[nChn].szName, hdr.channels[nChn].name); // TODO: reverb/chorus? switch(hdr.channels[nChn].status) @@ -504,8 +502,7 @@ Instruments[nIns + 1] = pIns; - memcpy(pIns->name, imfins.name, 31); - StringFixer::SpaceToNullStringFixed<31>(pIns->name); + StringFixer::ReadString<StringFixer::nullTerminated>(pIns->name, imfins.name); if(imfins.smpnum) { @@ -542,8 +539,7 @@ ModSample &sample = Samples[firstsample + nSmp]; - memcpy(sample.filename, imfsmp.filename, 12); - StringFixer::SpaceToNullStringFixed<12>(sample.filename); + StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, imfsmp.filename); strcpy(m_szNames[m_nSamples], sample.filename); uint32 byteLen = sample.nLength = LittleEndian(imfsmp.length); Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -406,8 +406,7 @@ if ((itHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (itHeader.special & ITFileHeader::embedMIDIConfiguration)) m_dwSongFlags |= SONG_EMBEDMIDICFG; if (itHeader.flags & ITFileHeader::extendedFilterRange) m_dwSongFlags |= SONG_EXFILTERRANGE; - memcpy(m_szNames[0], itHeader.songname, 26); - StringFixer::SpaceToNullStringFixed<26>(m_szNames[0]); + StringFixer::ReadString<StringFixer::spacePaddedNull>(m_szNames[0], itHeader.songname); // Global Volume m_nDefaultGlobalVolume = itHeader.globalvol << 1; @@ -763,8 +762,7 @@ { size_t sampleOffset = pis->ConvertToMPT(Samples[nsmp + 1]); - memcpy(m_szNames[nsmp + 1], pis->name, 26); - StringFixer::SpaceToNullStringFixed<25>(m_szNames[nsmp + 1]); + StringFixer::ReadString<StringFixer::spacePaddedNull>(m_szNames[nsmp + 1], pis->name); lastSampleOffset = Util::Max(lastSampleOffset, sampleOffset + ReadSample(&Samples[nsmp + 1], pis->GetSampleFormat(itHeader.cwtv), (LPSTR)(lpStream + sampleOffset), dwMemLength - sampleOffset)); } @@ -1090,10 +1088,10 @@ #pragma warning(disable:4100) -bool CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking, const bool compatExport) -//---------------------------------------------------------------------------------- +bool CSoundFile::SaveIT(LPCSTR lpszFileName, bool compatibilityExport) +//-------------------------------------------------------------------- { - const CModSpecifications &specs = (GetType() == MOD_TYPE_MPT ? ModSpecs::mptm : (compatExport ? ModSpecs::it : ModSpecs::itEx)); + const CModSpecifications &specs = (GetType() == MOD_TYPE_MPT ? ModSpecs::mptm : (compatibilityExport ? ModSpecs::it : ModSpecs::itEx)); DWORD dwChnNamLen; ITFileHeader itHeader; @@ -1106,7 +1104,7 @@ MemsetZero(itHeader); dwChnNamLen = 0; itHeader.id = ITFileHeader::itMagic; - lstrcpyn(itHeader.songname, m_szNames[0], 26); + StringFixer::WriteString<StringFixer::nullTerminated>(itHeader.songname, m_szNames[0]); itHeader.highlight_minor = (BYTE)min(m_nDefaultRowsPerBeat, 0xFF); itHeader.highlight_major = (BYTE)min(m_nDefaultRowsPerMeasure, 0xFF); @@ -1156,7 +1154,7 @@ } } - if(!compatExport) + if(!compatibilityExport) { // This way, we indicate that the file will most likely contain OpenMPT hacks. Compatibility export puts 0 here. itHeader.reserved = ITFileHeader::omptMagic; @@ -1169,7 +1167,7 @@ if (m_dwSongFlags & SONG_LINEARSLIDES) itHeader.flags |= ITFileHeader::linearSlides; if (m_dwSongFlags & SONG_ITOLDEFFECTS) itHeader.flags |= ITFileHeader::itOldEffects; if (m_dwSongFlags & SONG_ITCOMPATGXX) itHeader.flags |= ITFileHeader::itCompatGxx; - if ((m_dwSongFlags & SONG_EXFILTERRANGE) && !compatExport) itHeader.flags |= ITFileHeader::extendedFilterRange; + if ((m_dwSongFlags & SONG_EXFILTERRANGE) && !compatibilityExport) itHeader.flags |= ITFileHeader::extendedFilterRange; itHeader.globalvol = m_nDefaultGlobalVolume >> 1; itHeader.mv = min(m_nSamplePreAmp, 128); itHeader.speed = m_nDefaultSpeed; @@ -1189,7 +1187,7 @@ } // Channel names - if(!compatExport) + if(!compatibilityExport) { for (UINT ich=0; ich<m_nChannels; ich++) { @@ -1209,14 +1207,14 @@ } // Pattern Names - const PATTERNINDEX numNamedPats = compatExport ? 0 : Patterns.GetNumNamedPatterns(); + const PATTERNINDEX numNamedPats = compatibilityExport ? 0 : Patterns.GetNumNamedPatterns(); if(numNamedPats > 0) { dwExtra += (numNamedPats * MAX_PATTERNNAME) + 8; } // Mix Plugins. Just calculate the size of this extra block for now. - if(!compatExport) + if(!compatibilityExport) { dwExtra += SaveMixPlugins(NULL, TRUE); } @@ -1270,7 +1268,7 @@ } // Writing channel names - if(dwChnNamLen && !compatExport) + if(dwChnNamLen && !compatibilityExport) { DWORD d = LittleEndian(magicChannelNames); // "CNAM" fwrite(&d, 1, 4, f); @@ -1283,7 +1281,7 @@ } // Writing mix plugins info - if(!compatExport) + if(!compatibilityExport) { SaveMixPlugins(f, FALSE); } @@ -1304,12 +1302,12 @@ if(Instruments[nins]) { - instSize = iti.ConvertToIT(*Instruments[nins], compatExport, *this); + instSize = iti.ConvertToIT(*Instruments[nins], compatibilityExport, *this); } else // Save Empty Instrument { ModInstrument dummy; - instSize = iti.ConvertToIT(dummy, compatExport, *this); + instSize = iti.ConvertToIT(dummy, compatibilityExport, *this); } // Writing instrument @@ -1318,7 +1316,7 @@ fwrite(&iti, 1, instSize, f); //------------ rewbs.modularInstData - if (Instruments[nins] && !compatExport) + if (Instruments[nins] && !compatibilityExport) { dwPos += SaveModularInstrumentData(f, Instruments[nins]); } @@ -1417,7 +1415,7 @@ case VOLCMD_TONEPORTAMENTO: vol = 193 + ConvertVolParam(m); break; case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m); break; case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m); break; - case VOLCMD_OFFSET: if(!compatExport) vol = 223 + ConvertVolParam(m); //rewbs.volOff + case VOLCMD_OFFSET: if(!compatibilityExport) vol = 223 + ConvertVolParam(m); //rewbs.volOff break; default: vol = 0xFF; } @@ -1425,7 +1423,7 @@ if (vol != 0xFF) b |= 4; if (command) { - S3MSaveConvert(&command, ¶m, true, compatExport); + S3MSaveConvert(&command, ¶m, true, compatibilityExport); if (command) b |= 8; } // Packing information @@ -1532,8 +1530,7 @@ { itss.ConvertToIT(Samples[nsmp], GetType()); - memcpy(itss.name, m_szNames[nsmp], 26); - StringFixer::FixNullString(itss.name); + StringFixer::WriteString<StringFixer::nullTerminated>(itss.name, m_szNames[nsmp]); itss.samplepointer = dwPos; fseek(f, smppos[nsmp - 1], SEEK_SET); @@ -1546,7 +1543,7 @@ } //Save hacked-on extra info - if(!compatExport) + if(!compatibilityExport) { SaveExtendedInstrumentProperties(itHeader.insnum, f); SaveExtendedSongProperties(f); Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -336,8 +336,7 @@ { pis.ConvertToMPT(Samples[nsmp]); - memcpy(m_szNames[nsmp], pis.name, 26); - StringFixer::SpaceToNullStringFixed<25>(m_szNames[nsmp]); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[nsmp], pis.name); // Read sample data ReadSample(&Samples[nsmp], pis.GetSampleFormat(), (LPSTR)(lpStream + dwMemPos), len); @@ -622,8 +621,7 @@ ITSample itss; itss.ConvertToIT(Samples[nsmp], GetType()); - memcpy(itss.name, m_szNames[nsmp], 26); - StringFixer::FixNullString(itss.name); + StringFixer::WriteString<StringFixer::nullTerminated>(itss.name, m_szNames[nsmp]); id = nsmp; fwrite(&id, 1, sizeof(id), f); Modified: trunk/OpenMPT/soundlib/Load_mdl.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mdl.cpp 2012-03-20 16:27:14 UTC (rev 1225) +++ trunk/OpenMPT/soundlib/Load_mdl.cpp 2012-03-21 00:36:20 UTC (rev 1226) @@ -1,7 +1,7 @@ /* * Load_mdl.cpp * ------------ - * Purpose: DigiTracker (MDL) module loader + * Purpose: DigiTrakker (MDL) module loader * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs @@ -16,36 +16,77 @@ #pragma warning(disable:4244) //"conversion from 'type1' to 'type2', possible loss of data" -typedef struct MDLSONGHEADER +#pragma pack(push, 1) + +struct MDLFileHeader { DWORD id; // "DMDL" = 0x4C444D44 BYTE version; -} MDLSONGHEADER; +}; -typedef struct MDLINFOBLOCK +struct MDLInfoBlock { - CHAR songname[32]; - CHAR composer[20]; - WORD norders; - WORD repeatpos; - BYTE globalvol; - BYTE speed; - BYTE tempo; - BYTE channelinfo[32]; - BYTE seq[256]; -} MDLINFOBLOCK; + char songname[32]; + char composer[20]; + uint16 norders; + uint16 repeatpos; + uint8 globalvol; + uint8 speed; + uint8 tempo; + uint8 channelinfo[32]; + uint8 seq[256]; +}; -typedef struct MDLPATTERNDATA +struct MDLPatternHeader { - BYTE channels; - BYTE lastrow; // nrows = lastrow+1 - CHAR name[16]; - WORD data[1]; -} MDLPATTERNDATA; + uint8 channels; + uint8 lastrow; // nrows = lastrow+1 + char name[16]; + uint16 data[1]; +}; +struct MDLSampleHeaderCommon +{ + uint8 sampleIndex; + char name[32]; + char filename[8]; +}; + + +struct MDLSampleHeader +{ + MDLSampleHeaderCommon info; + uint32 c4Speed; + uint32 length; + uint32 loopStart; + uint32 loopLength; + uint8 unused; // was volume in v0.0, why it was changed I have no idea + uint8 flags; +}; + +STATIC_ASSERT(sizeof(MDLSampleHeader) == 59); + + +struct MDLSampleHeaderv0 +{ + MDLSampleHeaderCommon info; + uint16 c4Speed; + uint32 length; + uint32 loopStart; + uint32 loopLength; + uint8 volume; + uint8 flags; +}; + +STATIC_ASSERT(sizeof(MDLSampleHeaderv0) == 57); + + +#pragma pack(pop) + + void ConvertMDLCommand(ModCommand *m, UINT eff, UINT data) //-------------------------------------------------------- { @@ -235,8 +276,8 @@ //--------------------------------------------------------------------- { DWORD dwMemPos, dwPos, blocklen, dwTrackPos; - const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream; - MDLINFOBLOCK *pmib; + const MDLFileHeader *pmsh = (const MDLFileHeader *)lpStream; + MDLInfoBlock *pmib; UINT i,j, norders = 0, npatterns = 0, ntracks = 0; UINT ninstruments = 0, nsamples = 0; WORD block; @@ -253,10 +294,10 @@ #ifdef MDL_LOG Log("MDL v%d.%d\n", pmsh->version>>4, pmsh->version&0x0f); #endif - memset(patterntracks, 0, sizeof(patterntracks)); - memset(smpinfo, 0, sizeof(smpinfo)); - memset(insvolenv, 0, sizeof(insvolenv)); - memset(inspanenv, 0, sizeof(inspanenv)); + MemsetZero(patterntracks); + MemsetZero(smpinfo); + MemsetZero(insvolenv); + MemsetZero(inspanenv); dwMemPos = 5; dwTrackPos = 0; pvolenv = ppanenv = ppitchenv = NULL; @@ -279,9 +320,8 @@ #ifdef MDL_LOG Log("infoblock: %d bytes\n", blocklen); #endif - pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos); - memcpy(m_szNames[0], pmib->songname, 31); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[0]); + pmib = (MDLInfoBlock *)(lpStream+dwMemPos); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], pmib->songname); norders = pmib->norders; if (norders > MAX_ORDERS) norders = MAX_ORDERS; @@ -330,7 +370,7 @@ if (dwPos+18 >= dwMemLength) break; if (pmsh->version > 0) { - const MDLPATTERNDATA *pmpd = (const MDLPATTERNDATA *)(lpStream + dwPos); + const MDLPatternHeader *pmpd = (const MDLPatternHeader *)(lpStream + dwPos); if (pmpd->channels > 32) break; patternLength[i] = pmpd->lastrow + 1; if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels; @@ -383,9 +423,10 @@ break; } ModInstrument *pIns = Instruments[nins]; - memcpy(pIns->name, lpStream+dwPos+2, 32); - StringFixer::SpaceToNullStringFixed<31>(pIns->name); + // I give up. better rewrite this crap (or take SchismTracker's MDL loader). + StringFixer::ReadString<StringFixer::maybeNullTerminated>(pIns->name, reinterpret_cast<const char *>(lpStream + dwPos + 2), 32); + for (j=0; j<lpStream[dwPos+1]; j++) { const BYTE *ps = lpStream+dwPos+34+14*j; @@ -467,41 +508,77 @@ Log("sample infoblock: %d bytes\n", blocklen); #endif nsamples = lpStream[dwMemPos]; - dwPos = dwMemPos+1; - for (i=0; i<nsamples; i++, dwPos += (pmsh->version > 0) ? 59 : 57) + dwPos = dwMemPos + 1; + for (i = 0; i < nsamples; i++, dwPos += (pmsh->version > 0) ? sizeof(MDLSampleHeader) : sizeof(MDLSampleHeaderv0)) { - UINT nins = lpStream[dwPos]; - if ((nins >= MAX_SAMPLES) || (!nins)) continue; - if (m_nSamples < nins) m_nSamples = nins; - ModSample *pSmp = &Samples[nins]; - memcpy(m_szNames[nins], lpStream+dwPos+1, 31); - memcpy(pSmp->filename, lpStream+dwPos+33, 8); - StringFixer::SpaceToNullStringFixed<31>(m_szNames[nins]); - StringFixer::SpaceToNullStringFixed<8>(pSmp->filename); - const BYTE *p = lpStream+dwPos+41; - if (pmsh->version > 0) + const MDLSampleHeaderCommon *info = reinterpret_cast<const MDLSampleHeaderCommon *>(lpStream + dwPos); + if(info->sampleIndex >= MAX_SAMPLES || info->sampleIndex == 0) { - pSmp->nC5Speed = *((DWORD *)p); - p += 4; + continue; + } + + ModSample &sample = Samples[info->sampleIndex]; + + StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[info->sampleIndex], info->name); + StringFixer::ReadString<StringFixer::maybeNullTerminated>(sample.filename, info->filename); + + if(pmsh->version > 0) + { + const MDLSampleHeader *sampleHeader = reinterpret_cast<const MDLSampleHeader *>(lpStream + dwPos); + + sample.nC5Speed = LittleEndian(sampleHeader->c4Speed); + sample.nLength = LittleEndian(sampleHeader->length); + sample.nLoopStart = LittleEndian(sampleHeader->loopStart); + sample.nLoopEnd = sample.nLoopStart + LittleEndian(sampleHeader->loopLength); + if(sample.nLoopEnd > sample.nLoopStart) + { + sample.uFlags |= CHN_LOOP; + if((sampleHeader->flags & 0x02)) + { + sample.uFlags |= CHN_PINGPONGLOOP; + } + } + sample.nGlobalVol = 64; + sample.nVolume = 256; + + if((sampleHeader->flags & 0x01)) + { + sample.uFlags |= CHN_16BIT; + sample.nLength /= 2; + sample.nLoopStart /= 2; + sample.nLoopEnd /= 2; + } + + smpinfo[info->sampleIndex] = (sampleHeader->flags >> 2) & 3; } else { - pSmp->nC5Speed = *((WORD *)p); - p += 2; + const MDLSampleHeaderv0 *sampleHeader = reinterpret_cast<const MDLSampleHeaderv0 *>(lpStream + dwPos); + + sample.nC5Speed = LittleEndianW(sampleHeader->c4Speed); + sample.... [truncated message content] |
From: <sag...@us...> - 2012-03-21 14:19:06
|
Revision: 1227 http://modplug.svn.sourceforge.net/modplug/?rev=1227&view=rev Author: saga-games Date: 2012-03-21 14:18:54 +0000 (Wed, 21 Mar 2012) Log Message: ----------- [Fix] DBM Loader: Global volume command was broken since OpenMPT 1.19.02.00 [Imp] XM Loader: Samples that are not associated to any instrument are now tried to be written to the XM file anyway (http://forum.openmpt.org/index.php?topic=4688.0, http://bugs.openmpt.org/view.php?id=234). [Mod] OpenMPT: Version is now 1.20.00.80 Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/LOAD_DBM.CPP trunk/OpenMPT/soundlib/Load_xm.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/mptrack/version.h 2012-03-21 14:18:54 UTC (rev 1227) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 79 +#define VER_MINORMINOR 80 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-21 14:18:54 UTC (rev 1227) @@ -26,70 +26,70 @@ #pragma pack(push, 1) -typedef struct DBMFILEHEADER +struct DBMFileHeader { - DWORD dbm_id; // "DBM0" = 0x304d4244 - WORD trkver; // Tracker version: 02.15 - WORD reserved; - DWORD name_id; // "NAME" = 0x454d414e - DWORD name_len; // name length: always 44 - CHAR songname[44]; - DWORD info_id; // "INFO" = 0x4f464e49 - DWORD info_len; // 0x0a000000 - WORD instruments; - WORD samples; - WORD songs; - WORD patterns; - WORD channels; - DWORD song_id; // "SONG" = 0x474e4f53 - DWORD song_len; - CHAR songname2[44]; - WORD orders; -// WORD orderlist[0]; // orderlist[orders] in words -} DBMFILEHEADER; + uint32 dbm_id; // "DBM0" = 0x304d4244 + uint16 trkver; // Tracker version: 02.15 + uint16 reserved; + uint32 name_id; // "NAME" = 0x454d414e + uint32 name_len; // name length: always 44 + char songname[44]; + uint32 info_id; // "INFO" = 0x4f464e49 + uint32 info_len; // 0x0a000000 + uint16 instruments; + uint16 samples; + uint16 songs; + uint16 patterns; + uint16 channels; + uint32 song_id; // "SONG" = 0x474e4f53 + uint32 song_len; + char songname2[44]; + uint16 orders; +// uint16 orderlist[0]; // orderlist[orders] in words +}; -typedef struct DBMINSTRUMENT +struct DBMInstrument { - CHAR name[30]; - WORD sampleno; - WORD volume; - DWORD finetune; - DWORD loopstart; - DWORD looplen; - WORD panning; - WORD flags; -} DBMINSTRUMENT; + char name[30]; + uint16 sampleno; + uint16 volume; + uint32 finetune; + uint32 loopstart; + uint32 looplen; + uint16 panning; + uint16 flags; +}; -typedef struct DBMENVELOPE +struct DBMEnvelope { - WORD instrument; - BYTE flags; - BYTE numpoints; - BYTE sustain1; - BYTE loopbegin; - BYTE loopend; - BYTE sustain2; - WORD volenv[2*32]; -} DBMENVELOPE; + uint16 instrument; + uint8 flags; + uint8 numpoints; + uint8 sustain1; + uint8 loopbegin; + uint8 loopend; + uint8 sustain2; + uint16 volenv[2 * 32]; +}; -typedef struct DBMPATTERN +struct DBMPattern { - WORD rows; - DWORD packedsize; - BYTE patterndata[2]; // [packedsize] -} DBMPATTERN; + uint16 rows; + uint32 packedsize; + uint8 patterndata[2]; // [packedsize] +}; -typedef struct DBMSAMPLE +struct DBMSample { - DWORD flags; - DWORD samplesize; - BYTE sampledata[2]; // [samplesize] -} DBMSAMPLE; + uint32 flags; + uint32 samplesize; + uint8 sampledata[2]; // [samplesize] +}; #pragma pack(pop) -static ModCommand::COMMAND dbm_efftrans[23] = +static const ModCommand::COMMAND dbmEffects[23] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, @@ -103,8 +103,8 @@ void ConvertDBMEffect(uint8 &command, uint8 ¶m) //------------------------------------------------- { - if(command < CountOf(dbm_efftrans)) - command = dbm_efftrans[command]; + if(command < CountOf(dbmEffects)) + command = dbmEffects[command]; else command = CMD_NONE; @@ -114,15 +114,19 @@ if(param == 0) command = CMD_NONE; break; + case CMD_VOLUMESLIDE: if(param & 0xF0) param &= 0xF0; break; + case CMD_GLOBALVOLUME: if(param <= 64) param *= 2; else param = 128; + break; + case CMD_MODCMDEX: switch(param & 0xF0) { @@ -158,15 +162,18 @@ break; } break; + case CMD_TEMPO: if(param <= 0x1F) command = CMD_SPEED; break; + case CMD_KEYOFF: if (param == 0) { // TODO key of at tick 0 } break; + case CMD_OFFSET: // TODO Sample offset slide command = CMD_NONE; @@ -178,15 +185,15 @@ bool CSoundFile::ReadDBM(const BYTE *lpStream, const DWORD dwMemLength) //--------------------------------------------------------------------- { - const DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream; + const DBMFileHeader *pfh = (DBMFileHeader *)lpStream; DWORD dwMemPos; uint16 nOrders, nSamples, nInstruments, nPatterns; - if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels) + if ((!lpStream) || (dwMemLength <= sizeof(DBMFileHeader)) || (!pfh->channels) || (pfh->dbm_id != DBM_FILE_MAGIC) || (!pfh->songs) || (pfh->song_id != DBM_ID_SONG) || (pfh->name_id != DBM_ID_NAME) || (pfh->name_len != DBM_NAMELEN) || (pfh->info_id != DBM_ID_INFO) || (pfh->info_len != DBM_INFOLEN)) return false; - dwMemPos = sizeof(DBMFILEHEADER); + dwMemPos = sizeof(DBMFileHeader); nOrders = BigEndianW(pfh->orders); if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return false; nInstruments = BigEndianW(pfh->instruments); @@ -210,12 +217,12 @@ if (iOrd >= MAX_ORDERS) break; Order[iOrd] = (PATTERNINDEX)BigEndianW(*((WORD *)(lpStream + dwMemPos + iOrd * 2))); } - dwMemPos += 2*nOrders; + dwMemPos += 2 * nOrders; while (dwMemPos + 10 < dwMemLength) { - DWORD chunk_id = LittleEndian(((LPDWORD)(lpStream+dwMemPos))[0]); - DWORD chunk_size = BigEndian(((LPDWORD)(lpStream+dwMemPos))[1]); - DWORD chunk_pos; + uint32 chunk_id = LittleEndian(((uint32 *)(lpStream + dwMemPos))[0]); + uint32 chunk_size = BigEndian(((uint32 *)(lpStream + dwMemPos))[1]); + uint32 chunk_pos; dwMemPos += 8; chunk_pos = dwMemPos; @@ -229,12 +236,12 @@ { ModSample *psmp; ModInstrument *pIns; - DBMINSTRUMENT *pih; - WORD nsmp; + DBMInstrument *pih; + uint16 nsmp; - if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break; + if (chunk_pos + sizeof(DBMInstrument) > dwMemPos) break; - pih = (DBMINSTRUMENT *)(lpStream + chunk_pos); + pih = (DBMInstrument *)(lpStream + chunk_pos); nsmp = BigEndianW(pih->sampleno); psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Samples[nsmp] : nullptr; @@ -262,26 +269,24 @@ pIns->nPan = 128; // Sample Info - if (psmp) + if(psmp) { - DWORD sflags = BigEndianW(pih->flags); + uint16 sflags = BigEndianW(pih->flags); psmp->nVolume = BigEndianW(pih->volume) * 4; - if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256; + if(/*!psmp->nVolume ||*/ psmp->nVolume > 256) psmp->nVolume = 256; // XXX First condition looks like a typical "modplug-ism" psmp->nGlobalVol = 64; psmp->nC5Speed = BigEndian(pih->finetune); - int f2t = FrequencyToTranspose(psmp->nC5Speed); - psmp->RelativeTone = (signed char)(f2t >> 7); - psmp->nFineTune = f2t & 0x7F; - if ((pih->looplen) && (sflags & 3)) + + if(pih->looplen && (sflags & 3)) { psmp->nLoopStart = BigEndian(pih->loopstart); psmp->nLoopEnd = psmp->nLoopStart + BigEndian(pih->looplen); psmp->uFlags |= CHN_LOOP; psmp->uFlags &= ~CHN_PINGPONGLOOP; - if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP; + if(sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP; } } - chunk_pos += sizeof(DBMINSTRUMENT); + chunk_pos += sizeof(DBMInstrument); m_nInstruments = iIns + 1; } } else @@ -293,11 +298,11 @@ chunk_pos += 2; for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++) { - DBMENVELOPE *peh; + DBMEnvelope *peh; UINT nins; - if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break; - peh = (DBMENVELOPE *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMEnvelope) > dwMemPos) break; + peh = (DBMEnvelope *)(lpStream+chunk_pos); nins = BigEndianW(peh->instrument); if ((nins) && (nins < MAX_INSTRUMENTS) && (Instruments[nins]) && (peh->numpoints)) { @@ -317,7 +322,7 @@ pIns->VolEnv.Values[i] = (BYTE)BigEndianW(peh->volenv[i*2+1]); } } - chunk_pos += sizeof(DBMENVELOPE); + chunk_pos += sizeof(DBMEnvelope); } } else // Packed Pattern Data @@ -326,12 +331,12 @@ if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS; for(PATTERNINDEX iPat = 0; iPat < nPatterns; iPat++) { - DBMPATTERN *pph; + DBMPattern *pph; DWORD pksize; UINT nRows; - if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break; - pph = (DBMPATTERN *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMPattern) > dwMemPos) break; + pph = (DBMPattern *)(lpStream+chunk_pos); pksize = BigEndian(pph->packedsize); if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break; nRows = BigEndianW(pph->rows); @@ -444,12 +449,12 @@ for (UINT iSmp=1; iSmp<=nSamples; iSmp++) { ModSample *pSmp; - DBMSAMPLE *psh; + DBMSample *psh; DWORD samplesize; DWORD sampleflags; - if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break; - psh = (DBMSAMPLE *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMSample) >= dwMemPos) break; + psh = (DBMSample *)(lpStream+chunk_pos); chunk_pos += 8; samplesize = BigEndian(psh->samplesize); sampleflags = BigEndian(psh->flags); Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-03-21 14:18:54 UTC (rev 1227) @@ -606,7 +606,7 @@ \ if((len > uint16_max - (UINT)x) && GetpModDoc()) /*Reaching the limits of file format?*/ \ { \ - CString str; str.Format("%s (%s %u)\n", str_tooMuchPatternData, str_pattern, i); \ + CString str; str.Format("%s (%s %u)\n", str_tooMuchPatternData, str_pattern, pat); \ GetpModDoc()->AddToLog(str); \ break; \ } @@ -620,7 +620,6 @@ //BYTE s[64*64*5]; vector<BYTE> s(64*64*5, 0); BYTE xmph[9]; - int i; bool addChannel = false; // avoid odd channel count for FT2 compatibility XMFileHeader xmheader; @@ -691,19 +690,19 @@ } // Writing patterns - for (i = 0; i < nPatterns; i++) if (Patterns[i]) + for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) if (Patterns[pat]) { - ModCommand *p = Patterns[i]; + ModCommand *p = Patterns[pat]; UINT len = 0; // Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size... - bool emptyPatNeedsFixing = (Patterns[i].GetNumRows() != 64); + bool emptyPatNeedsFixing = (Patterns[pat].GetNumRows() != 64); MemsetZero(xmph); xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[i].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[i].GetNumRows() >> 8); + xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); + xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); - for (UINT j = m_nChannels * Patterns[i].GetNumRows(); j > 0; j--, p++) + for (UINT j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++) { // Don't write more than 32 channels if(compatibilityExport && m_nChannels - ((j - 1) % m_nChannels) > 32) continue; @@ -801,32 +800,70 @@ { MemsetZero(xmph); xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[i].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[i].GetNumRows() >> 8); + xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); + xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); fwrite(xmph, 1, 9, f); } + // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) + vector<bool> sampleAssigned(GetNumSamples(), false); + for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) + { + if(Instruments[ins] == nullptr) + { + continue; + } + const std::set<SAMPLEINDEX> referencedSamples = Instruments[ins]->GetSamples(); + for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++) + { + if(*sample <= GetNumSamples()) + { + sampleAssigned[*sample - 1] = true; + } + } + } + // Writing instruments - for(i = 1; i <= writeInstruments; i++) + for(INSTRUMENTINDEX ins = 1; ins <= writeInstruments; ins++) { XMInstrumentHeader insHeader; vector<SAMPLEINDEX> samples; if(GetNumInstruments()) { - if(Instruments[i] != nullptr) + if(Instruments[ins] != nullptr) { // Convert instrument - insHeader.ConvertToXM(*Instruments[i], compatibilityExport); + insHeader.ConvertToXM(*Instruments[ins], compatibilityExport); - samples = insHeader.instrument.GetSampleList(*Instruments[i], compatibilityExport); + samples = insHeader.instrument.GetSampleList(*Instruments[ins], compatibilityExport); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample insHeader.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType()); } - // XXX Try to save "instrument-less" samples as well. + vector<SAMPLEINDEX> additionalSamples; + + // Try to save "instrument-less" samples as well by adding those after the "normal" samples of our sample. + // We look for unassigned samples directly after the samples assigned to our current instrument, so if + // f.e. sample 1 is assigned to instrument 1 and samples 2 to 10 aren't assigned to any instrument, + // we will assign those to sample 1. Any samples before the first referenced sample are going to be lost, + // but hey, I wrote this mostly for preserving instrument texts in existing modules, where we shouldn't encounter this situation... + for(vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++) + { + SAMPLEINDEX smp = *sample; + while(smp < GetNumSamples() + && !sampleAssigned[smp] // zero-based + && insHeader.numSamples < (compatibilityExport ? 16 : 32)) + { + sampleAssigned[smp++] = true; // Don't want to add this sample again. + additionalSamples.push_back(smp); // Not zero-based :) + insHeader.numSamples++; + } + } + + samples.insert(samples.end(), additionalSamples.begin(), additionalSamples.end()); } else { MemsetZero(insHeader); @@ -836,8 +873,8 @@ // Convert samples to instruments MemsetZero(insHeader); insHeader.numSamples = 1; - insHeader.instrument.ApplyAutoVibratoToXM(Samples[i], GetType()); - samples.push_back(i); + insHeader.instrument.ApplyAutoVibratoToXM(Samples[ins], GetType()); + samples.push_back(ins); } insHeader.Finalise(); @@ -848,29 +885,29 @@ vector<UINT> sampleFlags(samples.size()); // Write Sample Headers - for(SAMPLEINDEX i = 0; i < samples.size(); i++) + for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { XMSample xmSample; - if(samples[i] <= GetNumSamples()) + if(samples[smp] <= GetNumSamples()) { - xmSample.ConvertToXM(Samples[samples[i]], GetType(), compatibilityExport); + xmSample.ConvertToXM(Samples[samples[smp]], GetType(), compatibilityExport); } else { MemsetZero(xmSample); } - sampleFlags[i] = xmSample.GetSampleFormat(); + sampleFlags[smp] = xmSample.GetSampleFormat(); - StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[i]]); + StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[smp]]); fwrite(&xmSample, 1, sizeof(xmSample), f); } // Write Sample Data - for(SAMPLEINDEX i = 0; i < samples.size(); i++) + for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { - if(samples[i] <= GetNumSamples()) + if(samples[smp] <= GetNumSamples()) { - WriteSample(f, &Samples[samples[i]], sampleFlags[i]); + WriteSample(f, &Samples[samples[smp]], sampleFlags[smp]); } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-22 19:48:59
|
Revision: 1228 http://modplug.svn.sourceforge.net/modplug/?rev=1228&view=rev Author: saga-games Date: 2012-03-22 19:48:52 +0000 (Thu, 22 Mar 2012) Log Message: ----------- [Fix] FT2 note limit fix from rev. 1225 should now be correct. [Imp] Pattern Editor: Shift-Selecting now uses the select key instead of the hard-coded shift key. [Ref] Small changes here and there Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_pat.cpp trunk/OpenMPT/mptrack/Ctrl_pat.h trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/PatternGotoDialog.cpp trunk/OpenMPT/mptrack/SampleGenerator.cpp trunk/OpenMPT/mptrack/SampleGenerator.h trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_pat.h trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/PluginEventQueue.h trunk/OpenMPT/soundlib/RowVisitor.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp Modified: trunk/OpenMPT/mptrack/Ctrl_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/Ctrl_pat.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -803,7 +803,7 @@ { nCurOrd++; // only if the current oder is already occupied, create a new pattern at the next position. rows = pSndFile->Patterns[nCurPat].GetNumRows(); - rows = CLAMP(rows, pSndFile->GetModSpecifications().patternRowsMin, pSndFile->GetModSpecifications().patternRowsMax); + rows = Clamp(rows, pSndFile->GetModSpecifications().patternRowsMin, pSndFile->GetModSpecifications().patternRowsMax); } PATTERNINDEX nNewPat = m_pModDoc->InsertPattern(nCurOrd, rows); if ((nNewPat != PATTERNINDEX_INVALID) && (nNewPat < pSndFile->Patterns.Size())) Modified: trunk/OpenMPT/mptrack/Ctrl_pat.h =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_pat.h 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/Ctrl_pat.h 2012-03-22 19:48:52 UTC (rev 1228) @@ -102,7 +102,8 @@ void SelectSequence(const SEQUENCEINDEX nSeq); // Little helper function to avoid copypasta - bool IsSelectionKeyPressed() {return CMainFrame::GetInputHandler()->SelectionPressed();} + bool IsSelectionKeyPressed() const { return CMainFrame::GetInputHandler()->SelectionPressed(); } + bool IsCtrlKeyPressed() const { return CMainFrame::GetInputHandler()->CtrlPressed(); } // Clipboard. void OnEditCopy(); Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -818,9 +818,9 @@ LineTo(dc.m_hDC, rect.right-4, rect.bottom-4); } - CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); + CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); - //Drawing 'playing'-indicator. + //Drawing 'playing'-indicator. if(nIndex == pSndFile->GetCurrentOrder() && pMainFrm->IsPlaying() ) { MoveToEx(dc.m_hDC, rect.left+4, rect.top+2, NULL); @@ -872,9 +872,8 @@ if (pt.y < rect.bottom) { SetFocus(); - CInputHandler* ih = (CMainFrame::GetMainFrame())->GetInputHandler(); - if (ih->CtrlPressed()) + if(IsCtrlKeyPressed()) { // queue pattern QueuePattern(pt); @@ -884,15 +883,15 @@ const int oldXScroll = m_nXScroll; ORDERINDEX nOrder = GetOrderFromPoint(rect, pt); - ORD_SELECTION selection = GetCurSel(false); + ORD_SELECTION selection = GetCurSel(false); // check if cursor is in selection - if it is, only react on MouseUp as the user might want to drag those orders if(m_nScrollPos2nd == ORDERINDEX_INVALID || nOrder < selection.nOrdLo || nOrder > selection.nOrdHi) { m_nScrollPos2nd = ORDERINDEX_INVALID; - SetCurSel(nOrder, true, ih->ShiftPressed()); + SetCurSel(nOrder, true, IsSelectionKeyPressed()); } - m_bDragging = IsOrderInMargins(m_nScrollPos, oldXScroll) ? false : true; + m_bDragging = !IsOrderInMargins(m_nScrollPos, oldXScroll); if(m_bDragging == true) { Modified: trunk/OpenMPT/mptrack/PatternGotoDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternGotoDialog.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/PatternGotoDialog.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -68,34 +68,41 @@ bool validated=true; //is pattern number sensible? - if (m_nPattern>=m_pSndFile->Patterns.Size()) { + if(m_nPattern>=m_pSndFile->Patterns.Size()) + { validated=false; } //Does pattern exist? - if (validated && !(m_pSndFile->Patterns[m_nPattern])) { + if(validated && !(m_pSndFile->Patterns[m_nPattern])) + { validated=false; } //Does order match pattern? - if (validated && m_pSndFile->Order[m_nOrder] != m_nPattern) { + if(validated && m_pSndFile->Order[m_nOrder] != m_nPattern) + { validated=false; } //Does pattern have enough rows? - if (validated && m_pSndFile->Patterns[m_nPattern].GetNumRows() <= m_nRow) { + if(validated && m_pSndFile->Patterns[m_nPattern].GetNumRows() <= m_nRow) + { validated=false; } //Does track have enough channels? - if (validated && m_pSndFile->m_nChannels < m_nChannel) { + if(validated && m_pSndFile->m_nChannels < m_nChannel) + { validated=false; } - if (validated) { + if (validated) + { CDialog::OnOK(); - } else { + } else + { CDialog::OnCancel(); } @@ -105,14 +112,16 @@ void CPatternGotoDialog::OnEnChangeGotoPat() //------------------------------------------ { - if (ControlsLocked()) { + if(ControlsLocked()) + { return; //the change to textbox did not come from user. } UpdateData(); m_nOrder = m_pSndFile->Order.FindOrder(static_cast<PATTERNINDEX>(m_nPattern), m_nActiveOrder); - if (m_nOrder >= m_pSndFile->Order.size()) { + if(m_nOrder == ORDERINDEX_INVALID) + { m_nOrder=0; } @@ -123,15 +132,18 @@ void CPatternGotoDialog::OnEnChangeGotoOrd() { - if (ControlsLocked()) { + if(ControlsLocked()) + { return; //the change to textbox did not come from user. } UpdateData(); - if (m_nOrder<m_pSndFile->Order.size()) { + if(m_nOrder<m_pSndFile->Order.size()) + { UINT candidatePattern = m_pSndFile->Order[m_nOrder]; - if (candidatePattern<m_pSndFile->Patterns.Size() && m_pSndFile->Patterns[candidatePattern]) { + if(candidatePattern<m_pSndFile->Patterns.Size() && m_pSndFile->Patterns[candidatePattern]) + { m_nPattern = candidatePattern; } } Modified: trunk/OpenMPT/mptrack/SampleGenerator.cpp =================================================================== --- trunk/OpenMPT/mptrack/SampleGenerator.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/SampleGenerator.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -4,6 +4,7 @@ * Purpose: Generate samples from math formulas using muParser * Notes : (currently none) * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ @@ -99,8 +100,8 @@ // Check if sample parameters are valid. -bool CSampleGenerator::CanRenderSample() -//-------------------------------------- +bool CSampleGenerator::CanRenderSample() const +//-------------------------------------------- { if(sample_frequency < SMPGEN_MINFREQ || sample_frequency > SMPGEN_MAXFREQ || sample_length < SMPGEN_MINLENGTH || sample_length > SMPGEN_MAXLENGTH) return false; return true; Modified: trunk/OpenMPT/mptrack/SampleGenerator.h =================================================================== --- trunk/OpenMPT/mptrack/SampleGenerator.h 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/SampleGenerator.h 2012-03-22 19:48:52 UTC (rev 1228) @@ -1,12 +1,15 @@ /* * SampleGenerator.h * ----------------- - * Purpose: Header file for sample generator + * Purpose: Generate samples from math formulas using muParser * Notes : (currently none) * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ + #pragma once + #include "mptrack.h" #include "Mainfrm.h" #include "Sndfile.h" @@ -52,9 +55,9 @@ // Rendering callback functions // functions - static mu::value_type ClipCallback(mu::value_type val, mu::value_type min, mu::value_type max) { return CLAMP(val, min, max); }; + static mu::value_type ClipCallback(mu::value_type val, mu::value_type min, mu::value_type max) { return Clamp(val, min, max); }; static mu::value_type PWMCallback(mu::value_type pos, mu::value_type duty, mu::value_type width) { if(width == 0) return 0; else return (fmod(pos, width) < ((duty / 100) * width)) ? 1 : -1; }; - static mu::value_type RndCallback(mu::value_type v) { return v*std::rand()/(mu::value_type)(RAND_MAX+1.0); }; + static mu::value_type RndCallback(mu::value_type v) { return v * std::rand() / (mu::value_type)(RAND_MAX + 1.0); }; static mu::value_type SampleDataCallback(mu::value_type v); static mu::value_type TriangleCallback(mu::value_type pos, mu::value_type width) { if((int)width == 0) return 0; else return abs(((int)pos % (int)(width)) - width / 2) / (width / 4) - 1; }; @@ -67,7 +70,7 @@ bool ShowDialog(); bool TestExpression(); - bool CanRenderSample(); + bool CanRenderSample() const; bool RenderSample(CSoundFile *pSndFile, SAMPLEINDEX nSample); CSampleGenerator(); Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -439,7 +439,7 @@ CheckDlgButton(IDC_CHECK10, pPlugin->IsBypassed() ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(IDC_CHECK11, pPlugin->IsWetMix() ? BST_CHECKED : BST_UNCHECKED); CVstPlugin *pVstPlugin = (pPlugin->pMixPlugin) ? (CVstPlugin *)pPlugin->pMixPlugin : NULL; - m_BtnEdit.EnableWindow(((pVstPlugin) && ((pVstPlugin->HasEditor()) || (pVstPlugin->GetNumCommands()))) ? TRUE : FALSE); + m_BtnEdit.EnableWindow((pVstPlugin != nullptr && (pVstPlugin->HasEditor() || pVstPlugin->GetNumCommands())) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_MOVEFXSLOT), (pVstPlugin) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_INSERTFXSLOT), (pVstPlugin) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_CLONEPLUG), (pVstPlugin) ? TRUE : FALSE); Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -1148,7 +1148,7 @@ } else if ((point.x >= m_szHeader.cx) && (point.y > m_szHeader.cy)) { - if(CMainFrame::GetInputHandler()->ShiftPressed() && m_StartSel == m_Selection.GetLowerRight()) + if(CMainFrame::GetInputHandler()->SelectionPressed() && m_StartSel == m_Selection.GetLowerRight()) { // Shift pressed -> set 2nd selection point DragToSel(GetPositionFromPoint(point), true, true); @@ -1621,6 +1621,7 @@ } } + void CViewPattern::OnChannelReset() //--------------------------------- { @@ -1649,6 +1650,7 @@ OnMuteChannel(false); } + void CViewPattern::OnMuteChannel(bool current) //-------------------------------------------- { @@ -1672,7 +1674,9 @@ } } + void CViewPattern::OnSoloFromClick() +//---------------------------------- { OnSoloChannel(false); } @@ -2529,13 +2533,6 @@ } -void CViewPattern::OnInterpolateVolume() -//-------------------------------------- -{ - Interpolate(PatternCursor::volumeColumn); -} - - void CViewPattern::OnOpenRandomizer() //----------------------------------- { @@ -2598,21 +2595,6 @@ //end rewbs.fxvis -void CViewPattern::OnInterpolateEffect() -//-------------------------------------- -{ - Interpolate(PatternCursor::effectColumn); -} - -void CViewPattern::OnInterpolateNote() -//-------------------------------------- -{ - Interpolate(PatternCursor::noteColumn); -} - - -//static void CArrayUtils<UINT>::Merge(CArray<UINT,UINT>& Dest, CArray<UINT,UINT>& Src); - void CViewPattern::Interpolate(PatternCursor::Columns type) //--------------------------------------------------------- { @@ -3071,34 +3053,7 @@ } -void CViewPattern::OnTransposeUp() -//-------------------------------- -{ - TransposeSelection(1); -} - -void CViewPattern::OnTransposeDown() -//---------------------------------- -{ - TransposeSelection(-1); -} - - -void CViewPattern::OnTransposeOctUp() -//----------------------------------- -{ - TransposeSelection(12); -} - - -void CViewPattern::OnTransposeOctDown() -//------------------------------------- -{ - TransposeSelection(-12); -} - - void CViewPattern::OnSwitchToOrderList() //-------------------------------------- { Modified: trunk/OpenMPT/mptrack/View_pat.h =================================================================== --- trunk/OpenMPT/mptrack/View_pat.h 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/View_pat.h 2012-03-22 19:48:52 UTC (rev 1228) @@ -357,15 +357,15 @@ afx_msg void OnPatternPlayNoLoop() {} */ //end rewbs.customKeys afx_msg void OnPatternRecord() { PostCtrlMessage(CTRLMSG_SETRECORD, -1); } - afx_msg void OnInterpolateVolume(); - afx_msg void OnInterpolateEffect(); - afx_msg void OnInterpolateNote(); + afx_msg void OnInterpolateVolume() { Interpolate(PatternCursor::volumeColumn); } + afx_msg void OnInterpolateEffect() { Interpolate(PatternCursor::effectColumn); } + afx_msg void OnInterpolateNote() { Interpolate(PatternCursor::noteColumn); } afx_msg void OnVisualizeEffect(); //rewbs.fxvis afx_msg void OnOpenRandomizer(); //rewbs.fxvis - afx_msg void OnTransposeUp(); - afx_msg void OnTransposeDown(); - afx_msg void OnTransposeOctUp(); - afx_msg void OnTransposeOctDown(); + afx_msg void OnTransposeUp() { TransposeSelection(1); } + afx_msg void OnTransposeDown() { TransposeSelection(-1); } + afx_msg void OnTransposeOctUp() { TransposeSelection(12); } + afx_msg void OnTransposeOctDown() { TransposeSelection(-12); } afx_msg void OnSetSelInstrument(); afx_msg void OnAddChannelFront() { AddChannelBefore(m_MenuCursor.GetChannel()); } afx_msg void OnAddChannelAfter() { AddChannelBefore(m_MenuCursor.GetChannel() + 1); }; Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -1240,8 +1240,8 @@ template<class T, class uT> -T CViewSample::GetSampleValueFromPoint(const CPoint& point) -//------------------------------------------------------------ +T CViewSample::GetSampleValueFromPoint(const CPoint &point) +//--------------------------------------------------------- { STATIC_ASSERT(sizeof(T) == sizeof(uT) && sizeof(T) <= 2); int value = (std::numeric_limits<T>::max)() - (std::numeric_limits<uT>::max)() * point.y / (m_rcClient.bottom - m_rcClient.top); @@ -1251,7 +1251,7 @@ template<class T, class uT> -void CViewSample::SetInitialDrawPoint(void* pSample, const CPoint& point) +void CViewSample::SetInitialDrawPoint(void *pSample, const CPoint &point) //----------------------------------------------------------------------- { T* data = reinterpret_cast<T*>(pSample); @@ -1260,8 +1260,8 @@ template<class T, class uT> -void CViewSample::SetSampleData(void* pSample, const CPoint& point, const DWORD old ) -//----------------------------------------------------------------------------------- +void CViewSample::SetSampleData(void *pSample, const CPoint &point, const DWORD old) +//---------------------------------------------------------------------------------- { T* data = reinterpret_cast<T*>(pSample); const int oldvalue = data[old]; @@ -1300,6 +1300,7 @@ if (pMainFrm && m_dwEndSel <= m_dwBeginSel) { + // Show cursor position as offset effect if no selection is made. if(m_nSample > 0 && m_nSample <= pSndFile->GetNumSamples() && x < pSndFile->GetSample(m_nSample).nLength) { const DWORD xLow = (x / 0x100) % 0x100; Modified: trunk/OpenMPT/soundlib/PluginEventQueue.h =================================================================== --- trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/soundlib/PluginEventQueue.h 2012-03-22 19:48:52 UTC (rev 1228) @@ -88,7 +88,7 @@ return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); #else // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. - static_assert(sizeof(VstEvent) <= sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + static_assert(sizeof(VstEvent) <= sizeof(VstMidiSysexEvent), "This is no 64-Bit host!"); VstMidiSysexEvent copyEvent; memcpy(©Event, &event, min(event.byteSize, sizeof(event))); return Enqueue(copyEvent, insertFront); @@ -104,7 +104,7 @@ return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); #else // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. - static_assert(sizeof(VstMidiEvent) <= sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); + static_assert(sizeof(VstMidiEvent) <= sizeof(VstMidiSysexEvent), "This is no 64-Bit host!"); VstMidiSysexEvent copyEvent; memcpy(©Event, &event, min(event.byteSize, sizeof(event))); return Enqueue(copyEvent, insertFront); Modified: trunk/OpenMPT/soundlib/RowVisitor.cpp =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/soundlib/RowVisitor.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -93,9 +93,7 @@ { // We visited this row already - this module must be looping. return true; - } - - if(autoSet) + } else if(autoSet) { visitedRows[order][row] = true; } @@ -111,8 +109,7 @@ if(sndFile.Patterns.IsValidPat(pattern)) { return static_cast<size_t>(sndFile.Patterns[pattern].GetNumRows()); - } - else + } else { // Invalid patterns consist of a "fake" row. return 1; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-21 14:18:54 UTC (rev 1227) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-03-22 19:48:52 UTC (rev 1228) @@ -856,9 +856,10 @@ if ((pChn->dwFlags & CHN_LOOP) && (pChn->nLoopEnd < pChn->nLength)) pChn->nLength = pChn->nLoopEnd; // Fix sample position on instrument change. This is needed for PT1x MOD and IT "on the fly" sample change. + // XXX is this actually called? In ProcessEffects(), a note-on effect is emulated if there's an on the fly sample change! if(pChn->nPos >= pChn->nLength) { - if((GetType() & MOD_TYPE_IT)) + if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) { pChn->nPos = pChn->nPosLo = 0; } else if((GetType() & MOD_TYPE_MOD)) // TODO does not always seem to work, especially with short chip samples? @@ -1640,7 +1641,7 @@ // Instrument mode if(instr <= GetNumInstruments() && Instruments[instr] != nullptr) { - sample = Instruments[instr]->Keyboard[note]; + sample = Instruments[instr]->Keyboard[note - NOTE_MIN]; } } else { @@ -1649,7 +1650,7 @@ } if(sample <= GetNumSamples()) { - transpose = GetSample(instr).RelativeTone; + transpose = GetSample(sample).RelativeTone; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-25 00:07:20
|
Revision: 1230 http://modplug.svn.sourceforge.net/modplug/?rev=1230&view=rev Author: saga-games Date: 2012-03-25 00:07:09 +0000 (Sun, 25 Mar 2012) Log Message: ----------- [Fix] Instrument plugins made with SynthEdit should now load the programs properly - that effMainsChanged opcode upon plugin initialization was not only superfluous as I thought for a long time now, it actually broke those plugins! (http://bugs.openmpt.org/view.php?id=210) [Fix] DX plugins were not processed correctly since the plugin buffer code has been changed from int to float. Now the plugins have to be clamped again to +-1.0 to sound correclty, so I might just as well go back to int mixing... [Imp] Pattern Editor: Note limits for S3M files with amiga limits enforced are now evaluated properly (not relying purely on the pattern note but also on the C-5 frequency of the sample) [Mod] Updated defaultKeybindings.mkb and DE_jojo.mkb [Mod] OpenMPT: Version is now 1.20.00.81 Modified Paths: -------------- trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp 2012-03-25 00:07:09 UTC (rev 1230) @@ -955,7 +955,6 @@ bk_col = MODCOLOR_BACKSELECTED; } // Speedup: Empty command which is either not or fully selected - //if ((!*((LPDWORD)m)) && (!*(((LPWORD)m)+2)) && ((!col_sel) || (col_sel == 0x1F))) if (m->IsEmpty() && ((!col_sel) || (col_sel == 0x1F))) { m_Dib.SetTextColor(tx_col, bk_col); @@ -968,12 +967,23 @@ { tx_col = row_col; bk_col = row_bkcol; - if ((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_EFFECTHILIGHT) && (m->note) && (m->note <= NOTE_MAX)) + if((CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_EFFECTHILIGHT) && m->IsNote()) { tx_col = MODCOLOR_NOTE; - // Highlight notes that are not supported by the Amiga (for S3M this is not always correct) - if((pSndFile->m_dwSongFlags & (SONG_PT1XMODE|SONG_AMIGALIMITS)) && (m->note < NOTE_MIDDLEC - 12 || m->note >= NOTE_MIDDLEC + 2 * 12)) + + if((pSndFile->m_dwSongFlags & SONG_PT1XMODE) && (m->note < NOTE_MIDDLEC - 12 || m->note >= NOTE_MIDDLEC + 2 * 12)) + { + // MOD "ProTracker 1.x" flag: Highlight notes that are not supported by Amiga trackers. tx_col = MODCOLOR_DODGY_COMMANDS; + } else if((pSndFile->m_dwSongFlags & SONG_AMIGALIMITS) && m->instr != 0 && m->instr <= pSndFile->GetNumSamples()) + { + // S3M "Force Amiga Limits": Highlight notes that exceed the Amiga's frequency range. + UINT period = pSndFile->GetPeriodFromNote(m->note, 0, pSndFile->GetSample(m->instr).nC5Speed); + if(period < 113 * 4 || period > 856 * 4) + { + tx_col = MODCOLOR_DODGY_COMMANDS; + } + } } if (col_sel & 0x01) { @@ -999,7 +1009,7 @@ { tx_col = MODCOLOR_INSTRUMENT; } - if (col_sel & 0x02 /*|| col_sel & 0x01*/) //LP Style select + if (col_sel & 0x02) { tx_col = MODCOLOR_TEXTSELECTED; bk_col = MODCOLOR_BACKSELECTED; @@ -1073,7 +1083,6 @@ ModCommand::COMMAND command = m->command & 0x3F; int n = pSndFile->GetModSpecifications().GetEffectLetter(command); ASSERT(n > ' '); - //if (n <= ' ') n = '?'; DrawLetter(xbmp+x, 0, (char)n, pfnt->nEltWidths[3], pfnt->nCmdOfs); } else { @@ -1171,8 +1180,6 @@ void CViewPattern::DrawDragSel(HDC hdc) //------------------------------------- { - // Ugly! - // XXX broken! CModDoc *pModDoc; CSoundFile *pSndFile; CRect rect; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-25 00:07:09 UTC (rev 1230) @@ -92,7 +92,7 @@ CVstPluginManager::CVstPluginManager() //------------------------------------ { - m_pVstHead = NULL; + m_pVstHead = nullptr; //m_bNeedIdle = FALSE; //rewbs.VSTCompliance - now member of plugin class CSoundFile::gpMixPluginCreateProc = CreateMixPluginProc; EnumerateDirectXDMOs(); @@ -102,14 +102,14 @@ CVstPluginManager::~CVstPluginManager() //------------------------------------- { - CSoundFile::gpMixPluginCreateProc = NULL; + CSoundFile::gpMixPluginCreateProc = nullptr; while (m_pVstHead) { PVSTPLUGINLIB p = m_pVstHead; m_pVstHead = m_pVstHead->pNext; - if (m_pVstHead) m_pVstHead->pPrev = NULL; - p->pPrev = p->pNext = NULL; - while ((volatile void *)(p->pPluginsList) != NULL) + if (m_pVstHead) m_pVstHead->pPrev = nullptr; + p->pPrev = p->pNext = nullptr; + while ((volatile void *)(p->pPluginsList) != nullptr) { p->pPluginsList->Release(); } @@ -161,19 +161,19 @@ DWORD datatype = REG_SZ; DWORD datasize = 64; - if (ERROR_SUCCESS == RegQueryValueEx(hksub, NULL, 0, &datatype, (LPBYTE)s, &datasize)) + if (ERROR_SUCCESS == RegQueryValueEx(hksub, nullptr, 0, &datatype, (LPBYTE)s, &datasize)) { PVSTPLUGINLIB p = new VSTPLUGINLIB; - p->pPrev = NULL; + p->pPrev = nullptr; p->pNext = m_pVstHead; p->dwPluginId1 = kDmoMagic; p->dwPluginId2 = clsid.Data1; - p->pPluginsList = NULL; + p->pPluginsList = nullptr; p->bIsInstrument = FALSE; lstrcpyn(p->szLibraryName, s, sizeof(p->szLibraryName)); StringFromGUID2(clsid, w, 100); - WideCharToMultiByte(CP_ACP, 0, w, -1, p->szDllPath, sizeof(p->szDllPath), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, w, -1, p->szDllPath, sizeof(p->szDllPath), nullptr, nullptr); #ifdef DMO_LOG if (theApp.IsDebug()) Log("Found \"%s\" clsid=%s\n", p->szLibraryName, p->szDllPath); #endif @@ -223,7 +223,7 @@ const CString cacheSection = "PluginCache"; const CString cacheFile = theApp.GetPluginCacheFileName(); char fileName[_MAX_PATH]; - _splitpath(pszDllPath, NULL, NULL, fileName, NULL); + _splitpath(pszDllPath, nullptr, nullptr, fileName, nullptr); CString IDs = CMainFrame::GetPrivateProfileCString(cacheSection, fileName, "", cacheFile); @@ -247,12 +247,12 @@ p->dwPluginId1 = 0; p->dwPluginId2 = 0; p->bIsInstrument = FALSE; - p->pPluginsList = NULL; + p->pPluginsList = nullptr; lstrcpyn(p->szDllPath, pszDllPath, sizeof(p->szDllPath)); - _splitpath(pszDllPath, NULL, NULL, p->szLibraryName, NULL); + _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); p->szLibraryName[63] = 0; p->pNext = m_pVstHead; - p->pPrev = NULL; + p->pPrev = nullptr; if (m_pVstHead) m_pVstHead->pPrev = p; m_pVstHead = p; // Extract plugin Ids @@ -292,7 +292,7 @@ } } - HINSTANCE hLib = NULL; + HINSTANCE hLib = nullptr; // If this key contains a file name on program launch, a plugin previously crashed OpenMPT. @@ -365,7 +365,7 @@ if ((pEffect->flags & effFlagsIsSynth) || (!pEffect->numInputs)) p->bIsInstrument = TRUE; #ifdef VST_LOG - int nver = pEffect->dispatcher(pEffect, effGetVstVersion, 0,0, NULL, 0); + int nver = pEffect->dispatcher(pEffect, effGetVstVersion, 0,0, nullptr, 0); if (!nver) nver = pEffect->version; Log("%-20s: v%d.0, %d in, %d out, %2d programs, %2d params, flags=0x%04X realQ=%d offQ=%d\n", p->szLibraryName, nver, @@ -419,12 +419,12 @@ p->dwPluginId1 = kBuzzMagic; p->dwPluginId2 = 0; - p->pPluginsList = NULL; + p->pPluginsList = nullptr; lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); - _splitpath(pszDllPath, NULL, NULL, p->szLibraryName, NULL); + _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); p->szLibraryName[63] = 0; p->pNext = m_pVstHead; - p->pPrev = NULL; + p->pPrev = nullptr; if (m_pVstHead) m_pVstHead->pPrev = p; m_pVstHead = p; try @@ -454,7 +454,7 @@ FreeLibrary(hLib); // Now it should be safe to assume that this plugin loaded properly. :) - WritePrivateProfileString("VST Plugins", "FailedPlugin", NULL, theApp.GetConfigFileName()); + WritePrivateProfileString("VST Plugins", "FailedPlugin", nullptr, theApp.GetConfigFileName()); return (validPlug ? m_pVstHead : nullptr); } else @@ -463,7 +463,7 @@ Log("LoadLibrary(%s) failed!\n", pszDllPath); #endif // VST_LOG - WritePrivateProfileString("VST Plugins", "FailedPlugin", NULL, theApp.GetConfigFileName()); + WritePrivateProfileString("VST Plugins", "FailedPlugin", nullptr, theApp.GetConfigFileName()); } return nullptr; } @@ -481,13 +481,13 @@ if (p == m_pVstHead) m_pVstHead = p->pNext; if (p->pPrev) p->pPrev->pNext = p->pNext; if (p->pNext) p->pNext->pPrev = p->pPrev; - p->pPrev = p->pNext = NULL; + p->pPrev = p->pNext = nullptr; try { CriticalSection cs; - while ((volatile void *)(p->pPluginsList) != NULL) + while ((volatile void *)(p->pPluginsList) != nullptr) { p->pPluginsList->Release(); } @@ -570,7 +570,7 @@ if ((!pFound) && strcmp(pMixPlugin->GetLibraryName(), "")) { CHAR s[_MAX_PATH], dir[_MAX_PATH]; - _splitpath(theApp.GetConfigFileName(), s, dir, NULL, NULL); + _splitpath(theApp.GetConfigFileName(), s, dir, nullptr, nullptr); strcat(s, dir); int len = strlen(s); if ((len > 0) && (s[len - 1] != '\\')) strcat(s, "\\"); @@ -689,7 +689,7 @@ //rewbs. VSTCompliance: A specific plug has requested indefinite periodic processing time. if (p->m_bNeedIdle) { - if (!(p->Dispatch(effIdle, 0,0, NULL, 0))) + if (!(p->Dispatch(effIdle, 0, 0, nullptr, 0.0f))) p->m_bNeedIdle=false; } //We need to update all open editors @@ -743,8 +743,7 @@ return kVstVersion; // Returns the unique id of a plug that's currently loading - // (not sure what this is actually for - we return *effect's UID, cos Herman Seib does something similar :) - // Let's see what happens...) + // We don't support shell plugins currently, so we only support one effect ID as well. case audioMasterCurrentId: return (effect != nullptr) ? effect->uniqueID : 0; @@ -757,15 +756,6 @@ // value is 0 for input and != 0 otherwise. note: the return value is 0 for <true> such that older versions // will always return true. case audioMasterPinConnected: - //if (effect) - //{ - // OnIdle(); - // if (value) - // return ((index < effect->numOutputs) && (index < 2)) ? 0 : 1; - // else - // return ((index < effect->numInputs) && (index < 2)) ? 0 : 1; - //} - //Olivier seemed to do some superfluous stuff (above). Time will tell if it was necessary. if (value) //input: return (index < 2) ? 0 : 1; //we only support up to 2 inputs. Remember: 0 means yes. else //output: @@ -774,15 +764,12 @@ //---from here VST 2.0 extension opcodes------------------------------------------------------ // <value> is a filter which is currently ignored - DEPRECATED in VST 2.4 - // Herman Seib only processes Midi events for plugs that call this. Keep in mind. case audioMasterWantMidi: return 1; // returns const VstTimeInfo* (or 0 if not supported) // <value> should contain a mask indicating which fields are required case audioMasterGetTime: - { - MemsetZero(timeInfo); timeInfo.sampleRate = CMainFrame::GetMainFrame()->GetSampleRate(); @@ -838,7 +825,6 @@ } } return ToVstPtr(&timeInfo); - } // Receive MIDI events from plugin case audioMasterProcessEvents: @@ -1092,7 +1078,7 @@ case audioMasterBeginEdit: Log("VST plugin to host: Begin Edit\n"); break; - + // end of automation session (when mouse up), parameter index in <index> case audioMasterEndEdit: Log("VST plugin to host: End Edit\n"); @@ -1263,7 +1249,7 @@ bi.pszDisplayName = szInitPath; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; LPITEMIDLIST pid = SHBrowseForFolder(&bi); - if(pid != NULL && SHGetPathFromIDList(pid, szBuffer)) + if(pid != nullptr && SHGetPathFromIDList(pid, szBuffer)) { if(CCONST('V', 'S', 'T', 'r') == effect->uniqueID && pFileSel->returnPath != nullptr && pFileSel->sizeReturnPath == 0) { @@ -1386,7 +1372,6 @@ m_bSongPlaying = false; //rewbs.VSTCompliance m_bPlugResumed = false; m_bModified = false; - m_dwTimeAtStartOfProcess=0; m_nSampleRate = nInvalidSampleRate; //rewbs.VSTCompliance: gets set on Resume() MemsetZero(m_MidiCh); @@ -1394,8 +1379,6 @@ { m_nMidiPitchBendPos[ch]=MIDI_PitchBend_Centre; //centre pitch bend on all channels } - - processCalled = CreateEvent(NULL,FALSE,FALSE,NULL); } @@ -1410,17 +1393,17 @@ //rewbs.VSTcompliance //Store a pointer so we can get the CVstPlugin object from the basic VST effect object. - m_pEffect->resvd1 = ToVstPtr(this); + m_pEffect->resvd1 = ToVstPtr(this); //rewbs.plugDocAware m_pSndFile = pSndFile; m_pModDoc = pSndFile->GetpModDoc(); m_nSlot = FindSlot(); //end rewbs.plugDocAware - Dispatch(effOpen, 0, 0, NULL, 0); + Dispatch(effOpen, 0, 0, nullptr, 0.0f); // VST 2.0 plugins return 2 here, VST 2.4 plugins return 2400... Great! - m_bIsVst2 = (CVstPlugin::Dispatch(effGetVstVersion, 0,0, NULL, 0) >= 2); - if (m_bIsVst2) + m_bIsVst2 = (CVstPlugin::Dispatch(effGetVstVersion, 0,0, nullptr, 0.0f) >= 2); + if (m_bIsVst2) { // Set VST speaker in/out setup to Stereo. Required for some plugins (possibly all VST 2.4+ plugins?) // All this might get more interesting when adding sidechaining support... @@ -1459,27 +1442,26 @@ Dispatch(effGetInputProperties, 0, 0, &tempPinProperties, 0); Dispatch(effGetOutputProperties, 0, 0, &tempPinProperties, 0); - Dispatch(effConnectInput, 0, 1, NULL, 0); - if (m_pEffect->numInputs > 1) Dispatch(effConnectInput, 1, 1, NULL, 0.0f); - Dispatch(effConnectOutput, 0, 1, NULL, 0); - if (m_pEffect->numOutputs > 1) Dispatch(effConnectOutput, 1, 1, NULL, 0.0f); + Dispatch(effConnectInput, 0, 1, nullptr, 0.0f); + if (m_pEffect->numInputs > 1) Dispatch(effConnectInput, 1, 1, nullptr, 0.0f); + Dispatch(effConnectOutput, 0, 1, nullptr, 0.0f); + if (m_pEffect->numOutputs > 1) Dispatch(effConnectOutput, 1, 1, nullptr, 0.0f); //rewbs.VSTCompliance: disable all inputs and outputs beyond stereo left and right: for (int i=2; i<m_pEffect->numInputs; i++) - Dispatch(effConnectInput, i, 0, NULL, 0.0f); + Dispatch(effConnectInput, i, 0, nullptr, 0.0f); for (int i=2; i<m_pEffect->numOutputs; i++) - Dispatch(effConnectOutput, i, 0, NULL, 0.0f); + Dispatch(effConnectOutput, i, 0, nullptr, 0.0f); //end rewbs.VSTCompliance } m_nSampleRate=CSoundFile::gdwMixingFreq; - Dispatch(effSetSampleRate, 0, 0, NULL, static_cast<float>(CSoundFile::gdwMixingFreq)); - Dispatch(effSetBlockSize, 0, MIXBUFFERSIZE, NULL, 0.0f); + Dispatch(effSetSampleRate, 0, 0, nullptr, static_cast<float>(CSoundFile::gdwMixingFreq)); + Dispatch(effSetBlockSize, 0, MIXBUFFERSIZE, nullptr, 0.0f); if (m_pEffect->numPrograms > 0) { - Dispatch(effSetProgram, 0, 0, NULL, 0); + Dispatch(effSetProgram, 0, 0, nullptr, 0); } - Dispatch(effMainsChanged, 0, 1, NULL, 0.0f); InitializeIOBuffers(); @@ -1503,7 +1485,7 @@ m_pProcessFP = (m_pEffect->flags & effFlagsCanReplacing) ? m_pEffect->processReplacing : m_pEffect->process; // issue samplerate again here, cos some plugs like it before the block size, other like it right at the end. - Dispatch(effSetSampleRate, 0, 0, NULL, static_cast<float>(CSoundFile::gdwMixingFreq)); + Dispatch(effSetSampleRate, 0, 0, nullptr, static_cast<float>(CSoundFile::gdwMixingFreq)); } @@ -1535,37 +1517,36 @@ if ((m_pFactory) && (m_pFactory->pPluginsList == this)) m_pFactory->pPluginsList = m_pNext; if (m_pMixStruct) { - m_pMixStruct->pMixPlugin = NULL; - m_pMixStruct->pMixState = NULL; - m_pMixStruct = NULL; + m_pMixStruct->pMixPlugin = nullptr; + m_pMixStruct->pMixState = nullptr; + m_pMixStruct = nullptr; } if (m_pNext) m_pNext->m_pPrev = m_pPrev; if (m_pPrev) m_pPrev->m_pNext = m_pNext; - m_pPrev = NULL; - m_pNext = NULL; + m_pPrev = nullptr; + m_pNext = nullptr; if (m_pEditor) { if (m_pEditor->m_hWnd) m_pEditor->OnClose(); if ((volatile void *)m_pEditor) delete m_pEditor; - m_pEditor = NULL; + m_pEditor = nullptr; } if (m_bIsVst2) { - Dispatch(effConnectInput, 0, 0, NULL, 0); - if (m_pEffect->numInputs > 1) Dispatch(effConnectInput, 1, 0, NULL, 0); - Dispatch(effConnectOutput, 0, 0, NULL, 0); - if (m_pEffect->numOutputs > 1) Dispatch(effConnectOutput, 1, 0, NULL, 0); + Dispatch(effConnectInput, 0, 0, nullptr, 0); + if (m_pEffect->numInputs > 1) Dispatch(effConnectInput, 1, 0, nullptr, 0); + Dispatch(effConnectOutput, 0, 0, nullptr, 0); + if (m_pEffect->numOutputs > 1) Dispatch(effConnectOutput, 1, 0, nullptr, 0); } - CVstPlugin::Dispatch(effMainsChanged, 0,0, NULL, 0); - CVstPlugin::Dispatch(effClose, 0, 0, NULL, 0); - m_pFactory = NULL; + CVstPlugin::Dispatch(effMainsChanged, 0,0, nullptr, 0); + CVstPlugin::Dispatch(effClose, 0, 0, nullptr, 0); + m_pFactory = nullptr; if (m_hLibrary) { FreeLibrary(m_hLibrary); - m_hLibrary = NULL; + m_hLibrary = nullptr; } - CloseHandle(processCalled); } @@ -1720,7 +1701,7 @@ // try chunk-based preset: if((m_pEffect->flags & effFlagsProgramChunks) != 0) { - void *chunk = NULL; + void *chunk = nullptr; long chunkSize = Dispatch(effGetChunk, 1,0, &chunk, 0); if(chunkSize && chunk) fxp = new Cfxp(ID, plugVersion, 1, chunkSize, chunk); @@ -1803,7 +1784,7 @@ { if ((m_pEffect) && (m_pEffect->numPrograms > 0)) { - return Dispatch(effGetProgram, 0, 0, NULL, 0); + return Dispatch(effGetProgram, 0, 0, nullptr, 0); } return 0; } @@ -1859,7 +1840,7 @@ { if (nIndex < (UINT)m_pEffect->numPrograms) { - Dispatch(effSetProgram, 0, nIndex, NULL, 0); + Dispatch(effSetProgram, 0, nIndex, nullptr, 0); } } } @@ -1985,18 +1966,18 @@ m_MixState.nVolDecayR = 0; if(m_bPlugResumed) { - Dispatch(effStopProcess, 0, 0, NULL, 0.0f); - Dispatch(effMainsChanged, 0, 0, NULL, 0.0f); // calls plugin's suspend + Dispatch(effStopProcess, 0, 0, nullptr, 0.0f); + Dispatch(effMainsChanged, 0, 0, nullptr, 0.0f); // calls plugin's suspend } if (sampleRate != m_nSampleRate) { m_nSampleRate = sampleRate; - Dispatch(effSetSampleRate, 0, 0, NULL, static_cast<float>(m_nSampleRate)); + Dispatch(effSetSampleRate, 0, 0, nullptr, static_cast<float>(m_nSampleRate)); } - Dispatch(effSetBlockSize, 0, MIXBUFFERSIZE, NULL, 0); + Dispatch(effSetBlockSize, 0, MIXBUFFERSIZE, nullptr, 0.0f); //start off some stuff - Dispatch(effMainsChanged, 0, 1, NULL, 0.0f); // calls plugin's resume - Dispatch(effStartProcess, 0, 0, NULL, 0.0f); + Dispatch(effMainsChanged, 0, 1, nullptr, 0.0f); // calls plugin's resume + Dispatch(effStartProcess, 0, 0, nullptr, 0.0f); m_bPlugResumed = true; } catch (...) { @@ -2013,8 +1994,8 @@ { if(m_bPlugResumed) { - Dispatch(effStopProcess, 0, 0, NULL, 0.0f); - Dispatch(effMainsChanged, 0, 0, NULL, 0.0f); // calls plugin's suspend (theoretically, plugins should clean their buffers here, but oh well, the number of plugins which don't do this is surprisingly high.) + Dispatch(effStopProcess, 0, 0, nullptr, 0.0f); + Dispatch(effMainsChanged, 0, 0, nullptr, 0.0f); // calls plugin's suspend (theoretically, plugins should clean their buffers here, but oh well, the number of plugins which don't do this is surprisingly high.) m_bPlugResumed = false; } } catch (...) @@ -2132,7 +2113,6 @@ float **outputBuffers = mixBuffer.GetOutputBufferArray(); mixBuffer.ClearOutputBuffers(nSamples); - m_dwTimeAtStartOfProcess = timeGetTime(); // Do the VST processing magic try { @@ -2144,7 +2124,6 @@ CString processMethod = (m_pEffect->flags & effFlagsCanReplacing) ? "processReplacing" : "process"; CVstPluginManager::ReportPlugException("The plugin %s threw an exception in %s. It has automatically been set to \"Bypass\".", m_pMixStruct->GetName(), processMethod); vstEvents.Clear(); -// SetEvent(processCalled); } ASSERT(outputBuffers != nullptr); @@ -2194,7 +2173,6 @@ } vstEvents.Clear(); - //SetEvent(processCalled); } @@ -2351,11 +2329,6 @@ bool overflow; float in[2][SCRATCH_BUFFER_SIZE], out[2][SCRATCH_BUFFER_SIZE]; // scratch buffers - // Relies on a wait on processCalled, which will never get set - // if plug is bypassed. - //if (IsBypassed()) - // return; - // The JUCE framework doesn't like processing while being suspended. const bool wasSuspended = !IsResumed(); if(wasSuspended) @@ -2392,11 +2365,6 @@ if (overflow) break; //yuck } // let plug process events - // TODO: wait for notification from audio thread that process has been called, - // rather than re-call it here - //ResetEvent(processCalled); // Unset processCalled. - //WaitForSingleObject(processCalled, 10000); // Will not return until processCalled is set again, - // // i.e. until processReplacing() has been called. Process((float*)in, (float*)out, SCRATCH_BUFFER_SIZE); // If we had hit an overflow, we need to loop around and start again. @@ -2655,7 +2623,7 @@ // TODO: Could be used to update general tab in real time, but causes flickers in treeview // Better idea: add an update hint just for plugin params? - //pModDoc->UpdateAllViews(NULL, HINT_MIXPLUGINS, NULL); + //pModDoc->UpdateAllViews(nullptr, HINT_MIXPLUGINS, nullptr); if (CMainFrame::GetInputHandler()->ShiftPressed()) { @@ -2690,7 +2658,7 @@ m_bModified = false; if ((m_pEffect->flags & effFlagsProgramChunks) - && (Dispatch(effIdentify, 0,0, NULL, 0) == 'NvEf')) + && (Dispatch(effIdentify, 0,0, nullptr, 0.0f) == 'NvEf')) { void *p = nullptr; LONG nByteSize = 0; @@ -2772,7 +2740,7 @@ if ((Dispatch(effIdentify, 0, nullptr, nullptr, 0) == 'NvEf') && (nType == 'NvEf')) { - void *p = NULL; + void *p = nullptr; Dispatch(effGetChunk, 0,0, &p, 0); //init plug for chunk reception if ((nProgram>=0) && (nProgram < m_pEffect->numPrograms)) @@ -2896,7 +2864,7 @@ #ifdef MODPLUG_TRACKER if (m_pModDoc) - m_pModDoc->UpdateAllViews(NULL, HINT_MIXPLUGINS, NULL); + m_pModDoc->UpdateAllViews(nullptr, HINT_MIXPLUGINS, nullptr); #endif // MODPLUG_TRACKER } @@ -2909,9 +2877,8 @@ bool CVstPlugin::GetSpeakerArrangement() //-------------------------------------- { - VstSpeakerArrangement **pSA = NULL; + VstSpeakerArrangement **pSA = nullptr; Dispatch(effGetSpeakerArrangement, 0, 0, pSA, 0); - //Dispatch(effGetSpeakerArrangement, 0,(long)pSA,NULL,0); if (pSA) { MemCopy(speakerArrangement, **pSA); @@ -2984,10 +2951,10 @@ //------------------------------------------------------------------------ { // At the moment we know there will only be 1 output. - // Returning NULL ptr means plugin outputs directly to master. + // Returning nullptr means plugin outputs directly to master. list.RemoveAll(); - CVstPlugin *pOutputPlug = NULL; + CVstPlugin *pOutputPlug = nullptr; if(!m_pMixStruct->IsOutputToMaster()) { PLUGINDEX nOutput = m_pMixStruct->GetOutputPlugin(); @@ -3007,7 +2974,7 @@ if(m_pSndFile == 0) return; CArray<CVstPlugin*, CVstPlugin*> candidatePlugOutputs; - CVstPlugin* pCandidatePlug = NULL; + CVstPlugin* pCandidatePlug = nullptr; list.RemoveAll(); for (int nPlug = 0; nPlug < MAX_MIXPLUGINS; nPlug++) @@ -3123,20 +3090,20 @@ // CMICallbacks interface public: - virtual CWaveInfo const *GetWave(int const) { Log("GetWave\n"); return NULL; } - virtual CWaveLevel const *GetWaveLevel(int const i, int const level) { Log("GetWaveLevel\n"); return NULL; } + virtual CWaveInfo const *GetWave(int const) { Log("GetWave\n"); return nullptr; } + virtual CWaveLevel const *GetWaveLevel(int const i, int const level) { Log("GetWaveLevel\n"); return nullptr; } virtual void MessageBox(char const *txt) { Reporting::Notification(txt, m_pMachineInfo->Name); } virtual void Lock() { Log("Lock\n"); } virtual void Unlock() { Log("Unlock\n"); } virtual int GetWritePos() { Log("GetWritePos\n"); return 0; } virtual int GetPlayPos() { Log("GetPlayPos\n"); return 0; } - virtual float *GetAuxBuffer() { Log("GetAuxBuffer\n"); return NULL; } + virtual float *GetAuxBuffer() { Log("GetAuxBuffer\n"); return nullptr; } virtual void ClearAuxBuffer() { Log("ClearAuxBuffer\n"); } virtual int GetFreeWave() { Log("GetFreeWave\n"); return 0; } virtual bool AllocateWave(int const i, int const size, char const *name) { Log("AllocateWave\n"); return false; } virtual void ScheduleEvent(int const time, dword const data) { Log("ScheduleEvent\n"); } virtual void MidiOut(int const dev, dword const data) { Log("MidiOut\n"); } - virtual short const *GetOscillatorTable(int const waveform) { Log("GetOscillatorTable\n"); return NULL; } + virtual short const *GetOscillatorTable(int const waveform) { Log("GetOscillatorTable\n"); return nullptr; } // envelopes virtual int GetEnvSize(int const wave, int const env) { Log("GetEnvSize\n"); return 0; } @@ -3145,8 +3112,8 @@ // pattern editing virtual void SetNumberOfTracks(int const n) { Log("SetNumberOfTracks\n"); } - virtual CPattern *CreatePattern(char const *name, int const length) { Log("CreatePattern\n"); return NULL; } - virtual CPattern *GetPattern(int const index) { Log("GetPattern\n"); return NULL; } + virtual CPattern *CreatePattern(char const *name, int const length) { Log("CreatePattern\n"); return nullptr; } + virtual CPattern *GetPattern(int const index) { Log("GetPattern\n"); return nullptr; } virtual char const *GetPatternName(CPattern *ppat) { Log("GetPatternName\n"); return ""; } virtual void RenamePattern(char const *oldname, char const *newname) { Log("RenamePattern\n"); } virtual void DeletePattern(CPattern *ppat) { Log("DeletePattern\n"); } @@ -3154,15 +3121,15 @@ virtual void SetPatternData(CPattern *ppat, int const row, int const group, int const track, int const field, int const value) { Log("SetPatternData\n"); } // sequence editing - virtual CSequence *CreateSequence() { Log("CreateSequence\n"); return NULL; } + virtual CSequence *CreateSequence() { Log("CreateSequence\n"); return nullptr; } virtual void DeleteSequence(CSequence *pseq) { Log("DeleteSequence\n"); } // special ppat values for GetSequenceData and SetSequenceData - // empty = NULL + // empty = nullptr // <break> = (CPattern *)1 // <mute> = (CPattern *)2 // <thru> = (CPattern *)3 - virtual CPattern *GetSequenceData(int const row) { Log("GetSequenceData\n"); return NULL; } + virtual CPattern *GetSequenceData(int const row) { Log("GetSequenceData\n"); return nullptr; } virtual void SetSequenceData(int const row, CPattern *ppat) { Log("SetSequenceData\n"); } // buzz v1.2 (MI_VERSION 15) additions start here @@ -3176,22 +3143,22 @@ virtual void ADWrite(int channel, float *psamples, int numsamples) { Log("ADWrite\n"); } virtual void ADRead(int channel, float *psamples, int numsamples) { Log("ADRead\n"); } - virtual CMachine *GetThisMachine() { Log("GetThisMachine\n"); return NULL; } + virtual CMachine *GetThisMachine() { Log("GetThisMachine\n"); return nullptr; } virtual void ControlChange(CMachine *pmac, int group, int track, int param, int value) { Log("ControlChange\n"); } // set value of parameter (group & 16 == don't record) // returns pointer to the sequence if there is a pattern playing - virtual CSequence *GetPlayingSequence(CMachine *pmac) { Log("GetPlayingSequence\n"); return NULL; } + virtual CSequence *GetPlayingSequence(CMachine *pmac) { Log("GetPlayingSequence\n"); return nullptr; } // gets ptr to raw pattern data for row of a track of a currently playing pattern (or something like that) - virtual void *GetPlayingRow(CSequence *pseq, int group, int track) { Log("GetPlayingRow\n"); return NULL; } + virtual void *GetPlayingRow(CSequence *pseq, int group, int track) { Log("GetPlayingRow\n"); return nullptr; } virtual int GetStateFlags() { Log("GetStateFlags\n"); return 0; } virtual void SetnumOutputChannels(CMachine *pmac, int n) { Log("SetNumOutputChannels\n"); } // if n=1 Work(), n=2 WorkMonoToStereo() virtual void SetEventHandler(CMachine *pmac, BEventType et, EVENT_HANDLER_PTR p, void *param) { Log("SetEventHandler\n"); } virtual char const *GetWaveName(int const i) { Log("GetWavename\n"); return ""; } - virtual void SetInternalWaveName(CMachine *pmac, int const i, char const *name) { Log("SetInternalWaveName\n"); } // i >= 1, NULL name to clear + virtual void SetInternalWaveName(CMachine *pmac, int const i, char const *name) { Log("SetInternalWaveName\n"); } // i >= 1, nullptr name to clear virtual void GetMachineNames(CMachineDataOutput *pout) { Log("GetMachineNames\n"); } // *pout will get one name per Write() - virtual CMachine *GetMachine(char const *name) { Log("GetMachine\n"); return NULL; } - virtual CMachineInfo const *GetMachineInfo(CMachine *pmac) { Log("GetMachineInfo\n"); return NULL; } + virtual CMachine *GetMachine(char const *name) { Log("GetMachine\n"); return nullptr; } + virtual CMachineInfo const *GetMachineInfo(CMachine *pmac) { Log("GetMachineInfo\n"); return nullptr; } virtual char const *GetMachineName(CMachine *pmac) { Log("GetMachineName\n"); return ""; } virtual bool GetInput(int index, float *psamples, int numsamples, bool stereo, float *extrabuffer) { Log("GetInput\n"); return false; } }; @@ -3220,7 +3187,7 @@ m_Effect.setParameter = BuzzSetParameter; m_Effect.getParameter = BuzzGetParameter; m_Effect.process = BuzzProcess; - m_Effect.processReplacing = NULL; + m_Effect.processReplacing = nullptr; // Buzz Info m_pMachineInterface->pMasterInfo = &m_MasterInfo; m_pMachineInterface->pCB = this; @@ -3244,20 +3211,20 @@ CBuzz2Vst::~CBuzz2Vst() //--------------------- { - m_Effect.object = NULL; + m_Effect.object = nullptr; if (m_pMachineInfo) { - m_pMachineInfo = NULL; + m_pMachineInfo = nullptr; } if (m_pMachineInterface) { delete m_pMachineInterface; - m_pMachineInterface = NULL; + m_pMachineInterface = nullptr; } if (m_pDataInput) { delete m_pDataInput; - m_pDataInput = NULL; + m_pDataInput = nullptr; } } @@ -3309,7 +3276,7 @@ break; case effClose: - m_Effect.object = NULL; + m_Effect.object = nullptr; delete this; return 0; @@ -3469,9 +3436,9 @@ { CBuzz2Vst *p; - if ((!pBuzzMachine) || (!pBuzzInfo)) return NULL; + if ((!pBuzzMachine) || (!pBuzzInfo)) return nullptr; p = new CBuzz2Vst(pBuzzMachine, pBuzzInfo); - return (p) ? p->GetEffect() : NULL; + return (p) ? p->GetEffect() : nullptr; } #endif // ENABLE_BUZZ @@ -3523,8 +3490,8 @@ { m_pMediaObject = pMO; m_pMediaProcess = pMOIP; - m_pParamInfo = NULL; - m_pMediaParams = NULL; + m_pParamInfo = nullptr; + m_pMediaParams = nullptr; MemsetZero(m_Effect); m_Effect.magic = kDmoMagic; m_Effect.numPrograms = 0; @@ -3538,21 +3505,21 @@ m_Effect.version = 2; m_nSamplesPerSec = 44100; m_DataTime = 0; - if (FAILED(m_pMediaObject->QueryInterface(IID_IMediaParamInfo, (void **)&m_pParamInfo))) m_pParamInfo = NULL; + if (FAILED(m_pMediaObject->QueryInterface(IID_IMediaParamInfo, (void **)&m_pParamInfo))) m_pParamInfo = nullptr; if (m_pParamInfo) { DWORD dwParamCount = 0; m_pParamInfo->GetParamCount(&dwParamCount); m_Effect.numParams = dwParamCount; } - if (FAILED(m_pMediaObject->QueryInterface(IID_IMediaParams, (void **)&m_pMediaParams))) m_pMediaParams = NULL; + if (FAILED(m_pMediaObject->QueryInterface(IID_IMediaParams, (void **)&m_pMediaParams))) m_pMediaParams = nullptr; m_pMixBuffer = (float *)((((int)m_MixBuffer)+15)&~15); // Callbacks m_Effect.dispatcher = DmoDispatcher; m_Effect.setParameter = DmoSetParameter; m_Effect.getParameter = DmoGetParameter; m_Effect.process = DmoProcess; - m_Effect.processReplacing = NULL; + m_Effect.processReplacing = nullptr; } @@ -3562,22 +3529,22 @@ if (m_pMediaParams) { m_pMediaParams->Release(); - m_pMediaParams = NULL; + m_pMediaParams = nullptr; } if (m_pParamInfo) { m_pParamInfo->Release(); - m_pParamInfo = NULL; + m_pParamInfo = nullptr; } if (m_pMediaProcess) { m_pMediaProcess->Release(); - m_pMediaProcess = NULL; + m_pMediaProcess = nullptr; } if (m_pMediaObject) { m_pMediaObject->Release(); - m_pMediaObject = NULL; + m_pMediaObject = nullptr; } } @@ -3687,7 +3654,7 @@ { text += wcslen(text) + 1; } - WideCharToMultiByte(CP_ACP, 0, text, -1, pszName, 32, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, text, -1, pszName, 32, nullptr, nullptr); } break; @@ -3699,7 +3666,7 @@ } } else { - WideCharToMultiByte(CP_ACP, 0, (opCode == effGetParamName) ? mpi.szLabel : mpi.szUnitText, -1, pszName, 32, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, (opCode == effGetParamName) ? mpi.szLabel : mpi.szUnitText, -1, pszName, 32, nullptr, nullptr); } } } @@ -3836,8 +3803,8 @@ const float *pin = m_pMixBuffer; for(int i = nsamples; i != 0; i--) { - *(poutL++) = *(pin++); - *(poutR++) = *(pin++); + *(poutL++) += Clamp(*(pin++), -1.0f, 1.0f); + *(poutR++) += Clamp(*(pin++), -1.0f, 1.0f); } } @@ -3866,12 +3833,12 @@ w[99] = 0; if (CLSIDFromString(w, &clsid) == S_OK) { - IMediaObject *pMO = NULL; - IMediaObjectInPlace *pMOIP = NULL; - if ((CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IMediaObject, (VOID **)&pMO) == S_OK) && (pMO)) + IMediaObject *pMO = nullptr; + IMediaObjectInPlace *pMOIP = nullptr; + if ((CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, IID_IMediaObject, (VOID **)&pMO) == S_OK) && (pMO)) { - if (pMO->QueryInterface(IID_IMediaObjectInPlace, (void **)&pMOIP) != S_OK) pMOIP = NULL; - } else pMO = NULL; + if (pMO->QueryInterface(IID_IMediaObjectInPlace, (void **)&pMOIP) != S_OK) pMOIP = nullptr; + } else pMO = nullptr; if ((pMO) && (pMOIP)) { DWORD dwInputs, dwOutputs; @@ -3881,7 +3848,7 @@ if (dwInputs == 1 && dwOutputs == 1) { CDmo2Vst *p = new CDmo2Vst(pMO, pMOIP, clsid.Data1); - return (p) ? p->GetEffect() : NULL; + return (p) ? p->GetEffect() : nullptr; } #ifdef DMO_LOG Log("%s: Unable to use this DMO\n", pLib->szLibraryName); @@ -3893,7 +3860,7 @@ if (pMO) pMO->Release(); if (pMOIP) pMOIP->Release(); } - return NULL; + return nullptr; } Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-03-25 00:07:09 UTC (rev 1230) @@ -79,7 +79,8 @@ enum { - VstEventQueueLength = 256, + // Number of MIDI events that can be sent to a plugin at once (the internal queue is not affected by this number, it can hold any number of events) + vstNumProcessEvents = 256, }; ULONG m_nRefCount; @@ -105,9 +106,7 @@ UINT m_nPreviousMidiChan; //rewbs.VSTCompliance bool m_bSongPlaying; //rewbs.VSTCompliance bool m_bPlugResumed; //rewbs.VSTCompliance - DWORD m_dwTimeAtStartOfProcess; bool m_bModified; - HANDLE processCalled; PLUGINDEX m_nSlot; float m_fGain; bool m_bIsInstrument; @@ -116,7 +115,7 @@ PluginMixBuffer<float, MIXBUFFERSIZE> mixBuffer; // Float buffers (input and output) for plugins int m_MixBuffer[MIXBUFFERSIZE * 2 + 2]; // Stereo interleaved - PluginEventQueue<VstEventQueueLength> vstEvents; // MIDI events that should be sent to the plugin + PluginEventQueue<vstNumProcessEvents> vstEvents; // MIDI events that should be sent to the plugin public: CVstPlugin(HINSTANCE hLibrary, VSTPLUGINLIB *pFactory, SNDMIXPLUGIN *pMixPlugin, AEffect *pEffect); @@ -202,7 +201,6 @@ bool IsResumed() {return m_bPlugResumed;} void Resume(); void Suspend(); - DWORD GetTimeAtStartOfProcess() {return m_dwTimeAtStartOfProcess;} void SetDryRatio(UINT param); void AutomateParameter(PlugParamIndex param); Modified: trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb =================================================================== --- trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/mptrack/res/defaultKeybindings.mkb 2012-03-25 00:07:09 UTC (rev 1230) @@ -380,3 +380,5 @@ 19:1817:0:187:5 //Increase pattern index : = (KeyDown|KeyHold) 19:1818:0:109:5 //Decrease pattern index: NUM SUB (KeyDown|KeyHold) 19:1818:0:189:5 //Decrease pattern index: - (KeyDown|KeyHold) +19:1853:0:83:1 //Separator (+++) Index: S (KeyDown) +19:1854:0:32:1 //Stop (---) Index: SPACE (KeyDown) Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/mptrack/version.h 2012-03-25 00:07:09 UTC (rev 1230) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 80 +#define VER_MINORMINOR 81 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb =================================================================== --- trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-23 19:31:33 UTC (rev 1229) +++ trunk/OpenMPT/packageTemplate/extraKeymaps/DE_jojo.mkb 2012-03-25 00:07:09 UTC (rev 1230) @@ -65,6 +65,7 @@ 2:1341:2:33:5 //Snap up to beat: Ctrl+BILD-NACH-OBEN (KeyDown|KeyHold) 2:1038:0:40:5 //Navigate down by 1 row: NACH-UNTEN (KeyDown|KeyHold) 2:1039:0:38:5 //Navigate up by 1 row: NACH-OBEN (KeyDown|KeyHold) +2:1691:4:32:5 //Navigate down by spacing: Alt+LEER (KeyDown|KeyHold) 2:1040:0:37:5 //Navigate left: NACH-LINKS (KeyDown|KeyHold) 2:1041:0:39:5 //Navigate right: NACH-RECHTS (KeyDown|KeyHold) 2:1042:0:9:1 //Navigate to next channel: TABULATOR (KeyDown) @@ -378,7 +379,7 @@ 19:1816:0:105:5 //Pattern index digit 9: 9 (ZEHNERTASTATUR) (KeyDown|KeyHold) 19:1817:0:107:5 //Increase pattern index : + (ZEHNERTASTATUR) (KeyDown|KeyHold) 19:1817:0:187:5 //Increase pattern index : + (KeyDown|KeyHold) -19:1818:0:109:1 //Decrease pattern index: - (ZEHNERTASTATUR) (KeyDown) -19:1818:0:189:1 //Decrease pattern index: - (KeyDown) +19:1818:0:109:5 //Decrease pattern index: - (ZEHNERTASTATUR) (KeyDown|KeyHold) +19:1818:0:189:5 //Decrease pattern index: - (KeyDown|KeyHold) 19:1853:0:73:1 //Separator (+++) Index: I (KeyDown) 19:1854:0:32:1 //Stop (---) Index: LEER (KeyDown) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-03-30 23:29:19
|
Revision: 1233 http://modplug.svn.sourceforge.net/modplug/?rev=1233&view=rev Author: saga-games Date: 2012-03-30 23:29:11 +0000 (Fri, 30 Mar 2012) Log Message: ----------- [Ref] PSM loaders also use FileReader now. Modified Paths: -------------- trunk/OpenMPT/soundlib/Load_psm.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Removed Paths: ------------- trunk/OpenMPT/unzip/Debug/ Modified: trunk/OpenMPT/soundlib/Load_psm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_psm.cpp 2012-03-30 20:12:57 UTC (rev 1232) +++ trunk/OpenMPT/soundlib/Load_psm.cpp 2012-03-30 23:29:11 UTC (rev 1233) @@ -33,43 +33,73 @@ // New PSM support starts here. PSM16 structs are below. // -// 32-Bit PSM header identifiers -#define PSM16HEAD_PSM_ 0xFE4D5350 -#define PSMHEAD_PSM_ 0x204D5350 -#define PSMHEAD_FILE 0x454C4946 +// PSM File Header +struct PSMFileHeader +{ + // Magic Bytes + enum PSMMagic + { + magicPSM_ = 0x204D5350, + magicFILE = 0x454C4946, + }; -// 32-Bit chunk identifiers -#define PSMCHUNKID_TITL 0x4C544954 -#define PSMCHUNKID_SDFT 0x54464453 -#define PSMCHUNKID_PBOD 0x444F4250 -#define PSMCHUNKID_SONG 0x474E4F53 -#define PSMCHUNKID_DATE 0x45544144 -#define PSMCHUNKID_OPLH 0x484C504F -#define PSMCHUNKID_PPAN 0x4E415050 -#define PSMCHUNKID_PATT 0x54544150 -#define PSMCHUNKID_DSAM 0x4D415344 -#define PSMCHUNKID_DSMP 0x504D5344 - -struct PSMNEWHEADER -{ uint32 formatID; // "PSM " (new format) uint32 fileSize; // Filesize - 12 uint32 fileInfoID; // "FILE" Start of file info + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(formatID); + SwapBytesLE(fileSize); + SwapBytesLE(fileInfoID); + } }; -struct PSMSONGHEADER +// RIFF-style Chunk +struct PSMChunk { + // 32-Bit chunk identifiers + enum ChunkIdentifiers + { + idTITL = 0x4C544954, + idSDFT = 0x54464453, + idPBOD = 0x444F4250, + idSONG = 0x474E4F53, + idDATE = 0x45544144, + idOPLH = 0x484C504F, + idPPAN = 0x4E415050, + idPATT = 0x54544150, + idDSAM = 0x4D415344, + idDSMP = 0x504D5344, + }; + + uint32 id; + uint32 length; + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(id); + SwapBytesLE(length); + } +}; + +// Song Information +struct PSMSongHeader +{ char songType[9]; // Mostly "MAINSONG " (But not in Extreme Pinball!) uint8 compression; // 1 - uncompressed uint8 numChannels; // Number of channels, usually 4 }; -struct PSMOLDSAMPLEHEADER // Regular sample header +// Regular sample header +struct PSMOldSampleHeader { uint8 flags; char fileName[8]; // Filename of the original module (without extension) - uint32 sampleID; // INS0...INS9 (only last digit of sample ID, i.e. sample 1 and sample 11 are equal) + char sampleID[4]; // INS0...INS9 (only last digit of sample ID, i.e. sample 1 and sample 11 are equal) char sampleName[33]; uint8 unknown1[6]; // 00 00 00 00 00 FF uint16 sampleNumber; @@ -80,11 +110,40 @@ uint8 defaulPan; // unused? uint8 defaultVolume; uint32 unknown4; - uint16 C5Freq; + uint16 c5Freq; uint8 unknown5[21]; // 00 ... 00 + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(sampleNumber); + SwapBytesLE(sampleLength); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c5Freq); + } + + // Convert header data to OpenMPT's internal format + void ConvertToMPT(ModSample &mptSmp) const + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(mptSmp.filename, fileName); + + mptSmp.nGlobalVol = 64; + mptSmp.nC5Speed = c5Freq; + mptSmp.nLength = sampleLength; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; // Hmm... apparently we should add +1 for Extreme Pinball tunes here? See sample 8 in the medieval table music. + mptSmp.nPan = 128; + mptSmp.nVolume = (defaultVolume + 1) * 2; + mptSmp.uFlags = (flags & 0x80) ? CHN_LOOP : 0; + LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); + LimitMax(mptSmp.nLoopStart, mptSmp.nLoopEnd); + } }; -struct PSMNEWSAMPLEHEADER // Sinaria sample header (and possibly other games) + +// Sinaria sample header (and possibly other games) +struct PSMNewSampleHeader { uint8 flags; char fileName[8]; // Filename of the original module (without extension) @@ -99,13 +158,40 @@ uint8 defaultPan; // unused? uint8 defaultVolume; uint32 unknown4; - uint16 C5Freq; + uint16 c5Freq; char unknown5[16]; // 00 ... 00 + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(sampleNumber); + SwapBytesLE(sampleLength); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c5Freq); + } + + // Convert header data to OpenMPT's internal format + void ConvertToMPT(ModSample &mptSmp) const + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(mptSmp.filename, fileName); + + mptSmp.nGlobalVol = 64; + mptSmp.nC5Speed = c5Freq; + mptSmp.nLength = sampleLength; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + mptSmp.nPan = 128; + mptSmp.nVolume = (defaultVolume + 1) * 2; + mptSmp.uFlags = (flags & 0x80) ? CHN_LOOP : 0; + LimitMax(mptSmp.nLoopEnd, mptSmp.nLength); + LimitMax(mptSmp.nLoopStart, mptSmp.nLoopEnd); + } }; #pragma pack(pop) -struct PSMSUBSONG // For internal use (pattern conversion) +struct PSMSubSong // For internal use (pattern conversion) { vector<uint8> channelPanning, channelVolume; vector<bool> channelSurround; @@ -113,7 +199,7 @@ char songName[10]; ORDERINDEX startOrder, endOrder, restartPos; - PSMSUBSONG() + PSMSubSong() { channelPanning.assign(MAX_BASECHANNELS, 128); channelVolume.assign(MAX_BASECHANNELS, 64); @@ -127,30 +213,36 @@ // Portamento effect conversion (depending on format version) -inline BYTE ConvertPSMPorta(BYTE param, bool bNewFormat) -//------------------------------------------------------ +uint8 ConvertPSMPorta(uint8 param, bool newFormat) +//------------------------------------------------ { - return ((bNewFormat) ? (param) : ((param < 4) ? (param | 0xF0) : (param >> 2))); + return (newFormat + ? param + : ((param < 4) + ? (param | 0xF0) + : (param >> 2))); } -bool CSoundFile::ReadPSM(const LPCBYTE lpStream, const DWORD dwMemLength) -//----------------------------------------------------------------------- +bool CSoundFile::ReadPSM(FileReader &file) +//---------------------------------------- { - DWORD dwMemPos = 0; - bool bNewFormat = false; // The game "Sinaria" uses a slightly modified PSM structure + file.Rewind(); + PSMFileHeader fileHeader; + if(!file.ReadConvertEndianness(fileHeader)) + { + return false; + } - ASSERT_CAN_READ(sizeof(PSMNEWHEADER)); - PSMNEWHEADER *shdr = (PSMNEWHEADER *)lpStream; + bool newFormat = false; // The game "Sinaria" uses a slightly modified PSM structure - if(LittleEndian(shdr->formatID) == PSM16HEAD_PSM_) // "PSM\xFE" - PSM16 format - return ReadPSM16(lpStream, dwMemLength); - // Check header - if(LittleEndian(shdr->formatID) != PSMHEAD_PSM_ // "PSM " - || LittleEndian(shdr->fileSize) != dwMemLength - 12 - || LittleEndian(shdr->fileInfoID) != PSMHEAD_FILE // "FILE" - ) return false; + if(fileHeader.formatID != PSMFileHeader::magicPSM_ // "PSM " + || fileHeader.fileSize != file.BytesLeft() + || fileHeader.fileInfoID != PSMFileHeader::magicFILE) // "FILE" + { + return false; + } // Yep, this seems to be a valid file. m_nType = MOD_TYPE_PSM; @@ -158,229 +250,252 @@ SetModFlag(MSF_COMPATIBLE_PLAY, true); m_nChannels = 0; - dwMemPos += 12; - MemsetZero(m_szNames); m_nVSTiVolume = m_nSamplePreAmp = 48; // not supported in this format, so use a good default value // pattern offset and identifier - PATTERNINDEX numPatterns = 0; // used for setting up the orderlist - final pattern count - vector<uint32> patternOffsets; // pattern offsets (sorted as they occour in the file) - vector<uint32> patternIDs; // pattern IDs (sorted as they occour in the file) - vector<uint32> orderOffsets; // combine the upper two vectors to get the offsets for each order item + PATTERNINDEX numPatterns = 0; // used for setting up the orderlist - final pattern count + vector<FileReader> patternChunks; // pattern offsets (sorted as they occour in the file) + vector<uint32> patternIDs; // pattern IDs (sorted as they occour in the file) + vector<FileReader *> orderOffsets; // combine the upper two vectors to get the offsets for each order item Order.clear(); // subsong setup - vector<PSMSUBSONG> subsongs; - bool bSubsongPanningDiffers = false; // do we have subsongs with different panning positions? + vector<PSMSubSong> subsongs; + bool subsongPanningDiffers = false; // do we have subsongs with different panning positions? - while(dwMemPos + 8 < dwMemLength) + while(file.BytesLeft()) { - // Skip through the chunks - ASSERT_CAN_READ(8); - uint32 chunkID = LittleEndian(*(uint32 *)(lpStream + dwMemPos)); - uint32 chunkSize = LittleEndian(*(uint32 *)(lpStream + dwMemPos + 4)); - dwMemPos += 8; + // Go through the chunks + PSMChunk chunkHead; + if(!file.ReadConvertEndianness(chunkHead)) + { + break; + } - ASSERT_CAN_READ(chunkSize); + FileReader chunk = file.GetChunk(chunkHead.length); - switch(chunkID) + switch(chunkHead.id) { - case PSMCHUNKID_TITL: // "TITL" - Song Title - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], reinterpret_cast<const char *>(lpStream + dwMemPos), chunkSize); + case PSMChunk::idTITL: // "TITL" - Song Title + chunk.ReadString<StringFixer::spacePadded>(m_szNames[0], chunk.GetLength()); break; - case PSMCHUNKID_SDFT: // "SDFT" - Format info (song data starts here) - if(chunkSize != 8 || memcmp(lpStream + dwMemPos, "MAINSONG", 8)) return false; + case PSMChunk::idSDFT: // "SDFT" - Format info (song data starts here) + if(chunk.GetLength() != 8 || !chunk.ReadMagic("MAINSONG")) + { + return false; + } break; - case PSMCHUNKID_PBOD: // "PBOD" - Pattern data of a single pattern - if(chunkSize < 8 || chunkSize != LittleEndian(*(uint32 *)(lpStream + dwMemPos))) return false; // same value twice + case PSMChunk::idPBOD: // "PBOD" - Pattern data of a single pattern + if(chunk.GetLength() != chunk.ReadUint32LE() // Same value twice + || chunk.GetLength() < 8) + { + break; + } // Pattern ID (something like "P0 " or "P13 ", or "PATT0 " in Sinaria) follows - if(memcmp(lpStream + dwMemPos + 4, "P", 1)) return false; - if(!memcmp(lpStream + dwMemPos + 4, "PATT", 4)) bNewFormat = true; - if(bNewFormat && chunkSize < 12) return false; // 4 additional bytes + char patternID[5]; + if(!chunk.ReadString<StringFixer::spacePadded>(patternID, 4) || patternID[0] != 'P') + { + break; + } + if(!memcmp(patternID, "PATT", 4)) + { + // New format has four additional bytes - read patternID again. + newFormat = true; + chunk.ReadString<StringFixer::spacePadded>(patternID, 4); + } + patternIDs.push_back(atoi(&patternID[newFormat ? 0 : 1])); + // We're going to read the rest of the pattern data later. + patternChunks.push_back(chunk.GetChunk(chunk.BytesLeft())); - char patternID[4]; - memcpy(patternID, lpStream + dwMemPos + 5 + (bNewFormat ? 3 : 0), 3); - patternID[3] = 0; - patternIDs.push_back(atoi(patternID)); - patternOffsets.push_back(dwMemPos + 8 + (bNewFormat ? 4 : 0)); - // Convert later as we have to know how many channels there are. break; - case PSMCHUNKID_SONG: // "SONG" - Subsong information (channel count etc) + case PSMChunk::idSONG: // "SONG" - Subsong information (channel count etc) { - if(chunkSize < sizeof(PSMSONGHEADER)) return false; - PSMSONGHEADER *pSong = (PSMSONGHEADER *)(lpStream + dwMemPos); - if(pSong->compression != 0x01) return false; // no compression for PSM files - m_nChannels = Clamp(CHANNELINDEX(pSong->numChannels), m_nChannels, MAX_BASECHANNELS); // subsongs *might* have different channel count + PSMSongHeader songHeader; + if(!chunk.Read(songHeader)) + { + break; + } + if(songHeader.compression != 0x01) + { + // No compression for PSM files + return false; + } + // Subsongs *might* have different channel count + m_nChannels = Clamp(static_cast<CHANNELINDEX>(songHeader.numChannels), m_nChannels, MAX_BASECHANNELS); - PSMSUBSONG subsong; + PSMSubSong subsong; subsong.restartPos = (ORDERINDEX)Order.size(); // restart order "offset": current orderlist length - StringFixer::ReadString<StringFixer::nullTerminated>(subsong.songName, pSong->songType); // subsong name + StringFixer::ReadString<StringFixer::nullTerminated>(subsong.songName, songHeader.songType); // subsong name - DWORD dwChunkPos = dwMemPos + sizeof(PSMSONGHEADER); - - // "Sub sub chunks" - while(dwChunkPos + 8 < dwMemPos + chunkSize) + // Read "Sub sub chunks" + FileReader subChunk = chunk.GetChunk(chunk.BytesLeft()); + while(subChunk.BytesLeft()) { - uint32 subChunkID = LittleEndian(*(uint32 *)(lpStream + dwChunkPos)); - uint32 subChunkSize = LittleEndian(*(uint32 *)(lpStream + dwChunkPos + 4)); - dwChunkPos += 8; + PSMChunk subChunkHead; + if(!subChunk.ReadConvertEndianness(subChunkHead)) + { + break; + } - switch(subChunkID) + switch(subChunkHead.id) { - case PSMCHUNKID_DATE: // "DATE" - Conversion date (YYMMDD) - if(subChunkSize != 6) break; - + case PSMChunk::idDATE: // "DATE" - Conversion date (YYMMDD) + if(subChunkHead.length == 6) { char cversion[7]; - memcpy(cversion, lpStream + dwChunkPos, 6); - cversion[6] = 0; + subChunk.ReadString<StringFixer::maybeNullTerminated>(cversion, 6); int version = atoi(cversion); // Sinaria song dates (just to go sure...) if(version == 800211 || version == 940902 || version == 940903 || version == 940906 || version == 940914 || version == 941213) - bNewFormat = true; + newFormat = true; } break; - case PSMCHUNKID_OPLH: // "OPLH" - Order list, channel + module settings + case PSMChunk::idOPLH: // "OPLH" - Order list, channel + module settings + if(subChunkHead.length >= 9) { - if(subChunkSize < 9) return false; // First two bytes = Number of chunks that follow - //uint16 nTotalChunks = LittleEndian(*(uint16 *)(lpStream + dwChunkPos)); + //uint16 totalChunks = subChunk.ReadUint16LE(); + subChunk.Skip(2); // Now, the interesting part begins! - DWORD dwSettingsOffset = dwChunkPos + 2; - uint16 nChunkCount = 0, nFirstOrderChunk = uint16_max; + uint16 chunkCount = 0, firstOrderChunk = uint16_max; // "Sub sub sub chunks" (grrrr, silly format) - while(dwSettingsOffset - dwChunkPos + 1 < subChunkSize) + while(subChunk.BytesLeft()) { - switch(lpStream[dwSettingsOffset]) + uint8 subChunkID = subChunk.ReadUint8(); + if(!subChunkID) { - case 0x00: // End - dwSettingsOffset += 1; + // Last chunk was reached. break; + } + switch(subChunkID) + { case 0x01: // Order list item - if(dwSettingsOffset - dwChunkPos + 5 > subChunkSize) return false; // Pattern name follows - find pattern (this is the orderlist) { - char patternID[4]; // temporary - memcpy(patternID, lpStream + dwSettingsOffset + 2 + (bNewFormat ? 3 : 0), 3); - patternID[3] = 0; - uint32 nPattern = atoi(patternID); + char patternID[5]; // temporary + if(newFormat) + { + subChunk.Skip(4); + subChunk.ReadString<StringFixer::spacePadded>(patternID, 4); + } else + { + subChunk.Skip(1); + subChunk.ReadString<StringFixer::spacePadded>(patternID, 3); + } + uint32 pat = atoi(patternID); // seek which pattern has this ID - for(uint32 i = 0; i < patternIDs.size(); i++) + for(size_t i = 0; i < patternIDs.size(); i++) { - if(patternIDs[i] == nPattern) + if(patternIDs[i] == pat) { // found the right pattern, copy offset + start / end positions. if(subsong.startOrder == ORDERINDEX_INVALID) - subsong.startOrder = (ORDERINDEX)orderOffsets.size(); - subsong.endOrder = (ORDERINDEX)orderOffsets.size(); + subsong.startOrder = static_cast<ORDERINDEX>(orderOffsets.size()); + subsong.endOrder = static_cast<ORDERINDEX>(orderOffsets.size()); // every pattern in the order will be unique, so store the pointer + pattern ID - orderOffsets.push_back(patternOffsets[i]); + orderOffsets.push_back(&patternChunks[i]); Order.Append(numPatterns); numPatterns++; break; } } } - // decide whether this is the first order chunk or not (for finding out the correct restart position) - if(nFirstOrderChunk == uint16_max) nFirstOrderChunk = nChunkCount; - dwSettingsOffset += 5 + (bNewFormat ? 4 : 0); + // Decide whether this is the first order chunk or not (for finding out the correct restart position) + if(firstOrderChunk == uint16_max) firstOrderChunk = chunkCount; break; case 0x04: // Restart position { - uint16 nRestartChunk = LittleEndianW(*(uint16 *)(lpStream + dwSettingsOffset + 1)); - ORDERINDEX nRestartPosition = 0; - if(nRestartChunk >= nFirstOrderChunk) nRestartPosition = (ORDERINDEX)(nRestartChunk - nFirstOrderChunk); - subsong.restartPos += nRestartPosition; + uint16 restartChunk = subChunk.ReadUint16LE(); + ORDERINDEX restartPosition = 0; + if(restartChunk >= firstOrderChunk) restartPosition = static_cast<ORDERINDEX>(restartChunk - firstOrderChunk); + subsong.restartPos += restartPosition; } - dwSettingsOffset += 3; break; case 0x07: // Default Speed - if(dwSettingsOffset - dwChunkPos + 2 > subChunkSize) break; - subsong.defaultSpeed = lpStream[dwSettingsOffset + 1]; - dwSettingsOffset += 2; + subsong.defaultSpeed = subChunk.ReadUint8(); break; case 0x08: // Default Tempo - if(dwSettingsOffset - dwChunkPos + 2 > subChunkSize) break; - subsong.defaultTempo = lpStream[dwSettingsOffset + 1]; - dwSettingsOffset += 2; + subsong.defaultTempo = subChunk.ReadUint8(); break; case 0x0C: // Sample map table (???) - if(dwSettingsOffset - dwChunkPos + 7 > subChunkSize) break; - // Never seems to be different, so... - if (lpStream[dwSettingsOffset + 1] != 0x00 || lpStream[dwSettingsOffset + 2] != 0xFF || - lpStream[dwSettingsOffset + 3] != 0x00 || lpStream[dwSettingsOffset + 4] != 0x00 || - lpStream[dwSettingsOffset + 5] != 0x01 || lpStream[dwSettingsOffset + 6] != 0x00) + if (subChunk.ReadUint8() != 0x00 || subChunk.ReadUint8() != 0xFF || + subChunk.ReadUint8() != 0x00 || subChunk.ReadUint8() != 0x00 || + subChunk.ReadUint8() != 0x01 || subChunk.ReadUint8() != 0x00) + { return false; - dwSettingsOffset += 7; + } break; case 0x0D: // Channel panning table - if(dwSettingsOffset - dwChunkPos + 4 > subChunkSize) break; - - if(lpStream[dwSettingsOffset + 1] < MAX_BASECHANNELS) { - CHANNELINDEX nChn = lpStream[dwSettingsOffset + 1]; - switch(lpStream[dwSettingsOffset + 3]) + uint8 chn = subChunk.ReadUint8(); + uint8 pan = subChunk.ReadUint8(); + uint8 type = subChunk.ReadUint8(); + if(chn < subsong.channelPanning.size()) { - case 0: // use panning - subsong.channelPanning[nChn] = lpStream[dwSettingsOffset + 2] ^ 128; - subsong.channelSurround[nChn] = false; - break; + switch(type) + { + case 0: // use panning + subsong.channelPanning[chn] = pan ^ 128; + subsong.channelSurround[chn] = false; + break; - case 2: // surround - subsong.channelPanning[nChn] = 128; - subsong.channelSurround[nChn] = true; - break; + case 2: // surround + subsong.channelPanning[chn] = 128; + subsong.channelSurround[chn] = true; + break; - case 4: // center - subsong.channelPanning[nChn] = 128; - subsong.channelSurround[nChn] = false; - break; + case 4: // center + subsong.channelPanning[chn] = 128; + subsong.channelSurround[chn] = false; + break; + } + if(subsongPanningDiffers == false && subsongs.size() > 0) + { + if(subsongs.back().channelPanning[chn] != subsong.channelPanning[chn] + || subsongs.back().channelSurround[chn] != subsong.channelSurround[chn]) + subsongPanningDiffers = true; + } } - if(bSubsongPanningDiffers == false && subsongs.size() > 0) - { - if(subsongs.back().channelPanning[nChn] != subsong.channelPanning[nChn] - || subsongs.back().channelSurround[nChn] != subsong.channelSurround[nChn]) - bSubsongPanningDiffers = true; - } } - dwSettingsOffset += 4; break; case 0x0E: // Channel volume table (0...255) - apparently always 255 - if(dwSettingsOffset - dwChunkPos + 3 > subChunkSize) break; - if(lpStream[dwSettingsOffset + 1] < MAX_BASECHANNELS) - subsong.channelVolume[lpStream[dwSettingsOffset + 1]] = (lpStream[dwSettingsOffset + 2] >> 2) + 1; - - dwSettingsOffset += 3; + { + uint8 chn = subChunk.ReadUint8(); + uint8 vol = subChunk.ReadUint8(); + if(chn < subsong.channelVolume.size()) + { + subsong.channelVolume[chn] = (vol / 4) + 1; + } + } break; default: // How the hell should this happen? I've listened through almost all existing (original) PSM files. :) // anyway, in such cases, we have to quit as we don't know how big the chunk really is. return false; - break; } - nChunkCount++; + chunkCount++; } // separate subsongs by "---" patterns orderOffsets.push_back(nullptr); @@ -388,37 +503,44 @@ } break; - case PSMCHUNKID_PPAN: // PPAN - Channel panning table (used in Sinaria) - if(subChunkSize & 1) return false; - for(uint32 i = 0; i < subChunkSize; i += 2) + case PSMChunk::idPPAN: // PPAN - Channel panning table (used in Sinaria) + // In some Sinaria tunes, this is actually longer than 2 * channels... + ASSERT(subChunkHead.length >= m_nChannels * 2u); + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - CHANNELINDEX nChn = (CHANNELINDEX)(i >> 1); - if(nChn >= m_nChannels) break; - switch(lpStream[dwChunkPos + i]) + if(subChunk.BytesLeft() < 2) { + break; + } + + uint8 type = subChunk.ReadUint8(); + uint8 pan = subChunk.ReadUint8(); + + switch(type) + { case 0: // use panning - subsong.channelPanning[nChn] = lpStream[dwChunkPos + i + 1] ^ 128; - subsong.channelSurround[nChn] = false; + subsong.channelPanning[chn] = pan ^ 128; + subsong.channelSurround[chn] = false; break; case 2: // surround - subsong.channelPanning[nChn] = 128; - subsong.channelSurround[nChn] = true; + subsong.channelPanning[chn] = 128; + subsong.channelSurround[chn] = true; break; case 4: // center - subsong.channelPanning[nChn] = 128; - subsong.channelSurround[nChn] = false; + subsong.channelPanning[chn] = 128; + subsong.channelSurround[chn] = false; break; } } break; - case PSMCHUNKID_PATT: // PATT - Pattern list + case PSMChunk::idPATT: // PATT - Pattern list // We don't really need this. break; - case PSMCHUNKID_DSAM: // DSAM - Sample list + case PSMChunk::idDSAM: // DSAM - Sample list // We don't need this either. break; @@ -426,8 +548,6 @@ break; } - - dwChunkPos += subChunkSize; } // attach this subsong to the subsong list - finally, all "sub sub sub ..." chunks are parsed. @@ -436,51 +556,47 @@ break; - case PSMCHUNKID_DSMP: // DSMP - Samples - if(!bNewFormat) + case PSMChunk::idDSMP: // DSMP - Samples + if(!newFormat) { - // original header - if(chunkSize < sizeof(PSMOLDSAMPLEHEADER)) return false; - PSMOLDSAMPLEHEADER *pSample = (PSMOLDSAMPLEHEADER *)(lpStream + dwMemPos); - SAMPLEINDEX smp = (SAMPLEINDEX)(LittleEndianW(pSample->sampleNumber) + 1); - m_nSamples = max(m_nSamples, smp); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp], pSample->sampleName); - StringFixer::ReadString<StringFixer::maybeNullTerminated>(Samples[smp].filename, pSample->fileName); + // Original header + PSMOldSampleHeader sampleHeader; + if(!chunk.ReadConvertEndianness(sampleHeader)) + { + break; + } - Samples[smp].nGlobalVol = 0x40; - Samples[smp].nC5Speed = LittleEndianW(pSample->C5Freq); - Samples[smp].nLength = LittleEndian(pSample->sampleLength); - Samples[smp].nLoopStart = LittleEndian(pSample->loopStart); - Samples[smp].nLoopEnd = LittleEndian(pSample->loopEnd); // Hmm... apparently we should add +1 for Extreme Pinball tunes here? See sample 8 in the medieval table music. - Samples[smp].nPan = 128; - Samples[smp].nVolume = (pSample->defaultVolume + 1) << 1; - Samples[smp].uFlags = (pSample->flags & 0x80) ? CHN_LOOP : 0; - if(Samples[smp].nLoopEnd == 0xFFFFFF) Samples[smp].nLoopEnd = Samples[smp].nLength; + SAMPLEINDEX smp = static_cast<SAMPLEINDEX>(sampleHeader.sampleNumber + 1); + if(smp < MAX_SAMPLES) + { + m_nSamples = max(m_nSamples, smp); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp], sampleHeader.sampleName); - // Delta-encoded samples - ReadSample(&Samples[smp], RS_PCM8D, (LPCSTR)(lpStream + dwMemPos + sizeof(PSMOLDSAMPLEHEADER)), Samples[smp].nLength); + sampleHeader.ConvertToMPT(Samples[smp]); + + // Delta-encoded samples + ReadSample(&Samples[smp], RS_PCM8D, chunk); + } } else { // Sinaria uses a slightly different sample header - if(chunkSize < sizeof(PSMNEWSAMPLEHEADER)) return false; - PSMNEWSAMPLEHEADER *pSample = (PSMNEWSAMPLEHEADER *)(lpStream + dwMemPos); - SAMPLEINDEX smp = (SAMPLEINDEX)(LittleEndianW(pSample->sampleNumber) + 1); - m_nSamples = max(m_nSamples, smp); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp], pSample->sampleName); - StringFixer::ReadString<StringFixer::maybeNullTerminated>(Samples[smp].filename, pSample->fileName); + PSMNewSampleHeader sampleHeader; + if(!chunk.ReadConvertEndianness(sampleHeader)) + { + break; + } - Samples[smp].nGlobalVol = 0x40; - Samples[smp].nC5Speed = LittleEndianW(pSample->C5Freq); - Samples[smp].nLength = LittleEndian(pSample->sampleLength); - Samples[smp].nLoopStart = LittleEndian(pSample->loopStart); - Samples[smp].nLoopEnd = LittleEndian(pSample->loopEnd); - Samples[smp].nPan = 128; - Samples[smp].nVolume = (pSample->defaultVolume + 1) << 1; - Samples[smp].uFlags = (pSample->flags & 0x80) ? CHN_LOOP : 0; - if(Samples[smp].nLoopEnd == 0xFFFFFF) Samples[smp].nLoopEnd = Samples[smp].nLength; + SAMPLEINDEX smp = static_cast<SAMPLEINDEX>(sampleHeader.sampleNumber + 1); + if(smp < MAX_SAMPLES) + { + m_nSamples = max(m_nSamples, smp); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp], sampleHeader.sampleName); - // Delta-encoded samples - ReadSample(&Samples[smp], RS_PCM8D, (LPCSTR)(lpStream + dwMemPos + sizeof(PSMNEWSAMPLEHEADER)), Samples[smp].nLength); + sampleHeader.ConvertToMPT(Samples[smp]); + + // Delta-encoded samples + ReadSample(&Samples[smp], RS_PCM8D, chunk); + } } break; @@ -489,291 +605,292 @@ break; } - - dwMemPos += chunkSize; } if(m_nChannels == 0 || subsongs.size() == 0) + { return false; + } // Make the default variables of the first subsong global m_nDefaultSpeed = subsongs[0].defaultSpeed; m_nDefaultTempo = subsongs[0].defaultTempo; m_nRestartPos = subsongs[0].restartPos; - for(CHANNELINDEX nChn = 0; nChn < m_nChannels; nChn++) + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - ChnSettings[nChn].nVolume = subsongs[0].channelVolume[nChn]; - ChnSettings[nChn].nPan = subsongs[0].channelPanning[nChn]; - if(subsongs[0].channelSurround[nChn]) - ChnSettings[nChn].dwFlags |= CHN_SURROUND; + ChnSettings[chn].nVolume = subsongs[0].channelVolume[chn]; + ChnSettings[chn].nPan = subsongs[0].channelPanning[chn]; + if(subsongs[0].channelSurround[chn]) + ChnSettings[chn].dwFlags |= CHN_SURROUND; else - ChnSettings[nChn].dwFlags &= ~CHN_SURROUND; + ChnSettings[chn].dwFlags &= ~CHN_SURROUND; } // Now that we know the number of channels, we can go through all the patterns. // This is a bit stupid since we will even read duplicate patterns twice, but hey, we do this just once... so who cares? - PATTERNINDEX nPat = 0; - for(ORDERINDEX nOrd = 0; nOrd < Order.size(); nOrd++) + PATTERNINDEX pat = 0; + for(ORDERINDEX ord = 0; ord < Order.size(); ord++) { - if(orderOffsets[nOrd] == nullptr) continue; - uint32 dwPatternOffset = orderOffsets[nOrd]; - if(dwPatternOffset + 2 > dwMemLength) return false; - uint16 patternSize = LittleEndianW(*(uint16 *)(lpStream + dwPatternOffset)); - dwPatternOffset += 2; + if(orderOffsets[ord] == nullptr) + { + // Separator pattern + continue; + } - if(Patterns.Insert(nPat, patternSize)) + FileReader patternChunk = *orderOffsets[ord]; + + uint16 numRows = patternChunk.ReadUint16LE(); + + if(Patterns.Insert(pat, numRows)) + { break; + } + enum + { + noteFlag = 0x80, + instrFlag = 0x40, + volFlag = 0x20, + effectFlag = 0x10, + }; + // Read pattern. - ModCommand *row_data; - row_data = Patterns[nPat]; + for(int row = 0; row < numRows; row++) + { + PatternRow rowBase = Patterns[pat].GetRow(row); + uint16 rowSize = patternChunk.ReadUint16LE(); + if(rowSize < 2) + { + continue; + } - for(int nRow = 0; nRow < patternSize; nRow++) - { - if(dwPatternOffset + 2 > dwMemLength) return false; - uint16 rowSize = LittleEndianW(*(uint16 *)(lpStream + dwPatternOffset)); + FileReader rowChunk = patternChunk.GetChunk(rowSize - 2); - uint32 dwRowOffset = dwPatternOffset + 2; - - while(dwRowOffset < dwPatternOffset + rowSize) + while(rowChunk.BytesLeft()) { - if(dwRowOffset + 1 > dwMemLength) return false; - BYTE mask = lpStream[dwRowOffset]; + uint8 flags = rowChunk.ReadUint8(); + uint8 channel = rowChunk.ReadUint8(); // Point to the correct channel - ModCommand *m = row_data + min(m_nChannels - 1, lpStream[dwRowOffset + 1]); - dwRowOffset += 2; + ModCommand &m = rowBase[min(m_nChannels - 1, channel)]; - if(mask & 0x80) + if(flags & noteFlag) { - if(dwRowOffset + 1 > dwMemLength) return false; // Note present - BYTE bNote = lpStream[dwRowOffset]; - if(!bNewFormat) + uint8 note = rowChunk.ReadUint8(); + if(!newFormat) { - if(bNote == 0xFF) - bNote = NOTE_NOTECUT; + if(note == 0xFF) + note = NOTE_NOTECUT; else - if(bNote < 129) bNote = (bNote & 0x0F) + 12 * (bNote >> 4) + 13; + if(note < 129) note = (note & 0x0F) + 12 * (note >> 4) + 13; } else { - if(bNote < 85) bNote += 36; + if(note < 85) note += 36; } - m->note = bNote; - dwRowOffset++; + m.note = note; } - if(mask & 0x40) + if(flags & instrFlag) { - if(dwRowOffset + 1 > dwMemLength) return false; // Instrument present - m->instr = lpStream[dwRowOffset] + 1; - dwRowOffset++; + m.instr = rowChunk.ReadUint8() + 1; } - if(mask & 0x20) + if(flags & volFlag) { - if(dwRowOffset + 1 > dwMemLength) return false; // Volume present - m->volcmd = VOLCMD_VOLUME; - m->vol = (min(lpStream[dwRowOffset], 127) + 1) >> 1; - dwRowOffset++; + uint8 vol = rowChunk.ReadUint8(); + m.volcmd = VOLCMD_VOLUME; + m.vol = (min(vol, 127) + 1) / 2; } - if(mask & 0x10) + if(flags & effectFlag) { // Effect present - convert - if(dwRowOffset + 2 > dwMemLength) return false; - uint8 command = lpStream[dwRowOffset], param = lpStream[dwRowOffset + 1]; + m.command = rowChunk.ReadUint8(); + m.param = rowChunk.ReadUint8(); - switch(command) + switch(m.command) { // Volslides case 0x01: // fine volslide up - command = CMD_VOLUMESLIDE; - if (bNewFormat) param = (param << 4) | 0x0F; - else param = ((param & 0x1E) << 3) | 0x0F; + m.command = CMD_VOLUMESLIDE; + if (newFormat) m.param = (m.param << 4) | 0x0F; + else m.param = ((m.param & 0x1E) << 3) | 0x0F; break; case 0x02: // volslide up - command = CMD_VOLUMESLIDE; - if (bNewFormat) param = 0xF0 & (param << 4); - else param = 0xF0 & (param << 3); + m.command = CMD_VOLUMESLIDE; + if (newFormat) m.param = 0xF0 & (m.param << 4); + else m.param = 0xF0 & (m.param << 3); break; case 0x03: // fine volslide down - command = CMD_VOLUMESLIDE; - if (bNewFormat) param |= 0xF0; - else param = 0xF0 | (param >> 1); + m.command = CMD_VOLUMESLIDE; + if (newFormat) m.param |= 0xF0; + else m.param = 0xF0 | (m.param >> 1); break; case 0x04: // volslide down - command = CMD_VOLUMESLIDE; - if (bNewFormat) param &= 0x0F; - else if(param < 2) param |= 0xF0; else param = (param >> 1) & 0x0F; + m.command = CMD_VOLUMESLIDE; + if (newFormat) m.param &= 0x0F; + else if(m.param < 2) m.param |= 0xF0; else m.param = (m.param >> 1) & 0x0F; break; // Portamento case 0x0B: // fine portamento up - command = CMD_PORTAMENTOUP; - param = 0xF0 | ConvertPSMPorta(param, bNewFormat); + m.command = CMD_PORTAMENTOUP; + m.param = 0xF0 | ConvertPSMPorta(m.param, newFormat); break; case 0x0C: // portamento up - command = CMD_PORTAMENTOUP; - param = ConvertPSMPorta(param, bNewFormat); + m.command = CMD_PORTAMENTOUP; + m.param = ConvertPSMPorta(m.param, newFormat); break; case 0x0D: // fine portamento down - command = CMD_PORTAMENTODOWN; - param = 0xF0 | ConvertPSMPorta(param, bNewFormat); + m.command = CMD_PORTAMENTODOWN; + m.param = 0xF0 | ConvertPSMPorta(m.param, newFormat); break; case 0x0E: // portamento down - command = CMD_PORTAMENTODOWN; - param = ConvertPSMPorta(param, bNewFormat); + m.command = CMD_PORTAMENTODOWN; + m.param = ConvertPSMPorta(m.param, newFormat); break; case 0x0F: // tone portamento - command = CMD_TONEPORTAMENTO; - if(!bNewFormat) param >>= 2; + m.command = CMD_TONEPORTAMENTO; + if(!newFormat) m.param >>= 2; break; case 0x11: // glissando control - command = CMD_S3MCMDEX; - param = 0x10 | (param & 0x01); + m.command = CMD_S3MCMDEX; + m.param = 0x10 | (m.param & 0x01); break; case 0x10: // tone portamento + volslide up - command = CMD_TONEPORTAVOL; - param = param & 0xF0; + m.command = CMD_TONEPORTAVOL; + m.param = m.param & 0xF0; break; case 0x12: // tone portamento + volslide down - command = CMD_TONEPORTAVOL; - param = (param >> 4) & 0x0F; + m.command = CMD_TONEPORTAVOL; + m.param = (m.param >> 4) & 0x0F; break; // Vibrato case 0x15: // vibrato - command = CMD_VIBRATO; + m.command = CMD_VIBRATO; break; case 0x16: // vibrato waveform - command = CMD_S3MCMDEX; - param = 0x30 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0x30 | (m.param & 0x0F); break; case 0x17: // vibrato + volslide up - command = CMD_VIBRATOVOL; - param = 0xF0 | param; + m.command = CMD_VIBRATOVOL; + m.param = 0xF0 | m.param; break; case 0x18: // vibrato + volslide down - command = CMD_VIBRATOVOL; + m.command = CMD_VIBRATOVOL; break; // Tremolo case 0x1F: // tremolo - command = CMD_TREMOLO; + m.command = CMD_TREMOLO; break; case 0x20: // tremolo waveform - command = CMD_S3MCMDEX; - param = 0x40 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0x40 | (m.param & 0x0F); break; // Sample commands case 0x29: // 3-byte offset - we only support the middle byte. - if(dwRowOffset + 4 > dwMemLength) return false; - command = CMD_OFFSET; - param = lpStream[dwRowOffset + 2]; - dwRowOffset += 2; + m.command = CMD_OFFSET; + m.param = rowChunk.ReadUint8(); + rowChunk.Skip(1); break; case 0x2A: // retrigger - command = CMD_RETRIG; + m.command = CMD_RETRIG; break; case 0x2B: // note cut - command = CMD_S3MCMDEX; - param = 0xC0 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0xC0 | (m.param & 0x0F); break; case 0x2C: // note delay - command = CMD_S3MCMDEX; - param = 0xD0 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0xD0 | (m.param & 0x0F); break; // Position change case 0x33: // position jump - command = CMD_POSITIONJUMP; - param >>= 1; - dwRowOffset += 1; + m.command = CMD_POSITIONJUMP; + m.param >>= 1; + rowChunk.Skip(1); break; case 0x34: // pattern break - command = CMD_PATTERNBREAK; - param >>= 1; + m.command = CMD_PATTERNBREAK; + m.param >>= 1; break; case 0x35: // loop pattern - command = CMD_S3MCMDEX; - param = 0xB0 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0xB0 | (m.param & 0x0F); break; case 0x36: // pattern delay - command = CMD_S3MCMDEX; - param = 0xE0 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0xE0 | (m.param & 0x0F); break; // speed change case 0x3D: // set speed - command = CMD_SPEED; + m.command = CMD_SPEED; break; case 0x3E: // set tempo - command = CMD_TEMPO; + m.command = CMD_TEMPO; break; // misc commands case 0x47: // arpeggio - command = CMD_ARPEGGIO; + m.command = CMD_ARPEGGIO; break; case 0x48: // set finetune - command = CMD_S3MCMDEX; - param = 0x20 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0x20 | (m.param & 0x0F); break; case 0x49: // set balance - command = CMD_S3MCMDEX; - param = 0x80 | (param & 0x0F); + m.command = CMD_S3MCMDEX; + m.param = 0x80 | (m.param & 0x0F); break; case CMD_MODCMDEX: // for some strange home-made tunes - command = CMD_S3MCMDEX; + m.command = CMD_S3MCMDEX; break; default: - command = CMD_NONE; + m.command = CMD_NONE; break; } - - m->command = command; - m->param = param; - - dwRowOffset += 2; } } + } - row_data += m_nChannels; - dwPatternOffset += rowSize; - } - nPat++; + pat++; } if(subsongs.size() > 1) { // write subsong "configuration" to patterns (only if there are multiple subsongs) - for(uint32 i = 0; i < subsongs.size(); i++) + for(size_t i = 0; i < subsongs.size(); i++) { PATTERNINDEX startPattern = Order[subsongs[i].startOrder], endPattern = Order[subsongs[i].endOrder]; if(startPattern == PATTERNINDEX_INVALID || endPattern == PATTERNINDEX_INVALID) continue; // what, invalid subtune? // set the subsong name to all pattern names - for(PATTERNINDEX nPat = startPattern; nPat <= endPattern; nPat++) + for(PATTERNINDEX pat = startPattern; pat <= endPattern; pat++) { - Patterns[nPat].SetName(subsongs[i].songName); + Patterns[pat].SetName(subsongs[i].songName); } // subsongs with different panning setup -> write to pattern (MUSIC_C.PSM) - if(bSubsongPanningDiffers) + if(subsongPanningDiffers) { - for(CHANNELINDEX nChn = 0; nChn < m_nChannels; nChn++) + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - if(subsongs[i].channelSurround[nChn] == true) - TryWriteEffect(startPattern, 0, CMD_S3MCMDEX, 0x91, false, nChn, false, weTryNextRow); + if(subsongs[i].channelSurround[chn] == true) + TryWriteEffect(startPattern, 0, CMD_S3MCMDEX, 0x91, false, chn, false, weTryNextRow); else - TryWriteEffect(startPattern, 0, CMD_PANNING8, subsongs[i].channelPanning[nChn], false, nChn, false, weTryNextRow); + TryWriteEffect(startPattern, 0, CMD_PANNING8, subsongs[i].channelPanning[chn], false, chn, false, weTryNextRow); } } // write default tempo/speed to pattern @@ -786,13 +903,13 @@ if(subsongs[i].restartPos != ORDERINDEX_INVALID) { ROWINDEX lastRow = Patterns[endPattern].GetNumRows() - 1; - ModCommand *row_data; - row_data = Patterns[endPattern]; - for(uint32 nCell = 0; nCell < m_nChannels * Patterns[endPattern].GetNumRows(); nCell++, row_data++) + ModCommand *m; + m = Patterns[endPattern]; + for(uint32 cell = 0; cell < m_nChannels * Patterns[endPattern].GetNumRows(); cell++, m++) { - if(row_data->command == CMD_PATTERNBREAK || row_data->command == CMD_POSITIONJUMP) + if(m->command == CMD_PATTERNBREAK || m->command == CMD_POSITIONJUMP) { - lastRow = nCell / m_nChannels; + lastRow = cell / m_nChannels; break; } } @@ -809,16 +926,21 @@ // PSM16 support starts here. // -// 32-Bit chunk identifiers -#define PSM16_PORD 0x44524f50 -#define PSM16_PPAN 0x4E415050 -#define PSM16_PSAH 0x48415350 -#define PSM16_PPAT 0x54415050 - #pragma pack(push, 1) -struct PSM16HEADER +struct PSM16FileHeader { + // 32-Bit chunk identifiers + enum PSM16Magic + { + magicPSM_ = 0xFE4D5350, + + idPORD = 0x44524f50, + idPPAN = 0x4E415050, + idPSAH = 0x48415350, + idPPAT = 0x54415050, + }; + uint32 formatID; // "PSM\xFE" (PSM16) char songName[59]; // Song title, padded with nulls uint8 lineEnd; // $1A @@ -841,10 +963,38 @@ uint32 commentsOffset; // Pointer to song comment uint32 patSize; // Size of all patterns uint8 filler[40]; + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(formatID); + SwapBytesLE(songLength); + SwapBytesLE(songOrders); + SwapBytesLE(numPatterns); + SwapBytesLE(numSamples); + SwapBytesLE(numChannelsPlay); + SwapBytesLE(numChannelsReal); + SwapBytesLE(orderOffset); + SwapBytesLE(panOffset); + SwapBytesLE(patOffset); + SwapBytesLE(smpOffset); + SwapBytesLE(commentsOffset); + SwapBytesLE(patSize); + } }; -struct PSM16SMPHEADER +struct PSM16SampleHeader { + enum SampleFlags + { + smpMask = 0x7F, + smp16Bit = 0x04, + smpUnsigned = 0x08, + smpDelta = 0x10, + smpPingPong = 0x20, + smpLoop = 0x80, + }; + char filename[13]; // null-terminated char name[24]; // dito uint32 offset; // in file @@ -857,350 +1007,385 @@ int8 finetune; // Low nibble = MOD finetune, high nibble = transpose (7 = center) uint8 volume; // default volume uint16 c2freq; // Middle-C frequency, which has to be combined with the finetune and transpose. + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(offset); + SwapBytesLE(memoffset); + SwapBytesLE(sampleNumber); + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c2freq); + } + + // Convert sample header to OpenMPT's internal format + void ConvertToMPT(ModSample &mptSmp) const + { + StringFixer::ReadString<StringFixer::nullTerminated>(mptSmp.filename, filename); + + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + mptSmp.nC5Speed = c2freq; + + // It seems like that finetune and transpose are added to the already given c2freq... That's a double WTF! + // Why on earth would you want to use both systems at the same time? + CSoundFile::FrequencyToTranspose(&mptSmp); + mptSmp.nC5Speed = CSoundFile::TransposeToFrequency(mptSmp.RelativeTone + (finetune >> 4) - 7, MOD2XMFineTune(finetune & 0x0F)); + + mptSmp.nVolume = volume << 2; + mptSmp.nGlobalVol = 256; + + mptSmp.uFlags = 0; + if(flags & PSM16SampleHeader::smp16Bit) + { + mptSmp.uFlags |= CHN_16BIT; + mptSmp.nLength /= 2; + } + if(flags & PSM16SampleHeader::smpPingPong) + { + mptSmp.uFlags |= CHN_PINGPONGLOOP; + } + if(flags & PSM16SampleHeader::smpLoop) + { + mptSmp.uFlags |= CHN_LOOP; + } + } + + // Retrieve the internal sample format flags for this sample. + UINT GetSampleFormat() + { + UINT sampleFormat = (flags & PSM16SampleHeader::smp16Bit) ? RS_PCM16S : RS_PCM8S; + + if(flags & PSM16SampleHeader::smpUnsigned) + { + if(sampleFormat == RS_PCM16S) + sampleFormat = RS_PCM16U; + else + sampleFormat = RS_PCM8U; + } else if(flags & PSM16SampleHeader::smpDelta) + { + if(sampleFormat == RS_PCM16S) + sampleFormat = RS_PCM16D; + else + sampleFormat = RS_PCM8D; + } else if((flags & PSM16SampleHeader::smpMask) == 0) + { + sampleFormat = RS_PCM8D; + } + return sampleFormat; + } }; -struct PSM16PATHEADER +struct PSM16PatternHeader { uint16 size; // includes header bytes uint8 numRows; // 1 ... 64 uint8 numChans; // 1 ... 32 + + void ConvertEndianness() + { + SwapBytesLE(size); + } }; #pragma pack(pop) -bool CSoundFile::ReadPSM16(const LPCBYTE lpStream, const DWORD dwMemLength) -//------------------------------------------------------------------------- +bool CSoundFile::ReadPSM16(FileReader &file) +//------------------------------------------ { - DWORD dwMemPos = 0; + file.Rewind(); + PSM16FileHeader fileHeader; + if(!file.ReadConvertEndianness(fileHeader)) + { + return false; + } - ASSERT_CAN_READ(sizeof(PSM16HEADER)); - const PSM16HEADER *shdr = (PSM16HEADER *)lpStream; - // Check header - if((shdr->formatID != LittleEndian(PSM16HEAD_PSM_)) // "PSM\xFE" - || (shdr->lineEnd != 0x1A) - || (shdr->formatVersion != 0x10 && shdr->formatVersion != 0x01) // why is this sometimes 0x01? - || (shdr->patternVersion != 0) // 255ch pattern version not supported (did anyone use this?) - || ((shdr->songType & 3) != 0) - || (min(shdr->numChannelsPlay, shdr->numChannelsReal) == 0) - ) return false; + if(fileHeader.formatID != PSM16FileHeader::magicPSM_ // "PSM\xFE" + || fileHeader.lineEnd != 0x1A + || (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01? + || fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?) + || (fileHeader.songType & 3) != 0 + || max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0) + { + return false; + } // Seems to be valid! m_nType = MOD_TYPE_S3M; - m_nChannels = min(max(shdr->numChannelsPlay, shdr->numChannelsReal), MAX_BASECHANNELS); - m_nMasterVolume = shdr->masterVolume; + m_nChannels = min(max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal), MAX_BASECHANNELS); + m_nMasterVolume = fileHeader.masterVolume; m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; - m_nDefaultSpeed = shdr->songSpeed; - m_nDefaultTempo = shdr->songTempo; + m_nDefaultSpeed = fileHeader.songSpeed; + m_nDefaultTempo = fileHeader.songTempo; MemsetZero(m_szNames); - StringFixer::ReadString<StringFixer::maybeNullTerminated>(m_szNames[0], shdr->songName); + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], fileHeader.songName); // Read orders - dwMemPos = LittleEndian(shdr->orderOffset); - ASSERT_CAN_READ((DWORD)LittleEndianW(shdr->songOrders) + 2); - if(LittleEndian(shdr->orderOffset) > 4 && *(uint32 *)(lpStream + dwMemPos - 4) == LittleEndian(PSM16_PORD)) // PORD + if(fileHeader.orderOffset > 4 && file.Seek(fileHeader.orderOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPORD) { - Order.ReadAsByte(lpStream + dwMemPos, LittleEndianW(shdr->songOrders), dwMemLength - dwMemPos); + Order.ReadAsByte(file, fileHeader.songOrders); } // Read pan positions - dwMemPos = LittleEndian(shdr->panOffset); - ASSERT_CAN_READ(32); - if(LittleEndian(shdr->panOffset) > 4 && LittleEndian(*(uint32 *)(lpStream + dwMemPos - 4)) == PSM16_PPAN) // PPAN + if(fileHeader.panOffset > 4 && file.Seek(fileHeader.panOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPPAN) { for(CHANNELINDEX i = 0; i < 32; i++) { - ChnSettings[i].nPan = ((15 - (lpStream[dwMemPos + i] & 0x0F)) * 256 + 8) / 15; // 15 seems to be left and 0 seems to be right... + ChnSettings[i].nPan = ((15 - (file.ReadUint8() & 0x0F)) * 256 + 8) / 15; // 15 seems to be left and 0 seems to be right... ChnSettings[i].nVolume = 64; - ChnSettings[i].dwFlags = 0; // (i >= shdr->numChannelsPlay) ? CHN_MUTE : 0; // don't mute channels, as muted channels are completely ignored in S3M + ChnSettings[i].dwFlags = 0; // (i >= fileHeader.numChannelsPlay) ? CHN_MUTE : 0; // don't mute channels, as muted channels are completely ignored in S3M } } // Read samples - dwMemPos = LittleEndian(shdr->smpOffset); - ASSERT_CAN_READ(0); - if(LittleEndian(shdr->smpOffset) > 4 && *(uint32 *)(lpStream + dwMemPos - 4) == LittleEndian(PSM16_PSAH)) // PSAH + if(fileHeader.smpOffset > 4 && file.Seek(fileHeader.smpOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPSAH) { - SAMPLEINDEX iSmpCount = 0; - m_nSamples = LittleEndianW(shdr->numSamples); - while(iSmpCount < LittleEndianW(shdr->numSamples)) + FileReader sampleChunk = file.GetChunk(file.BytesLeft()); + + for(SAMPLEINDEX fileSample = 0; fileSample < fileHeader.numSamples; fileSample++) { - ASSERT_CAN_READ(sizeof(PSM16SMPHEADER)); - const PSM16SMPHEADER *smphdr = (PSM16SMPHEADER *)(lpStream + dwMemPos); - dwMemPos += sizeof(PSM16SMPHEADER); - - SAMPLEINDEX iSmp = LittleEndianW(smphdr->sampleNumber); - m_nSamples = max(m_nSamples, iSmp); - - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[iSmp], smphdr->name); - StringFixer::ReadString<StringFixer::nullTerminated>(Samples[iSmp].filename, smphdr->filename); - - Samples[iSmp].nLength = LittleEndian(smphdr->length); - Samples[iSmp].nLoopStart = LittleEndian(smphdr->loopStart); - Samples[iSmp].nLoopEnd = LittleEndian(smphdr->loopEnd); - Samples[iSmp].nC5Speed = LittleEndianW(smphdr->c2freq); - - // It seems like that finetune and transpose are added to the already given c2freq... That's a double WTF! Why on earth would you want to use both systems at the same time? - FrequencyToTranspose(&Samples[iSmp]); - Samples[iSmp].nC5Speed = TransposeToFrequency(Samples[iSmp].RelativeTone + (smphdr->finetune >> 4) - 7, MOD2XMFineTune(smphdr->finetune & 0x0F)); - - Samples[iSmp].nVolume = smphdr->volume << 2; - Samples[iSmp].nGlobalVol = 256; - - UINT sampleFormat = RS_PCM8S; - if(smphdr->flags & 0x04) // 16-Bit + PSM16SampleHeader sampleHeader; + if(!sampleChunk.ReadConvertEndianness(sampleHeader)) { - Samples[iSmp].uFlags |= CHN_16BIT; - Samples[iSmp].nLength >>= 1; - sampleFormat = RS_PCM16S; + break; } - if(smphdr->flags & 0x08) // Signed/Unsigned - { - if(Samples[iSmp].uFlags & CHN_16BIT) - sampleFormat = RS_PCM16U; - else - sampleFormat = RS_PCM8U; - } - if(smphdr->flags & 0x10) // Delta/Raw - { - if(Samples[iSmp].uFlags & CHN_16BIT) - sampleFormat = RS_PCM16D; - else - sampleFormat = RS_PCM8D; - } - if(smphdr->flags & 0x20) // Bidi Loop - { - Samples[iSmp].uFlags |= CHN_PINGPONGLOOP; - } - if(smphdr->flags & 0x80) // Loop - { - Samples[iSmp].uFlags |= CHN_LOOP; - } - if((smphdr->flags & 0x7F) == 0) - sampleFormat = RS_PCM8D; + + SAMPLEINDEX smp = sampleHeader.sampleNumber; + m_nSamples = max(m_nSamples, smp); - ReadSample(&Samples[iSmp], sampleFormat, reinterpret_cast<LPCSTR>(lpStream + LittleEndianW(smphdr->offset)), dwMemLength - LittleEndianW(smphdr->offset)); - - iSmpCount++; + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp], sampleHeader.name); + sampleHeader.ConvertToMPT(Samples[smp]); + + file.Seek(sampleHeader.offset); + ReadSample(&Samples[smp], sampleHeader.GetSampleFormat(), file); } } // Read patterns - dwMemPos = LittleEndian(shdr->patOffset); - ASSERT_CAN_READ(LittleEndian(shdr->patSize)); - if(LittleEndian(shdr->patOffset) > 4 && *(uint32 *)(lpStream + dwMemPos - 4) == LittleEndian(PSM16_PPAT)) // PPAT + if(fileHeader.patOffset > 4 && file.Seek(fileHeader.patOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPPAT) { - DWORD dwPatEndPos = LittleEndian(shdr->patOffset) + LittleEndian(shdr->patSize); - - for(PATTERNINDEX nPat = 0; nPat < LittleEndianW(shdr->numPatterns); nPat++) + for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++) { - ASSERT_CAN_READ(sizeof(PSM16PATHEADER)); - PSM16PATHEADER *phdr = (PSM16PATHEADER *)(lpStream + dwMemPos); - ASSERT_CAN_READ(LittleEndianW(phdr->size)); + PSM16PatternHeader patternHeader; + if(!file.ReadConvertEndianness(patternHeader)) + { + break; + } - DWORD dwNextPattern = dwMemPos + ((LittleEndianW(phdr->size) + 15) & ~15); - dwMemPos += sizeof(PSM16PATHEADER); + if(patternHeader.size < sizeof(PSM16PatternHeader)) + { + continue; + } - if(Patterns.Insert(nPat, phdr->numRows)) - break; + // Patterns are padded to 16 Bytes + FileReader patternChunk = file.GetChunk(((patternHeader.size + 15) & ~15) - sizeof(PSM16PatternHeader)); + if(Patterns.Insert(pat, patternHeader.numRows)) + { + continue; + } + + enum + { + channelMask = 0x1F, + noteFlag = 0x80, + volFlag = 0x40, + effectFlag = 0x20, + }; + ROWINDEX curRow = 0; - while(dwMemPos < dwNextPattern && curRow < phdr->numRows) + while(patternChunk.BytesLeft() && curRow < patternHeader.numRows) { - ASSERT_CAN_READ(1); - uint8 bChnFlag = lpStream[dwMemPos++]; - if(bChnFlag == 0) + uint8 chnFlag = patternChunk.ReadUint8(); + if(chnFlag == 0) { curRow++; continue; } - ModCommand *rowData = Patterns[nPat].GetpModCommand(curRow, min(bChnFlag & 0x1F, m_nChannels - 1)); + ModCommand &m = *Patterns[pat].GetpModCommand(curRow, min(chnFlag & channelMask, m_nChannels - 1)); - if(bChnFlag & 0x80) + if(chnFlag & noteFlag) { // note + instr present - ASSERT_CAN_READ(2); - rowData->note = lpStream[dwMemPos++] + 36; - rowData->instr = lpStream[dwMemPos++]; + m.note = patternChunk.ReadUint8() + 36; + m.instr = patternChunk.ReadUint8(); } - if(bChnFlag & 0x40) + if(chnFlag & volFlag) { // volume present - ASSERT_CAN_READ(1); - rowData->volcmd = VOLCMD_VOLUME; - rowData->vol = lpStream[dwMemPos++]; + m.volcmd = VOLCMD_VOLUME; + m.vol = patternChunk.ReadUint8(); } - if(bChnFlag & 0x20) + if(chnFlag & effectFlag) { // effect present - convert - ASSERT_CAN_READ(2); - BYTE command = lpStream[dwMemPos++], param = lpStream[dwMemPos++]; + m.command = patternChunk.ReadUint8(); + m.param = patternChunk.ReadUint8(); - switch(command) + switch(m.command) { // Volslides case 0x01: // fine volslide up - command = CMD_VOLUMESLIDE; - param = (param << 4) | 0x0F; + m.command = CMD_VOLUMESLIDE; + m.param = (m.param << 4) | 0x0F; break; case 0x02: // volslide up - command = CMD_VOLUMESLIDE; - param = (param << 4) & 0xF0; + m.command = CMD_VOLUMESLIDE; + m.param = (m.param << 4) & 0xF0; break; case 0x03: // fine voslide down - command = CMD_VOLUMESLIDE; - param = 0xF0 | param; + m.command = CMD_VOLUMESLIDE; + m.param = 0xF0 | m.param; break; case 0x04: // volslide down - command = CMD_VOLUMESLIDE; - param = param & 0x0F; + m.command = CMD_VOLUMESLIDE; + m.param = m.param & 0x0F; break; // Portamento case 0x0A: // fine portamento up - command = CMD_PORTAMENTOUP; - param |= 0xF0; + m.command = CMD_PORTAMENTOUP; + m.param |= 0xF0; break; case 0x0B: // portamento down - command = CMD_PORTAMENTOUP; + m.command = CMD_PORTAMENTOUP; break; case 0x0C: // fine portamento down - command = CMD_PORTAMENTODOWN; - param |= 0xF0; + m.command = CMD_PORTAMENTODOWN; + m.param |= 0xF0; break; case 0x0D: // portamento down - command = CMD_PORTAMENTODOWN; + m.command = CMD_PORTAMENTODOWN; break; case 0x0E: // tone portamento - command = CMD_TONEPORTAMENTO; + m.command = CMD_TONEPORTAMENTO; break; case 0x0F: // glissando control - command = CMD_S3MCMDEX; - param |= 0x10; + m.command = CMD_S3MCMDEX; + m.param |= 0x10; break; case 0x10: // tone portamento + volslide up - command = CMD_TONEPORTAVOL; - param <<= 4; + m.command = CMD_TONEPORTAVOL; + m.param <<= 4; break; case 0x11: // tone portamento + volslide down - command = CMD_TONEPORTAVOL; - param &= 0x0F; + m.command = CMD_TONEPORTAVOL; + m.param &= 0x0F; break; // Vibrato case 0x14: // vibrato - command = CMD_VIBRATO; + m.command = CMD_VIBRATO; break; case 0x15: // vibrato waveform - command = CMD_S3MCMDEX; - param |= 0x30; + m.command = CMD_S3MCMDEX; + m.param |= 0x30; break; case 0x16: // vibrato + volslide up - command = CMD_VIBRATOVOL; - param <<= 4; + m.command = CMD_VIBRATOVOL; + m.param <<= 4; break; case 0x17: // vibrato + volslide down - command = CMD_VIBRATOVOL; - param &= 0x0F; + m.command = CMD_VIBRATOVOL; + m.param &= 0x0F; break; // Tremolo case 0x1E: // tremolo - command = CMD_TREMOLO; + m.command = CMD_TREMOLO; break; case 0x1F: // tremolo waveform - command = CMD_S3MCMDEX; - param |= 0x40; + m.command = CMD_S3MCMDEX; + m.param |= 0x40; break; // Sample commands case 0x28: // 3-byte offset - we only support the middle byte. - ASSERT_CAN_READ(2); - command = CMD_OFFSET; - param = lpStream[dwMemPos++]; - dwMemPos++; + m.command = CMD_OFFSET; + m.param = patternChunk.ReadUint8(); + patternChunk.Skip(1); break; case 0x29: // retrigger - command = CMD_RETRIG; - param &= 0x0F; + m.command = CMD_RETRIG; + m.param &= 0x0F; break; case 0x2A: // note cut - command = CMD_S3MCMDEX; - if(param == 0) // in S3M mode, SC0 is ignored, so we convert it to a note cut. + m.command = CMD_S3MCMDEX; + if(m.param == 0) // in S3M mode, SC0 is ignored, so we convert it to a note cut. { - if(rowData->note == NOTE_NONE) + if(m.note == NOTE_NONE) { - rowData->note = NOTE_NOTECUT; - command = CMD_NONE; + m.note = NOTE_NOTECUT; + m.command = CMD_NONE; } else { - param = 1; + m.param = 1; } } - param |= 0xC0; + m.param |= 0xC0; break; case 0x2B: // note delay - command = CMD_S3MCMDEX; ... [truncated message content] |
From: <sag...@us...> - 2012-04-01 19:25:09
|
Revision: 1238 http://modplug.svn.sourceforge.net/modplug/?rev=1238&view=rev Author: saga-games Date: 2012-04-01 19:25:00 +0000 (Sun, 01 Apr 2012) Log Message: ----------- [New] Experimental built-in support for JBridge. Still has some small issues when switching plugins, but apart from that it seems to work (with admin privileges enabled). [Ref] Removed unused buzz machines support and general cleanup. Modified Paths: -------------- trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/mptrack/SelectPluginDialog.cpp trunk/OpenMPT/mptrack/SelectPluginDialog.h trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/View_gen.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/mptrack/resource.h trunk/OpenMPT/soundlib/MIDIMacros.h trunk/OpenMPT/soundlib/Sndfile.h Added Paths: ----------- trunk/OpenMPT/soundlib/plugins/ trunk/OpenMPT/soundlib/plugins/JBridge.cpp trunk/OpenMPT/soundlib/plugins/JBridge.h trunk/OpenMPT/soundlib/plugins/PlugInterface.h trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h trunk/OpenMPT/soundlib/plugins/PluginMixBuffer.h Removed Paths: ------------- trunk/OpenMPT/soundlib/PlugInterface.h trunk/OpenMPT/soundlib/PluginEventQueue.h trunk/OpenMPT/soundlib/PluginMixBuffer.h Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-01 19:25:00 UTC (rev 1238) @@ -2509,15 +2509,15 @@ void CModDoc::TogglePluginEditor(UINT m_nCurrentPlugin) //----------------------------------------------------- { - SNDMIXPLUGIN &plugin = m_SndFile.m_MixPlugins[m_nCurrentPlugin]; - - if (m_nCurrentPlugin < MAX_MIXPLUGINS && plugin.pMixPlugin) + if(m_nCurrentPlugin < MAX_MIXPLUGINS) { + SNDMIXPLUGIN &plugin = m_SndFile.m_MixPlugins[m_nCurrentPlugin]; CVstPlugin *pVstPlugin = dynamic_cast<CVstPlugin *>(plugin.pMixPlugin); - pVstPlugin->ToggleEditor(); + if(pVstPlugin != nullptr) + { + pVstPlugin->ToggleEditor(); + } } - - return; } void CModDoc::ChangeFileExtension(MODTYPE nNewType) Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2012-04-01 19:25:00 UTC (rev 1238) @@ -2242,14 +2242,13 @@ BOOL CTrackApp::UninitializeDXPlugins() //------------------------------------- { - TCHAR s[_MAX_PATH], tmp[32]; - PVSTPLUGINLIB pPlug; - UINT iPlug; - if (!m_pPluginManager) return FALSE; #ifndef NO_VST - pPlug = m_pPluginManager->GetFirstPlugin(); + TCHAR s[_MAX_PATH], tmp[32]; + VSTPluginLib *pPlug; + + PLUGINDEX pPlug = m_pPluginManager->GetFirstPlugin(); iPlug = 0; while (pPlug) { Modified: trunk/OpenMPT/mptrack/SelectPluginDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/SelectPluginDialog.cpp 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/SelectPluginDialog.cpp 2012-04-01 19:25:00 UTC (rev 1238) @@ -107,30 +107,38 @@ { // -> CODE#0002 // -> DESC="list box to choose VST plugin presets (programs)" - if(m_pPlugin==NULL) { CDialog::OnOK(); return; } + if(m_pPlugin==nullptr) { CDialog::OnOK(); return; } // -! NEW_FEATURE#0002 - BOOL bChanged = FALSE; + bool changed = false; CVstPluginManager *pManager = theApp.GetPluginManager(); - PVSTPLUGINLIB pNewPlug = (PVSTPLUGINLIB)m_treePlugins.GetItemData(m_treePlugins.GetSelectedItem()); - PVSTPLUGINLIB pFactory = NULL; - CVstPlugin *pCurrentPlugin = NULL; - if (m_pPlugin) pCurrentPlugin = (CVstPlugin *)m_pPlugin->pMixPlugin; + VSTPluginLib *pNewPlug = (VSTPluginLib *)m_treePlugins.GetItemData(m_treePlugins.GetSelectedItem()); + VSTPluginLib *pFactory = nullptr; + CVstPlugin *pCurrentPlugin = nullptr; + if (m_pPlugin) pCurrentPlugin = dynamic_cast<CVstPlugin *>(m_pPlugin->pMixPlugin); if ((pManager) && (pManager->IsValidPlugin(pNewPlug))) pFactory = pNewPlug; - // Plugin selected + if (pFactory) { + // Plugin selected if ((!pCurrentPlugin) || (pCurrentPlugin->GetPluginFactory() != pFactory)) { CriticalSection cs; - if (pCurrentPlugin) pCurrentPlugin->Release(); + + if (pCurrentPlugin != nullptr) + { + pCurrentPlugin->Release(); + } + // Just in case... - m_pPlugin->pMixPlugin = NULL; - m_pPlugin->pMixState = NULL; + m_pPlugin->pMixPlugin = nullptr; + m_pPlugin->pMixState = nullptr; + // Remove old state m_pPlugin->nPluginDataSize = 0; if (m_pPlugin->pPluginData) delete[] m_pPlugin->pPluginData; - m_pPlugin->pPluginData = NULL; + m_pPlugin->pPluginData = nullptr; + // Initialize plugin info MemsetZero(m_pPlugin->Info); m_pPlugin->Info.dwPluginId1 = pFactory->dwPluginId1; @@ -167,24 +175,27 @@ } } } - bChanged = TRUE; + changed = true; } } else + { // No effect - { CriticalSection cs; if (pCurrentPlugin) { pCurrentPlugin->Release(); - bChanged = TRUE; + changed = true; } + // Just in case... - m_pPlugin->pMixPlugin = NULL; - m_pPlugin->pMixState = NULL; + m_pPlugin->pMixPlugin = nullptr; + m_pPlugin->pMixState = nullptr; + // Remove old state m_pPlugin->nPluginDataSize = 0; if (m_pPlugin->pPluginData) delete[] m_pPlugin->pPluginData; - m_pPlugin->pPluginData = NULL; + m_pPlugin->pPluginData = nullptr; + // Clear plugin info MemsetZero(m_pPlugin->Info); } @@ -197,7 +208,7 @@ CMainFrame::GetSettings().gnPlugWindowWidth = rect.right - rect.left; CMainFrame::GetSettings().gnPlugWindowHeight = rect.bottom - rect.top; - if (bChanged) + if (changed) { CMainFrame::GetSettings().gnPlugWindowLast = m_pPlugin->Info.dwPluginId2; CDialog::OnOK(); @@ -249,8 +260,8 @@ if (pManager) { - PVSTPLUGINLIB pCurrent = NULL; - PVSTPLUGINLIB p = pManager->GetFirstPlugin(); + VSTPluginLib *pCurrent = NULL; + VSTPluginLib *p = pManager->GetFirstPlugin(); while (p) { // Apply name filter @@ -270,10 +281,10 @@ hParent = hDmo; } else { - hParent = (p->bIsInstrument) ? hSynth : hVst; + hParent = (p->isInstrument) ? hSynth : hVst; } - HTREEITEM h = AddTreeItem(p->szLibraryName, p->bIsInstrument ? IMAGE_PLUGININSTRUMENT : IMAGE_EFFECTPLUGIN, true, hParent, (LPARAM)p); + HTREEITEM h = AddTreeItem(p->szLibraryName, p->isInstrument ? IMAGE_PLUGININSTRUMENT : IMAGE_EFFECTPLUGIN, true, hParent, (LPARAM)p); //If filter is active, expand nodes. if (m_sNameFilter != "") m_treePlugins.EnsureVisible(h); @@ -367,7 +378,7 @@ //----------------------------------------------------------- { CVstPluginManager *pManager = theApp.GetPluginManager(); - PVSTPLUGINLIB pPlug = (PVSTPLUGINLIB)m_treePlugins.GetItemData(m_treePlugins.GetSelectedItem()); + VSTPluginLib *pPlug = (VSTPluginLib *)m_treePlugins.GetItemData(m_treePlugins.GetSelectedItem()); if ((pManager) && (pManager->IsValidPlugin(pPlug))) { SetDlgItemText(IDC_TEXT_CURRENT_VSTPLUG, pPlug->szDllPath); @@ -397,7 +408,7 @@ { kEffectMagic, CCONST('f', 'r', 'V', '2'), 1, "Farbrausch V2", "* This plugin can cause OpenMPT to freeze if being used in a combination with various other plugins.\nIt is recommended to not use V2 in combination with any other plugins. *" }, }; -bool CSelectPluginDlg::VerifyPlug(PVSTPLUGINLIB plug) +bool CSelectPluginDlg::VerifyPlug(VSTPluginLib *plug) //--------------------------------------------------- { CString s; @@ -429,7 +440,7 @@ CVstPluginManager *pManager = theApp.GetPluginManager(); bool bOk = false; - PVSTPLUGINLIB plugLib = nullptr; + VSTPluginLib *plugLib = nullptr; for(size_t counter = 0; counter < files.filenames.size(); counter++) { @@ -463,7 +474,7 @@ //------------------------------------- { const HTREEITEM pluginToDelete = m_treePlugins.GetSelectedItem(); - PVSTPLUGINLIB pPlug = (PVSTPLUGINLIB)m_treePlugins.GetItemData(pluginToDelete); + VSTPluginLib *pPlug = (VSTPluginLib *)m_treePlugins.GetItemData(pluginToDelete); CVstPluginManager *pManager = theApp.GetPluginManager(); if ((pManager) && (pPlug)) Modified: trunk/OpenMPT/mptrack/SelectPluginDialog.h =================================================================== --- trunk/OpenMPT/mptrack/SelectPluginDialog.h 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/SelectPluginDialog.h 2012-04-01 19:25:00 UTC (rev 1238) @@ -33,7 +33,7 @@ ~CSelectPluginDlg(); void DoClose(); void UpdatePluginsList(DWORD forceSelect = 0); - bool VerifyPlug(PVSTPLUGINLIB plug); + bool VerifyPlug(VSTPluginLib *plug); virtual void DoDataExchange(CDataExchange* pDX); virtual BOOL OnInitDialog(); virtual void OnOK(); Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2012-04-01 19:25:00 UTC (rev 1238) @@ -106,7 +106,6 @@ ON_CBN_SELCHANGE(IDC_COMBO9, OnSpecialMixProcessingChanged) // -! BEHAVIOUR_CHANGE#0028 - ON_COMMAND_RANGE(ID_FXCOMMANDS_BASE, ID_FXCOMMANDS_BASE+10, OnFxCommands) ON_NOTIFY(TCN_SELCHANGE, IDC_TABCTRL1, OnTabSelchange) ON_MESSAGE(WM_MOD_UNLOCKCONTROLS, OnUnlockControls) ON_MESSAGE(WM_MOD_VIEWMSG, OnModViewMsg) @@ -439,7 +438,7 @@ CheckDlgButton(IDC_CHECK10, pPlugin->IsBypassed() ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(IDC_CHECK11, pPlugin->IsWetMix() ? BST_CHECKED : BST_UNCHECKED); CVstPlugin *pVstPlugin = (pPlugin->pMixPlugin) ? (CVstPlugin *)pPlugin->pMixPlugin : NULL; - m_BtnEdit.EnableWindow((pVstPlugin != nullptr && (pVstPlugin->HasEditor() || pVstPlugin->GetNumCommands())) ? TRUE : FALSE); + m_BtnEdit.EnableWindow((pVstPlugin != nullptr && (pVstPlugin->HasEditor() || pVstPlugin->GetNumParameters())) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_MOVEFXSLOT), (pVstPlugin) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_INSERTFXSLOT), (pVstPlugin) ? TRUE : FALSE); ::EnableWindow(::GetDlgItem(m_hWnd, IDC_CLONEPLUG), (pVstPlugin) ? TRUE : FALSE); @@ -1226,27 +1225,6 @@ } -void CViewGlobals::OnFxCommands(UINT id) -//-------------------------------------- -{ - CModDoc *pModDoc = GetDocument(); - CSoundFile *pSndFile; - UINT nIndex = id - ID_FXCOMMANDS_BASE; - - if ((m_nCurrentPlugin >= MAX_MIXPLUGINS) || (!pModDoc)) return; - pSndFile = pModDoc->GetSoundFile(); - SNDMIXPLUGIN &plugin = pSndFile->m_MixPlugins[m_nCurrentPlugin]; - - if (plugin.pMixPlugin != nullptr) - { - CVstPlugin *pVstPlugin = dynamic_cast<CVstPlugin *>(plugin.pMixPlugin); - pVstPlugin->ExecuteCommand(nIndex); - if(pSndFile->GetModSpecifications().supportsPlugins) - pModDoc->SetModified(); - } -} - - void CViewGlobals::OnOutputRoutingChanged() //----------------------------------------- { Modified: trunk/OpenMPT/mptrack/View_gen.h =================================================================== --- trunk/OpenMPT/mptrack/View_gen.h 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/View_gen.h 2012-04-01 19:25:00 UTC (rev 1238) @@ -156,7 +156,6 @@ afx_msg void OnPrevPlugin(); afx_msg void OnNextPlugin(); afx_msg void OnDestroy(); - afx_msg void OnFxCommands(UINT id); afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnSize(UINT nType, int cx, int cy); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-01 19:25:00 UTC (rev 1238) @@ -26,6 +26,7 @@ #include "version.h" #include "midimappingdialog.h" #include "../common/StringFixer.h" +#include "../soundlib/plugins/JBridge.h" #ifdef VST_USE_ALTERNATIVE_MAGIC //Pelya's plugin ID fix. Breaks fx presets, so let's avoid it for now. #define ZLIB_WINAPI #include "../zlib/zlib.h" //For CRC32 calculation (to detect plugins with same UID) @@ -40,17 +41,10 @@ VstIntPtr CVstPluginManager::s_nHostVendorVersion = MptVersion::num; //#define VST_LOG -//#define ENABLE_BUZZ #define DMO_LOG -#ifdef ENABLE_BUZZ -#define STATIC_BUILD -#include <machineinterface.h> // Buzz -AEffect *Buzz2Vst(CMachineInterface *pBuzzMachine, const CMachineInfo *pBuzzInfo); -#endif // ENABLE_BUZZ +AEffect *DmoToVst(VSTPluginLib *pLib); -AEffect *DmoToVst(PVSTPLUGINLIB pLib); - #ifdef VST_USE_ALTERNATIVE_MAGIC UINT32 CalculateCRC32fromFilename(const char *s) //---------------------------------------------- @@ -105,7 +99,7 @@ CSoundFile::gpMixPluginCreateProc = nullptr; while (m_pVstHead) { - PVSTPLUGINLIB p = m_pVstHead; + VSTPluginLib *p = m_pVstHead; m_pVstHead = m_pVstHead->pNext; if (m_pVstHead) m_pVstHead->pPrev = nullptr; p->pPrev = p->pNext = nullptr; @@ -118,10 +112,10 @@ } -BOOL CVstPluginManager::IsValidPlugin(const VSTPLUGINLIB *pLib) +BOOL CVstPluginManager::IsValidPlugin(const VSTPluginLib *pLib) //------------------------------------------------------------- { - PVSTPLUGINLIB p = m_pVstHead; + VSTPluginLib *p = m_pVstHead; while (p) { if (p == pLib) return TRUE; @@ -163,14 +157,14 @@ if (ERROR_SUCCESS == RegQueryValueEx(hksub, nullptr, 0, &datatype, (LPBYTE)s, &datasize)) { - PVSTPLUGINLIB p = new VSTPLUGINLIB; + VSTPluginLib *p = new VSTPluginLib(); p->pPrev = nullptr; p->pNext = m_pVstHead; p->dwPluginId1 = kDmoMagic; p->dwPluginId2 = clsid.Data1; p->pPluginsList = nullptr; - p->bIsInstrument = FALSE; + p->isInstrument = false; lstrcpyn(p->szLibraryName, s, sizeof(p->szLibraryName)); StringFromGUID2(clsid, w, 100); WideCharToMultiByte(CP_ACP, 0, w, -1, p->szDllPath, sizeof(p->szDllPath), nullptr, nullptr); @@ -189,15 +183,63 @@ if (hkEnum) RegCloseKey(hkEnum); } + +void CVstPluginManager::LoadPlugin(const char *pluginPath, AEffect *&effect, HINSTANCE &library) +//---------------------------------------------------------------------------------------------- +{ + library = nullptr; + effect = nullptr; + + try + { + library = LoadLibrary(pluginPath); + +#ifdef _DEBUG + DWORD dw = GetLastError(); + if(library == nullptr && dw != ERROR_MOD_NOT_FOUND) // "File not found errors" are annoying. + { + TCHAR szBuf[256]; + wsprintf(szBuf, "Warning: encountered problem when loading plugin dll. Error %d: %s", dw, (LPCTSTR)GetErrorMessage(dw)); + Reporting::Error(szBuf, "DEBUG: Error when loading plugin dll"); + } +#endif //_DEBUG + } catch(...) + { + CVstPluginManager::ReportPlugException("Exception caught in LoadLibrary (%s)", pluginPath); + } + + if(library != nullptr && library != INVALID_HANDLE_VALUE) + { + // Try loading the VST plugin. + PVSTPLUGENTRY pMainProc = (PVSTPLUGENTRY)GetProcAddress(library, "VSTPluginMain"); + if(pMainProc == nullptr) + { + pMainProc = (PVSTPLUGENTRY)GetProcAddress(library, "main"); + } + + if(pMainProc != nullptr) + { + effect = pMainProc(MasterCallBack); + } else + { +#ifdef VST_LOG + Log("Entry point not found! (handle=%08X)\n", library); +#endif // VST_LOG + } + } else + { + // Try loading the plugin using JBridge instead. + effect = JBridge::LoadBridgedPlugin(MasterCallBack, pluginPath); + } +} + // // PluginCache format: // LibraryName = ID100000ID200000 // ID100000ID200000 = FullDllPath // ID100000ID200000.Flags = Plugin Flags (for now, just isInstrument). - - - -PVSTPLUGINLIB CVstPluginManager::AddPlugin(LPCSTR pszDllPath, BOOL bCache, const bool checkFileExistence, CString* const errStr) + +VSTPluginLib *CVstPluginManager::AddPlugin(LPCSTR pszDllPath, BOOL bCache, const bool checkFileExistence, CString* const errStr) //------------------------------------------------------------------------------------------------------------------------------ { TCHAR szPath[_MAX_PATH]; @@ -211,8 +253,8 @@ } } - PVSTPLUGINLIB pDup = m_pVstHead; - while (pDup) + VSTPluginLib *pDup = m_pVstHead; + while(pDup != nullptr) { if (!lstrcmpi(pszDllPath, pDup->szDllPath)) return pDup; pDup = pDup->pNext; @@ -236,21 +278,17 @@ if ((szPath[0]) && (!lstrcmpi(szPath, pszDllPath))) { - PVSTPLUGINLIB p; + VSTPluginLib *p; try { - p = new VSTPLUGINLIB; + p = new VSTPluginLib(); } catch(MPTMemoryException) { return nullptr; } - p->dwPluginId1 = 0; - p->dwPluginId2 = 0; - p->bIsInstrument = FALSE; - p->pPluginsList = nullptr; lstrcpyn(p->szDllPath, pszDllPath, sizeof(p->szDllPath)); _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); - p->szLibraryName[63] = 0; + p->szLibraryName[63] = '\0'; p->pNext = m_pVstHead; p->pPrev = nullptr; if (m_pVstHead) m_pVstHead->pPrev = p; @@ -272,7 +310,7 @@ CString flagKey; flagKey.Format("%s.Flags", IDs); int infoex = CMainFrame::GetPrivateProfileLong(cacheSection, flagKey, 0, cacheFile); - if (infoex&1) p->bIsInstrument = TRUE; + if (infoex & 1) p->isInstrument = true; #ifdef VST_USE_ALTERNATIVE_MAGIC if( p->dwPluginId1 == kEffectMagic ) { @@ -292,187 +330,101 @@ } } - HINSTANCE hLib = nullptr; - - // If this key contains a file name on program launch, a plugin previously crashed OpenMPT. WritePrivateProfileString("VST Plugins", "FailedPlugin", pszDllPath, theApp.GetConfigFileName()); + AEffect *pEffect; + HINSTANCE hLib; + bool validPlug = false; + + VSTPluginLib *p = nullptr; try { - hLib = LoadLibrary(pszDllPath); - -#ifdef _DEBUG - DWORD dw = GetLastError(); - if (!hLib && dw != ERROR_MOD_NOT_FOUND) // "File not found errors" are annoying. - { - TCHAR szBuf[256]; - wsprintf(szBuf, "Warning: encountered problem when loading plugin dll. Error %d: %s", dw, (LPCTSTR)GetErrorMessage(dw)); - Reporting::Error(szBuf, "DEBUG: Error when loading plugin dll"); - } -#endif //_DEBUG - - } catch(...) + p = new VSTPluginLib(); + } catch(MPTMemoryException) { - CVstPluginManager::ReportPlugException("Exception caught in LoadLibrary (%s)", pszDllPath); + return nullptr; } - if ((hLib) && (hLib != INVALID_HANDLE_VALUE)) + p->pPluginsList = nullptr; + lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); + _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); + p->szLibraryName[63] = 0; + p->pNext = m_pVstHead; + p->pPrev = nullptr; + + try { - bool validPlug = false; - PVSTPLUGENTRY pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "VSTPluginMain"); - if(pMainProc == nullptr) + LoadPlugin(pszDllPath, pEffect, hLib); + + if(pEffect != nullptr && pEffect->magic == kEffectMagic && pEffect->dispatcher != nullptr) { - pMainProc = (PVSTPLUGENTRY)GetProcAddress(hLib, "main"); - } - #ifdef ENABLE_BUZZ - GET_INFO pBuzzGetInfo = (GET_INFO)GetProcAddress(hLib, "GetInfo"); - #endif // ENABLE_BUZZ - if (pMainProc) - { - PVSTPLUGINLIB p; - try - { - p = new VSTPLUGINLIB; - } catch(MPTMemoryException) - { - return nullptr; - } - p->dwPluginId1 = 0; - p->dwPluginId2 = 0; - p->bIsInstrument = FALSE; - p->pPluginsList = nullptr; - lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); - _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); - p->szLibraryName[63] = 0; - p->pNext = m_pVstHead; - p->pPrev = nullptr; + pEffect->dispatcher(pEffect, effOpen, 0, 0, 0, 0); + if (m_pVstHead) m_pVstHead->pPrev = p; m_pVstHead = p; - try - { - AEffect *pEffect = pMainProc(MasterCallBack); - if(pEffect != nullptr && pEffect->magic == kEffectMagic && pEffect->dispatcher != nullptr) - { - pEffect->dispatcher(pEffect, effOpen, 0, 0, 0, 0); +#ifdef VST_USE_ALTERNATIVE_MAGIC + p->dwPluginId1 = CalculateCRC32fromFilename(p->szLibraryName); // Make Plugin ID unique for sure +#else + p->dwPluginId1 = pEffect->magic; +#endif // VST_USE_ALTERNATIVE_MAGIC + p->dwPluginId2 = pEffect->uniqueID; + p->isInstrument = ((pEffect->flags & effFlagsIsSynth) || !pEffect->numInputs); - #ifdef VST_USE_ALTERNATIVE_MAGIC - p->dwPluginId1 = CalculateCRC32fromFilename(p->szLibraryName); // Make Plugin ID unique for sure - #else - p->dwPluginId1 = pEffect->magic; - #endif // VST_USE_ALTERNATIVE_MAGIC - p->dwPluginId2 = pEffect->uniqueID; - if ((pEffect->flags & effFlagsIsSynth) || (!pEffect->numInputs)) p->bIsInstrument = TRUE; +#ifdef VST_LOG + int nver = pEffect->dispatcher(pEffect, effGetVstVersion, 0,0, nullptr, 0); + if (!nver) nver = pEffect->version; + Log("%-20s: v%d.0, %d in, %d out, %2d programs, %2d params, flags=0x%04X realQ=%d offQ=%d\n", + p->szLibraryName, nver, + pEffect->numInputs, pEffect->numOutputs, + pEffect->numPrograms, pEffect->numParams, + pEffect->flags, pEffect->realQualities, pEffect->offQualities); +#endif // VST_LOG - #ifdef VST_LOG - int nver = pEffect->dispatcher(pEffect, effGetVstVersion, 0,0, nullptr, 0); - if (!nver) nver = pEffect->version; - Log("%-20s: v%d.0, %d in, %d out, %2d programs, %2d params, flags=0x%04X realQ=%d offQ=%d\n", - p->szLibraryName, nver, - pEffect->numInputs, pEffect->numOutputs, - pEffect->numPrograms, pEffect->numParams, - pEffect->flags, pEffect->realQualities, pEffect->offQualities); - #endif // VST_LOG + pEffect->dispatcher(pEffect, effClose, 0, 0, 0, 0); - pEffect->dispatcher(pEffect, effClose, 0, 0, 0, 0); - - validPlug = true; - } - } catch(...) - { - CVstPluginManager::ReportPlugException("Exception while trying to load plugin \"%s\"!\n", p->szLibraryName); - } - - // If OK, write the information in PluginCache - if(validPlug) - { - const CString cacheSection = "PluginCache"; - const CString cacheFile = theApp.GetPluginCacheFileName(); - CString IDs, flagsKey; - IDs.Format("%08X%08X", p->dwPluginId1, p->dwPluginId2); - flagsKey.Format("%s.Flags", IDs); - - _tcsncpy(szPath, pszDllPath, CountOf(szPath) - 1); - if(theApp.IsPortableMode()) - { - theApp.AbsolutePathToRelative(szPath); - } - StringFixer::SetNullTerminator(szPath); - - WritePrivateProfileString(cacheSection, IDs, szPath, cacheFile); - CMainFrame::WritePrivateProfileCString(cacheSection, IDs, pszDllPath, cacheFile); - CMainFrame::WritePrivateProfileCString(cacheSection, p->szLibraryName, IDs, cacheFile); - CMainFrame::WritePrivateProfileLong(cacheSection, flagsKey, p->bIsInstrument, cacheFile); - } - } else - #ifdef ENABLE_BUZZ - if (pBuzzGetInfo) - { - PVSTPLUGINLIB p - try - { - p = new VSTPLUGINLIB; - } catch(MPTMemoryException) - { - return nullptr; - } - - p->dwPluginId1 = kBuzzMagic; - p->dwPluginId2 = 0; - p->pPluginsList = nullptr; - lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); - _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); - p->szLibraryName[63] = 0; - p->pNext = m_pVstHead; - p->pPrev = nullptr; - if (m_pVstHead) m_pVstHead->pPrev = p; - m_pVstHead = p; - try - { - const CMachineInfo *pInfo = pBuzzGetInfo(); - if (pInfo) - { - p->dwPluginId2 = pInfo->Version; - if (pInfo->Name) - { - lstrcpyn(p->szLibraryName, pInfo->Name, CountOf(p->szLibraryName)); - } - validPlug = true; - } - } catch (...) - { - CVstPluginManager::ReportPlugException("Exception while trying to load buzz plugin \"%s\"!\n", p->szLibraryName); - } - } else - #endif // ENABLE_BUZZ - { - #ifdef VST_LOG - Log("Entry point not found!\n"); - #endif // VST_LOG + validPlug = true; } FreeLibrary(hLib); + } catch(...) + { + CVstPluginManager::ReportPlugException("Exception while trying to load plugin \"%s\"!\n", p->szLibraryName); + } - // Now it should be safe to assume that this plugin loaded properly. :) - WritePrivateProfileString("VST Plugins", "FailedPlugin", nullptr, theApp.GetConfigFileName()); + // Now it should be safe to assume that this plugin loaded properly. :) + WritePrivateProfileString("VST Plugins", "FailedPlugin", nullptr, theApp.GetConfigFileName()); - return (validPlug ? m_pVstHead : nullptr); - } else + // If OK, write the information in PluginCache + if(validPlug) { - #ifdef VST_LOG - Log("LoadLibrary(%s) failed!\n", pszDllPath); - #endif // VST_LOG + const CString cacheSection = "PluginCache"; + const CString cacheFile = theApp.GetPluginCacheFileName(); + CString IDs, flagsKey; + IDs.Format("%08X%08X", p->dwPluginId1, p->dwPluginId2); + flagsKey.Format("%s.Flags", IDs); - WritePrivateProfileString("VST Plugins", "FailedPlugin", nullptr, theApp.GetConfigFileName()); + _tcsncpy(szPath, pszDllPath, CountOf(szPath) - 1); + if(theApp.IsPortableMode()) + { + theApp.AbsolutePathToRelative(szPath); + } + StringFixer::SetNullTerminator(szPath); + + WritePrivateProfileString(cacheSection, IDs, szPath, cacheFile); + CMainFrame::WritePrivateProfileCString(cacheSection, IDs, pszDllPath, cacheFile); + CMainFrame::WritePrivateProfileCString(cacheSection, p->szLibraryName, IDs, cacheFile); + CMainFrame::WritePrivateProfileLong(cacheSection, flagsKey, p->isInstrument, cacheFile); } - return nullptr; + + return (validPlug ? m_pVstHead : nullptr); } -bool CVstPluginManager::RemovePlugin(PVSTPLUGINLIB pFactory) +bool CVstPluginManager::RemovePlugin(VSTPluginLib *pFactory) //---------------------------------------------------------- { - PVSTPLUGINLIB p = m_pVstHead; + VSTPluginLib *p = m_pVstHead; while (p) { @@ -509,11 +461,11 @@ //------------------------------------------------------------------------------------- { UINT nMatch = 0; - PVSTPLUGINLIB pFound = nullptr; + VSTPluginLib *pFound = nullptr; if (pMixPlugin) { - PVSTPLUGINLIB p = m_pVstHead; + VSTPluginLib *p = m_pVstHead; while (p) { @@ -567,6 +519,7 @@ return bOk; } } + if ((!pFound) && strcmp(pMixPlugin->GetLibraryName(), "")) { CHAR s[_MAX_PATH], dir[_MAX_PATH]; @@ -590,81 +543,52 @@ } } } + if (pFound) { - HINSTANCE hLibrary = NULL; - BOOL bOk = FALSE; + AEffect *pEffect = nullptr; + HINSTANCE hLibrary = nullptr; + bool validPlugin = false; + try { CriticalSection cs; - hLibrary = LoadLibrary(pFound->szDllPath); - if (hLibrary != NULL) + LoadPlugin(pFound->szDllPath, pEffect, hLibrary); + + if(pEffect != nullptr && pEffect->dispatcher != nullptr && pEffect->magic == kEffectMagic) { - AEffect *pEffect = NULL; - PVSTPLUGENTRY pEntryPoint = (PVSTPLUGENTRY)GetProcAddress(hLibrary, "main"); - if(pEntryPoint == NULL) + validPlugin = true; + + if(pEffect->flags & effFlagsIsSynth || !pEffect->numInputs) { - pEntryPoint = (PVSTPLUGENTRY)GetProcAddress(hLibrary, "VSTPluginMain"); - } - #ifdef ENABLE_BUZZ - GET_INFO pBuzzGetInfo = (GET_INFO)GetProcAddress(hLibrary, "GetInfo"); - CREATE_MACHINE pBuzzCreateMachine = (CREATE_MACHINE)GetProcAddress(hLibrary, "CreateMachine"); - #endif - if (pEntryPoint) - { - pEffect = pEntryPoint(MasterCallBack); - } else - #ifdef ENABLE_BUZZ - if ((pBuzzCreateMachine) && (pBuzzGetInfo)) - { - CMachineInterface *pBuzzMachine = pBuzzCreateMachine(); - const CMachineInfo *pBuzzInfo = pBuzzGetInfo(); - if ((pBuzzMachine) && (pBuzzInfo) && (pBuzzInfo->Type == MT_EFFECT)) + // Flag as instrument plugin + if (!pFound->isInstrument) { - pEffect = Buzz2Vst(pBuzzMachine, pBuzzInfo); + CString cacheSection = "PluginCache"; + CString cacheFile = theApp.GetPluginCacheFileName(); + //LPCSTR pszSection = "PluginCache"; + pFound->isInstrument = true; + CString flagsKey; + flagsKey.Format("%08X%08X.Flags", pFound->dwPluginId1, pFound->dwPluginId2); + CMainFrame::WritePrivateProfileLong(cacheSection, flagsKey, 1, cacheFile); } - } else - #endif - { - #ifdef VST_LOG - Log("Entry point not found! (handle=%08X)\n", hLibrary); - #endif } - if ((pEffect) && (pEffect->dispatcher) - && ((pEffect->magic == kEffectMagic) || (pEffect->magic == kBuzzMagic))) - { - bOk = TRUE; - if ((pEffect->flags & effFlagsIsSynth) || (!pEffect->numInputs)) - { - if (!pFound->bIsInstrument) - { - CString cacheSection = "PluginCache"; - CString cacheFile = theApp.GetPluginCacheFileName(); - //LPCSTR pszSection = "PluginCache"; - pFound->bIsInstrument = TRUE; - CString flagsKey; - flagsKey.Format("%08X%08X.Flags", pFound->dwPluginId1, pFound->dwPluginId2); - CMainFrame::WritePrivateProfileLong(cacheSection, flagsKey, 1, cacheFile); - } - } - CVstPlugin *pVstPlug = new CVstPlugin(hLibrary, pFound, pMixPlugin, pEffect); - if (pVstPlug) pVstPlug->Initialize(pSndFile); - } - } else + CVstPlugin *pVstPlug = new CVstPlugin(hLibrary, pFound, pMixPlugin, pEffect); + if (pVstPlug) pVstPlug->Initialize(pSndFile); + } + + if(!validPlugin) { - #ifdef VST_LOG - Log("LoadLibrary(\"%s\") failed!\n", pFound->szDllPath); - #endif + FreeLibrary(hLibrary); } - if ((!bOk) && (hLibrary)) FreeLibrary(hLibrary); } catch(...) { CVstPluginManager::ReportPlugException("Exception while trying to create plugin \"%s\"!\n", pFound->szLibraryName); } - return bOk; + return validPlugin; } else { // "plug not found" notification code MOVED to CSoundFile::Create @@ -679,7 +603,7 @@ void CVstPluginManager::OnIdle() //------------------------------ { - PVSTPLUGINLIB pFactory = m_pVstHead; + VSTPluginLib *pFactory = m_pVstHead; while (pFactory) { @@ -1335,7 +1259,7 @@ // CVstPlugin // -CVstPlugin::CVstPlugin(HMODULE hLibrary, VSTPLUGINLIB *pFactory, SNDMIXPLUGIN *pMixStruct, AEffect *pEffect) +CVstPlugin::CVstPlugin(HMODULE hLibrary, VSTPluginLib *pFactory, SNDMIXPLUGIN *pMixStruct, AEffect *pEffect) //---------------------------------------------------------------------------------------------------------- { m_hLibrary = hLibrary; @@ -1538,7 +1462,7 @@ Dispatch(effConnectOutput, 0, 0, nullptr, 0); if (m_pEffect->numOutputs > 1) Dispatch(effConnectOutput, 1, 0, nullptr, 0); } - CVstPlugin::Dispatch(effMainsChanged, 0,0, nullptr, 0); + Suspend(); CVstPlugin::Dispatch(effClose, 0, 0, nullptr, 0); m_pFactory = nullptr; if (m_hLibrary) @@ -1593,8 +1517,8 @@ } //rewbs.VSTcompliance: changed from BOOL to long -long CVstPlugin::GetNumPrograms() -//------------------------------- +VstInt32 CVstPlugin::GetNumPrograms() +//----------------------------------- { if ((m_pEffect) && (m_pEffect->numPrograms > 0)) { @@ -1759,7 +1683,7 @@ VstIntPtr CVstPlugin::Dispatch(VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt) //---------------------------------------------------------------------------------------------------- { - long lresult = 0; + VstIntPtr lresult = 0; try { @@ -1990,17 +1914,17 @@ void CVstPlugin::Suspend() //------------------------ { - try + if(m_bPlugResumed) { - if(m_bPlugResumed) + try { Dispatch(effStopProcess, 0, 0, nullptr, 0.0f); Dispatch(effMainsChanged, 0, 0, nullptr, 0.0f); // calls plugin's suspend (theoretically, plugins should clean their buffers here, but oh well, the number of plugins which don't do this is surprisingly high.) m_bPlugResumed = false; + } catch (...) + { + CVstPluginManager::ReportPlugException("Exception in Suspend() (Plugin=%s)\n", m_pFactory->szLibraryName); } - } catch (...) - { - CVstPluginManager::ReportPlugException("Exception in Suspend() (Plugin=%s)\n", m_pFactory->szLibraryName); } } @@ -2342,21 +2266,21 @@ for (int mc=0; mc<16; mc++) //all midi chans { DWORD dwMidiCode = 0x80 | (mc & 0x0f); //command|channel|velocity - PVSTINSTCH pCh = &m_MidiCh[mc]; + VSTInstrChannel &channel = m_MidiCh[mc]; MidiPitchBend(mc, MIDI_PitchBend_Centre); // centre pitch bend MidiSend(0xB0|mc|(0x79<<8)); // reset all controllers MidiSend(0xB0|mc|(0x7b<<8)); // all notes off MidiSend(0xB0|mc|(0x78<<8)); // all sounds off - for (size_t i = 0; i < CountOf(pCh->uNoteOnMap); i++) //all notes + for (size_t i = 0; i < CountOf(channel.uNoteOnMap); i++) //all notes { - for (CHANNELINDEX c = 0; c < CountOf(pCh->uNoteOnMap[i]); c++) + for (CHANNELINDEX c = 0; c < CountOf(channel.uNoteOnMap[i]); c++) { - while (pCh->uNoteOnMap[i][c] && !overflow) + while (channel.uNoteOnMap[i][c] && !overflow) { overflow=!(MidiSend(dwMidiCode | (i << 8))); - pCh->uNoteOnMap[i][c]--; + channel.uNoteOnMap[i][c]--; } if (overflow) break; //yuck } @@ -2436,10 +2360,10 @@ void CVstPlugin::MidiCommand(UINT nMidiCh, UINT nMidiProg, WORD wMidiBank, UINT note, UINT vol, UINT trackChannel) //---------------------------------------------------------------------------------------------------------------- { - PVSTINSTCH pCh = &m_MidiCh[nMidiCh]; + VSTInstrChannel &channel = m_MidiCh[nMidiCh]; DWORD dwMidiCode = 0; - bool bankChanged = (pCh->wMidiBank != --wMidiBank) && (wMidiBank < 0x80); - bool progChanged = (pCh->nProgram != --nMidiProg) && (nMidiProg < 0x80); + bool bankChanged = (channel.wMidiBank != --wMidiBank) && (wMidiBank < 0x80); + bool progChanged = (channel.nProgram != --nMidiProg) && (nMidiProg < 0x80); //bool chanChanged = nCh != m_nPreviousMidiChan; //get vol in [0,128[ vol = min(vol / 2, 127); @@ -2452,7 +2376,7 @@ // Bank change if ((wMidiBank < 0x80) && ( bankChanged /*|| chanChanged */)) { - pCh->wMidiBank = wMidiBank; + channel.wMidiBank = wMidiBank; MidiSend(((wMidiBank<<16)|(0x20<<8))|(0xB0|nMidiCh)); } // Program change @@ -2460,7 +2384,7 @@ // need to force it by sending prog change too. if ((nMidiProg < 0x80) && (progChanged || bankChanged /*|| chanChanged */ )) { - pCh->nProgram = nMidiProg; + channel.nProgram = nMidiProg; //GetSoundFile()->ProcessMIDIMacro(trackChannel, false, GetSoundFile()->m_MidiCfg.szMidiGlb[MIDIOUT_PROGRAM], 0); MidiSend((nMidiProg<<8)|(0xC0|nMidiCh)); } @@ -2473,9 +2397,9 @@ note--; UINT i = note - NOTE_KEYOFF; - if (pCh->uNoteOnMap[i][trackChannel]) + if (channel.uNoteOnMap[i][trackChannel]) { - pCh->uNoteOnMap[i][trackChannel]--; + channel.uNoteOnMap[i][trackChannel]--; MidiSend(dwMidiCode|(i<<8)); } } @@ -2492,7 +2416,7 @@ dwMidiCode = 0x80|nMidiCh|(vol<<16); //note off, on chan nCh; vol is note off velocity. for (UINT i=0; i<128; i++) //all notes { - pCh->uNoteOnMap[i][trackChannel]=0; + channel.uNoteOnMap[i][trackChannel]=0; MidiSend(dwMidiCode|(i<<8)); } @@ -2508,11 +2432,11 @@ { // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. // But this can cause a VST event overflow if we have many active notes... - while (pCh->uNoteOnMap[i][trackChannel]) + while (channel.uNoteOnMap[i][trackChannel]) { if (MidiSend(dwMidiCode|(i<<8))) { - pCh->uNoteOnMap[i][trackChannel]--; + channel.uNoteOnMap[i][trackChannel]--; } else { // VST event queue overflow, no point in submitting more note offs. @@ -2541,8 +2465,8 @@ // Problem: if a note dies out naturally and we never send a note off, this counter // will block at max until note off. Is this a problem? // Safe to assume we won't need more than 16 note offs max on a given note? - if (pCh->uNoteOnMap[note][trackChannel]<17) - pCh->uNoteOnMap[note][trackChannel]++; + if (channel.uNoteOnMap[note][trackChannel] < 17) + channel.uNoteOnMap[note][trackChannel]++; @@ -2558,8 +2482,7 @@ //------------------------------------------------------------------ { note--; - PVSTINSTCH pMidiCh = &m_MidiCh[midiChn]; - return (pMidiCh->uNoteOnMap[note][trackerChn] != 0); + return (m_MidiCh[midiChn].uNoteOnMap[note][trackerChn] != 0); } @@ -2567,7 +2490,7 @@ //--------------------------------------------------------------------------------------------- { note--; - PVSTINSTCH pMidiCh = &m_MidiCh[midiChn & 0x0f]; + VSTInstrChannel *pMidiCh = &m_MidiCh[midiChn & 0x0f]; if (!(pMidiCh->uNoteOnMap[note][sourceTrackerChn])) return false; @@ -2806,47 +2729,17 @@ } -UINT CVstPlugin::GetNumCommands() -//------------------------------- -{ - if ((m_pEffect) && (m_pEffect->magic == kBuzzMagic)) - { - return Dispatch(effBuzzGetNumCommands, 0, nullptr, nullptr, 0.0f); - } - else if (m_pEffect) - { - return m_pEffect->numParams; - } - return 0; -} - - BOOL CVstPlugin::GetCommandName(UINT nIndex, LPSTR pszName) //--------------------------------------------------------- { - if ((m_pEffect) && (m_pEffect->magic == kBuzzMagic)) + if (m_pEffect) { - return Dispatch(effBuzzGetCommandName, nIndex, nullptr, pszName, 0.0f); - } - else if (m_pEffect) - { return Dispatch(effGetParamName, nIndex, nullptr, pszName, 0.0f); } return 0; } -BOOL CVstPlugin::ExecuteCommand(UINT nIndex) -//------------------------------------------ -{ - if ((m_pEffect) && (m_pEffect->magic == kBuzzMagic)) - { - return Dispatch(effBuzzExecuteCommand, nIndex, nullptr, nullptr, 0.0f); - } - return 0; -} - - //rewbs.defaultPlugGui CAbstractVstEditor* CVstPlugin::GetEditor() //----------------------------------------- @@ -3038,412 +2931,6 @@ } -////////////////////////////////////////////////////////////////////////////////////// -// -// BUZZ -> VST converter -// - -#ifdef ENABLE_BUZZ - -class CBuzz2Vst; - -//=========================================== -class CVSTDataInput: public CMachineDataInput -//=========================================== -{ -protected: - CBuzz2Vst *m_pParent; - -public: - CVSTDataInput(CBuzz2Vst *p) { m_pParent = p; } - virtual void Read(void *pbuf, int const numbytes) { Log("Read(%08X, %d)\n", pbuf, numbytes);} -}; - - -//================================== -class CBuzz2Vst: public CMICallbacks -//================================== -{ -protected: - AEffect m_Effect; - const CMachineInfo *m_pMachineInfo; - CMachineInterface *m_pMachineInterface; - CVSTDataInput *m_pDataInput; - CMasterInfo m_MasterInfo; - CWaveLevel m_WaveLevel; - short m_Waveform[32]; - -public: - CBuzz2Vst(CMachineInterface *, const CMachineInfo *); - ~CBuzz2Vst(); - AEffect *GetEffect() { return &m_Effect; } - VstIntPtr Dispatcher(VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt); - void SetParameter(VstInt32 index, float parameter); - float GetParameter(VstInt32 index); - void Process(float **inputs, float **outputs, long sampleframes); - -public: - static VstIntPtr VSTCALLBACK BuzzDispatcher(AEffect *effect, VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt); - static void VSTCALLBACK BuzzSetParameter(AEffect *effect, VstInt32 index, float parameter); - static float VSTCALLBACK BuzzGetParameter(AEffect *effect, VstInt32 index); - static void VSTCALLBACK BuzzProcess(AEffect *effect, float **inputs, float **outputs, VstInt32 sampleframes); - - // CMICallbacks interface -public: - virtual CWaveInfo const *GetWave(int const) { Log("GetWave\n"); return nullptr; } - virtual CWaveLevel const *GetWaveLevel(int const i, int const level) { Log("GetWaveLevel\n"); return nullptr; } - virtual void MessageBox(char const *txt) { Reporting::Notification(txt, m_pMachineInfo->Name); } - virtual void Lock() { Log("Lock\n"); } - virtual void Unlock() { Log("Unlock\n"); } - virtual int GetWritePos() { Log("GetWritePos\n"); return 0; } - virtual int GetPlayPos() { Log("GetPlayPos\n"); return 0; } - virtual float *GetAuxBuffer() { Log("GetAuxBuffer\n"); return nullptr; } - virtual void ClearAuxBuffer() { Log("ClearAuxBuffer\n"); } - virtual int GetFreeWave() { Log("GetFreeWave\n"); return 0; } - virtual bool AllocateWave(int const i, int const size, char const *name) { Log("AllocateWave\n"); return false; } - virtual void ScheduleEvent(int const time, dword const data) { Log("ScheduleEvent\n"); } - virtual void MidiOut(int const dev, dword const data) { Log("MidiOut\n"); } - virtual short const *GetOscillatorTable(int const waveform) { Log("GetOscillatorTable\n"); return nullptr; } - - // envelopes - virtual int GetEnvSize(int const wave, int const env) { Log("GetEnvSize\n"); return 0; } - virtual bool GetEnvPoint(int const wave, int const env, int const i, word &x, word &y, int &flags) { Log("GetEnvPoint\n"); return false; } - virtual CWaveLevel const *GetNearestWaveLevel(int const i, int const note) { Log("GetNearestWaveLevel(%d, %d)\n", i, note); return &m_WaveLevel; } - - // pattern editing - virtual void SetNumberOfTracks(int const n) { Log("SetNumberOfTracks\n"); } - virtual CPattern *CreatePattern(char const *name, int const length) { Log("CreatePattern\n"); return nullptr; } - virtual CPattern *GetPattern(int const index) { Log("GetPattern\n"); return nullptr; } - virtual char const *GetPatternName(CPattern *ppat) { Log("GetPatternName\n"); return ""; } - virtual void RenamePattern(char const *oldname, char const *newname) { Log("RenamePattern\n"); } - virtual void DeletePattern(CPattern *ppat) { Log("DeletePattern\n"); } - virtual int GetPatternData(CPattern *ppat, int const row, int const group, int const track, int const field) { Log("GetPatternData\n"); return 0; } - virtual void SetPatternData(CPattern *ppat, int const row, int const group, int const track, int const field, int const value) { Log("SetPatternData\n"); } - - // sequence editing - virtual CSequence *CreateSequence() { Log("CreateSequence\n"); return nullptr; } - virtual void DeleteSequence(CSequence *pseq) { Log("DeleteSequence\n"); } - - // special ppat values for GetSequenceData and SetSequenceData - // empty = nullptr - // <break> = (CPattern *)1 - // <mute> = (CPattern *)2 - // <thru> = (CPattern *)3 - virtual CPattern *GetSequenceData(int const row) { Log("GetSequenceData\n"); return nullptr; } - virtual void SetSequenceData(int const row, CPattern *ppat) { Log("SetSequenceData\n"); } - - // buzz v1.2 (MI_VERSION 15) additions start here - virtual void SetMachineInterfaceEx(CMachineInterfaceEx *pex) { Log("SetMachineInterfaceEx\n"); } - // group 1=global, 2=track - virtual void ControlChange__obsolete__(int group, int track, int param, int value) { Log("ControlChange__obsolete__\n"); } - - // direct calls to audiodriver, used by WaveInput and WaveOutput - // shouldn't be used for anything else - virtual int ADGetnumChannels(bool input) { Log("ADGetNumChannels\n"); return 2; } - virtual void ADWrite(int channel, float *psamples, int numsamples) { Log("ADWrite\n"); } - virtual void ADRead(int channel, float *psamples, int numsamples) { Log("ADRead\n"); } - - virtual CMachine *GetThisMachine() { Log("GetThisMachine\n"); return nullptr; } - virtual void ControlChange(CMachine *pmac, int group, int track, int param, int value) { Log("ControlChange\n"); } // set value of parameter (group & 16 == don't record) - - // returns pointer to the sequence if there is a pattern playing - virtual CSequence *GetPlayingSequence(CMachine *pmac) { Log("GetPlayingSequence\n"); return nullptr; } - - // gets ptr to raw pattern data for row of a track of a currently playing pattern (or something like that) - virtual void *GetPlayingRow(CSequence *pseq, int group, int track) { Log("GetPlayingRow\n"); return nullptr; } - virtual int GetStateFlags() { Log("GetStateFlags\n"); return 0; } - virtual void SetnumOutputChannels(CMachine *pmac, int n) { Log("SetNumOutputChannels\n"); } // if n=1 Work(), n=2 WorkMonoToStereo() - virtual void SetEventHandler(CMachine *pmac, BEventType et, EVENT_HANDLER_PTR p, void *param) { Log("SetEventHandler\n"); } - virtual char const *GetWaveName(int const i) { Log("GetWavename\n"); return ""; } - virtual void SetInternalWaveName(CMachine *pmac, int const i, char const *name) { Log("SetInternalWaveName\n"); } // i >= 1, nullptr name to clear - virtual void GetMachineNames(CMachineDataOutput *pout) { Log("GetMachineNames\n"); } // *pout will get one name per Write() - virtual CMachine *GetMachine(char const *name) { Log("GetMachine\n"); return nullptr; } - virtual CMachineInfo const *GetMachineInfo(CMachine *pmac) { Log("GetMachineInfo\n"); return nullptr; } - virtual char const *GetMachineName(CMachine *pmac) { Log("GetMachineName\n"); return ""; } - virtual bool GetInput(int index, float *psamples, int numsamples, bool stereo, float *extrabuffer) { Log("GetInput\n"); return false; } -}; - - -CBuzz2Vst::CBuzz2Vst(CMachineInterface *pBuzzMachine, const CMachineInfo *pBuzzInfo) -//---------------------------------------------------------------------------------- -{ - m_pMachineInfo = pBuzzInfo; - m_pMachineInterface = pBuzzMachine; - m_pDataInput = new CVSTDataInput(this); - - MemsetZero(m_Effect); - m_Effect.magic = kBuzzMagic; - m_Effect.numPrograms = 1; - m_Effect.numParams = pBuzzInfo->numGlobalParameters; - m_Effect.numInputs = 2; - m_Effect.numOutputs = 2; - m_Effect.flags = 0; // see constants - m_Effect.ioRatio = 1.0f; - m_Effect.object = this; - m_Effect.uniqueID = pBuzzInfo->Version; - m_Effect.version = 2; - // Callbacks - m_Effect.dispatcher = BuzzDispatcher; - m_Effect.setParameter = BuzzSetParameter; - m_Effect.getParameter = BuzzGetParameter; - m_Effect.process = BuzzProcess; - m_Effect.processReplacing = nullptr; - // Buzz Info - m_pMachineInterface->pMasterInfo = &m_MasterInfo; - m_pMachineInterface->pCB = this; - m_MasterInfo.BeatsPerMin = 125; - m_MasterInfo.TicksPerBeat = 6; - m_MasterInfo.SamplesPerSec = CSoundFile::gdwMixingFreq; - m_MasterInfo.SamplesPerTick = (int)((60*m_MasterInfo.SamplesPerSec) / (125*6)); - m_MasterInfo.PosInTick = 0; - m_MasterInfo.TicksPerSec = (float)m_MasterInfo.SamplesPerSec / (float)m_MasterInfo.SamplesPerTick; - // Dummy Wave Level - MemsetZero(m_Waveform); - m_WaveLevel.numSamples = 16; - m_WaveLevel.pSamples = m_Waveform; - m_WaveLevel.RootNote = 60; - m_WaveLevel.SamplesPerSec = 44100; - m_WaveLevel.LoopStart = 0; - m_WaveLevel.LoopEnd = 0; -} - - -CBuzz2Vst::~CBuzz2Vst() -//--------------------- -{ - m_Effect.object = nullptr; - if (m_pMachineInfo) - { - m_pMachineInfo = nullptr; - } - if (m_pMachineInterface) - { - delete m_pMachineInterface; - m_pMachineInterface = nullptr; - } - if (m_pDataInput) - { - delete m_pDataInput; - m_pDataInput = nullptr; - } -} - - -VstIntPtr CBuzz2Vst::BuzzDispatcher(AEffect *effect, VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt) -//-------------------------------------------------------------------------------------------------------------------------- -{ - CBuzz2Vst *pBuzz2Vst = (CBuzz2Vst *)effect->object; - if (pBuzz2Vst) return pBuzz2Vst->Dispatcher(opCode, index, value, ptr, opt); - return 0; -} - - -void CBuzz2Vst::BuzzSetParameter(AEffect *effect, VstInt32 index, float parameter) -//-------------------------------------------------------------------------------- -{ - CBuzz2Vst *pBuzz2Vst = (CBuzz2Vst *)effect->object; - if (pBuzz2Vst) pBuzz2Vst->SetParameter(index, parameter); -} - - -float CBuzz2Vst::BuzzGetParameter(AEffect *effect, VstInt32 index) -//---------------------------------------------------------------- -{ - CBuzz2Vst *pBuzz2Vst = (CBuzz2Vst *)effect->object; - if (pBuzz2Vst) return pBuzz2Vst->GetParameter(index); - return 0; -} - - -void CBuzz2Vst::BuzzProcess(AEffect *effect, float **inputs, float **outputs, VstInt32 sampleframes) -//-------------------------------------------------------------------------------------------------- -{ - CBuzz2Vst *pBuzz2Vst = (CBuzz2Vst *)effect->object; - if (pBuzz2Vst) pBuzz2Vst->Process(inputs, outputs, sampleframes); -} - - -VstIntPtr CBuzz2Vst::Dispatcher(VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt) -//----------------------------------------------------------------------------------------------------- -{ - if (!m_pMachineInterface) return 0; - switch(opCode) - { - case effOpen: - Log("Initializing machine...\n"); - m_pMachineInterface->Init(m_pDataInput); - Log("Done.\n"); - break; - - case effClose: - m_Effect.object = nullptr; - delete this; - return 0; - - case effIdentify: - return 'NvEf'; - - case effGetParamName: - if (index < m_pMachineInfo->numGlobalParameters) - { - const CMachineParameter *p = m_pMachineInfo->Parameters[index]; - if ((p) && (ptr) && (p->Name)) - { - lstrcpyn((char *)ptr, p->Name, 9); - } - } - break; - - case effGetParamDisplay: - if (index < m_pMachineInfo->numGlobalParameters) - { - const CMachineParameter *p = m_pMachineInfo->Parameters[index]; - if (p) - { - int value = p->DefValue; - const char *s = m_pMachineInterface->DescribeValue(index, value); - if ((s) && (ptr)) - { - lstrcpyn((char *)ptr, s, 9); - } - } - } - break; - - case effCanBeAutomated: - return (index < m_pMachineInfo->numGlobalParameters); - - // Buzz extensions - case effBuzzGetNumCommands: - { - const char *p = m_pMachineInfo->Commands; - UINT n = 0; - while (p) - { - if (!*p) - { - n++; - break; - } - if (*p == '\n') n++; - p++; - } - return n; - } - - case effBuzzGetCommandName: - if (ptr) - { - const char *p = m_pMachineInfo->Commands; - char *s = (char *)ptr; - UINT n = 0, len = 0; - while ((p) && (n <= (UINT)index)) - { - if (!*p) - { - n++; - break; - } - if (*p == '\n') n++; - if ((n == (UINT)index) && (len < 10)) - { - *s++ = *p; - len++; - } - p++; - } - *s = 0; - return 0; - } - - case effBuzzExecuteCommand: - { - m_pMachineInterface->Command(index); - } - } - return 0; -} - - -void CBuzz2Vst::SetParameter(VstInt32 index, float parameter) -//----------------------------------------------------------- -{ - -} - - -float CBuzz2Vst::GetParameter(VstInt32 index) -//------------------------------------------- -{ - if (index < m_pMachineInfo->numGlobalParameters) - { - const CMachineParameter *p = m_pMachineInfo->Parameters[index]; - if (p) - { - float fmin = (float)p->MinValue; - float fmax = (float)p->MaxValue; - float f = (float)p->DefValue; - if (p->MinValue < p->MaxValue) - { - return (f - fmin) / (fmax - fmin); - } - } - } - return 0; -} - - -void X86_Interleave(const float *pinL, const float *pinR, float *pout, int nsamples) -//---------------------------------------------------------------------------------- -{ - for (int i=0; i<nsamples; i++) - { - pout[i*2] = pinL[i]; - pout[i*2+1] = pinR[i]; - } -} - - -void X86_AddAndDeinterleave(const float *pin, float *poutL, float *poutR, int nsamples) -//------------------------------------------------------------------------------------- -{ - for (int i=0; i<nsamples; i++) - { - poutL[i] += pin[i*2]; - poutR[i] += pin[i*2+1]; - } -} - - -void CBuzz2Vst::Process(float **inputs, float **outputs, long sampleframes) -//------------------------------------------------------------------------- -{ - float *pinL = inputs[0], *pinR = inputs[1]; - float *poutL = outputs[0], *poutR = outputs[1]; - float Buffer[MIXBUFFERSIZE * 2]; // Stereo interleaved - - // Re-interleave the stereo mix - X86_Interleave(pinL, pinR, Buffer, sampleframes); - // Process - m_pMachineInterface->Work(Buffer, sampleframes, WM_READWRITE); - // De-interleave and add the result - X86_AddAndDeinterleave(Buffer, poutL, poutR, sampleframes); -} - - -AEffect *Buzz2Vst(CMachineInterface *pBuzzMachine, const CMachineInfo *pBuzzInfo) -//------------------------------------------------------------------------------- -{ - CBuzz2Vst *p; - - if ((!pBuzzMachine) || (!pBuzzInfo)) return nullptr; - p = new CBuzz2Vst(pBuzzMachine, pBuzzInfo); - return (p) ? p->GetEffect() : nullptr; -} - -#endif // ENABLE_BUZZ - - ////////////////////////////////////////////////////////////////////////////////////////////////// // // DirectX Media Object support @@ -3933,7 +3420,7 @@ } -AEffect *DmoToVst(PVSTPLUGINLIB pLib) +AEffect *DmoToVst(VSTPluginLib *pLib) //----------------------------------- { WCHAR w[100]; Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-04-01 19:25:00 UTC (rev 1238) @@ -16,9 +16,9 @@ #endif #include "../soundlib/Snd_defs.h" -#include "../soundlib/PluginMixBuffer.h" +#include "../soundlib/plugins/PluginMixBuffer.h" -#define kBuzzMagic 'Buzz' +//#define kBuzzMagic 'Buzz' #define kDmoMagic 'DXMO' @@ -29,42 +29,35 @@ class CModDoc; class CSoundFile; -enum -{ - effBuzzGetNumCommands=0x1000, - effBuzzGetCommandName, - effBuzzExecuteCommand, -}; - #ifndef NO_VST typedef AEffect * (VSTCALLBACK * PVSTPLUGENTRY)(audioMasterCallback); -#endif +#endif // NO_VST -typedef struct _VSTPLUGINLIB +struct VSTPluginLib { - struct _VSTPLUGINLIB *pPrev, *pNext; - DWORD dwPluginId1; - DWORD dwPluginId2; - BOOL bIsInstrument; + VSTPluginLib *pPrev, *pNext; + VstInt32 dwPluginId1; + VstInt32 dwPluginId2; + bool isInstrument; CVstPlugin *pPluginsList; CHAR szLibraryName[_MAX_FNAME]; CHAR szDllPath[_MAX_PATH]; -} VSTPLUGINLIB, *PVSTPLUGINLIB; +}; -typedef struct _VSTINSTCH +struct VSTInstrChannel { //BYTE uNoteOnMap[128/8]; rewbs.deMystifyMidiNoteMap - BYTE uNoteOnMap[128][MAX_CHANNELS]; - UINT nProgram; - WORD wMidiBank; //rewbs.MidiBank -} VSTINSTCH, *PVSTINSTCH; + uint8 uNoteOnMap[128][MAX_CHANNELS]; + uint32 nProgram; + uint16 wMidiBank; //rewbs.MidiBank +}; #ifndef NO_VST -#include "../soundlib/PluginEventQueue.h" +#include "../soundlib/plugins/PluginEventQueue.h" #endif // NO_VST @@ -86,7 +79,7 @@ ULONG m_nRefCount; CVstPlugin *m_pNext, *m_pPrev; HINSTANCE m_hLibrary; - VSTPLUGINLIB *m_pFactory; + VSTPluginLib *m_pFactory; SNDMIXPLUGIN *m_pMixStruct; AEffect *m_pEffect; void (*m_pProcessFP)(AEffect*, float**, float**, VstInt32); //Function pointer to AEffect processReplacing if supported, else process. @@ -96,7 +89,7 @@ bool m_bIsVst2; SNDMIXPLUGINSTATE m_MixState; UINT m_nInputs, m_nOutputs; - VSTINSTCH m_MidiCh[16]; + VSTInstrChannel m_MidiCh[16]; short m_nMidiPitchBendPos[16]; CModDoc* m_pModDoc; //rewbs.plugDocAware @@ -118,17 +111,17 @@ PluginEventQueue<vstNumProcessEvents> vstEvents; // MIDI events that should be sent to the plugin public: - CVstPlugin(HINSTANCE hLibrary, VSTPLUGINLIB *pFactory, SNDMIXPLUGIN *pMixPlugin, AEffect *pEffect); + CVstPlugin(HINSTANCE hLibrary, VSTPluginLib *pFactory, SNDMIXPLUGIN *pMixPlugin, AEffect *pEffect); virtual ~CVstPlugin(); void Initialize(CSoundFile* pSndFile); public: - PVSTPLUGINLIB GetPluginFactory() const { return m_pFactory; } + VSTPluginLib *GetPluginFactory() const { return m_pFactory; } bool HasEditor(); - long GetNumPrograms(); + VstInt32 GetNumPrograms(); PlugParamIndex GetNumParameters(); - long GetCurrentProgram(); - long GetNumProgramCategories(); //rewbs.VSTpresets + VstInt32 GetCurrentProgram(); + VstInt32 GetNumProgramCategories(); //rewbs.VSTpresets CString GetFormattedProgramName(VstInt32 index, bool allowFallback = false); bool LoadProgram(CString fileName); bool SaveProgram(CString fileName); @@ -161,9 +154,7 @@ void ToggleEditor(); void GetPluginType(LPSTR pszType); BOOL GetDefaultEffectName(LPSTR pszName); - UINT GetNumCommands(); BOOL GetCommandName(UINT index, LPSTR pszName); - BOOL ExecuteCommand(UINT nIndex); CAbstractVstEditor* GetEditor(); //rewbs.defaultPlugGUI bool GetSpeakerArrangement(); //rewbs.VSTCompliance @@ -235,9 +226,9 @@ PlugParamIndex GetNumParameters() { return 0; } void ToggleEditor() {} bool HasEditor() { return false; } - UINT GetNumCommands() { return 0; } void GetPluginType(LPSTR) {} - PlugParamIndex GetNumPrograms() { return 0; } + VstInt32 GetNumPrograms() { return 0; } + VstInt32 GetCurrentProgram() { return 0; } bool GetProgramNameIndexed(long, long, char*) { return false; } CString GetFormattedProgramName(VstInt32, bool = false) { return ""; } void SetParameter(PlugParamIndex, PlugParamValue) {} @@ -254,7 +245,6 @@ bool LoadProgram(CString) {return false;} bool SaveProgram(CString) {return false;} void SetCurrentProgram(UINT) {} - BOOL ExecuteCommand(UINT) {return FALSE;} void SetSlot(UINT) {} void UpdateMixStructPtr(void*) {} void Bypass(bool = true) { } @@ -270,23 +260,24 @@ { #ifndef NO_VST protected: - PVSTPLUGINLIB m_pVstHead; + VSTPluginLib *m_pVstHead; public: CVstPluginManager(); ~CVstPluginManager(); public: - PVSTPLUGINLIB GetFirstPlugin() const { return m_pVstHead; } - BOOL IsValidPlugin(const VSTPLUGINLIB *pLib); - PVSTPLUGINLIB AddPlugin(LPCSTR pszDllPath, BOOL bCache=TRUE, const bool checkFileExistence = false, CString* const errStr = 0); - bool RemovePlugin(PVSTPLUGINLIB); + VSTPluginLib *GetFirstPlugin() const { return m_pVstHead; } + BOOL IsValidPlugin(const VSTPluginLib *pLib); + VSTPluginLib *AddPlugin(LPCSTR pszDllPath, BOOL bCache=TRUE, const bool checkFileExistence = false, CString* const errStr = 0); + bool RemovePlugin(VSTPluginLib *); BOOL CreateMixPlugin(SNDMIXPLUGIN *, CSoundFile *); void OnIdle(); static void ReportPlugException(LPCSTR format,...); protected: void EnumerateDirectXDMOs(); + void LoadPlugin(const char *pluginPath, AEffect *&effect, HINSTANCE &library); protected: VstIntPtr VstCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); @@ -302,8 +293,8 @@ #else // NO_VST public: - PVSTPLUGINLIB AddPlugin(LPCSTR, BOOL =TRUE, const bool = false, CString* const = 0) {return 0;} - PVSTPLUGINLIB GetFirstPlugin() const { return 0; } + VSTPluginLib *AddPlugin(LPCSTR, BOOL =TRUE, const bool = false, CString* const = 0) {return 0;} + VSTPluginLib *GetFirstPlugin() const { return 0; } void OnIdle() {} #endif // NO_VST }; Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-04-01 19:25:00 UTC (rev 1238) @@ -521,6 +521,10 @@ > </File> <File + RelativePath="..\soundlib\plugins\JBridge.cpp" + > + </File> + <File RelativePath=".\SampleEditorDialogs.cpp" > </File> @@ -1139,18 +1143,22 @@ > </File> <File - RelativePath=".\soundlib\PluginEventQueue.h" + RelativePath=".\soundlib\plugins\PluginEventQueue.h" > </File> <File - RelativePath=".\soundlib\PluginMixBuffer.h" + RelativePath=".\soundlib\plugins\PluginMixBuffer.h" > </File> <File - RelativePath=".\soundlib\PlugInterface.h" + RelativePath=".\soundlib\plugins\PlugInterface.h" > </File> <File + RelativePath=".\soundlib\plugins\JBridge.h" + > + </File> + <File RelativePath=".\soundlib\RowVisitor.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-03-31 23:47:31 UTC (rev 1237) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-04-01 19:25:00 UTC (rev 1238) @@ -174,6 +174,7 @@ <ClCompile Include="..\soundlib\ModChannel.cpp" /> <ClCompile Include="..\soundlib\ModInstrument.cpp" /> <ClCompile Include="..\soundlib\ModSample.cpp" /> + <ClCompile Include="..\soundlib\plugins\JBridge.cpp" /> <ClCompile Include="..\soundlib\RowVisitor.cpp" /> <ClCompile Include="..\soundlib\XMTools.cpp" /> <ClCompile Include="AbstractVstEditor.cpp" /> @@ -336,9 +337,10 @@ <ClInclude Include="..\soundlib\ModChannel.h" /> <ClInclude Include="..\soundlib\ModInstrument.h" /> <ClInclude Include="..\soundlib\ModSample.h" /> - <ClInclude Include="..\soundlib\PluginEventQueue.h" /> - <ClInclude Include="..\soundlib\PluginMixBuffer.h" /> - <ClInclude Include="..\soundlib\PlugInterface.h" /> + <ClInclude Include="..\soundlib\plugins\JBridge.h" /> + <ClInclude Include="..\soundlib\plugins\PluginEventQueue.h" /> + <ClInclude Include="..\soundlib\plugins\PluginMixBuffer.h" /> + <ClInclude Include="..\soundlib\plugins\PlugInterface.h" /> <ClInclude Include="..\soundlib\RowVisitor.h" /> <ClInclude Include="..\soundlib\XMTools.h" /> <ClInclude Include="ACMConvert.h" /> Modified: trunk/OpenMPT/mptrack/mptrack... [truncated message content] |
From: <sag...@us...> - 2012-04-02 17:59:17
|
Revision: 1240 http://modplug.svn.sourceforge.net/modplug/?rev=1240&view=rev Author: saga-games Date: 2012-04-02 17:59:09 +0000 (Mon, 02 Apr 2012) Log Message: ----------- [Fix] IT/ST3 Compatibility: Delayed notes that are on a row that has a row delay effect should be retriggered. [Fix] Sample Editor: Propagating autovibrato changes in XM files didn't work for the last instrument. [Mod] VST: Changed JBridge handling a bit. [Mod] VST: If the plugin DLL is not found, OpenMPT tries to find it in the plugin directory instead of the settings directory. [Mod] Updated XM loading/saving test to check for unreferenced sample handling. Modified Paths: -------------- trunk/OpenMPT/mptrack/Childfrm.cpp trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/Moddoc.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/mptrack/test/test.xm trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/MIDIMacros.cpp trunk/OpenMPT/soundlib/ModInstrument.h trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/XMTools.cpp trunk/OpenMPT/soundlib/plugins/JBridge.cpp trunk/OpenMPT/soundlib/plugins/JBridge.h trunk/OpenMPT/soundlib/plugins/PlugInterface.h Modified: trunk/OpenMPT/mptrack/Childfrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/Childfrm.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Childfrm.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -312,6 +312,10 @@ if ((!wParam) && (pSndFile->m_nInstruments > 0)) { nIns = pModDoc->FindSampleParent(nIns); + if(nIns == INSTRUMENTINDEX_INVALID) + { + nIns = 0; + } } ::SendMessage(m_hWndCtrl, WM_MOD_CTRLMSG, CTRLMSG_PAT_SETINSTRUMENT, nIns); } Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -1288,21 +1288,21 @@ //end rewbs.instroVSTi for(int nRes = 0; nRes<m_CbnResampling.GetCount(); nRes++) { - DWORD v = m_CbnResampling.GetItemData(nRes); - if (pIns->nResampling == v) + DWORD v = m_CbnResampling.GetItemData(nRes); + if (pIns->nResampling == v) { m_CbnResampling.SetCurSel(nRes); break; - } + } } for(int nFltMode = 0; nFltMode<m_CbnFilterMode.GetCount(); nFltMode++) { - DWORD v = m_CbnFilterMode.GetItemData(nFltMode); - if (pIns->nFilterMode == v) + DWORD v = m_CbnFilterMode.GetItemData(nFltMode); + if (pIns->nFilterMode == v) { m_CbnFilterMode.SetCurSel(nFltMode); break; - } + } } // NNA, DCT, DCA @@ -1313,7 +1313,7 @@ m_ComboPPC.SetCurSel(pIns->nPPC); SetDlgItemInt(IDC_EDIT15, pIns->nPPS); // Filter - if (m_pSndFile->m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT)) + if (m_pSndFile->GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) { m_CheckCutOff.SetCheck((pIns->IsCutoffEnabled()) ? TRUE : FALSE); m_CheckResonance.SetCheck((pIns->IsResonanceEnabled()) ? TRUE : FALSE); @@ -2168,6 +2168,28 @@ m_pModDoc->SetModified(); } UpdatePluginList(); + + if(plugin.pMixPlugin != nullptr && plugin.pMixPlugin->isInstrument()) + { + // If we just added an instrument plugin, zap the sample assignments. + const std::set<SAMPLEINDEX> referencedSamples = pIns->GetSamples(); + bool hasSamples = false; + for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++) + { + if(*sample > 0 && *sample <= m_pSndFile->GetNumSamples() && m_pSndFile->GetSample(*sample).pSample != nullptr) + { + hasSamples = true; + break; + } + } + + if(!hasSamples || Reporting::Confirm("Remove sample associations of this instrument?") == cnfYes) + { + pIns->AssignSample(0); + m_NoteMap.Invalidate(); + } + } + m_pModDoc->UpdateAllViews(NULL, HINT_MIXPLUGINS, NULL); } #endif // NO_VST Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -385,8 +385,11 @@ INSTRUMENTINDEX k = m_pParent->GetInstrumentChange(); if (!pModDoc->IsChildSample(k, lParam)) { - UINT nins = pModDoc->FindSampleParent(lParam); - if (nins) m_pParent->InstrumentChanged(nins); + INSTRUMENTINDEX nins = pModDoc->FindSampleParent(lParam); + if(nins != INSTRUMENTINDEX_INVALID) + { + m_pParent->InstrumentChanged(nins); + } } } else { @@ -920,8 +923,11 @@ UINT k = m_pParent->GetInstrumentChange(); if (!m_pModDoc->IsChildSample(k, m_nSample)) { - UINT nins = m_pModDoc->FindSampleParent(m_nSample); - if (nins) m_pParent->InstrumentChanged(nins); + INSTRUMENTINDEX nins = m_pModDoc->FindSampleParent(m_nSample); + if(nins != INSTRUMENTINDEX_INVALID) + { + m_pParent->InstrumentChanged(nins); + } } } else { @@ -970,9 +976,9 @@ } m_pModDoc->UpdateAllViews(NULL, (smp << HINT_SHIFT_SMP) | HINT_SAMPLEINFO | HINT_SAMPLEDATA | HINT_SMPNAMES); - if ((pSndFile->m_nInstruments) && (!m_pModDoc->FindSampleParent(smp))) + if(m_pModDoc->FindSampleParent(smp) == INSTRUMENTINDEX_INVALID) { - if (Reporting::Confirm("This sample is not used by any instrument. Do you want to create a new instrument using this sample?") == cnfYes) + if(Reporting::Confirm("This sample is not used by any instrument. Do you want to create a new instrument using this sample?") == cnfYes) { INSTRUMENTINDEX nins = m_pModDoc->InsertInstrument(smp); m_pModDoc->UpdateAllViews(NULL, (nins << HINT_SHIFT_INS) | HINT_INSTRUMENT | HINT_INSNAMES | HINT_ENVELOPE); @@ -3241,7 +3247,7 @@ return; } - for(INSTRUMENTINDEX i = 1; i < m_pSndFile->GetNumInstruments(); i++) + for(INSTRUMENTINDEX i = 1; i <= m_pSndFile->GetNumInstruments(); i++) { if(m_pSndFile->IsSampleReferencedByInstrument(m_nSample, i)) { Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -952,8 +952,9 @@ pChn->nMasterChn = 0; // remove NNA association pChn->nNewNote = static_cast<BYTE>(note); - if (nins) // Set instrument + if (nins) { + // Set instrument pChn->ResetEnvelopes(); m_SndFile.InstrumentChange(pChn, nins); pChn->nFadeOutVol = 0x10000; // Needed for XM files, as the nRowInstr check in NoteChange() will fail. @@ -1321,6 +1322,7 @@ return true; } + bool CModDoc::MuteInstrument(INSTRUMENTINDEX nInstr, bool bMute) //-------------------------------------------------------------- { @@ -1445,22 +1447,30 @@ } -UINT CModDoc::FindSampleParent(UINT nSmp) const -//--------------------------------------------- +// Find an instrument that references the given sample. +// If no such instrument is found, INSTRUMENTINDEX_INVALID is returned. +INSTRUMENTINDEX CModDoc::FindSampleParent(SAMPLEINDEX sample) const +//----------------------------------------------------------------- { - if ((!m_SndFile.m_nInstruments) || (!nSmp)) return 0; - for (UINT i=1; i<=m_SndFile.m_nInstruments; i++) + if(sample == 0) { - ModInstrument *pIns = m_SndFile.Instruments[i]; - if (pIns) + return INSTRUMENTINDEX_INVALID; + } + for(INSTRUMENTINDEX i = 1; i <= m_SndFile.GetNumInstruments(); i++) + { + const ModInstrument *pIns = m_SndFile.Instruments[i]; + if(pIns != nullptr) { - for (UINT j=0; j<NOTE_MAX; j++) + for(size_t j = 0; j < NOTE_MAX; j++) { - if (pIns->Keyboard[j] == nSmp) return i; + if(pIns->Keyboard[j] == sample) + { + return i; + } } } } - return 0; + return INSTRUMENTINDEX_INVALID; } Modified: trunk/OpenMPT/mptrack/Moddoc.h =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.h 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Moddoc.h 2012-04-02 17:59:09 UTC (rev 1240) @@ -278,7 +278,7 @@ UINT GetPatternSize(PATTERNINDEX nPat) const; BOOL AdjustEndOfSample(UINT nSample); bool IsChildSample(INSTRUMENTINDEX nIns, SAMPLEINDEX nSmp) const; - UINT FindSampleParent(UINT nSmp) const; + INSTRUMENTINDEX FindSampleParent(SAMPLEINDEX sample) const; UINT FindInstrumentChild(UINT nIns) const; bool MoveOrder(ORDERINDEX nSourceNdx, ORDERINDEX nDestNdx, bool bUpdate = true, bool bCopy = false, SEQUENCEINDEX nSourceSeq = SEQUENCEINDEX_INVALID, SEQUENCEINDEX nDestSeq = SEQUENCEINDEX_INVALID); BOOL ExpandPattern(PATTERNINDEX nPattern); Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -158,16 +158,15 @@ if (ERROR_SUCCESS == RegQueryValueEx(hksub, nullptr, 0, &datatype, (LPBYTE)s, &datasize)) { VSTPluginLib *p = new VSTPluginLib(); - - p->pPrev = nullptr; p->pNext = m_pVstHead; p->dwPluginId1 = kDmoMagic; p->dwPluginId2 = clsid.Data1; - p->pPluginsList = nullptr; - p->isInstrument = false; lstrcpyn(p->szLibraryName, s, sizeof(p->szLibraryName)); + StringFixer::SetNullTerminator(p->szLibraryName); + StringFromGUID2(clsid, w, 100); WideCharToMultiByte(CP_ACP, 0, w, -1, p->szDllPath, sizeof(p->szDllPath), nullptr, nullptr); + StringFixer::SetNullTerminator(p->szDllPath); #ifdef DMO_LOG if (theApp.IsDebug()) Log("Found \"%s\" clsid=%s\n", p->szLibraryName, p->szDllPath); #endif @@ -194,15 +193,25 @@ { library = LoadLibrary(pluginPath); + if(library == nullptr) + { + DWORD error = GetLastError(); + #ifdef _DEBUG - DWORD dw = GetLastError(); - if(library == nullptr && dw != ERROR_MOD_NOT_FOUND) // "File not found errors" are annoying. - { - TCHAR szBuf[256]; - wsprintf(szBuf, "Warning: encountered problem when loading plugin dll. Error %d: %s", dw, (LPCTSTR)GetErrorMessage(dw)); - Reporting::Error(szBuf, "DEBUG: Error when loading plugin dll"); + if(error != ERROR_MOD_NOT_FOUND) // "File not found errors" are annoying. + { + TCHAR szBuf[256]; + wsprintf(szBuf, "Warning: encountered problem when loading plugin dll. Error %d: %s", error, (LPCTSTR)GetErrorMessage(error)); + Reporting::Error(szBuf, "DEBUG: Error when loading plugin dll"); + } +#endif //_DEBUG + + if(error == ERROR_MOD_NOT_FOUND) + { + // No point in trying with JBride, either... + return; + } } -#endif //_DEBUG } catch(...) { CVstPluginManager::ReportPlugException("Exception caught in LoadLibrary (%s)", pluginPath); @@ -226,9 +235,13 @@ Log("Entry point not found! (handle=%08X)\n", library); #endif // VST_LOG } - } else + } + + if(effect == nullptr) { // Try loading the plugin using JBridge instead. + FreeLibrary(library); + library = nullptr; effect = JBridge::LoadBridgedPlugin(MasterCallBack, pluginPath); } } @@ -238,8 +251,8 @@ // LibraryName = ID100000ID200000 // ID100000ID200000 = FullDllPath // ID100000ID200000.Flags = Plugin Flags (for now, just isInstrument). - -VSTPluginLib *CVstPluginManager::AddPlugin(LPCSTR pszDllPath, BOOL bCache, const bool checkFileExistence, CString* const errStr) + +VSTPluginLib *CVstPluginManager::AddPlugin(LPCSTR pszDllPath, BOOL bCache, const bool checkFileExistence, CString *const errStr) //------------------------------------------------------------------------------------------------------------------------------ { TCHAR szPath[_MAX_PATH]; @@ -281,18 +294,17 @@ VSTPluginLib *p; try { - p = new VSTPluginLib(); + p = new VSTPluginLib(pszDllPath); } catch(MPTMemoryException) { return nullptr; } - lstrcpyn(p->szDllPath, pszDllPath, sizeof(p->szDllPath)); _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); p->szLibraryName[63] = '\0'; p->pNext = m_pVstHead; - p->pPrev = nullptr; if (m_pVstHead) m_pVstHead->pPrev = p; m_pVstHead = p; + // Extract plugin Ids for (UINT i=0; i<16; i++) { @@ -340,17 +352,14 @@ VSTPluginLib *p = nullptr; try { - p = new VSTPluginLib(); + p = new VSTPluginLib(pszDllPath); } catch(MPTMemoryException) { return nullptr; } - p->pPluginsList = nullptr; - lstrcpyn(p->szDllPath, pszDllPath, CountOf(p->szDllPath)); _splitpath(pszDllPath, nullptr, nullptr, p->szLibraryName, nullptr); p->szLibraryName[63] = 0; p->pNext = m_pVstHead; - p->pPrev = nullptr; try { @@ -522,14 +531,23 @@ if ((!pFound) && strcmp(pMixPlugin->GetLibraryName(), "")) { - CHAR s[_MAX_PATH], dir[_MAX_PATH]; - _splitpath(theApp.GetConfigFileName(), s, dir, nullptr, nullptr); - strcat(s, dir); - int len = strlen(s); - if ((len > 0) && (s[len - 1] != '\\')) strcat(s, "\\"); - strncat(s, "plugins\\", _MAX_PATH - 1); - strncat(s, pMixPlugin->GetLibraryName(), _MAX_PATH - 1); - strncat(s, ".dll", _MAX_PATH-1); + // Try finding the plugin DLL in the plugin directory instead. + CHAR s[_MAX_PATH]; + strncpy(s, CMainFrame::GetSettings().GetDefaultDirectory(DIR_PLUGINS), CountOf(s)); + if(!strcmp(s, "")) + { + strncpy(s, theApp.GetAppDirPath(), CountOf(s)); + } + size_t len = strlen(s); + if((len > 0) && (s[len - 1] != '\\') && (s[len - 1] != '/')) + { + strcat(s, "\\"); + } + strncat(s, pMixPlugin->GetLibraryName(), CountOf(s)); + strncat(s, ".dll", CountOf(s)); + + StringFixer::SetNullTerminator(s); + pFound = AddPlugin(s); if (!pFound) { @@ -949,21 +967,23 @@ //"startStopProcess" //"sendVstMidiEventFlagIsRealtime" - if ((strcmp((char*)ptr,"sendVstEvents") == 0 || - strcmp((char*)ptr,"sendVstMidiEvent") == 0 || - strcmp((char*)ptr,"sendVstTimeInfo") == 0 || - strcmp((char*)ptr,"receiveVstEvents") == 0 || - strcmp((char*)ptr,"receiveVstMidiEvent") == 0 || - strcmp((char*)ptr,"supplyIdle") == 0 || - strcmp((char*)ptr,"sizeWindow") == 0 || - strcmp((char*)ptr,"openFileSelector") == 0 || - strcmp((char*)ptr,"closeFileSelector") == 0 || - strcmp((char*)ptr,"acceptIOChanges") == 0 || - strcmp((char*)ptr,"reportConnectionChanges") == 0 - )) + if(!strcmp((char*)ptr,"sendVstEvents") + || !strcmp((char*)ptr,"sendVstMidiEvent") + || !strcmp((char*)ptr,"sendVstTimeInfo") + || !strcmp((char*)ptr,"receiveVstEvents") + || !strcmp((char*)ptr,"receiveVstMidiEvent") + || !strcmp((char*)ptr,"supplyIdle") + || !strcmp((char*)ptr,"sizeWindow") + || !strcmp((char*)ptr,"openFileSelector") + || !strcmp((char*)ptr,"closeFileSelector") + || !strcmp((char*)ptr,"acceptIOChanges") + || !strcmp((char*)ptr,"reportConnectionChanges")) + { return HostCanDo; - else + } else + { return HostCanNotDo; + } case audioMasterGetLanguage: return kVstLangEnglish; @@ -1015,7 +1035,7 @@ // close a fileselector operation with VstFileSelect* in <ptr>: Must be always called after an open ! case audioMasterCloseFileSelector: - return VstFileSelector(opcode == audioMasterCloseFileSelector, (VstFileSelect *)ptr, effect); + return VstFileSelector(opcode == audioMasterCloseFileSelector, static_cast<VstFileSelect *>(ptr), effect); // open an editor for audio (defined by XML text in ptr) - DEPRECATED in VST 2.4 case audioMasterEditFile: @@ -1051,26 +1071,26 @@ // Helper function for file selection dialog stuff. -VstIntPtr CVstPluginManager::VstFileSelector(const bool destructor, VstFileSelect *pFileSel, const AEffect *effect) -//----------------------------------------------------------------------------------------------------------------- +VstIntPtr CVstPluginManager::VstFileSelector(bool destructor, VstFileSelect *fileSel, const AEffect *effect) +//---------------------------------------------------------------------------------------------------------- { - if(pFileSel == nullptr) + if(fileSel == nullptr) { return 0; } if(!destructor) { - pFileSel->nbReturnPath = 0; - pFileSel->reserved = 0; + fileSel->nbReturnPath = 0; + fileSel->reserved = 0; - if(pFileSel->command != kVstDirectorySelect) + if(fileSel->command != kVstDirectorySelect) { // Plugin wants to load or save a file. std::string extensions, workingDir; - for(VstInt32 i = 0; i < pFileSel->nbFileTypes; i++) + for(VstInt32 i = 0; i < fileSel->nbFileTypes; i++) { - VstFileType *pType = &(pFileSel->fileTypes[i]); + VstFileType *pType = &(fileSel->fileTypes[i]); extensions += pType->name; extensions += "|"; #if (defined(WIN32) || (defined(WINDOWS) && WINDOWS == 1)) @@ -1088,9 +1108,9 @@ extensions += "|"; } - if(pFileSel->initialPath != nullptr) + if(fileSel->initialPath != nullptr) { - workingDir = pFileSel->initialPath; + workingDir = fileSel->initialPath; } else { // Plugins are probably looking for presets...? @@ -1098,9 +1118,9 @@ } FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog( - (pFileSel->command != kVstFileSave), + (fileSel->command != kVstFileSave), "", "", extensions, workingDir, - (pFileSel->command == kVstMultipleFilesLoad) + (fileSel->command == kVstMultipleFilesLoad) ); if(files.abort) @@ -1108,16 +1128,16 @@ return 0; } - if(pFileSel->command == kVstMultipleFilesLoad) + if(fileSel->command == kVstMultipleFilesLoad) { // Multiple paths - pFileSel->nbReturnPath = files.filenames.size(); - pFileSel->returnMultiplePaths = new char *[pFileSel->nbReturnPath]; + fileSel->nbReturnPath = files.filenames.size(); + fileSel->returnMultiplePaths = new char *[fileSel->nbReturnPath]; for(size_t i = 0; i < files.filenames.size(); i++) { char *fname = new char[files.filenames[i].length() + 1]; strcpy(fname, files.filenames[i].c_str()); - pFileSel->returnMultiplePaths[i] = fname; + fileSel->returnMultiplePaths[i] = fname; } return 1; } else @@ -1127,28 +1147,28 @@ // VOPM doesn't initialize required information properly (it doesn't memset the struct to 0)... if(CCONST('V', 'O', 'P', 'M') == effect->uniqueID) { - pFileSel->sizeReturnPath = _MAX_PATH; + fileSel->sizeReturnPath = _MAX_PATH; } - if(pFileSel->returnPath == nullptr || pFileSel->sizeReturnPath == 0) + if(fileSel->returnPath == nullptr || fileSel->sizeReturnPath == 0) { // Provide some memory for the return path. - pFileSel->sizeReturnPath = files.first_file.length() + 1; - pFileSel->returnPath = new char[pFileSel->sizeReturnPath]; - if(pFileSel->returnPath == nullptr) + fileSel->sizeReturnPath = files.first_file.length() + 1; + fileSel->returnPath = new char[fileSel->sizeReturnPath]; + if(fileSel->returnPath == nullptr) { return 0; } - pFileSel->returnPath[pFileSel->sizeReturnPath - 1] = '\0'; - pFileSel->reserved = 1; + fileSel->returnPath[fileSel->sizeReturnPath - 1] = '\0'; + fileSel->reserved = 1; } else { - pFileSel->reserved = 0; + fileSel->reserved = 0; } - strncpy(pFileSel->returnPath, files.first_file.c_str(), pFileSel->sizeReturnPath - 1); - pFileSel->nbReturnPath = 1; - pFileSel->returnMultiplePaths = nullptr; + strncpy(fileSel->returnPath, files.first_file.c_str(), fileSel->sizeReturnPath - 1); + fileSel->nbReturnPath = 1; + fileSel->returnMultiplePaths = nullptr; } return 1; @@ -1158,9 +1178,9 @@ char szInitPath[_MAX_PATH]; MemsetZero(szInitPath); - if(pFileSel->initialPath) + if(fileSel->initialPath) { - strncpy(szInitPath, pFileSel->initialPath, _MAX_PATH - 1); + strncpy(szInitPath, fileSel->initialPath, _MAX_PATH - 1); } char szBuffer[_MAX_PATH]; @@ -1169,37 +1189,37 @@ BROWSEINFO bi; MemsetZero(bi); bi.hwndOwner = CMainFrame::GetMainFrame()->m_hWnd; - bi.lpszTitle = pFileSel->title; + bi.lpszTitle = fileSel->title; bi.pszDisplayName = szInitPath; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; LPITEMIDLIST pid = SHBrowseForFolder(&bi); if(pid != nullptr && SHGetPathFromIDList(pid, szBuffer)) { - if(CCONST('V', 'S', 'T', 'r') == effect->uniqueID && pFileSel->returnPath != nullptr && pFileSel->sizeReturnPath == 0) + if(CCONST('V', 'S', 'T', 'r') == effect->uniqueID && fileSel->returnPath != nullptr && fileSel->sizeReturnPath == 0) { // old versions of reViSiT (which still relied on the host's file selection code) seem to be dodgy. // They report a path size of 0, but when using an own buffer, they will crash. // So we'll just assume that reViSiT can handle long enough (_MAX_PATH) paths here. - pFileSel->sizeReturnPath = strlen(szBuffer) + 1; - pFileSel->returnPath[pFileSel->sizeReturnPath - 1] = '\0'; + fileSel->sizeReturnPath = strlen(szBuffer) + 1; + fileSel->returnPath[fileSel->sizeReturnPath - 1] = '\0'; } - if(pFileSel->returnPath == nullptr || pFileSel->sizeReturnPath == 0) + if(fileSel->returnPath == nullptr || fileSel->sizeReturnPath == 0) { // Provide some memory for the return path. - pFileSel->sizeReturnPath = strlen(szBuffer) + 1; - pFileSel->returnPath = new char[pFileSel->sizeReturnPath]; - if(pFileSel->returnPath == nullptr) + fileSel->sizeReturnPath = strlen(szBuffer) + 1; + fileSel->returnPath = new char[fileSel->sizeReturnPath]; + if(fileSel->returnPath == nullptr) { return 0; } - pFileSel->returnPath[pFileSel->sizeReturnPath - 1] = '\0'; - pFileSel->reserved = 1; + fileSel->returnPath[fileSel->sizeReturnPath - 1] = '\0'; + fileSel->reserved = 1; } else { - pFileSel->reserved = 0; + fileSel->reserved = 0; } - strncpy(pFileSel->returnPath, szBuffer, pFileSel->sizeReturnPath - 1); - pFileSel->nbReturnPath = 1; + strncpy(fileSel->returnPath, szBuffer, fileSel->sizeReturnPath - 1); + fileSel->nbReturnPath = 1; return 1; } else { @@ -1209,23 +1229,23 @@ } else { // Close file selector - delete allocated strings. - if(pFileSel->command == kVstMultipleFilesLoad && pFileSel->returnMultiplePaths != nullptr) + if(fileSel->command == kVstMultipleFilesLoad && fileSel->returnMultiplePaths != nullptr) { - for(VstInt32 i = 0; i < pFileSel->nbReturnPath; i++) + for(VstInt32 i = 0; i < fileSel->nbReturnPath; i++) { - if(pFileSel->returnMultiplePaths[i] != nullptr) + if(fileSel->returnMultiplePaths[i] != nullptr) { - delete[] pFileSel->returnMultiplePaths[i]; + delete[] fileSel->returnMultiplePaths[i]; } } - delete[] pFileSel->returnMultiplePaths; - pFileSel->returnMultiplePaths = nullptr; + delete[] fileSel->returnMultiplePaths; + fileSel->returnMultiplePaths = nullptr; } else { - if(pFileSel->reserved == 1 && pFileSel->returnPath != nullptr) + if(fileSel->reserved == 1 && fileSel->returnPath != nullptr) { - delete[] pFileSel->returnPath; - pFileSel->returnPath = nullptr; + delete[] fileSel->returnPath; + fileSel->returnPath = nullptr; } } return 1; Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-04-02 17:59:09 UTC (rev 1240) @@ -44,6 +44,19 @@ CVstPlugin *pPluginsList; CHAR szLibraryName[_MAX_FNAME]; CHAR szDllPath[_MAX_PATH]; + + VSTPluginLib(const CHAR *dllPath = nullptr) + { + pPrev = pNext = nullptr; + dwPluginId1 = dwPluginId2 = 0; + isInstrument = false; + pPluginsList = nullptr; + if(dllPath != nullptr) + { + lstrcpyn(szDllPath, dllPath, CountOf(szDllPath)); + StringFixer::SetNullTerminator(szDllPath); + } + } }; @@ -281,7 +294,7 @@ protected: VstIntPtr VstCallback(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); - VstIntPtr VstFileSelector(const bool destructor, VstFileSelect *pFileSel, const AEffect *effect); + VstIntPtr VstFileSelector(bool destructor, VstFileSelect *fileSel, const AEffect *effect); static VstIntPtr VSTCALLBACK MasterCallBack(AEffect *effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt); static BOOL __cdecl CreateMixPluginProc(SNDMIXPLUGIN *, CSoundFile *); VstTimeInfo timeInfo; //rewbs.VSTcompliance Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -305,7 +305,13 @@ VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].nMixPlugin, 1); // Samples - VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 2); + VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 3); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[1], "Pulse Sample"), 0); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[2], "Empty Sample"), 0); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[3], "Unassigned Sample"), 0); + VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(1), 1); + VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(2), 1); + VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(3), INSTRUMENTINDEX_INVALID); const ModSample &sample = pSndFile->GetSample(1); VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1); VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1); Modified: trunk/OpenMPT/mptrack/test/test.xm =================================================================== (Binary files differ) Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -806,21 +806,13 @@ } // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) - vector<bool> sampleAssigned(GetNumSamples(), false); + vector<bool> sampleAssigned(GetNumSamples() + 1, false); for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) { - if(Instruments[ins] == nullptr) + if(Instruments[ins] != nullptr) { - continue; + Instruments[ins]->GetSamples(sampleAssigned); } - const std::set<SAMPLEINDEX> referencedSamples = Instruments[ins]->GetSamples(); - for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++) - { - if(*sample <= GetNumSamples()) - { - sampleAssigned[*sample - 1] = true; - } - } } // Writing instruments @@ -853,12 +845,12 @@ for(vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++) { SAMPLEINDEX smp = *sample; - while(smp < GetNumSamples() - && !sampleAssigned[smp] // zero-based + while(++smp <= GetNumSamples() + && !sampleAssigned[smp] && insHeader.numSamples < (compatibilityExport ? 16 : 32)) { - sampleAssigned[smp++] = true; // Don't want to add this sample again. - additionalSamples.push_back(smp); // Not zero-based :) + sampleAssigned[smp] = true; // Don't want to add this sample again. + additionalSamples.push_back(smp); insHeader.numSamples++; } } Modified: trunk/OpenMPT/soundlib/MIDIMacros.cpp =================================================================== --- trunk/OpenMPT/soundlib/MIDIMacros.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/MIDIMacros.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -180,7 +180,7 @@ #ifndef NO_VST if(plugin < MAX_MIXPLUGINS) { - CVstPlugin *pPlug = reinterpret_cast<CVstPlugin *>(sndFile.m_MixPlugins[plugin].pMixPlugin); + CVstPlugin *pPlug = dynamic_cast<CVstPlugin *>(sndFile.m_MixPlugins[plugin].pMixPlugin); if(pPlug) { paramName = pPlug->GetParamName(param); Modified: trunk/OpenMPT/soundlib/ModInstrument.h =================================================================== --- trunk/OpenMPT/soundlib/ModInstrument.h 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/ModInstrument.h 2012-04-02 17:59:09 UTC (rev 1240) @@ -165,6 +165,20 @@ return referencedSamples; } + // Write sample references into a bool vector. If a sample is referenced by this instrument, true is written. + // The caller has to initialize the vector. + void GetSamples(std::vector<bool> &referencedSamples) const + { + for(size_t i = 0; i < CountOf(Keyboard); i++) + { + // 0 isn't a sample. + if(Keyboard[i] != 0 && Keyboard[i] < referencedSamples.size()) + { + referencedSamples[Keyboard[i]] = true; + } + } + } + // Translate instrument properties between two given formats. void Convert(MODTYPE fromType, MODTYPE toType); Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -173,12 +173,7 @@ // Check if any of those samples are referenced by other instruments as well, in which case we want to keep them of course. for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++) if (Instruments[nIns] != nullptr && nIns != nInstr) { - referencedSamples = Instruments[nIns]->GetSamples(); - for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++) - { - if((*sample) <= GetNumSamples()) - keepSamples[*sample] = true; - } + Instruments[nIns]->GetSamples(keepSamples); } // Now nuke the selected samples. Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -1620,8 +1620,16 @@ } } + bool triggerNote = (m_nTickCount == nStartTick); // Can be delayed by a note delay effect + // IT Compatibility: Delayed notes (using SDx) that are on the same row as a Row Delay effect are retriggered. Scream Tracker 3 does the same. + // Test case: PatternDelay-NoteDelay.it + if((GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) && nStartTick > 0 && (m_nTickCount % (m_nMusicSpeed + m_nFrameDelay)) == nStartTick) + { + triggerNote = true; + } + // Handles note/instrument/volume changes - if (m_nTickCount == nStartTick) // can be delayed by a note delay effect + if(triggerNote) { UINT note = pChn->rowCommand.note; if (instr) pChn->nNewIns = instr; Modified: trunk/OpenMPT/soundlib/XMTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/XMTools.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/XMTools.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -254,7 +254,7 @@ type = mptIns.nMidiProgram; // If FT2 writes crap here, we can do so, too! - numSamples = static_cast<uint16>(min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32))); + numSamples = static_cast<uint16>(Util::Min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32))); } @@ -305,7 +305,7 @@ version = LittleEndianW(0x102); - numSamples = static_cast<uint16>(LittleEndianW(min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32)))); + numSamples = static_cast<uint16>(LittleEndianW(Util::Min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32)))); } Modified: trunk/OpenMPT/soundlib/plugins/JBridge.cpp =================================================================== --- trunk/OpenMPT/soundlib/plugins/JBridge.cpp 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/plugins/JBridge.cpp 2012-04-02 17:59:09 UTC (rev 1240) @@ -11,17 +11,22 @@ #include "stdafx.h" #include <pluginterfaces/vst2.x/aeffectx.h> +#include "JBridge.h" namespace JBridge { +#ifdef ENABLE_JBRIDGE + // Name of the proxy DLL to load static const char *proxyRegKey = "Software\\JBridge"; #ifdef _M_X64 static const char *proxyRegVal = "Proxy64"; //use this for x64 builds +static_assert(sizeof(void *) == 8, "Wrong platform!"); #else static const char *proxyRegVal = "Proxy32"; //use this for x86 builds +static_assert(sizeof(void *) == 4, "Wrong platform!"); #endif // Typedef for BridgeMain proc @@ -101,4 +106,6 @@ return pfnBridgeMain(audioMaster, pluginPath); } +#endif // ENABLE_JBRIDGE + } Modified: trunk/OpenMPT/soundlib/plugins/JBridge.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/JBridge.h 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/plugins/JBridge.h 2012-04-02 17:59:09 UTC (rev 1240) @@ -10,7 +10,15 @@ #pragma once +#if !defined(NO_VST) && (defined(WIN32) || (defined(WINDOWS) && WINDOWS == 1)) +#define ENABLE_JBRIDGE +#endif + namespace JBridge { +#ifdef ENABLE_JBRIDGE AEffect *LoadBridgedPlugin(audioMasterCallback audioMaster, const char *pluginPath); +#else + void *LoadBridgedPlugin(void *, const char *) { return nullptr; } +#endif // ENABLE_JBRIDGE } Modified: trunk/OpenMPT/soundlib/plugins/PlugInterface.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-04-01 19:26:38 UTC (rev 1239) +++ trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-04-02 17:59:09 UTC (rev 1240) @@ -105,11 +105,11 @@ irExpandMix = 0x08, // [0%,100%] -> [-200%,200%] }; - DWORD dwPluginId1; // Plugin type (kEffectMagic, kDmoMagic, kBuzzMagic) - DWORD dwPluginId2; // Plugin unique ID - DWORD dwInputRouting; // Bits 0 to 7 = RoutingFlags, bits 8 - 15 = mixing mode, bits 16-23 = gain - DWORD dwOutputRouting; // 0 = send to master 0x80 + x = send to plugin x - DWORD dwReserved[4]; // Reserved for routing info + VstInt32 dwPluginId1; // Plugin type (kEffectMagic, kDmoMagic, kBuzzMagic) + VstInt32 dwPluginId2; // Plugin unique ID + uint32 dwInputRouting; // Bits 0 to 7 = RoutingFlags, bits 8 - 15 = mixing mode, bits 16-23 = gain + uint32 dwOutputRouting; // 0 = send to master 0x80 + x = send to plugin x + uint32 dwReserved[4]; // Reserved for routing info CHAR szName[32]; // User-chosen plugin name CHAR szLibraryName[64]; // original DLL name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-04 15:38:40
|
Revision: 1243 http://modplug.svn.sourceforge.net/modplug/?rev=1243&view=rev Author: saga-games Date: 2012-04-04 15:38:31 +0000 (Wed, 04 Apr 2012) Log Message: ----------- [Fix] Sample Editor: Loop point handling was forgotten to be updated to match the changes in Sampleio.cpp. Modified Paths: -------------- trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Wav.h Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-03 13:54:41 UTC (rev 1242) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-04 15:38:31 UTC (rev 1243) @@ -1901,33 +1901,27 @@ if (bExtra) { WAVESMPLHEADER *psh = (WAVESMPLHEADER *)(psamples+dwSmpLen); + MemsetZero(*psh); psh->smpl_id = 0x6C706D73; psh->smpl_len = sizeof(WAVESMPLHEADER) - 8; psh->dwSamplePeriod = 22675; if (sample.nC5Speed > 256) psh->dwSamplePeriod = 1000000000 / sample.nC5Speed; psh->dwBaseNote = 60; - if (sample.uFlags & (CHN_LOOP|CHN_SUSTAINLOOP)) + + // Write loops + WAVESAMPLERINFO *psmpl = (WAVESAMPLERINFO *)psh; + MemsetZero(psmpl->wsiLoops); + if((sample.uFlags & CHN_SUSTAINLOOP) != 0) { - WAVESAMPLERINFO *psmpl = (WAVESAMPLERINFO *)psh; - MemsetZero(psmpl->wsiLoops); - if (sample.uFlags & CHN_SUSTAINLOOP) - { - psmpl->wsiHdr.dwSampleLoops = 2; - psmpl->wsiLoops[0].dwLoopType = (sample.uFlags & CHN_PINGPONGSUSTAIN) ? 1 : 0; - psmpl->wsiLoops[0].dwLoopStart = sample.nSustainStart; - psmpl->wsiLoops[0].dwLoopEnd = sample.nSustainEnd; - psmpl->wsiLoops[1].dwLoopType = (sample.uFlags & CHN_PINGPONGLOOP) ? 1 : 0; - psmpl->wsiLoops[1].dwLoopStart = sample.nLoopStart; - psmpl->wsiLoops[1].dwLoopEnd = sample.nLoopEnd; - } else - { - psmpl->wsiHdr.dwSampleLoops = 1; - psmpl->wsiLoops[0].dwLoopType = (sample.uFlags & CHN_PINGPONGLOOP) ? 1 : 0; - psmpl->wsiLoops[0].dwLoopStart = sample.nLoopStart; - psmpl->wsiLoops[0].dwLoopEnd = sample.nLoopEnd; - } - psmpl->wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT) * psmpl->wsiHdr.dwSampleLoops; + psmpl->wsiLoops[psmpl->wsiHdr.dwSampleLoops++].SetLoop(sample.nSustainStart, sample.nSustainEnd, (sample.uFlags & CHN_PINGPONGSUSTAIN) != 0); + psmpl->wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); } + if((sample.uFlags & CHN_LOOP) != 0) + { + psmpl->wsiLoops[psmpl->wsiHdr.dwSampleLoops++].SetLoop(sample.nLoopStart, sample.nLoopEnd, (sample.uFlags & CHN_PINGPONGLOOP) != 0); + psmpl->wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); + } + WAVEEXTRAHEADER *pxh = (WAVEEXTRAHEADER *)(psamples+dwSmpLen+psh->smpl_len+8); pxh->xtra_id = IFFID_xtra; pxh->xtra_len = sizeof(WAVEEXTRAHEADER)-8; Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-03 13:54:41 UTC (rev 1242) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-04 15:38:31 UTC (rev 1243) @@ -608,20 +608,6 @@ /////////////////////////////////////////////////////////////// // Save WAV -void SetLoop(SAMPLELOOPSTRUCT &loopData, DWORD loopStart, DWORD loopEnd, bool bidi) -//--------------------------------------------------------------------------------- -{ - loopData.dwLoopType = LittleEndian(bidi ? 1 : 0); - loopData.dwLoopStart = LittleEndian(loopStart); - // Loop ends are *inclusive* in the RIFF standard, while they're *exclusive* in OpenMPT. - if(loopEnd > loopStart) - { - loopData.dwLoopEnd = LittleEndian(loopEnd - 1); - } else - { - loopData.dwLoopEnd = LittleEndian(loopStart); - } -} bool CSoundFile::SaveWAVSample(UINT nSample, const LPCSTR lpszFileName) const //--------------------------------------------------------------------------- @@ -688,12 +674,12 @@ // Write loops if((pSmp->uFlags & CHN_SUSTAINLOOP) != 0) { - SetLoop(smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++], pSmp->nSustainStart, pSmp->nSustainEnd, (pSmp->uFlags & CHN_PINGPONGSUSTAIN) != 0); + smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(pSmp->nSustainStart, pSmp->nSustainEnd, (pSmp->uFlags & CHN_PINGPONGSUSTAIN) != 0); smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); } if((pSmp->uFlags & CHN_LOOP) != 0) { - SetLoop(smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++], pSmp->nLoopStart, pSmp->nLoopEnd, (pSmp->uFlags & CHN_PINGPONGLOOP) != 0); + smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(pSmp->nLoopStart, pSmp->nLoopEnd, (pSmp->uFlags & CHN_PINGPONGLOOP) != 0); smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); } smpl.wsiHdr.smpl_len = LittleEndian(smpl.wsiHdr.smpl_len); Modified: trunk/OpenMPT/soundlib/Wav.h =================================================================== --- trunk/OpenMPT/soundlib/Wav.h 2012-04-03 13:54:41 UTC (rev 1242) +++ trunk/OpenMPT/soundlib/Wav.h 2012-04-04 15:38:31 UTC (rev 1243) @@ -95,6 +95,25 @@ DWORD dwLoopEnd; // Byte offset ? DWORD dwFraction; DWORD dwPlayCount; // Loop Count, 0=infinite + + // Set up a loop struct. + void SetLoop(DWORD loopStart, DWORD loopEnd, bool bidi) + { + dwIdentifier = 0; + dwLoopType = LittleEndian(bidi ? 1 : 0); + dwLoopStart = LittleEndian(loopStart); + // Loop ends are *inclusive* in the RIFF standard, while they're *exclusive* in OpenMPT. + if(loopEnd > loopStart) + { + dwLoopEnd = LittleEndian(loopEnd - 1); + } else + { + dwLoopEnd = LittleEndian(loopStart); + } + dwFraction = 0; + dwPlayCount = 0; + } + } SAMPLELOOPSTRUCT; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-11 19:09:17
|
Revision: 1244 http://modplug.svn.sourceforge.net/modplug/?rev=1244&view=rev Author: saga-games Date: 2012-04-11 19:09:10 +0000 (Wed, 11 Apr 2012) Log Message: ----------- [Fix] Sample Editor: Saved WAV sample header was incorrect (tx coda). [Fix] Sample Editor: Pasting a sample into an empty sample slot didn't make this slot available from the pattern editor. [Fix] Wave Export: Most likely fixed http://forum.openmpt.org/index.php?topic=3874.0 [Mod] OpenMPT: Version is now 1.20.00.84 Modified Paths: -------------- trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Sampleio.cpp Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-04-04 15:38:31 UTC (rev 1243) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-04-11 19:09:10 UTC (rev 1244) @@ -640,10 +640,10 @@ int oldVol = m_pSndFile->GetMasterVolume(); int nOldRepeat = m_pSndFile->GetRepeatCount(); CSoundFile::gdwSoundSetup |= SNDMIX_DIRECTTODISK; - if ((!m_dwFileLimit) && (!m_dwSongLimit)) CSoundFile::gdwSoundSetup |= SNDMIX_NOBACKWARDJUMPS; CSoundFile::gdwMixingFreq = m_pWaveFormat->nSamplesPerSec; CSoundFile::gnBitsPerSample = m_pWaveFormat->wBitsPerSample; CSoundFile::gnChannels = m_pWaveFormat->nChannels; + m_pSndFile->m_dwSongFlags &= ~(SONG_PAUSED | SONG_STEP); // -> CODE#0024 // -> DESC="wav export update" // if ((m_bNormalize) && (m_pWaveFormat->wBitsPerSample <= 16)) @@ -900,7 +900,7 @@ fseek(f, dwDataOffset-sizeof(datahdr), SEEK_SET); fwrite(&datahdr, sizeof(datahdr), 1, f); fclose(f); - CSoundFile::gdwSoundSetup &= ~(SNDMIX_DIRECTTODISK|SNDMIX_NOBACKWARDJUMPS); + CSoundFile::gdwSoundSetup &= ~SNDMIX_DIRECTTODISK; m_pSndFile->SetRepeatCount(nOldRepeat); m_pSndFile->m_nMaxOrderPosition = 0; if (m_bNormalize) @@ -1059,7 +1059,7 @@ m_pSndFile->ResetChannels(); CSoundFile::InitPlayer(TRUE); CSoundFile::gdwSoundSetup |= SNDMIX_DIRECTTODISK; - if ((!m_dwFileLimit) && (!m_dwSongLimit)) CSoundFile::gdwSoundSetup |= SNDMIX_NOBACKWARDJUMPS; + m_pSndFile->m_dwSongFlags &= ~(SONG_PAUSED | SONG_STEP); m_pSndFile->visitedSongRows.Initialize(true); @@ -1150,7 +1150,7 @@ CMainFrame::GetMainFrame()->StopRenderer(m_pSndFile); //rewbs.VSTTimeInfo // Done CSoundFile::gdwSoundSetup = oldsndcfg; - CSoundFile::gdwSoundSetup &= ~(SNDMIX_DIRECTTODISK|SNDMIX_NOBACKWARDJUMPS); + CSoundFile::gdwSoundSetup &= ~SNDMIX_DIRECTTODISK; m_pSndFile->SetRepeatCount(oldrepeat); m_pSndFile->m_nMaxOrderPosition = 0; m_pSndFile->visitedSongRows.Initialize(true); Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-04 15:38:31 UTC (rev 1243) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-11 19:09:10 UTC (rev 1244) @@ -2005,7 +2005,7 @@ SetCurSel(0, 0); pModDoc->AdjustEndOfSample(m_nSample); pModDoc->SetModified(); - pModDoc->UpdateAllViews(NULL, (m_nSample << HINT_SHIFT_SMP) | HINT_SAMPLEINFO | HINT_SAMPLEDATA, NULL); + pModDoc->UpdateAllViews(NULL, (m_nSample << HINT_SHIFT_SMP) | HINT_SAMPLEINFO | HINT_SAMPLEDATA | HINT_SMPNAMES, NULL); } CloseClipboard(); } Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-04-04 15:38:31 UTC (rev 1243) +++ trunk/OpenMPT/mptrack/version.h 2012-04-11 19:09:10 UTC (rev 1244) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 83 +#define VER_MINORMINOR 84 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-04 15:38:31 UTC (rev 1243) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-11 19:09:10 UTC (rev 1244) @@ -621,69 +621,73 @@ WAVESAMPLERINFO smpl; WAVELISTHEADER list; WAVEEXTRAHEADER extra; - const ModSample *pSmp = &Samples[nSample]; + const ModSample &sample = Samples[nSample]; FILE *f; if ((f = fopen(lpszFileName, "wb")) == NULL) return false; MemsetZero(extra); MemsetZero(smpl); header.id_RIFF = LittleEndian(IFFID_RIFF); - header.filesize = sizeof(header) + sizeof(format) + sizeof(data) + sizeof(smpl) + sizeof(extra) - 8 - + sizeof(list) + 8 + 16 + 8 + 32; // LIST(INAM, ISFT) + header.filesize = sizeof(header) - 8 + sizeof(format) + sizeof(data) + sizeof(extra) + + sizeof(list) + 8 + softwareIdLength + 8 + 32; // LIST(INAM, ISFT) header.id_WAVE = LittleEndian(IFFID_WAVE); format.id_fmt = LittleEndian(IFFID_fmt); format.hdrlen = LittleEndian(16); format.format = LittleEndianW(1); if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) - format.freqHz = LittleEndian(pSmp->nC5Speed); + format.freqHz = LittleEndian(sample.nC5Speed); else - format.freqHz = LittleEndian(TransposeToFrequency(pSmp->RelativeTone, pSmp->nFineTune)); - format.channels = LittleEndianW(pSmp->GetNumChannels()); - format.bitspersample = LittleEndianW(pSmp->GetElementarySampleSize() * 8); - format.samplesize = LittleEndianW(pSmp->GetBytesPerSample() * 8); + format.freqHz = LittleEndian(TransposeToFrequency(sample.RelativeTone, sample.nFineTune)); + format.channels = LittleEndianW(sample.GetNumChannels()); + format.bitspersample = LittleEndianW(sample.GetElementarySampleSize() * 8); + format.samplesize = LittleEndianW(sample.GetBytesPerSample()); format.bytessec = LittleEndian(format.freqHz * format.samplesize); data.id_data = LittleEndian(IFFID_data); UINT nType; - data.length = LittleEndian(pSmp->GetSampleSizeInBytes()); - if (pSmp->uFlags & CHN_STEREO) + data.length = sample.GetSampleSizeInBytes(); + if (sample.uFlags & CHN_STEREO) { - nType = (pSmp->uFlags & CHN_16BIT) ? RS_STIPCM16S : RS_STIPCM8U; + nType = (sample.uFlags & CHN_16BIT) ? RS_STIPCM16S : RS_STIPCM8U; } else { - nType = (pSmp->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8U; + nType = (sample.uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8U; } header.filesize += data.length; - header.filesize = LittleEndian(header.filesize); - fwrite(&header, 1, sizeof(header), f); - fwrite(&format, 1, sizeof(format), f); - fwrite(&data, 1, sizeof(data), f); - WriteSample(f, pSmp, nType); // "smpl" field smpl.wsiHdr.smpl_id = LittleEndian(IFFID_smpl); smpl.wsiHdr.smpl_len = sizeof(WAVESMPLHEADER) - 8; - if (pSmp->nC5Speed >= 256) - smpl.wsiHdr.dwSamplePeriod = LittleEndian(1000000000 / pSmp->nC5Speed); + if (sample.nC5Speed >= 256) + smpl.wsiHdr.dwSamplePeriod = LittleEndian(1000000000 / sample.nC5Speed); else - smpl.wsiHdr.dwSamplePeriod = LittleEndian(22675); + smpl.wsiHdr.dwSamplePeriod = LittleEndian(22675); // 44100 Hz - smpl.wsiHdr.dwBaseNote = LittleEndian(60); + smpl.wsiHdr.dwBaseNote = LittleEndian(NOTE_MIDDLEC - NOTE_MIN); // Write loops - if((pSmp->uFlags & CHN_SUSTAINLOOP) != 0) + if((sample.uFlags & CHN_SUSTAINLOOP) != 0) { - smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(pSmp->nSustainStart, pSmp->nSustainEnd, (pSmp->uFlags & CHN_PINGPONGSUSTAIN) != 0); + smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(sample.nSustainStart, sample.nSustainEnd, (sample.uFlags & CHN_PINGPONGSUSTAIN) != 0); smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); } - if((pSmp->uFlags & CHN_LOOP) != 0) + if((sample.uFlags & CHN_LOOP) != 0) { - smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(pSmp->nLoopStart, pSmp->nLoopEnd, (pSmp->uFlags & CHN_PINGPONGLOOP) != 0); + smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(sample.nLoopStart, sample.nLoopEnd, (sample.uFlags & CHN_PINGPONGLOOP) != 0); smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); } + + // Update file length in header + header.filesize += smpl.wsiHdr.smpl_len + 8; + + header.filesize = LittleEndian(header.filesize); + data.length = LittleEndian(data.length); smpl.wsiHdr.smpl_len = LittleEndian(smpl.wsiHdr.smpl_len); - + fwrite(&header, 1, sizeof(header), f); + fwrite(&format, 1, sizeof(format), f); + fwrite(&data, 1, sizeof(data), f); + WriteSample(f, &sample, nType); fwrite(&smpl, 1, smpl.wsiHdr.smpl_len + 8, f); // "LIST" field @@ -708,16 +712,16 @@ extra.xtra_id = LittleEndian(IFFID_xtra); extra.xtra_len = LittleEndian(sizeof(extra) - 8); - extra.dwFlags = LittleEndian(pSmp->uFlags); - extra.wPan = LittleEndianW(pSmp->nPan); - extra.wVolume = LittleEndianW(pSmp->nVolume); - extra.wGlobalVol = LittleEndianW(pSmp->nGlobalVol); + extra.dwFlags = LittleEndian(sample.uFlags); + extra.wPan = LittleEndianW(sample.nPan); + extra.wVolume = LittleEndianW(sample.nVolume); + extra.wGlobalVol = LittleEndianW(sample.nGlobalVol); extra.wReserved = 0; - extra.nVibType = pSmp->nVibType; - extra.nVibSweep = pSmp->nVibSweep; - extra.nVibDepth = pSmp->nVibDepth; - extra.nVibRate = pSmp->nVibRate; + extra.nVibType = sample.nVibType; + extra.nVibSweep = sample.nVibSweep; + extra.nVibDepth = sample.nVibDepth; + extra.nVibRate = sample.nVibRate; if((GetType() & MOD_TYPE_XM) && (extra.nVibDepth | extra.nVibRate)) { // XM vibrato is upside down This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-13 16:57:16
|
Revision: 1245 http://modplug.svn.sourceforge.net/modplug/?rev=1245&view=rev Author: saga-games Date: 2012-04-13 16:57:10 +0000 (Fri, 13 Apr 2012) Log Message: ----------- [Fix] Adding instrument plugins from instrument view didn't set up a MIDI channel (http://bugs.openmpt.org/view.php?id=239). [Mod] VST: Allow MIDI banks up to 16384 (seems to work with Synth1, but mostly untested otherwise). Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Vstplug.cpp Added Paths: ----------- trunk/OpenMPT/packageTemplate/Plugins/ trunk/OpenMPT/packageTemplate/Plugins/MIDI/ Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-04-11 19:09:10 UTC (rev 1244) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2012-04-13 16:57:10 UTC (rev 1245) @@ -932,7 +932,7 @@ // Midi Program m_SpinMidiPR.SetRange(0, 128); // rewbs.MidiBank - m_SpinMidiBK.SetRange(0, 128); + m_SpinMidiBK.SetRange(0, 16384); m_CbnResampling.SetItemData(m_CbnResampling.AddString("Default"), SRCMODE_DEFAULT); m_CbnResampling.SetItemData(m_CbnResampling.AddString("None"), SRCMODE_NEAREST); @@ -1265,7 +1265,7 @@ SetDlgItemInt(IDC_EDIT10, pIns->nMidiProgram); else SetDlgItemText(IDC_EDIT10, "---"); - if (pIns->wMidiBank && pIns->wMidiBank<=128) + if (pIns->wMidiBank && pIns->wMidiBank <= 16384) SetDlgItemInt(IDC_EDIT11, pIns->wMidiBank); else SetDlgItemText(IDC_EDIT11, "---"); @@ -2069,16 +2069,13 @@ if ((!IsLocked()) && (pIns)) { WORD w = GetDlgItemInt(IDC_EDIT11); - if ((w >= 0) && (w <= 255)) + if(w >= 0 && w <= 16384 && pIns->wMidiBank != w) { - if (pIns->wMidiBank != w) - { - pIns->wMidiBank = w; - SetInstrumentModified(true); - } + pIns->wMidiBank = w; + SetInstrumentModified(true); } //rewbs.MidiBank: we will not set the midi bank/program if it is 0 - if (w==0) + if(w == 0) { LockControls(); SetDlgItemText(IDC_EDIT11, "---"); @@ -2093,12 +2090,12 @@ //----------------------------------- { ModInstrument *pIns = m_pSndFile->Instruments[m_nInstrument]; - if ((!IsLocked()) && (pIns)) + if(!IsLocked() && pIns) { - int n = m_CbnMidiCh.GetItemData(m_CbnMidiCh.GetCurSel()); - if (pIns->nMidiChannel != (BYTE)(n & 0xff)) + uint8 ch = m_CbnMidiCh.GetItemData(m_CbnMidiCh.GetCurSel()); + if(pIns->nMidiChannel != ch) { - pIns->nMidiChannel = (BYTE)(n & 0xff); + pIns->nMidiChannel = ch; SetInstrumentModified(true); } } @@ -2134,8 +2131,7 @@ { m_CbnPluginVelocityHandling.EnableWindow(FALSE); m_CbnPluginVolumeHandling.EnableWindow(FALSE); - } - else + } else { m_CbnPluginVelocityHandling.EnableWindow(); m_CbnPluginVolumeHandling.EnableWindow(); @@ -2152,11 +2148,13 @@ m_CbnPluginVelocityHandling.SetCurSel(pIns->nPluginVelocityHandling); m_CbnPluginVolumeHandling.SetCurSel(pIns->nPluginVolumeHandling); - if (pIns->nMixPlug) + if(pIns->nMixPlug) { // we have selected a plugin that's not "no plugin" const SNDMIXPLUGIN &plugin = m_pSndFile->m_MixPlugins[pIns->nMixPlug - 1]; - if(!plugin.IsValidPlugin() && !IsLocked()) + bool active = !IsLocked(); + + if(!plugin.IsValidPlugin() && active) { // No plugin in this slot yet: Ask user to add one. #ifndef NO_VST @@ -2178,7 +2176,7 @@ { ::EnableWindow(::GetDlgItem(m_hWnd, IDC_INSVIEWPLG), true); - if(!IsLocked() && plugin.pMixPlugin->isInstrument()) + if(active && plugin.pMixPlugin->isInstrument()) { if(pIns->nMidiChannel == MidiNoChannel) { Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-11 19:09:10 UTC (rev 1244) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-13 16:57:10 UTC (rev 1245) @@ -2372,7 +2372,7 @@ { m_nMidiPitchBendPos[nMidiCh] = newPitchBendPos; //store pitch bend position short converted = getMIDI14bitValueFromShort(newPitchBendPos); - MidiSend(converted<<8 | MIDI_PitchBend_Command|nMidiCh); + MidiSend(converted << 8 | MIDI_PitchBend_Command | nMidiCh); } @@ -2382,45 +2382,51 @@ { VSTInstrChannel &channel = m_MidiCh[nMidiCh]; DWORD dwMidiCode = 0; - bool bankChanged = (channel.wMidiBank != --wMidiBank) && (wMidiBank < 0x80); + bool bankChanged = (channel.wMidiBank != --wMidiBank) && (wMidiBank < 0x4000); bool progChanged = (channel.nProgram != --nMidiProg) && (nMidiProg < 0x80); - //bool chanChanged = nCh != m_nPreviousMidiChan; //get vol in [0,128[ vol = min(vol / 2, 127); - // Note: Some VSTis update bank/prog on midi channel change, others don't. - // For those that don't, we do it for them. - // Note 17/12/2005 - I have disabled that because it breaks Edirol Hypercanvas - // and I can't remember why it would be useful. - // Bank change - if ((wMidiBank < 0x80) && ( bankChanged /*|| chanChanged */)) + if(wMidiBank < 0x4000 && bankChanged) { + uint8 high = (wMidiBank >> 7); + uint8 low = (wMidiBank & 0x7F); + + if((channel.wMidiBank >> 7) != high) + { + // High byte changed + MidiSend(((high << 16) | (MIDICC_BankSelect_Coarse << 8)) | ((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh)); + } + // Low byte + //GetSoundFile()->ProcessMIDIMacro(trackChannel, false, GetSoundFile()->m_MidiCfg.szMidiGlb[MIDIOUT_BANKSEL], 0); + MidiSend((low << 16) | (MIDICC_BankSelect_Fine << 8) | ((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh)); + channel.wMidiBank = wMidiBank; - MidiSend(((wMidiBank<<16)|(0x20<<8))|(0xB0|nMidiCh)); } + // Program change - // Note: Some plugs (Edirol Orchestral) don't update on bank change only - - // need to force it by sending prog change too. - if ((nMidiProg < 0x80) && (progChanged || bankChanged /*|| chanChanged */ )) + // According to the MIDI specs, a bank change alone doesn't have to change the active program - it will only change the bank of subsequent program changes. + // Thus we send program changes also if only the bank has changed. + if(nMidiProg < 0x80 && (progChanged || bankChanged)) { channel.nProgram = nMidiProg; //GetSoundFile()->ProcessMIDIMacro(trackChannel, false, GetSoundFile()->m_MidiCfg.szMidiGlb[MIDIOUT_PROGRAM], 0); - MidiSend((nMidiProg<<8)|(0xC0|nMidiCh)); + MidiSend((nMidiProg << 8) | ((MIDIEVENT_PROGRAMCHANGE << 4) | nMidiCh)); } // Specific Note Off if (note > NOTE_KEYOFF) //rewbs.vstiLive { - dwMidiCode = 0x80|nMidiCh; //note off, on chan nCh + dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh; //note off, on chan nCh note--; UINT i = note - NOTE_KEYOFF; if (channel.uNoteOnMap[i][trackChannel]) { channel.uNoteOnMap[i][trackChannel]--; - MidiSend(dwMidiCode|(i<<8)); + MidiSend(dwMidiCode | (i << 8)); } } @@ -2429,11 +2435,10 @@ // Also less likely to cause a VST event buffer overflow. else if (note == NOTE_NOTECUT) // ^^ { - //MidiSend(0xB0|nCh|(0x79<<8)); // reset all controllers - MidiSend(0xB0|nMidiCh|(0x7b<<8)); // all notes off - MidiSend(0xB0|nMidiCh|(0x78<<8)); // all sounds off + MidiSend((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh | (MIDICC_AllNotesOff << 8)); // all notes off + MidiSend((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh | (MIDICC_AllSoundOff << 8)); // all sounds off - dwMidiCode = 0x80|nMidiCh|(vol<<16); //note off, on chan nCh; vol is note off velocity. + dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh | (vol << 16); //note off, on chan nCh; vol is note off velocity. for (UINT i=0; i<128; i++) //all notes { channel.uNoteOnMap[i][trackChannel]=0; @@ -2444,17 +2449,17 @@ // All "active" notes off on this midi and tracker channel // using note mask. - else if (note > 0x80) // == + else if(note == NOTE_KEYOFF || note == NOTE_FADE) // ==, ~~ { - dwMidiCode = 0x80|nMidiCh|(vol<<16); //note off, on chan nCh; vol is note off velocity. + dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh | (vol << 16); //note off, on chan nCh; vol is note off velocity. - for (UINT i=0; i<128; i++) + for(UINT i = 0; i < 128; i++) { // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. // But this can cause a VST event overflow if we have many active notes... - while (channel.uNoteOnMap[i][trackChannel]) + while(channel.uNoteOnMap[i][trackChannel]) { - if (MidiSend(dwMidiCode|(i<<8))) + if(MidiSend(dwMidiCode | (i << 8))) { channel.uNoteOnMap[i][trackChannel]--; } else @@ -2468,14 +2473,14 @@ } // Note On - else if (note > 0) + else if(ModCommand::IsNote(note)) { - dwMidiCode = 0x90|nMidiCh; //note on, on chan nCh + dwMidiCode = (MIDIEVENT_NOTEON << 4) | nMidiCh; //note on, on chan nCh note--; //reset pitch bend on each new note, tracker style. - if (m_nMidiPitchBendPos[nMidiCh] != MIDI_PitchBend_Centre) + if(m_nMidiPitchBendPos[nMidiCh] != MIDI_PitchBend_Centre) { MidiPitchBend(nMidiCh, MIDI_PitchBend_Centre); } @@ -2490,7 +2495,7 @@ - MidiSend(dwMidiCode|(note<<8)|(vol<<16)); + MidiSend(dwMidiCode | (note << 8) | (vol << 16)); } m_nPreviousMidiChan = nMidiCh; Property changes on: trunk/OpenMPT/packageTemplate/Plugins ___________________________________________________________________ Added: tsvn:logminsize + 10 Property changes on: trunk/OpenMPT/packageTemplate/Plugins/MIDI ___________________________________________________________________ Added: tsvn:logminsize + 10 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-13 20:46:47
|
Revision: 1246 http://modplug.svn.sourceforge.net/modplug/?rev=1246&view=rev Author: saga-games Date: 2012-04-13 20:46:38 +0000 (Fri, 13 Apr 2012) Log Message: ----------- [Ref] Cleaned up a lot of MIDI related stuff. Modified Paths: -------------- trunk/OpenMPT/mptrack/MIDIMacroDialog.cpp trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp trunk/OpenMPT/mptrack/MIDIMappingDialog.h trunk/OpenMPT/mptrack/Mainfrm.h trunk/OpenMPT/mptrack/Mpt_midi.cpp trunk/OpenMPT/mptrack/View_ins.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/dlg_misc.cpp trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/MIDIMacros.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h Added Paths: ----------- trunk/OpenMPT/mptrack/MIDIMapping.cpp trunk/OpenMPT/mptrack/MIDIMapping.h trunk/OpenMPT/soundlib/MIDIEvents.cpp trunk/OpenMPT/soundlib/MIDIEvents.h Removed Paths: ------------- trunk/OpenMPT/soundlib/midi.h Modified: trunk/OpenMPT/mptrack/MIDIMacroDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/MIDIMacroDialog.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/MIDIMacroDialog.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -16,6 +16,7 @@ #include "Vstplug.h" #include "resource.h" #include "MIDIMacroDialog.h" +#include "../soundlib/MIDIEvents.h" BEGIN_MESSAGE_MAP(CMidiMacroSetup, CDialog) @@ -80,9 +81,9 @@ OnSFxChanged(); // MIDI CC selection box - for (int cc = MIDICC_start; cc <= MIDICC_end; cc++) + for (int cc = MIDIEvents::MIDICC_start; cc <= MIDIEvents::MIDICC_end; cc++) { - wsprintf(s, "CC %02d %s", cc, MidiCCNames[cc]); + wsprintf(s, "CC %02d %s", cc, MIDIEvents::MidiCCNames[cc]); m_CbnMacroCC.SetItemData(m_CbnMacroCC.AddString(s), cc); } Added: trunk/OpenMPT/mptrack/MIDIMapping.cpp =================================================================== --- trunk/OpenMPT/mptrack/MIDIMapping.cpp (rev 0) +++ trunk/OpenMPT/mptrack/MIDIMapping.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -0,0 +1,182 @@ +/* + * MIDIMapping.cpp + * --------------- + * Purpose: MIDI Mapping management classes + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "MIDIMapping.h" +#include "../soundlib/MIDIEvents.h" +#include "Mainfrm.h" + + +CString CMIDIMappingDirective::ToString() const +//--------------------------------------------- +{ + CString str; str.Preallocate(20); + char flags[4] = "000"; + if(m_Active) flags[0] = '1'; + if(m_CaptureMIDI) flags[1] = '1'; + if(m_AllowPatternEdit) flags[2] = '1'; + str.Format("%s:%d:%x:%d:%d:%d", flags, (int)GetChannel(), (int)GetEvent(), (int)GetController(), (int)m_PluginIndex, m_Parameter); + str.Trim(); + return str; +} + + +size_t CMIDIMapper::GetSerializationSize() const +//---------------------------------------------- +{ + size_t s = 0; + for(const_iterator citer = Begin(); citer != End(); citer++) + { + if(citer->GetParamIndex() <= uint8_max) {s += 5; continue;} + if(citer->GetParamIndex() <= uint16_max) {s += 6; continue;} + s += 8; + } + return s; +} + + +void CMIDIMapper::Serialize(FILE* f) const +//---------------------------------------- +{ + //Bytes: 1 Flags, 2 key, 1 plugindex, 1,2,4,8 plug/etc. + for(const_iterator citer = Begin(); citer != End(); citer++) + { + uint16 temp16 = (citer->GetChnEvent() << 1) + (citer->GetController() << 9); + if(citer->GetAnyChannel()) temp16 |= 1; + uint32 temp32 = citer->GetParamIndex(); + + uint8 temp8 = citer->IsActive(); //bit 0 + if(citer->GetCaptureMIDI()) temp8 |= (1 << 1); //bit 1 + //bits 2-4: Mapping type: 0 for plug param control. + //bit 5: + if(citer->GetAllowPatternEdit()) temp8 |= (1 << 5); + //bits 6-7: Size: 5, 6, 8, 12 + + BYTE parambytes = 4; + if(temp32 <= uint16_max) + { + if(temp32 <= uint8_max) parambytes = 1; + else {parambytes = 2; temp8 |= (1 << 6);} + } + else temp8 |= (2 << 6); + + fwrite(&temp8, 1, sizeof(temp8), f); + fwrite(&temp16, 1, sizeof(temp16), f); + temp8 = citer->GetPlugIndex(); + fwrite(&temp8, 1, sizeof(temp8), f); + fwrite(&temp32, 1, parambytes, f); + } +} + + +bool CMIDIMapper::Deserialize(const BYTE* ptr, const size_t size) +//--------------------------------------------------------------- +{ + m_Directives.clear(); + const BYTE* endptr = ptr + size; + while(ptr + 5 <= endptr) + { + uint8 i8 = 0; + uint16 i16 = 0; + uint32 i32 = 0; + memcpy(&i8, ptr, 1); ptr++; + BYTE psize = 0; + switch(i8 >> 6) + { + case 0: psize = 5; break; + case 1: psize = 6; break; + case 2: psize = 8; break; + case 3: default: psize = 12; break; + } + + if(ptr + psize - 1 > endptr) return true; + if(((i8 >> 2) & 7) != 0) {ptr += psize - 1; continue;} //Skipping unrecognised mapping types. + + CMIDIMappingDirective s; + s.SetActive((i8 & 1) != 0); + s.SetCaptureMIDI((i8 & (1 << 1)) != 0); + s.SetAllowPatternEdit((i8 & (1 << 5)) != 0); + memcpy(&i16, ptr, 2); ptr += 2; //Channel, event, MIDIbyte1. + memcpy(&i8, ptr, 1); ptr++; //Plugindex + const BYTE remainingbytes = psize - 4; + memcpy(&i32, ptr, min(4, remainingbytes)); ptr += remainingbytes; + + s.SetChannel(((i16 & 1) != 0) ? 0 : 1 + ((i16 >> 1) & 0xF)); + s.SetEvent(static_cast<BYTE>((i16 >> 5) & 0xF)); + s.SetController(i16 >> 9); + s.SetPlugIndex(i8); + s.SetParamIndex(i32); + AddDirective(s); + } + + return false; +} + + +bool CMIDIMapper::OnMIDImsg(const DWORD midimsg, BYTE& mappedIndex, uint32& paramindex, BYTE& paramval) +//----------------------------------------------------------------------------------------------------- +{ + bool captured = false; + + if(MIDIEvents::GetTypeFromEvent(midimsg) != MIDIEvents::evControllerChange) return captured; + //For now only controllers can be mapped so if event is not controller change, + //no mapping will be found and thus no search is done. + //NOTE: The event value is not checked in code below. + + const BYTE controller = MIDIEvents::GetDataByte1FromEvent(midimsg); + + const_iterator citer = std::lower_bound(Begin(), End(), controller); + + const BYTE channel = MIDIEvents::GetChannelFromEvent(midimsg); + + for(; citer != End() && citer->GetController() == controller && !captured; citer++) + { + if(!citer->IsActive()) continue; + BYTE plugindex = 0; + uint32 param = 0; + if( citer->GetAnyChannel() || channel+1 == citer->GetChannel()) + { + plugindex = citer->GetPlugIndex(); + param = citer->GetParamIndex(); + if(citer->GetAllowPatternEdit()) + { + mappedIndex = plugindex; + paramindex = param; + paramval = MIDIEvents::GetDataByte2FromEvent(midimsg); + } + if(citer->GetCaptureMIDI()) captured = true; + + if(plugindex > 0 && plugindex <= MAX_MIXPLUGINS) + { + IMixPlugin* pPlug = m_rSndFile.m_MixPlugins[plugindex-1].pMixPlugin; + if(!pPlug) continue; + pPlug->SetZxxParameter(param, (midimsg >> 16) & 0x7F); + CMainFrame::GetMainFrame()->ThreadSafeSetModified(m_rSndFile.GetpModDoc()); + } + } + } + + return captured; +} + + +bool CMIDIMapper::Swap(const size_t a, const size_t b) +//---------------------------------------------------- +{ + if(a < m_Directives.size() && b < m_Directives.size()) + { + CMIDIMappingDirective temp = m_Directives[a]; + m_Directives[a] = m_Directives[b]; + m_Directives[b] = temp; + Sort(); + return false; + } + else return true; +} Added: trunk/OpenMPT/mptrack/MIDIMapping.h =================================================================== --- trunk/OpenMPT/mptrack/MIDIMapping.h (rev 0) +++ trunk/OpenMPT/mptrack/MIDIMapping.h 2012-04-13 20:46:38 UTC (rev 1246) @@ -0,0 +1,125 @@ +/* + * MIDIMapping.h + * ------------- + * Purpose: MIDI Mapping management classes + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include <vector> +#include <algorithm> +using std::vector; + + +//========================= +class CMIDIMappingDirective +//========================= +{ +public: + CMIDIMappingDirective() : + m_Active(true), m_CaptureMIDI(false), m_AllowPatternEdit(true), m_AnyChannel(true), + m_ChnEvent(0xB << 4), m_MIDIByte1(0), m_PluginIndex(1), m_Parameter(0) {} + + void SetActive(const bool b) {m_Active = b;} + bool IsActive() const {return m_Active;} + + void SetCaptureMIDI(const bool b) {m_CaptureMIDI = b;} + bool GetCaptureMIDI() const {return m_CaptureMIDI;} + + void SetAllowPatternEdit(const bool b) {m_AllowPatternEdit = b;} + bool GetAllowPatternEdit() const {return m_AllowPatternEdit;} + + bool GetAnyChannel() const {return m_AnyChannel;} + + //Note: In these functions, channel value is in range [1,16], + //GetChannel() returns 0 on 'any channel'. + void SetChannel(const int c){if(c < 1 || c > 16) m_AnyChannel = true; else {m_ChnEvent &= ~0xF; m_ChnEvent |= c-1; m_AnyChannel = false;}} + BYTE GetChannel() const {return (m_AnyChannel) ? 0 : (m_ChnEvent & 0xF) + 1;} + + void SetEvent(BYTE e) {if(e > 15) e = 15; m_ChnEvent &= ~0xF0; m_ChnEvent |= (e << 4);} + BYTE GetEvent() const {return static_cast<BYTE>((m_ChnEvent >> 4) & 0xF);} + + void SetController(int controller) {if(controller > 127) controller = 127; m_MIDIByte1 = static_cast<BYTE>(controller);} + BYTE GetController() const {return m_MIDIByte1;} + + //Note: Plug index starts from 1. + void SetPlugIndex(const int i) {m_PluginIndex = static_cast<BYTE>(i);} + BYTE GetPlugIndex() const {return m_PluginIndex;} + + void SetParamIndex(const int i) {m_Parameter = i;} + uint32 GetParamIndex() const {return m_Parameter;} + + bool IsDefault() const {return *this == CMIDIMappingDirective();} + + bool operator==(const CMIDIMappingDirective& d) const {return memcmp(this, &d, sizeof(CMIDIMappingDirective)) == 0;} + + CString ToString() const; + + BYTE GetChnEvent() const {return m_ChnEvent;} + +private: + bool m_Active; + bool m_CaptureMIDI; //When true, MIDI data should not be processed beyond this directive + bool m_AllowPatternEdit; //When true, the mapping can be used for modifying pattern. + bool m_AnyChannel; + uint8 m_ChnEvent; //0-3 channel, 4-7 event + BYTE m_MIDIByte1; + BYTE m_PluginIndex; + uint32 m_Parameter; +}; + +class CSoundFile; +inline bool operator<(const CMIDIMappingDirective& a, const CMIDIMappingDirective& b) {return a.GetController() < b.GetController();} +inline bool operator<(const CMIDIMappingDirective& d, const BYTE& ctrlVal) {return d.GetController() < ctrlVal;} +inline bool operator<(const BYTE& ctrlVal, const CMIDIMappingDirective& d) {return ctrlVal < d.GetController();} + +//=============== +class CMIDIMapper +//=============== +{ +public: + typedef vector<CMIDIMappingDirective>::const_iterator const_iterator; + CMIDIMapper(CSoundFile& sndfile) : m_rSndFile(sndfile) {} + + //If mapping found: + // -mappedIndex is set to mapped value(plug index) + // -paramindex to mapped parameter + // -paramvalue to parameter value. + //In case of multiple mappings, these get the values from the last mapping found. + //Returns true if MIDI was 'captured' by some directive, false otherwise. + bool OnMIDImsg(const DWORD midimsg, BYTE& mappedIndex, uint32& paramindex, BYTE& paramvalue); + + //Swaps the positions of two elements. Returns true if swap was not done. + bool Swap(const size_t a, const size_t b); + + //Return the index after sorting for the added element + size_t SetDirective(const size_t i, const CMIDIMappingDirective& d) {m_Directives[i] = d; Sort(); return std::find(m_Directives.begin(), m_Directives.end(), d) - m_Directives.begin();} + + //Return the index after sorting for the added element + size_t AddDirective(const CMIDIMappingDirective& d) {m_Directives.push_back(d); Sort(); return std::find(m_Directives.begin(), m_Directives.end(), d) - m_Directives.begin();} + + void RemoveDirective(const size_t i) {m_Directives.erase(m_Directives.begin()+i);} + + const CMIDIMappingDirective& GetDirective(const size_t i) const {return m_Directives[i];} + + const_iterator Begin() const {return m_Directives.begin();} + const_iterator End() const {return m_Directives.end();} + size_t GetCount() const {return m_Directives.size();} + + size_t GetSerializationSize() const; + void Serialize(FILE* f) const; + bool Deserialize(const BYTE* ptr, const size_t size); //Return false if succesful, true otherwise. + + bool AreOrderEqual(const size_t a, const size_t b) {return !(m_Directives[a] < m_Directives[b] || m_Directives[b] < m_Directives[a]);} + +private: + void Sort() {std::stable_sort(m_Directives.begin(), m_Directives.end());} + +private: + CSoundFile& m_rSndFile; + vector<CMIDIMappingDirective> m_Directives; +}; Modified: trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/MIDIMappingDialog.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -11,7 +11,7 @@ #include "stdafx.h" #include "mptrack.h" #include "MIDIMappingDialog.h" -#include "midi.h" +#include "../soundlib/MIDIEvents.h" #include "mainfrm.h" @@ -66,12 +66,12 @@ LRESULT CMIDIMappingDialog::OnMidiMsg(WPARAM dwMidiDataParam, LPARAM) //------------------------------------------------------------------- { - const BYTE event = GetFromMIDIMsg_Event(dwMidiDataParam); + const BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiDataParam); if(event == 0xB && IsDlgButtonChecked(IDC_CHECK_MIDILEARN)) { - m_ChannelCBox.SetCurSel(1+GetFromMIDIMsg_Channel(dwMidiDataParam)); + m_ChannelCBox.SetCurSel(1 + MIDIEvents::GetChannelFromEvent(dwMidiDataParam)); m_EventCBox.SetCurSel(0); - m_ControllerCBox.SetCurSel(GetFromMIDIMsg_DataByte1(dwMidiDataParam)); + m_ControllerCBox.SetCurSel(MIDIEvents::GetDataByte1FromEvent(dwMidiDataParam)); OnCbnSelchangeComboChannel(); OnCbnSelchangeComboEvent(); OnCbnSelchangeComboController(); @@ -89,10 +89,10 @@ m_EventCBox.SetCurSel(0); //Add controller names. - for(size_t i = MIDICC_start; i<=MIDICC_end; i++) + for(size_t i = MIDIEvents::MIDICC_start; i <= MIDIEvents::MIDICC_end; i++) { CString temp; - temp.Format("%3d %s", i, MidiCCNames[i]); + temp.Format("%3d %s", i, MIDIEvents::MidiCCNames[i]); m_ControllerCBox.AddString(temp); } @@ -147,7 +147,7 @@ m_ChannelCBox.SetCurSel(activeSetting.GetChannel()); - if(m_Setting.GetEvent() == MIDIEVENT_CONTROLLERCHANGE) + if(m_Setting.GetEvent() == MIDIEvents::evControllerChange) m_EventCBox.SetCurSel(0); else m_EventCBox.SetCurSel(-1); @@ -328,10 +328,10 @@ str.AppendChar('.'); //Controller name - if(s.GetController() <= MIDICC_end) + if(s.GetController() <= MIDIEvents::MIDICC_end) { CString tstr; - tstr.Format("%d %s", s.GetController(), MidiCCNames[s.GetController()]); + tstr.Format("%d %s", s.GetController(), MIDIEvents::MidiCCNames[s.GetController()]); str.Insert(20, tstr); } Modified: trunk/OpenMPT/mptrack/MIDIMappingDialog.h =================================================================== --- trunk/OpenMPT/mptrack/MIDIMappingDialog.h 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/MIDIMappingDialog.h 2012-04-13 20:46:38 UTC (rev 1246) @@ -10,7 +10,6 @@ #pragma once #include "moddoc.h" -#include "midi.h" #include <vector> #include "afxwin.h" #include "afxcmn.h" Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2012-04-13 20:46:38 UTC (rev 1246) @@ -488,6 +488,8 @@ void SetMidiRecordWnd(HWND hwnd) { m_hWndMidi = hwnd; } HWND GetMidiRecordWnd() const { return m_hWndMidi; } + static int ApplyVolumeRelatedSettings(const DWORD &dwParam1, const BYTE midivolume); + // static functions public: static CMainFrame *GetMainFrame() { return (CMainFrame *)theApp.m_pMainWnd; } Modified: trunk/OpenMPT/mptrack/Mpt_midi.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpt_midi.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/Mpt_midi.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -10,11 +10,9 @@ #include "stdafx.h" #include <mmsystem.h> -#include "mptrack.h" #include "mainfrm.h" -#include "moddoc.h" #include "dlsbank.h" -#include "midi.h" +#include "../soundlib/MIDIEvents.h" #include "Moptions.h" // for OPTIONS_PAGE_MIDI //#define MPTMIDI_RECORDLOG @@ -24,10 +22,10 @@ //Get Midi message(dwParam1), apply MIDI settings having effect on volume, and return //the volume value [0, 256]. In addition value -1 is used as 'use default value'-indicator. -int ApplyVolumeRelatedMidiSettings(const DWORD &dwParam1, const BYTE midivolume) -//------------------------------------------------------------------------------ +int CMainFrame::ApplyVolumeRelatedSettings(const DWORD &dwParam1, const BYTE midivolume) +//-------------------------------------------------------------------------------------- { - int nVol = GetFromMIDIMsg_DataByte2(dwParam1); + int nVol = MIDIEvents::GetDataByte2FromEvent(dwParam1); if (CMainFrame::GetSettings().m_dwMidiSetup & MIDISETUP_RECORDVELOCITY) { nVol = (CDLSBank::DLSMidiVolumeToLinear(nVol)+255) >> 8; @@ -51,12 +49,12 @@ //----------------------------------------------------------------------- { if ( (CMainFrame::GetSettings().m_dwMidiSetup & MIDISETUP_TRANSPOSEKEYBOARD) - && (GetFromMIDIMsg_Channel(dwParam1) != 9) ) + && (MIDIEvents::GetChannelFromEvent(dwParam1) != 9) ) { int nTranspose = rMainFrm.GetBaseOctave() - 4; if (nTranspose) { - int note = GetFromMIDIMsg_DataByte1(dwParam1); + int note = MIDIEvents::GetDataByte1FromEvent(dwParam1); if (note < 0x80) { note += nTranspose * 12; @@ -94,9 +92,9 @@ hWndMidi = pMainFrm->GetMidiRecordWnd(); if ((hWndMidi) && ((wMsg == MIM_DATA) || (wMsg == MIM_MOREDATA))) { - switch (dwParam1 & 0xF0) + switch(MIDIEvents::GetTypeFromEvent(dwParam1)) { - case 0xF0: // Midi Clock + case MIDIEvents::evSystem: // Midi Clock if (wMsg == MIM_DATA) { DWORD dwTime = timeGetTime(); @@ -107,8 +105,8 @@ } else break; - case 0x80: // Note Off - case 0x90: // Note On + case MIDIEvents::evNoteOff: // Note Off + case MIDIEvents::evNoteOn: // Note On ApplyTransposeKeyboardSetting(*pMainFrm, dwParam1); default: @@ -170,175 +168,3 @@ { if (pCmdUI) pCmdUI->SetCheck((shMidiIn) ? TRUE : FALSE); } - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- - - -CString CMIDIMappingDirective::ToString() const -//--------------------------------------------- -{ - CString str; str.Preallocate(20); - char flags[4] = "000"; - if(m_Active) flags[0] = '1'; - if(m_CaptureMIDI) flags[1] = '1'; - if(m_AllowPatternEdit) flags[2] = '1'; - str.Format("%s:%d:%x:%d:%d:%d", flags, (int)GetChannel(), (int)GetEvent(), (int)GetController(), (int)m_PluginIndex, m_Parameter); - str.Trim(); - return str; -} - - -size_t CMIDIMapper::GetSerializationSize() const -//---------------------------------------------- -{ - size_t s = 0; - for(const_iterator citer = Begin(); citer != End(); citer++) - { - if(citer->GetParamIndex() <= uint8_max) {s += 5; continue;} - if(citer->GetParamIndex() <= uint16_max) {s += 6; continue;} - s += 8; - } - return s; -} - - -void CMIDIMapper::Serialize(FILE* f) const -//---------------------------------------- -{ - //Bytes: 1 Flags, 2 key, 1 plugindex, 1,2,4,8 plug/etc. - for(const_iterator citer = Begin(); citer != End(); citer++) - { - uint16 temp16 = (citer->GetChnEvent() << 1) + (citer->GetController() << 9); - if(citer->GetAnyChannel()) temp16 |= 1; - uint32 temp32 = citer->GetParamIndex(); - - uint8 temp8 = citer->IsActive(); //bit 0 - if(citer->GetCaptureMIDI()) temp8 |= (1 << 1); //bit 1 - //bits 2-4: Mapping type: 0 for plug param control. - //bit 5: - if(citer->GetAllowPatternEdit()) temp8 |= (1 << 5); - //bits 6-7: Size: 5, 6, 8, 12 - - BYTE parambytes = 4; - if(temp32 <= uint16_max) - { - if(temp32 <= uint8_max) parambytes = 1; - else {parambytes = 2; temp8 |= (1 << 6);} - } - else temp8 |= (2 << 6); - - fwrite(&temp8, 1, sizeof(temp8), f); - fwrite(&temp16, 1, sizeof(temp16), f); - temp8 = citer->GetPlugIndex(); - fwrite(&temp8, 1, sizeof(temp8), f); - fwrite(&temp32, 1, parambytes, f); - } -} - - -bool CMIDIMapper::Deserialize(const BYTE* ptr, const size_t size) -//--------------------------------------------------------------- -{ - m_Directives.clear(); - const BYTE* endptr = ptr + size; - while(ptr + 5 <= endptr) - { - uint8 i8 = 0; - uint16 i16 = 0; - uint32 i32 = 0; - memcpy(&i8, ptr, 1); ptr++; - BYTE psize = 0; - switch(i8 >> 6) - { - case 0: psize = 5; break; - case 1: psize = 6; break; - case 2: psize = 8; break; - case 3: default: psize = 12; break; - } - - if(ptr + psize - 1 > endptr) return true; - if(((i8 >> 2) & 7) != 0) {ptr += psize - 1; continue;} //Skipping unrecognised mapping types. - - CMIDIMappingDirective s; - s.SetActive((i8 & 1) != 0); - s.SetCaptureMIDI((i8 & (1 << 1)) != 0); - s.SetAllowPatternEdit((i8 & (1 << 5)) != 0); - memcpy(&i16, ptr, 2); ptr += 2; //Channel, event, MIDIbyte1. - memcpy(&i8, ptr, 1); ptr++; //Plugindex - const BYTE remainingbytes = psize - 4; - memcpy(&i32, ptr, min(4, remainingbytes)); ptr += remainingbytes; - - s.SetChannel(((i16 & 1) != 0) ? 0 : 1 + ((i16 >> 1) & 0xF)); - s.SetEvent(static_cast<BYTE>((i16 >> 5) & 0xF)); - s.SetController(i16 >> 9); - s.SetPlugIndex(i8); - s.SetParamIndex(i32); - AddDirective(s); - } - - return false; -} - - -bool CMIDIMapper::OnMIDImsg(const DWORD midimsg, BYTE& mappedIndex, uint32& paramindex, BYTE& paramval) -//----------------------------------------------------------------------------------------------------- -{ - bool captured = false; - - if(GetFromMIDIMsg_Event(midimsg) != MIDIEVENT_CONTROLLERCHANGE) return captured; - //For now only controllers can be mapped so if event is not controller change, - //no mapping will be found and thus no search is done. - //NOTE: The event value is not checked in code below. - - const BYTE controller = GetFromMIDIMsg_DataByte1(midimsg); - - const_iterator citer = std::lower_bound(Begin(), End(), controller); - - const BYTE channel = GetFromMIDIMsg_Channel(midimsg); - - for(; citer != End() && citer->GetController() == controller && !captured; citer++) - { - if(!citer->IsActive()) continue; - BYTE plugindex = 0; - uint32 param = 0; - if( citer->GetAnyChannel() || channel+1 == citer->GetChannel()) - { - plugindex = citer->GetPlugIndex(); - param = citer->GetParamIndex(); - if(citer->GetAllowPatternEdit()) - { - mappedIndex = plugindex; - paramindex = param; - paramval = GetFromMIDIMsg_DataByte2(midimsg); - } - if(citer->GetCaptureMIDI()) captured = true; - - if(plugindex > 0 && plugindex <= MAX_MIXPLUGINS) - { - IMixPlugin* pPlug = m_rSndFile.m_MixPlugins[plugindex-1].pMixPlugin; - if(!pPlug) continue; - pPlug->SetZxxParameter(param, (midimsg >> 16) & 0x7F); - CMainFrame::GetMainFrame()->ThreadSafeSetModified(m_rSndFile.GetpModDoc()); - } - } - } - - return captured; -} - - -bool CMIDIMapper::Swap(const size_t a, const size_t b) -//---------------------------------------------------- -{ - if(a < m_Directives.size() && b < m_Directives.size()) - { - CMIDIMappingDirective temp = m_Directives[a]; - m_Directives[a] = m_Directives[b]; - m_Directives[b] = temp; - Sort(); - return false; - } - else return true; -} Modified: trunk/OpenMPT/mptrack/View_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_ins.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/View_ins.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -20,8 +20,8 @@ #include "dlsbank.h" #include "channelManagerDlg.h" #include "ScaleEnvPointsDlg.h" -#include ".\view_ins.h" -#include "midi.h" +#include "view_ins.h" +#include "../soundlib/MIDIEvents.h" #define ENV_ZOOM 4.0f #define ENV_MIN_ZOOM 2.0f @@ -2152,15 +2152,15 @@ static BYTE midivolume = 127; CModDoc *pModDoc = GetDocument(); - BYTE midiByte1 = GetFromMIDIMsg_DataByte1(dwMidiData); - BYTE midiByte2 = GetFromMIDIMsg_DataByte2(dwMidiData); + BYTE midiByte1 = MIDIEvents::GetDataByte1FromEvent(dwMidiData); + BYTE midiByte2 = MIDIEvents::GetDataByte2FromEvent(dwMidiData); CSoundFile* pSndFile = (pModDoc) ? pModDoc->GetSoundFile() : NULL; if (!pSndFile) return 0; const BYTE nNote = midiByte1 + 1; // +1 is for MPT, where middle C is 61 int nVol = midiByte2; - BYTE event = GetFromMIDIMsg_Event(dwMidiData); + BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiData); if ((event == 0x9) && !nVol) event = 0x8; //Convert event to note-off if req'd BYTE mappedIndex = 0, paramValue = 0; @@ -2170,42 +2170,42 @@ switch(event) { - case MIDIEVENT_NOTEOFF: // Note Off - midiByte2 = 0; + case MIDIEvents::evNoteOff: // Note Off + midiByte2 = 0; - case MIDIEVENT_NOTEON: // Note On - pModDoc->NoteOff(nNote, false, m_nInstrument); - if (midiByte2 & 0x7F) - { - nVol = ApplyVolumeRelatedMidiSettings(dwMidiData, midivolume); - pModDoc->PlayNote(nNote, m_nInstrument, 0, false, nVol); - } + case MIDIEvents::evNoteOn: // Note On + pModDoc->NoteOff(nNote, false, m_nInstrument); + if (midiByte2 & 0x7F) + { + nVol = CMainFrame::ApplyVolumeRelatedSettings(dwMidiData, midivolume); + pModDoc->PlayNote(nNote, m_nInstrument, 0, false, nVol); + } break; - case MIDIEVENT_CONTROLLERCHANGE: //Controller change - switch(midiByte1) - { - case 0x7: //Volume - midivolume = midiByte2; - break; - } + case MIDIEvents::evControllerChange: //Controller change + switch(midiByte1) + { + case MIDIEvents::MIDICC_Volume_Coarse: //Volume + midivolume = midiByte2; + break; + } - default: - if((CMainFrame::GetSettings().m_dwMidiSetup & MIDISETUP_MIDITOPLUG) && CMainFrame::GetMainFrame()->GetModPlaying() == pModDoc) + default: + if((CMainFrame::GetSettings().m_dwMidiSetup & MIDISETUP_MIDITOPLUG) && CMainFrame::GetMainFrame()->GetModPlaying() == pModDoc) + { + const INSTRUMENTINDEX instr = m_nInstrument; + IMixPlugin* plug = pSndFile->GetInstrumentPlugin(instr); + if(plug) { - const INSTRUMENTINDEX instr = m_nInstrument; - IMixPlugin* plug = pSndFile->GetInstrumentPlugin(instr); - if(plug) + plug->MidiSend(dwMidiData); + // Sending midi may modify the plug. For now, if MIDI data + // is not active sensing or aftertouch messages, set modified. + if(dwMidiData != MIDIEvents::BuildSystemEvent(MIDIEvents::sysActiveSense) && event != MIDIEvents::evPolyAftertouch && event != MIDIEvents::evChannelAftertouch) { - plug->MidiSend(dwMidiData); - // Sending midi may modify the plug. For now, if MIDI data - // is not active sensing or aftertouch messages, set modified. - if(dwMidiData != MIDISTATUS_ACTIVESENSING && event != MIDIEVENT_POLYAFTERTOUCH && event != MIDIEVENT_CHANAFTERTOUCH) - { - CMainFrame::GetMainFrame()->ThreadSafeSetModified(pModDoc); - } + CMainFrame::GetMainFrame()->ThreadSafeSetModified(pModDoc); } } + } break; } Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -29,7 +29,7 @@ #include "View_gen.h" #include "MIDIMacros.h" #include "../common/misc_util.h" -#include "midi.h" +#include "../soundlib/MIDIEvents.h" #include <cmath> #define PLUGNAME_HEIGHT 16 //rewbs.patPlugName @@ -3535,7 +3535,7 @@ // +---------------------------+---------------------------+-------------+-------------+ // | Velocity (0-127) | Note (middle C is 60) | Event | Channel | // +---------------------------+---------------------------+-------------+-------------+ -//(http://www.borg.com/~jglatt/tech/midispec.htm) +//(http://home.roadrunner.com/~jgglatt/tech/midispec.htm) //Notes: //. Initial midi data handling is done in MidiInCallBack(). @@ -3546,15 +3546,15 @@ // BYTE event = (dwMidiData>>16) & 0x64; //. Sample- and instrumentview handle midi mesages in their own methods. - const BYTE nByte1 = GetFromMIDIMsg_DataByte1(dwMidiData); - const BYTE nByte2 = GetFromMIDIMsg_DataByte2(dwMidiData); + const BYTE nByte1 = MIDIEvents::GetDataByte1FromEvent(dwMidiData); + const BYTE nByte2 = MIDIEvents::GetDataByte2FromEvent(dwMidiData); const BYTE nNote = nByte1 + 1; // +1 is for MPT, where middle C is 61 int nVol = nByte2; // At this stage nVol is a non linear value in [0;127] // Need to convert to linear in [0;64] - see below - BYTE event = GetFromMIDIMsg_Event(dwMidiData); + BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiData); - if ((event == MIDIEVENT_NOTEON) && !nVol) event = MIDIEVENT_NOTEOFF; //Convert event to note-off if req'd + if ((event == MIDIEvents::evNoteOn) && !nVol) event = MIDIEvents::evNoteOff; //Convert event to note-off if req'd // Handle MIDI mapping. @@ -3581,15 +3581,15 @@ switch(event) { - case MIDIEVENT_NOTEOFF: // Note Off + case MIDIEvents::evNoteOff: // Note Off // The following method takes care of: // . Silencing specific active notes (just setting nNote to 255 as was done before is not acceptible) // . Entering a note off in pattern if required TempStopNote(nNote, ((CMainFrame::GetSettings().m_dwMidiSetup & MIDISETUP_RECORDNOTEOFF) != 0)); break; - case MIDIEVENT_NOTEON: // Note On - nVol = ApplyVolumeRelatedMidiSettings(dwMidiData, midivolume); + case MIDIEvents::evNoteOn: // Note On + nVol = CMainFrame::ApplyVolumeRelatedSettings(dwMidiData, midivolume); if(nVol < 0) nVol = -1; else nVol = (nVol + 3) / 4; //Value from [0,256] to [0,64] TempEnterNote(nNote, true, nVol); @@ -3600,14 +3600,14 @@ break; - case MIDIEVENT_POLYAFTERTOUCH: - case MIDIEVENT_CHANAFTERTOUCH: + case MIDIEvents::evPolyAftertouch: + case MIDIEvents::evChannelAftertouch: break; - case MIDIEVENT_CONTROLLERCHANGE: //Controller change + case MIDIEvents::evControllerChange: //Controller change switch(nByte1) { - case MIDICC_Volume_Coarse: //Volume + case MIDIEvents::MIDICC_Volume_Coarse: //Volume midivolume = nByte2; break; } @@ -3666,7 +3666,7 @@ plug->MidiSend(dwMidiData); // Sending midi may modify the plug. For now, if MIDI data // is not active sensing, set modified. - if(dwMidiData != MIDISTATUS_ACTIVESENSING) + if(dwMidiData != MIDIEvents::BuildSystemEvent(MIDIEvents::sysActiveSense)) pMainFrm->ThreadSafeSetModified(pModDoc); } Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -19,7 +19,7 @@ #include "dlsbank.h" #include "channelManagerDlg.h" #include "view_smp.h" -#include "midi.h" +#include "../soundlib/MIDIEvents.h" #include "SampleEditorDialogs.h" #include "modsmp_ctrl.h" #include "Wav.h" @@ -2568,39 +2568,39 @@ static BYTE midivolume = 127; CModDoc *pModDoc = GetDocument(); - BYTE midibyte1 = GetFromMIDIMsg_DataByte1(dwMidiData); - BYTE midibyte2 = GetFromMIDIMsg_DataByte2(dwMidiData); + BYTE midibyte1 = MIDIEvents::GetDataByte1FromEvent(dwMidiData); + BYTE midibyte2 = MIDIEvents::GetDataByte2FromEvent(dwMidiData); CSoundFile* pSndFile = (pModDoc) ? pModDoc->GetSoundFile() : NULL; if (!pSndFile) return 0; const BYTE nNote = midibyte1 + 1; // +1 is for MPT, where middle C is 61 int nVol = midibyte2; - BYTE event = GetFromMIDIMsg_Event(dwMidiData); - if ((event == 0x9) && !nVol) event = 0x8; //Convert event to note-off if req'd + BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiData); + if ((event == MIDIEvents::evNoteOn) && !nVol) event = MIDIEvents::evNoteOff; //Convert event to note-off if req'd switch(event) { - case 0x8: // Note Off - midibyte2 = 0; + case MIDIEvents::evNoteOff: // Note Off + midibyte2 = 0; - case 0x9: // Note On - pModDoc->NoteOff(nNote, true); - if (midibyte2 & 0x7F) - { - nVol = ApplyVolumeRelatedMidiSettings(dwMidiData, midivolume); - //pModDoc->PlayNote(nNote, 0, m_nSample, FALSE, nVol); - PlayNote(nNote); - } + case MIDIEvents::evNoteOn: // Note On + pModDoc->NoteOff(nNote, true); + if(midibyte2 & 0x7F) + { + nVol = CMainFrame::ApplyVolumeRelatedSettings(dwMidiData, midivolume); + //pModDoc->PlayNote(nNote, 0, m_nSample, FALSE, nVol); + PlayNote(nNote); + } break; - case 0xB: //Controller change - switch(midibyte1) - { - case 0x7: //Volume - midivolume = midibyte2; - break; - } + case MIDIEvents::evControllerChange: //Controller change + switch(midibyte1) + { + case MIDIEvents::MIDICC_Volume_Coarse: //Volume + midivolume = midibyte2; + break; + } break; } Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -22,7 +22,7 @@ #include "AbstractVstEditor.h" //rewbs.defaultPlugGUI #include "VstEditor.h" //rewbs.defaultPlugGUI #include "defaultvsteditor.h" //rewbs.defaultPlugGUI -#include "midi.h" +#include "../soundlib/MIDIEvents.h" #include "version.h" #include "midimappingdialog.h" #include "../common/StringFixer.h" @@ -1321,7 +1321,7 @@ for (int ch=0; ch<16; ch++) { - m_nMidiPitchBendPos[ch]=MIDI_PitchBend_Centre; //centre pitch bend on all channels + m_nMidiPitchBendPos[ch] = MIDIEvents::pitchBendCentre; //centre pitch bend on all channels } } @@ -1949,7 +1949,7 @@ } -// Send events to plugin +// Send events to plugin. Returns true if there are events left to be processed. void CVstPlugin::ProcessVSTEvents() //--------------------------------- { @@ -2244,7 +2244,7 @@ //----------------------------------------- { // Note-Offs go at the start of the queue. - bool insertAtFront = ((dwMidiCode & 0xF0) == 0x80); + bool insertAtFront = (MIDIEvents::GetTypeFromEvent(dwMidiCode) == MIDIEvents::evNoteOff); VstMidiEvent event; event.type = kVstMidiType; @@ -2270,7 +2270,6 @@ void CVstPlugin::HardAllNotesOff() //-------------------------------- { - bool overflow; float in[2][SCRATCH_BUFFER_SIZE], out[2][SCRATCH_BUFFER_SIZE]; // scratch buffers // The JUCE framework doesn't like processing while being suspended. @@ -2280,40 +2279,33 @@ Resume(); } - do + for(int mc = 0; mc < 16; mc++) //all midi chans { - overflow=false; - for (int mc=0; mc<16; mc++) //all midi chans - { - DWORD dwMidiCode = 0x80 | (mc & 0x0f); //command|channel|velocity - VSTInstrChannel &channel = m_MidiCh[mc]; + VSTInstrChannel &channel = m_MidiCh[mc]; - MidiPitchBend(mc, MIDI_PitchBend_Centre); // centre pitch bend - MidiSend(0xB0|mc|(0x79<<8)); // reset all controllers - MidiSend(0xB0|mc|(0x7b<<8)); // all notes off - MidiSend(0xB0|mc|(0x78<<8)); // all sounds off + MidiPitchBend(mc, MIDIEvents::pitchBendCentre); // centre pitch bend + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllControllersOff, mc, 0)); // reset all controllers + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllNotesOff, mc, 0)); // all notes off + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllSoundOff, mc, 0)); // all sounds off - for (size_t i = 0; i < CountOf(channel.uNoteOnMap); i++) //all notes + for (size_t i = 0; i < CountOf(channel.uNoteOnMap); i++) //all notes + { + for (CHANNELINDEX c = 0; c < CountOf(channel.uNoteOnMap[i]); c++) { - for (CHANNELINDEX c = 0; c < CountOf(channel.uNoteOnMap[i]); c++) + while(channel.uNoteOnMap[i][c]) { - while (channel.uNoteOnMap[i][c] && !overflow) - { - overflow=!(MidiSend(dwMidiCode | (i << 8))); - channel.uNoteOnMap[i][c]--; - } - if (overflow) break; //yuck + MidiSend(MIDIEvents::BuildNoteOffEvent(mc, i, 0)); + channel.uNoteOnMap[i][c]--; } - if (overflow) break; //yuck } - if (overflow) break; //yuck } - // let plug process events + } + // let plug process events + while(vstEvents.GetNumQueuedEvents() > 0) + { Process((float*)in, (float*)out, SCRATCH_BUFFER_SIZE); + } - // If we had hit an overflow, we need to loop around and start again. - } while (overflow); - if(wasSuspended) { Suspend(); @@ -2330,38 +2322,19 @@ LimitMax(nParam, 127u); if(m_pSndFile && m_pSndFile->GetModFlag(MSF_MIDICC_BUGEMULATION)) - MidiSend((nController << 16) | (nParam << 8) | (0xB0 | nMidiCh)); + MidiSend(MIDIEvents::BuildEvent(MIDIEvents::evControllerChange, nMidiCh, nParam, nController)); // param and controller are swapped (old broken implementation) else - MidiSend((nParam << 16) | (nController << 8) | (0xB0 | nMidiCh)); + MidiSend(MIDIEvents::BuildCCEvent(static_cast<MIDIEvents::MidiCC>(nController), nMidiCh, nParam)); } -short CVstPlugin::getMIDI14bitValueFromShort(short value) -//------------------------------------------------------- -{ - //http://www.srm.com/qtma/davidsmidispec.html: - // The two bytes of the pitch bend message form a 14 bit number, 0 to 16383. - // The value 8192 (sent, LSB first, as 0x00 0x40), is centered, or "no pitch bend." - // The value 0 (0x00 0x00) means, "bend as low as possible," and, - // similarly, 16383 (0x7F 0x7F) is to "bend as high as possible." - // The exact range of the pitch bend is specific to the synthesizer. - ASSERT(0 <= value && value <= 16383); - - BYTE byte1 = static_cast<BYTE>(value >> 7); // get last 7 bits only - BYTE byte2 = static_cast<BYTE>(value & 0x7F); // get first 7 bits only - short converted = (byte1 << 8) | byte2; // merge - - return converted; - -} - // Bend midi pitch for given midi channel using tracker param (0x00-0xFF) void CVstPlugin::MidiPitchBend(UINT nMidiCh, int nParam, UINT /*trackChannel*/) //----------------------------------------------------------------------------- { const int16 increment = static_cast<int16>(nParam * 0x2000 / 0xFF); int16 newPitchBendPos = m_nMidiPitchBendPos[nMidiCh] + increment; - Limit(newPitchBendPos, int16(MIDI_PitchBend_Min), int16(MIDI_PitchBend_Max)); + Limit(newPitchBendPos, int16(MIDIEvents::pitchBendMin), int16(MIDIEvents::pitchBendMax)); MidiPitchBend(nMidiCh, newPitchBendPos); } @@ -2370,9 +2343,9 @@ void CVstPlugin::MidiPitchBend(UINT nMidiCh, short newPitchBendPos) //----------------------------------------------------------------- { - m_nMidiPitchBendPos[nMidiCh] = newPitchBendPos; //store pitch bend position - short converted = getMIDI14bitValueFromShort(newPitchBendPos); - MidiSend(converted << 8 | MIDI_PitchBend_Command | nMidiCh); + ASSERT(MIDIEvents::pitchBendMin <= newPitchBendPos && newPitchBendPos <= MIDIEvents::pitchBendMax); + m_nMidiPitchBendPos[nMidiCh] = newPitchBendPos; + MidiSend(MIDIEvents::BuildPitchBendEvent(nMidiCh, newPitchBendPos)); } @@ -2381,7 +2354,7 @@ //---------------------------------------------------------------------------------------------------------------- { VSTInstrChannel &channel = m_MidiCh[nMidiCh]; - DWORD dwMidiCode = 0; + bool bankChanged = (channel.wMidiBank != --wMidiBank) && (wMidiBank < 0x4000); bool progChanged = (channel.nProgram != --nMidiProg) && (nMidiProg < 0x80); //get vol in [0,128[ @@ -2396,11 +2369,11 @@ if((channel.wMidiBank >> 7) != high) { // High byte changed - MidiSend(((high << 16) | (MIDICC_BankSelect_Coarse << 8)) | ((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh)); + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_BankSelect_Coarse, nMidiCh, high)); } // Low byte //GetSoundFile()->ProcessMIDIMacro(trackChannel, false, GetSoundFile()->m_MidiCfg.szMidiGlb[MIDIOUT_BANKSEL], 0); - MidiSend((low << 16) | (MIDICC_BankSelect_Fine << 8) | ((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh)); + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_BankSelect_Fine, nMidiCh, low)); channel.wMidiBank = wMidiBank; } @@ -2412,21 +2385,19 @@ { channel.nProgram = nMidiProg; //GetSoundFile()->ProcessMIDIMacro(trackChannel, false, GetSoundFile()->m_MidiCfg.szMidiGlb[MIDIOUT_PROGRAM], 0); - MidiSend((nMidiProg << 8) | ((MIDIEVENT_PROGRAMCHANGE << 4) | nMidiCh)); + MidiSend(MIDIEvents::BuildProgramChangeEvent(nMidiCh, nMidiProg)); } // Specific Note Off if (note > NOTE_KEYOFF) //rewbs.vstiLive { - dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh; //note off, on chan nCh - note--; UINT i = note - NOTE_KEYOFF; - if (channel.uNoteOnMap[i][trackChannel]) + if(channel.uNoteOnMap[i][trackChannel]) { channel.uNoteOnMap[i][trackChannel]--; - MidiSend(dwMidiCode | (i << 8)); + MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, 0)); } } @@ -2435,14 +2406,14 @@ // Also less likely to cause a VST event buffer overflow. else if (note == NOTE_NOTECUT) // ^^ { - MidiSend((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh | (MIDICC_AllNotesOff << 8)); // all notes off - MidiSend((MIDIEVENT_CONTROLLERCHANGE << 4) | nMidiCh | (MIDICC_AllSoundOff << 8)); // all sounds off + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllNotesOff, nMidiCh, 0)); + MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllSoundOff, nMidiCh, 0)); - dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh | (vol << 16); //note off, on chan nCh; vol is note off velocity. - for (UINT i=0; i<128; i++) //all notes + // Turn off all notes + for(uint8 i = 0; i < 128; i++) { - channel.uNoteOnMap[i][trackChannel]=0; - MidiSend(dwMidiCode|(i<<8)); + channel.uNoteOnMap[i][trackChannel] = 0; + MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, vol)); } } @@ -2451,15 +2422,12 @@ // using note mask. else if(note == NOTE_KEYOFF || note == NOTE_FADE) // ==, ~~ { - dwMidiCode = (MIDIEVENT_NOTEOFF << 4) | nMidiCh | (vol << 16); //note off, on chan nCh; vol is note off velocity. - - for(UINT i = 0; i < 128; i++) + for(uint8 i = 0; i < 128; i++) { // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. - // But this can cause a VST event overflow if we have many active notes... while(channel.uNoteOnMap[i][trackChannel]) { - if(MidiSend(dwMidiCode | (i << 8))) + if(MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, vol))) { channel.uNoteOnMap[i][trackChannel]--; } else @@ -2475,14 +2443,12 @@ // Note On else if(ModCommand::IsNote(note)) { - dwMidiCode = (MIDIEVENT_NOTEON << 4) | nMidiCh; //note on, on chan nCh + note -= NOTE_MIN; - note--; - //reset pitch bend on each new note, tracker style. - if(m_nMidiPitchBendPos[nMidiCh] != MIDI_PitchBend_Centre) + if(m_nMidiPitchBendPos[nMidiCh] != MIDIEvents::pitchBendCentre) { - MidiPitchBend(nMidiCh, MIDI_PitchBend_Centre); + MidiPitchBend(nMidiCh, MIDIEvents::pitchBendCentre); } // count instances of active notes. @@ -2490,12 +2456,10 @@ // Problem: if a note dies out naturally and we never send a note off, this counter // will block at max until note off. Is this a problem? // Safe to assume we won't need more than 16 note offs max on a given note? - if (channel.uNoteOnMap[note][trackChannel] < 17) + if(channel.uNoteOnMap[note][trackChannel] < 17) channel.uNoteOnMap[note][trackChannel]++; - - - MidiSend(dwMidiCode | (note << 8) | (vol << 16)); + MidiSend(MIDIEvents::BuildNoteOnEvent(nMidiCh, note, vol)); } m_nPreviousMidiChan = nMidiCh; Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-04-13 20:46:38 UTC (rev 1246) @@ -217,7 +217,6 @@ VstSpeakerArrangement speakerArrangement; //rewbs.VSTcompliance private: - short getMIDI14bitValueFromShort(short value); void MidiPitchBend(UINT nMidiCh, short pitchBendPos); bool GetProgramNameIndexed(VstInt32 index, VstIntPtr category, char *text); //rewbs.VSTpresets Modified: trunk/OpenMPT/mptrack/dlg_misc.cpp =================================================================== --- trunk/OpenMPT/mptrack/dlg_misc.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/dlg_misc.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -17,7 +17,6 @@ #include "ChildFrm.h" #include "vstplug.h" #include "ChannelManagerDlg.h" -#include "midi.h" #include "version.h" #include "../common/StringFixer.h" Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2012-04-13 20:46:38 UTC (rev 1246) @@ -381,6 +381,10 @@ > </File> <File + RelativePath="..\soundlib\MIDIEvents.cpp" + > + </File> + <File RelativePath=".\MIDIMacroDialog.cpp" > </File> @@ -393,6 +397,10 @@ > </File> <File + RelativePath=".\MIDIMapping.cpp" + > + </File> + <File RelativePath="..\common\misc_util.cpp" > </File> @@ -1031,7 +1039,7 @@ > </File> <File - RelativePath="..\soundlib\midi.h" + RelativePath="..\soundlib\MIDIEvents.h" > </File> <File @@ -1047,6 +1055,10 @@ > </File> <File + RelativePath=".\MIDIMapping.h" + > + </File> + <File RelativePath="..\common\misc_util.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2012-04-13 20:46:38 UTC (rev 1246) @@ -170,6 +170,7 @@ <ClCompile Include="..\common\misc_util.cpp" /> <ClCompile Include="..\common\Reporting.cpp" /> <ClCompile Include="..\soundlib\ITTools.cpp" /> + <ClCompile Include="..\soundlib\MIDIEvents.cpp" /> <ClCompile Include="..\soundlib\MIDIMacros.cpp" /> <ClCompile Include="..\soundlib\ModChannel.cpp" /> <ClCompile Include="..\soundlib\ModInstrument.cpp" /> @@ -214,6 +215,7 @@ <ClCompile Include="MainFrm.cpp" /> <ClCompile Include="..\soundlib\Message.cpp" /> <ClCompile Include="MIDIMacroDialog.cpp" /> + <ClCompile Include="MIDIMapping.cpp" /> <ClCompile Include="MIDIMappingDialog.cpp" /> <ClCompile Include="..\soundlib\mmcmp.cpp" /> <ClCompile Include="..\soundlib\Mmx_mix.cpp" /> @@ -333,6 +335,7 @@ <ClInclude Include="..\common\StringFixer.h" /> <ClInclude Include="..\common\typedefs.h" /> <ClInclude Include="..\soundlib\ITTools.h" /> + <ClInclude Include="..\soundlib\MIDIEvents.h" /> <ClInclude Include="..\soundlib\MIDIMacros.h" /> <ClInclude Include="..\soundlib\ModChannel.h" /> <ClInclude Include="..\soundlib\ModInstrument.h" /> @@ -348,6 +351,7 @@ <ClInclude Include="EffectInfo.h" /> <ClInclude Include="ExceptionHandler.h" /> <ClInclude Include="MIDIMacroDialog.h" /> + <ClInclude Include="MIDIMapping.h" /> <ClInclude Include="PatternClipboard.h" /> <ClInclude Include="PatternCursor.h" /> <ClInclude Include="PatternRandomizer.h" /> @@ -392,7 +396,6 @@ <ClInclude Include="KeyConfigDlg.h" /> <ClInclude Include="mainbar.h" /> <ClInclude Include="MainFrm.h" /> - <ClInclude Include="..\soundlib\midi.h" /> <ClInclude Include="MIDIMappingDialog.h" /> <ClInclude Include="mod2midi.h" /> <ClInclude Include="mod2wave.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2012-04-13 20:46:38 UTC (rev 1246) @@ -454,6 +454,12 @@ <ClCompile Include="..\soundlib\plugins\JBridge.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="MIDIMapping.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\soundlib\MIDIEvents.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -537,9 +543,6 @@ <ClInclude Include="MainFrm.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\soundlib\midi.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="mod2midi.h"> <Filter>Header Files</Filter> </ClInclude> @@ -807,6 +810,12 @@ <ClInclude Include="..\soundlib\plugins\JBridge.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="MIDIMapping.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\soundlib\MIDIEvents.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -15,6 +15,7 @@ #include "../moddoc.h" #include "../MainFrm.h" #include "../version.h" +#include "../../soundlib/MIDIEvents.h" #include "../../soundlib/MIDIMacros.h" #include "../../common/misc_util.h" #include "../../common/StringFixer.h" @@ -75,6 +76,7 @@ void TestLoadSaveFile(); void TestPCnoteSerialization(); void TestMisc(); +void TestMIDIEvents(); void TestStringIO(); @@ -87,6 +89,7 @@ DO_TEST(TestTypes); DO_TEST(TestPCnoteSerialization); DO_TEST(TestMisc); + DO_TEST(TestMIDIEvents); DO_TEST(TestLoadSaveFile); DO_TEST(TestStringIO); @@ -266,6 +269,50 @@ } +// Test MIDI Event generating / reading +void TestMIDIEvents() +//------------------- +{ + uint32 midiEvent; + + midiEvent = MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_Balance_Coarse, 13, 40); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evControllerChange); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 13); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), MIDIEvents::MIDICC_Balance_Coarse); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 40); + + midiEvent = MIDIEvents::BuildNoteOnEvent(10, 50, 120); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evNoteOn); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 10); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 50); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 120); + + midiEvent = MIDIEvents::BuildNoteOffEvent(15, 127, 42); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evNoteOff); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 15); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 127); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 42); + + midiEvent = MIDIEvents::BuildProgramChangeEvent(1, 127); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evProgramChange); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 1); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 127); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0); + + midiEvent = MIDIEvents::BuildPitchBendEvent(2, MIDIEvents::pitchBendCentre); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evPitchBend); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 2); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 0x00); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0x40); + + midiEvent = MIDIEvents::BuildSystemEvent(MIDIEvents::sysStart); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evSystem); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), MIDIEvents::sysStart); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 0); + VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0); +} + + // Check if our test file was loaded correctly. void TestLoadXMFile(const CModDoc *pModDoc) //--------------------------------------- @@ -699,8 +746,8 @@ VERIFY_EQUAL_NONCONT(mapping.GetChannel(), 5); VERIFY_EQUAL_NONCONT(mapping.GetPlugIndex(), 1); VERIFY_EQUAL_NONCONT(mapping.GetParamIndex(), 0); - VERIFY_EQUAL_NONCONT(mapping.GetEvent(), MIDIEVENT_CONTROLLERCHANGE); - VERIFY_EQUAL_NONCONT(mapping.GetController(), MIDICC_ModulationWheel_Coarse); + VERIFY_EQUAL_NONCONT(mapping.GetEvent(), MIDIEvents::evControllerChange); + VERIFY_EQUAL_NONCONT(mapping.GetController(), MIDIEvents::MIDICC_ModulationWheel_Coarse); } Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-04-13 16:57:10 UTC (rev 1245) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -1804,6 +1804,7 @@ #ifndef MODPLUG_NO_FILESAVE + UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate) //---------------------------------------------------- { @@ -1910,9 +1911,10 @@ } return nTotalSize; } -#endif +#endif // MODPLUG_NO_FILESAVE + UINT CSoundFile::LoadMixPlugins(const void *pData, UINT nLen) //----------------------------------------------------------- { @@ -1998,7 +2000,7 @@ } } //end rewbs.plugDefaultProgram - //else if.. (add extra attempts to recognize chunks here) + //else if.. (add extra attempts to recognize chunks here) else // otherwise move forward a byte. { currPos++; @@ -2017,6 +2019,8 @@ } +#ifndef MODPLUG_NO_FILESAVE + // Used only when saving IT, XM and MPTM. // ITI, ITP saves using Ericus' macros etc... // The reason is that ITs and XMs save [code][size][ins1.Value][ins2.Value]... @@ -2207,7 +2211,7 @@ //Additional flags for XM/IT/MPTM if(m_ModFlags) { - code = 'MSF.'; + code = 'MSF.'; fwrite(&code, 1, sizeof(__int32), f); size = sizeof(m_ModFlags); fwrite(&size, 1, sizeof(__int16), f); @@ -2239,6 +2243,9 @@ return; } +#endif // MODPLUG_NO_FILESAVE + + LPCBYTE CSoundFile::LoadExtendedInstrumentProperties(const LPCBYTE pStart, const LPCBYTE pEnd, bool* pInterpretMptMade) @@ -2399,6 +2406,8 @@ } +#ifndef MODPLUG_NO_FILESAVE + size_t CSoundFile::SaveModularInstrumentData(FILE *f, const ModInstrument *pIns) const //------------------------------------------------------------------------------------ { @@ -2444,7 +2453,9 @@ return sizeof(ModInstID) + sizeof(modularInstSize) + modularInstSize; } +#endif // MODPLUG_NO_FILESAVE + size_t CSoundFile::LoadModularInstrumentData(const LPCBYTE lpStream, const DWORD dwMemLength, ModInstrument *pIns) const //---------------------------------------------------------------------------------------------------------------------- { Added: trunk/OpenMPT/soundlib/MIDIEvents.cpp =================================================================== --- trunk/OpenMPT/soundlib/MIDIEvents.cpp (rev 0) +++ trunk/OpenMPT/soundlib/MIDIEvents.cpp 2012-04-13 20:46:38 UTC (rev 1246) @@ -0,0 +1,104 @@ +/* + * MIDI.cpp + * -------- + * Purpose: MIDI event handling, event lists, ... + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "MIDIEvents.h" + +namespace MIDIEvents +{ + +// Build a generic MIDI event +uint32 BuildEvent(EventType eventType, uint8 midiChannel, uint8 dataByte1, uint8 dataByte2) +//----------------------------------------------------------------------------------------- +{ + return (eventType << 4) | (midiChannel & 0x0F) | (dataByte1 << 8) | (dataByte2 << 16); +} + + +// Build a MIDI CC event +uint32 BuildCCEvent(MidiCC midiCC, uint8 midiChannel, uint8 param) +//---------------------------------------------------------------- +{ + return BuildEvent(evControllerChange, midiChannel, midiCC, param); +} + + +// Build a MIDI Pitchbend event +uint32 BuildPitchBendEvent(uint8 midiChannel, uint16 bendAmount) +//-------------------------------------------------------------- +{ + return BuildEvent(evPitchBend, midiChannel, (bendAmount & 0x7F), (bendAmount >> 7)); +} + + +// Build a MIDI Program Change event +uint32 BuildProgramChangeEvent(uint8 midiChannel, uint8 program) +//-------------------------------------------------------------- +{ + return BuildEvent(evProgramChange, midiChannel, program, 0); +} + + +// Build a MIDI Note Off event +uint32 BuildNoteOffEvent(uint8 midiChannel, uint8 note, uint8 velocity) +//--------------------------------------------------------------------- +{ + return BuildEvent(evNoteOff, midiChannel, note, velocity); +} + + +// Build a MIDI Note On event +uint32 BuildNoteOnEvent(uint8 midiChannel, uint8 note, uint8 velocity) +//-------------------------------------------------------------------- +{ + return BuildEvent(evNoteOn, midiChannel, note, velocity); +} + + +// Build a MIDI System Event +uint8 BuildSystemEvent(SystemEvent eventType) +//------------------------------------------- +{ + return (evSystem << 4) | eventType; +} + + +// Get MIDI channel from a MIDI event +uint8 GetChannelFromEvent(uint32 midiMsg) +//--------------------------------------- +{ + return static_cast<uint8>((midiMsg & 0xF)); +} + + +// Get MIDI Event type from a MIDI event +EventType GetTypeFromEvent(uint32 midiMsg) +//---------------------------------------- +{ + return static_cast<EventType>(((midiMsg >> 4) & 0xF)); +} + + +// Get first data byte from a MIDI event +uint8 GetDataByte1FromEvent(uint32 midiMsg) +//----------------------------------------- +{ + return static_cast<uint8>(((midiMsg >> 8) & 0xFF)); +} + + +// Get second data byte from a MIDI event +uint8 GetDataByte2FromEvent(uint32 midiMsg) +//----------------------------------------- +{ + return static_cast<uint8>(((midiMsg >> 16) & 0xFF)); +} + +} // End namespace Copied: trunk/OpenMPT/soundlib/MIDIEvents.h (from rev 1224, trunk/OpenMPT/soundlib/midi.h) =================================================================== --- trunk/OpenMPT/soundlib/MIDIEvents.h (rev 0) +++ trunk/OpenMPT/soundlib/MIDIEvents.h 2012-04-13 20:46:38 UTC (rev 1246) @@ -0,0 +1,289 @@ +/* + * MIDI.h + * ------ + * Purpose: MIDI event handling, event lists, ... + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + + +// MIDI related enums and helper functions +namespace MIDIEvents +{ + + // MIDI Event Types + enum EventType + { + evNoteOff = 0x8, // Note Off event + evNoteOn = 0x9, // Note On event + evPolyAftertouch = 0xA, // Poly Aftertouch / Poly Pressure event + evControllerChange = 0xB, // Controller Change (see MidiCC enum) + evProgramChange = 0xC, // Program Change + evChannelAftertouch = 0xD, // Channel Aftertouch + evPitchBend = 0xE, // Pitchbend event (see PitchBend enum) + evSystem = 0xF, // System event (see SystemEvent enum) + }; + + // System Events (Fx ...) + enum SystemEvent + { + sysExStart = 0x0, // Begin of System Exclusive message + sysQuarterFrame = 0x1, // Quarter Frame Message + sysPositionPointer ... [truncated message content] |
From: <sag...@us...> - 2012-04-13 22:44:24
|
Revision: 1247 http://modplug.svn.sourceforge.net/modplug/?rev=1247&view=rev Author: saga-games Date: 2012-04-13 22:44:17 +0000 (Fri, 13 Apr 2012) Log Message: ----------- [Ref] Got rid of some (new) warnings Modified Paths: -------------- trunk/OpenMPT/mptrack/View_ins.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/soundlib/plugins/PlugInterface.h Modified: trunk/OpenMPT/mptrack/View_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_ins.cpp 2012-04-13 20:46:38 UTC (rev 1246) +++ trunk/OpenMPT/mptrack/View_ins.cpp 2012-04-13 22:44:17 UTC (rev 1247) @@ -2160,8 +2160,8 @@ const BYTE nNote = midiByte1 + 1; // +1 is for MPT, where middle C is 61 int nVol = midiByte2; - BYTE event = MIDIEvents::GetTypeFromEvent(dwMidiData); - if ((event == 0x9) && !nVol) event = 0x8; //Convert event to note-off if req'd + MIDIEvents::EventType event = MIDIEvents::GetTypeFromEvent(dwMidiData); + if((event == MIDIEvents::evNoteOn) && !nVol) event = MIDIEvents::evNoteOff; //Convert event to note-off if req'd BYTE mappedIndex = 0, paramValue = 0; uint32 paramIndex = 0; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-13 20:46:38 UTC (rev 1246) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2012-04-13 22:44:17 UTC (rev 1247) @@ -2279,7 +2279,7 @@ Resume(); } - for(int mc = 0; mc < 16; mc++) //all midi chans + for(uint8 mc = 0; mc < 16; mc++) //all midi chans { VSTInstrChannel &channel = m_MidiCh[mc]; @@ -2288,13 +2288,13 @@ MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllNotesOff, mc, 0)); // all notes off MidiSend(MIDIEvents::BuildCCEvent(MIDIEvents::MIDICC_AllSoundOff, mc, 0)); // all sounds off - for (size_t i = 0; i < CountOf(channel.uNoteOnMap); i++) //all notes + for(size_t i = 0; i < CountOf(channel.uNoteOnMap); i++) //all notes { - for (CHANNELINDEX c = 0; c < CountOf(channel.uNoteOnMap[i]); c++) + for(CHANNELINDEX c = 0; c < CountOf(channel.uNoteOnMap[i]); c++) { while(channel.uNoteOnMap[i][c]) { - MidiSend(MIDIEvents::BuildNoteOffEvent(mc, i, 0)); + MidiSend(MIDIEvents::BuildNoteOffEvent(mc, static_cast<uint8>(i), 0)); channel.uNoteOnMap[i][c]--; } } @@ -2314,23 +2314,23 @@ } //end rewbs.VSTiNoteHoldonStopFix -void CVstPlugin::MidiCC(UINT nMidiCh, UINT nController, UINT nParam, UINT /*trackChannel*/) -//------------------------------------------------------------------------------------------ +void CVstPlugin::MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX /*trackChannel*/) +//----------------------------------------------------------------------------------------------------------------- { //Error checking - LimitMax(nController, 127u); - LimitMax(nParam, 127u); + LimitMax(nController, MIDIEvents::MIDICC_end); + LimitMax(nParam, uint8(127)); if(m_pSndFile && m_pSndFile->GetModFlag(MSF_MIDICC_BUGEMULATION)) - MidiSend(MIDIEvents::BuildEvent(MIDIEvents::evControllerChange, nMidiCh, nParam, nController)); // param and controller are swapped (old broken implementation) + MidiSend(MIDIEvents::BuildEvent(MIDIEvents::evControllerChange, nMidiCh, nParam, static_cast<uint8>(nController))); // param and controller are swapped (old broken implementation) else - MidiSend(MIDIEvents::BuildCCEvent(static_cast<MIDIEvents::MidiCC>(nController), nMidiCh, nParam)); + MidiSend(MIDIEvents::BuildCCEvent(nController, nMidiCh, nParam)); } // Bend midi pitch for given midi channel using tracker param (0x00-0xFF) -void CVstPlugin::MidiPitchBend(UINT nMidiCh, int nParam, UINT /*trackChannel*/) -//----------------------------------------------------------------------------- +void CVstPlugin::MidiPitchBend(uint8 nMidiCh, int nParam, CHANNELINDEX /*trackChannel*/) +//-------------------------------------------------------------------------------------- { const int16 increment = static_cast<int16>(nParam * 0x2000 / 0xFF); int16 newPitchBendPos = m_nMidiPitchBendPos[nMidiCh] + increment; @@ -2340,8 +2340,8 @@ } //Set midi pitch for given midi channel using uncoverted midi value (0-16383) -void CVstPlugin::MidiPitchBend(UINT nMidiCh, short newPitchBendPos) -//----------------------------------------------------------------- +void CVstPlugin::MidiPitchBend(uint8 nMidiCh, int16 newPitchBendPos) +//------------------------------------------------------------------ { ASSERT(MIDIEvents::pitchBendMin <= newPitchBendPos && newPitchBendPos <= MIDIEvents::pitchBendMax); m_nMidiPitchBendPos[nMidiCh] = newPitchBendPos; @@ -2350,21 +2350,21 @@ //rewbs.introVST - many changes to MidiCommand, still to be refined. -void CVstPlugin::MidiCommand(UINT nMidiCh, UINT nMidiProg, WORD wMidiBank, UINT note, UINT vol, UINT trackChannel) -//---------------------------------------------------------------------------------------------------------------- +void CVstPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) +//-------------------------------------------------------------------------------------------------------------------------------- { VSTInstrChannel &channel = m_MidiCh[nMidiCh]; bool bankChanged = (channel.wMidiBank != --wMidiBank) && (wMidiBank < 0x4000); bool progChanged = (channel.nProgram != --nMidiProg) && (nMidiProg < 0x80); //get vol in [0,128[ - vol = min(vol / 2, 127); + uint8 volume = static_cast<uint8>(Util::Min(vol / 2, 127)); // Bank change if(wMidiBank < 0x4000 && bankChanged) { - uint8 high = (wMidiBank >> 7); - uint8 low = (wMidiBank & 0x7F); + uint8 high = static_cast<uint8>(wMidiBank >> 7); + uint8 low = static_cast<uint8>(wMidiBank & 0x7F); if((channel.wMidiBank >> 7) != high) { @@ -2393,7 +2393,7 @@ if (note > NOTE_KEYOFF) //rewbs.vstiLive { note--; - UINT i = note - NOTE_KEYOFF; + uint8 i = static_cast<uint8>(note - NOTE_KEYOFF); if(channel.uNoteOnMap[i][trackChannel]) { channel.uNoteOnMap[i][trackChannel]--; @@ -2413,7 +2413,7 @@ for(uint8 i = 0; i < 128; i++) { channel.uNoteOnMap[i][trackChannel] = 0; - MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, vol)); + MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, volume)); } } @@ -2427,7 +2427,7 @@ // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. while(channel.uNoteOnMap[i][trackChannel]) { - if(MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, vol))) + if(MidiSend(MIDIEvents::BuildNoteOffEvent(nMidiCh, i, volume))) { channel.uNoteOnMap[i][trackChannel]--; } else @@ -2441,7 +2441,7 @@ } // Note On - else if(ModCommand::IsNote(note)) + else if(ModCommand::IsNote(static_cast<ModCommand::NOTE>(note))) { note -= NOTE_MIN; @@ -2459,7 +2459,7 @@ if(channel.uNoteOnMap[note][trackChannel] < 17) channel.uNoteOnMap[note][trackChannel]++; - MidiSend(MIDIEvents::BuildNoteOnEvent(nMidiCh, note, vol)); + MidiSend(MIDIEvents::BuildNoteOnEvent(nMidiCh, static_cast<uint8>(note), volume)); } m_nPreviousMidiChan = nMidiCh; Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2012-04-13 20:46:38 UTC (rev 1246) +++ trunk/OpenMPT/mptrack/Vstplug.h 2012-04-13 22:44:17 UTC (rev 1247) @@ -191,9 +191,9 @@ void Process(float *pOutL, float *pOutR, size_t nSamples); void Init(unsigned long nFreq, int bReset); bool MidiSend(DWORD dwMidiCode); - void MidiCC(UINT nMidiCh, UINT nController, UINT nParam, UINT trackChannel); - void MidiPitchBend(UINT nMidiCh, int nParam, UINT trackChannel); - void MidiCommand(UINT nMidiCh, UINT nMidiProg, WORD wMidiBank, UINT note, UINT vol, UINT trackChan); + void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel); + void MidiPitchBend(uint8 nMidiCh, int nParam, CHANNELINDEX trackChannel); + void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel); void HardAllNotesOff(); //rewbs.VSTiNoteHoldonStopFix bool isPlaying(UINT note, UINT midiChn, UINT trackerChn); //rewbs.instroVST bool MoveNote(UINT note, UINT midiChn, UINT sourceTrackerChn, UINT destTrackerChn); //rewbs.instroVST @@ -217,7 +217,7 @@ VstSpeakerArrangement speakerArrangement; //rewbs.VSTcompliance private: - void MidiPitchBend(UINT nMidiCh, short pitchBendPos); + void MidiPitchBend(uint8 nMidiCh, int16 pitchBendPos); bool GetProgramNameIndexed(VstInt32 index, VstIntPtr category, char *text); //rewbs.VSTpresets Modified: trunk/OpenMPT/soundlib/plugins/PlugInterface.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-04-13 20:46:38 UTC (rev 1246) +++ trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2012-04-13 22:44:17 UTC (rev 1247) @@ -21,6 +21,7 @@ #include "Snd_defs.h" #include "../common/misc_util.h" +#include "../soundlib/MIDIEvents.h" //////////////////////////////////////////////////////////////////// // Mix Plugins @@ -40,9 +41,9 @@ virtual void Process(float *pOutL, float *pOutR, size_t nSamples) = 0; virtual void Init(unsigned long nFreq, int bReset) = 0; virtual bool MidiSend(DWORD dwMidiCode) = 0; - virtual void MidiCC(UINT nMidiCh, UINT nController, UINT nParam, UINT trackChannel) = 0; - virtual void MidiPitchBend(UINT nMidiCh, int nParam, UINT trackChannel) = 0; - virtual void MidiCommand(UINT nMidiCh, UINT nMidiProg, WORD wMidiBank, UINT note, UINT vol, UINT trackChan) = 0; + virtual void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) = 0; + virtual void MidiPitchBend(uint8 nMidiCh, int nParam, CHANNELINDEX trackChannel) = 0; + virtual void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) = 0; virtual void HardAllNotesOff() = 0; //rewbs.VSTCompliance virtual void RecalculateGain() = 0; virtual bool isPlaying(UINT note, UINT midiChn, UINT trackerChn) = 0; //rewbs.VSTiNNA This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-18 22:26:07
|
Revision: 1248 http://modplug.svn.sourceforge.net/modplug/?rev=1248&view=rev Author: saga-games Date: 2012-04-18 22:26:00 +0000 (Wed, 18 Apr 2012) Log Message: ----------- [Fix] WAV Loading / Writing didn't consider word padding since... forever. Not it should work as intended (and still load old broken samples). [Mod] Updated list of file extensions to display in tree view and to scan for in archives. By default, all known module types are now shown in the treeview, not only when "Show All Files" is active. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Sndfile.cpp Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-04-13 22:44:17 UTC (rev 1247) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2012-04-18 22:26:00 UTC (rev 1248) @@ -1157,6 +1157,15 @@ CMainFrame::UpdateAudioParameters(TRUE); // Success + + if((wdh.length % 2) != 0) + { + // Write padding byte if sample size is odd. + int8 padding = 0; + fwrite(&padding, 1, 1, f); + wfh.filesize++; + } + if (bSaveWave) { if (m_bSaveInfoField) Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2012-04-13 22:44:17 UTC (rev 1247) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2012-04-18 22:26:00 UTC (rev 1248) @@ -1702,44 +1702,42 @@ } } else // Songs - if ((!lstrcmpi(s, ".mod")) - || (!lstrcmpi(s, ".s3m")) - || (!lstrcmpi(s, ".xm")) - || (!lstrcmpi(s, ".it")) - || (!lstrcmpi(s, ".mptm")) -// -> CODE#0023 -// -> DESC="IT project files (.itp)" -// || (!lstrcmpi(s, ".itp")) ericus 03/03/2005 : temporarily deactivated 03/03/2005 -// -! NEW_FEATURE#0023 - || ((m_bShowAllFiles) - && ((!lstrcmpi(s, ".mdz")) - || (!lstrcmpi(s, ".s3z")) - || (!lstrcmpi(s, ".xmz")) - || (!lstrcmpi(s, ".itz")) - || (!lstrcmpi(s, ".669")) - || (!lstrcmpi(s, ".ams")) - || (!lstrcmpi(s, ".amf")) - || (!lstrcmpi(s, ".mdz")) - || (!lstrcmpi(s, ".dsm")) - || (!lstrcmpi(s, ".far")) - || (!lstrcmpi(s, ".mdl")) - || (!lstrcmpi(s, ".mtm")) - || (!lstrcmpi(s, ".nst")) - || (!lstrcmpi(s, ".okt")) - || (!lstrcmpi(s, ".stm")) - || (!lstrcmpi(s, ".ult")) - || (!lstrcmpi(s, ".psm")) - || (!lstrcmpi(s, ".dmf")) - || (!lstrcmpi(s, ".mt2")) - || (!lstrcmpi(s, ".med")) - || (!lstrcmpi(s, ".wow")) - || (!lstrcmpi(s, ".gdm")) - || (!lstrcmpi(s, ".imf")) - || (!lstrcmpi(s, ".j2b")) + if(!lstrcmpi(s, ".mod") + || !lstrcmpi(s, ".s3m") + || !lstrcmpi(s, ".xm") + || !lstrcmpi(s, ".it") + || !lstrcmpi(s, ".mptm") + || !lstrcmpi(s, ".itp") + || !lstrcmpi(s, ".mdz") + || !lstrcmpi(s, ".s3z") + || !lstrcmpi(s, ".xmz") + || !lstrcmpi(s, ".itz") + || !lstrcmpi(s, ".669") + || !lstrcmpi(s, ".ams") + || !lstrcmpi(s, ".amf") + || !lstrcmpi(s, ".mdz") + || !lstrcmpi(s, ".dsm") + || !lstrcmpi(s, ".far") + || !lstrcmpi(s, ".mdl") + || !lstrcmpi(s, ".mtm") + || !lstrcmpi(s, ".nst") + || !lstrcmpi(s, ".okt") + || !lstrcmpi(s, ".stm") + || !lstrcmpi(s, ".ult") + || !lstrcmpi(s, ".psm") + || !lstrcmpi(s, ".dmf") + || !lstrcmpi(s, ".mt2") + || !lstrcmpi(s, ".med") + || !lstrcmpi(s, ".wow") + || !lstrcmpi(s, ".gdm") + || !lstrcmpi(s, ".imf") + || !lstrcmpi(s, ".j2b") + || !lstrcmpi(s, ".umx") + || !lstrcmpi(s, ".uax") #ifndef NO_MO3_SUPPORT - || (!lstrcmpi(s, ".mo3")) -#endif - ))) + || !lstrcmpi(s, ".mo3") +#endif // NO_MO3_SUPPORT + ) { if (m_pDataTree) { @@ -1748,34 +1746,34 @@ } } else // Samples - if ((!lstrcmpi(s, ".wav")) - || (!lstrcmpi(s, ".smp")) - || (!lstrcmpi(s, ".raw")) - || (!lstrcmpi(s, ".s3i")) - || (!lstrcmpi(s, ".its")) - || (!lstrcmpi(s, ".aif")) - || (!lstrcmpi(s, ".aiff")) - || (!lstrcmpi(s, ".snd")) - || (!lstrcmpi(s, ".svx")) - || (!lstrcmpi(s, ".voc")) - || (!lstrcmpi(s, ".8sv")) - || (!lstrcmpi(s, ".8svx")) - || (!lstrcmpi(s, ".16sv")) - || (!lstrcmpi(s, ".16svx")) - || ((m_bShowAllFiles) // Exclude the extensions below - && (lstrcmpi(s, ".txt")) - && (lstrcmpi(s, ".diz")) - && (lstrcmpi(s, ".nfo")) - && (lstrcmpi(s, ".doc")) - && (lstrcmpi(s, ".ini")) - && (lstrcmpi(s, ".pdf")) - && (lstrcmpi(s, ".zip")) - && (lstrcmpi(s, ".rar")) - && (lstrcmpi(s, ".lha")) - && (lstrcmpi(s, ".exe")) - && (lstrcmpi(s, ".dll")) - && (lstrcmpi(s, ".mol"))) - ) + if(!lstrcmpi(s, ".wav") + || !lstrcmpi(s, ".smp") + || !lstrcmpi(s, ".raw") + || !lstrcmpi(s, ".s3i") + || !lstrcmpi(s, ".its") + || !lstrcmpi(s, ".aif") + || !lstrcmpi(s, ".aiff") + || !lstrcmpi(s, ".snd") + || !lstrcmpi(s, ".svx") + || !lstrcmpi(s, ".voc") + || !lstrcmpi(s, ".8sv") + || !lstrcmpi(s, ".8svx") + || !lstrcmpi(s, ".16sv") + || !lstrcmpi(s, ".16svx") + || (m_bShowAllFiles // Exclude the extensions below + && lstrcmpi(s, ".txt") + && lstrcmpi(s, ".diz") + && lstrcmpi(s, ".nfo") + && lstrcmpi(s, ".doc") + && lstrcmpi(s, ".ini") + && lstrcmpi(s, ".pdf") + && lstrcmpi(s, ".zip") + && lstrcmpi(s, ".rar") + && lstrcmpi(s, ".lha") + && lstrcmpi(s, ".exe") + && lstrcmpi(s, ".dll") + && lstrcmpi(s, ".mol")) + ) { if (!m_pDataTree) { Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-13 22:44:17 UTC (rev 1247) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2012-04-18 22:26:00 UTC (rev 1248) @@ -393,6 +393,19 @@ break; } dwMemPos += dwLen + 8; + + if((dwLen % 2) != 0 && dwMemPos < dwFileLength) + { + // Ignore the padding byte. Problem: Old versions of OpenMPT didn't write padding. -_- + // We will just do a heuristic check here: As OpenMPT always writes the "smpl" chunk after the "data" chunk + // (which happens to be the only chunk that has to be padded in OpenMPT's case), we just check if we can read "smpl" + // without incrementing the position. + if((dwMemPos + 8 < dwFileLength) && LittleEndian(*reinterpret_cast<uint32 *>(lpMemFile + dwMemPos)) == 0x6C706D73) + { + continue; + } + dwMemPos++; + } } if (!pdata || !pfmt || pdata->length < 4) return false; @@ -655,6 +668,11 @@ } header.filesize += data.length; + if((data.length % 2) != 0) + { + // Write padding byte if sample size is odd. + header.filesize++; + } // "smpl" field smpl.wsiHdr.smpl_id = LittleEndian(IFFID_smpl); @@ -688,6 +706,12 @@ fwrite(&format, 1, sizeof(format), f); fwrite(&data, 1, sizeof(data), f); WriteSample(f, &sample, nType); + if((data.length % 2) != 0) + { + // Write padding byte if sample size is odd. + int8 padding = 0; + fwrite(&padding, 1, 1, f); + } fwrite(&smpl, 1, smpl.wsiHdr.smpl_len + 8, f); // "LIST" field Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-13 22:44:17 UTC (rev 1247) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-18 22:26:00 UTC (rev 1248) @@ -35,7 +35,7 @@ #define UNLHA_SUPPORT #define UNGZIP_SUPPORT #define ZIPPED_MOD_SUPPORT -LPCSTR glpszModExtensions = "mod|s3m|xm|it|stm|nst|ult|669|wow|mtm|med|far|mdl|ams|dsm|amf|okt|dmf|ptm|psm|mt2|umx|gdm|imf|j2b" +LPCSTR glpszModExtensions = "mod|s3m|xm|it|itp|mptm|stm|nst|ult|669|wow|mtm|med|far|mdl|ams|dsm|amf|okt|dmf|ptm|psm|mt2|umx|uax|gdm|imf|j2b" #ifndef NO_UNMO3_SUPPORT "|mo3" #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-21 18:27:30
|
Revision: 1252 http://modplug.svn.sourceforge.net/modplug/?rev=1252&view=rev Author: saga-games Date: 2012-04-21 17:39:42 +0000 (Sat, 21 Apr 2012) Log Message: ----------- [Fix] XM / MOD volume/panning slide nibble priority was wrong for slides with both nibbles set. This was only relevent for newly entered note slides, since slides loaded from files were automatically fixed, so no compat settings are applied here (http://bugs.openmpt.org/view.php?id=242). [Mod] OpenMPT: Version is now 1.20.00.86 Modified Paths: -------------- trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2012-04-21 17:39:42 UTC (rev 1252) @@ -2314,7 +2314,6 @@ pSndFile->m_dwSongFlags &= ~(SONG_PAUSED|SONG_STEP); pSndFile->LoopPattern(nPat); pSndFile->m_nNextRow = 0; - pSndFile->ResetTotalTickCount(); //rewbs.vstCompliance if (pModPlaying == this) { Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/mptrack/version.h 2012-04-21 17:39:42 UTC (rev 1252) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 85 +#define VER_MINORMINOR 86 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2012-04-21 17:39:42 UTC (rev 1252) @@ -22,12 +22,12 @@ case 0x02: m.command = CMD_PORTAMENTODOWN; break; case 0x03: m.command = CMD_TONEPORTAMENTO; break; case 0x04: m.command = CMD_VIBRATO; break; - case 0x05: m.command = CMD_TONEPORTAVOL; if(m.param & 0xF0) m.param &= 0xF0; break; - case 0x06: m.command = CMD_VIBRATOVOL; if(m.param & 0xF0) m.param &= 0xF0; break; + case 0x05: m.command = CMD_TONEPORTAVOL; break; + case 0x06: m.command = CMD_VIBRATOVOL; break; case 0x07: m.command = CMD_TREMOLO; break; case 0x08: m.command = CMD_PANNING8; break; case 0x09: m.command = CMD_OFFSET; break; - case 0x0A: m.command = CMD_VOLUMESLIDE; if(m.param & 0xF0) m.param &= 0xF0; break; + case 0x0A: m.command = CMD_VOLUMESLIDE; break; case 0x0B: m.command = CMD_POSITIONJUMP; break; case 0x0C: m.command = CMD_VOLUME; break; case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; @@ -37,12 +37,12 @@ // Extension for XM extended effects case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16 - case 'H' - 55: m.command = CMD_GLOBALVOLSLIDE; if (m.param & 0xF0) m.param &= 0xF0; break; + case 'H' - 55: m.command = CMD_GLOBALVOLSLIDE; break; case 'K' - 55: m.command = CMD_KEYOFF; break; case 'L' - 55: m.command = CMD_SETENVPOSITION; break; case 'M' - 55: m.command = CMD_CHANNELVOLUME; break; case 'N' - 55: m.command = CMD_CHANNELVOLSLIDE; break; - case 'P' - 55: m.command = CMD_PANNINGSLIDE; if (m.param & 0xF0) m.param &= 0xF0; break; + case 'P' - 55: m.command = CMD_PANNINGSLIDE; break; case 'R' - 55: m.command = CMD_RETRIG; break; case 'T' - 55: m.command = CMD_TREMOR; break; case 'X' - 55: m.command = CMD_XFINEPORTAUPDOWN; break; Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2012-04-21 17:39:42 UTC (rev 1252) @@ -2843,8 +2843,20 @@ else param = pChn->nOldVolumeSlide; + if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2))) + { + // MOD / XM nibble priority + if((param & 0xF0) != 0) + { + param &= 0xF0; + } else + { + param &= 0x0F; + } + } + LONG newvolume = pChn->nVolume; - if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_STM|MOD_TYPE_AMF)) + if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_STM|MOD_TYPE_AMF)) { if ((param & 0x0F) == 0x0F) //Fine upslide or slide -15 { @@ -2903,8 +2915,21 @@ pChn->nOldPanSlide = param; else param = pChn->nOldPanSlide; - if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_STM)) + + if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) { + // XM nibble priority + if((param & 0xF0) != 0) + { + param &= 0xF0; + } else + { + param &= 0x0F; + } + } + + if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_STM)) + { if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if (m_dwSongFlags & SONG_FIRSTTICK) @@ -3000,6 +3025,7 @@ { LONG nChnSlide = 0; if (param) pChn->nOldChnVolSlide = param; else param = pChn->nOldChnVolSlide; + if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if (m_dwSongFlags & SONG_FIRSTTICK) nChnSlide = param >> 4; @@ -4161,6 +4187,19 @@ { LONG nGlbSlide = 0; if (param) nOldGlobalVolSlide = param; else param = nOldGlobalVolSlide; + + if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + { + // XM nibble priority + if((param & 0xF0) != 0) + { + param &= 0xF0; + } else + { + param &= 0x0F; + } + } + if (((param & 0x0F) == 0x0F) && (param & 0xF0)) { if (m_dwSongFlags & SONG_FIRSTTICK) nGlbSlide = (param >> 4) * 2; @@ -4442,7 +4481,7 @@ } -UINT CSoundFile::GetBestMidiChannel(CHANNELINDEX nChn) const +uint8 CSoundFile::GetBestMidiChannel(CHANNELINDEX nChn) const //---------------------------------------------------------- { if(nChn == CHANNELINDEX_INVALID) Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-21 17:39:42 UTC (rev 1252) @@ -1134,7 +1134,6 @@ m_nPattern = 0; m_nTickCount = m_nMusicSpeed; m_nBufferCount = 0; - m_nTotalCount = 0; m_nPatternDelay = 0; m_nFrameDelay = 0; m_nNextPatStartRow = 0; Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-04-21 17:39:42 UTC (rev 1252) @@ -255,7 +255,7 @@ bool m_bIsRendering; UINT m_nMixChannels, m_nMixStat, m_nBufferCount; double m_dBufferDiff; - UINT m_nTickCount, m_nTotalCount; + UINT m_nTickCount; UINT m_nPatternDelay, m_nFrameDelay; // m_nPatternDelay = pattern delay (rows), m_nFrameDelay = fine pattern delay (ticks) ULONG m_lTotalSampleCount; // rewbs.VSTTimeInfo UINT m_nSamplesPerTick; // rewbs.betterBPM @@ -449,8 +449,6 @@ UINT GetResamplingFlag(const ModChannel *pChannel); BOOL FadeSong(UINT msec); BOOL GlobalFadeSong(UINT msec); - UINT GetTotalTickCount() const { return m_nTotalCount; } - void ResetTotalTickCount() { m_nTotalCount = 0;} void ProcessPlugins(UINT nCount); public: @@ -737,7 +735,7 @@ public: PLUGINDEX GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const; - UINT GetBestMidiChannel(CHANNELINDEX nChn) const; + uint8 GetBestMidiChannel(CHANNELINDEX nChn) const; }; Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2012-04-21 16:58:44 UTC (rev 1251) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2012-04-21 17:39:42 UTC (rev 1252) @@ -1845,7 +1845,6 @@ return FALSE; } //////////////////////////////////////////////////////////////////////////////////// - m_nTotalCount++; if (!m_nMusicTempo) return FALSE; switch(m_nTempoMode) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2012-04-23 16:14:50
|
Revision: 1254 http://modplug.svn.sourceforge.net/modplug/?rev=1254&view=rev Author: saga-games Date: 2012-04-23 15:28:34 +0000 (Mon, 23 Apr 2012) Log Message: ----------- [Ref] The crap is gone: Rewrote S3M Loader / Saver completely. Also added S3M loading/saving test. Modified Paths: -------------- trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Load_umx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/pattern.h Added Paths: ----------- trunk/OpenMPT/mptrack/test/test.s3m Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -752,6 +752,130 @@ } +// Check if our test file was loaded correctly. +void TestLoadS3MFile(const CModDoc *pModDoc) +//------------------------------------------ +{ + const CSoundFile *pSndFile = pModDoc->GetSoundFile(); + + // Global Variables + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[0], "S3M_Test__________________X"), 0); + VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultTempo, 33); + VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultSpeed, 254); + VERIFY_EQUAL_NONCONT(pSndFile->m_nGlobalVolume, 32 * 4); + VERIFY_EQUAL_NONCONT(pSndFile->m_nVSTiVolume, 48); + VERIFY_EQUAL_NONCONT(pSndFile->m_nSamplePreAmp, 16); + VERIFY_EQUAL_NONCONT((pSndFile->m_dwSongFlags & SONG_FILE_FLAGS), SONG_FASTVOLSLIDES); + VERIFY_EQUAL_NONCONT(pSndFile->m_nMixLevels, mixLevels_compatible); + VERIFY_EQUAL_NONCONT(pSndFile->m_nTempoMode, tempo_mode_classic); + VERIFY_EQUAL_NONCONT(pSndFile->m_dwLastSavedWithVersion, MAKE_VERSION_NUMERIC(1, 20, 00, 00)); + VERIFY_EQUAL_NONCONT(pSndFile->m_nRestartPos, 0); + + // Channels + VERIFY_EQUAL_NONCONT(pSndFile->GetNumChannels(), 4); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[0].nPan, 0); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[0].dwFlags, 0); + + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].nPan, 256); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].dwFlags, CHN_MUTE); + + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[2].nPan, 85); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[2].dwFlags, 0); + + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[3].nPan, 171); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[3].dwFlags, CHN_MUTE); + + // Samples + VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 3); + { + const ModSample &sample = pSndFile->GetSample(1); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[1], "Sample_1__________________X"), 0); + VERIFY_EQUAL_NONCONT(strcmp(sample.filename, "Filename_1_X"), 0); + VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1); + VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1); + VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1); + VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 60); + VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 9001); + VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4); + VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 64); + VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP); + + VERIFY_EQUAL_NONCONT(sample.nLoopStart, 16); + VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 60); + + // Sample Data + for(size_t i = 0; i < 30; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], 127); + } + for(size_t i = 31; i < 60; i++) + { + VERIFY_EQUAL_NONCONT(sample.pSample[i], -128); + } + } + + { + const ModSample &sample = pSndFile->GetSample(2); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[2], "Empty"), 0); + VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 16384); + VERIFY_EQUAL_NONCONT(sample.nVolume, 2 * 4); + } + + { + const ModSample &sample = pSndFile->GetSample(3); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[3], "Stereo / 16-Bit"), 0); + VERIFY_EQUAL_NONCONT(strcmp(sample.filename, "Filename_3_X"), 0); + VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 4); + VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 2); + VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 2); + VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 64); + VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 16000); + VERIFY_EQUAL_NONCONT(sample.nVolume, 0); + VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP | CHN_16BIT | CHN_STEREO); + + VERIFY_EQUAL_NONCONT(sample.nLoopStart, 0); + VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 16); + + // Sample Data (Stereo Interleaved) + for(size_t i = 0; i < 7; i++) + { + VERIFY_EQUAL_NONCONT(reinterpret_cast<int16 *>(sample.pSample)[4 + i], int16(-32768)); + } + } + + // Orders + VERIFY_EQUAL_NONCONT(pSndFile->Order.GetLengthTailTrimmed(), 5); + VERIFY_EQUAL_NONCONT(pSndFile->Order[0], 0); + VERIFY_EQUAL_NONCONT(pSndFile->Order[1], pSndFile->Order.GetIgnoreIndex()); + VERIFY_EQUAL_NONCONT(pSndFile->Order[2], pSndFile->Order.GetInvalidPatIndex()); + VERIFY_EQUAL_NONCONT(pSndFile->Order[3], 1); + VERIFY_EQUAL_NONCONT(pSndFile->Order[4], 0); + + // Patterns + VERIFY_EQUAL_NONCONT(pSndFile->Patterns.GetNumPatterns(), 2); + + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetNumRows(), 64); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetNumChannels(), 4); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetOverrideSignature(), false); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(0, 0)->note, NOTE_MIN + 12); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(1, 0)->note, NOTE_MIN + 107); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(0, 1)->volcmd, VOLCMD_VOLUME); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(0, 1)->vol, 0); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(1, 1)->volcmd, VOLCMD_VOLUME); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(1, 1)->vol, 64); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(2, 1)->volcmd, VOLCMD_PANNING); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(2, 1)->vol, 0); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(3, 1)->volcmd, VOLCMD_PANNING); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(3, 1)->vol, 64); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(0, 3)->command, CMD_SPEED); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetpModCommand(0, 3)->param, 0x11); + + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetNumRows(), 64); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns.IsPatternEmpty(1), false); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetpModCommand(63, 3)->param, 0x04); +} + + // Test file loading and saving void TestLoadSaveFile() //--------------------- @@ -799,6 +923,24 @@ TestLoadXMFile(pModDoc); pModDoc->OnCloseDocument(); } + + // Test S3M file loading + { + CModDoc *pModDoc = (CModDoc *)theApp.OpenDocumentFile(theFile + "s3m", FALSE); + TestLoadS3MFile(pModDoc); + + // Test file saving + pModDoc->DoSave(theFile + "saved.s3m"); + pModDoc->OnCloseDocument(); + + // Saving the file puts it in the MRU list... + theApp.RemoveMruItem(0); + + // Reload the saved file and test if everything is still working correctly. + pModDoc = (CModDoc *)theApp.OpenDocumentFile(theFile + "saved.s3m", FALSE); + TestLoadS3MFile(pModDoc); + pModDoc->OnCloseDocument(); + } } double Rand01() {return rand() / double(RAND_MAX);} Added: trunk/OpenMPT/mptrack/test/test.s3m =================================================================== (Binary files differ) Property changes on: trunk/OpenMPT/mptrack/test/test.s3m ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -89,7 +89,7 @@ result = ReadXM(static_cast<const LPCBYTE>(stream), length) || ReadIT(static_cast<const LPCBYTE>(stream), length) - || ReadS3M(static_cast<const LPCBYTE>(stream), length) + || ReadS3M(unpackedFile) || ReadMTM(static_cast<const LPCBYTE>(stream), length) || ReadMod(unpackedFile); } Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -224,6 +224,7 @@ SwapBytesBE(loopLength); } + // Convert an MOD sample header to OpenMPT's internal sample header. void ConvertToMPT(ModSample &mptSmp) const { mptSmp.uFlags = 0; @@ -278,7 +279,7 @@ } } - // Convert OpenMPT's internal sample header to a MOD sample header. + // Convert OpenMPT's internal sample header to an MOD sample header. SmpLength ConvertToMOD(const ModSample &mptSmp) { SmpLength writeLength = mptSmp.nLength; @@ -729,13 +730,13 @@ extern WORD ProTrackerPeriodTable[6*12]; -bool CSoundFile::SaveMod(LPCSTR lpszFileName) -//------------------------------------------- +bool CSoundFile::SaveMod(LPCSTR lpszFileName) const +//------------------------------------------------- { FILE *f; - if ((!m_nChannels) || (!lpszFileName)) return false; - if ((f = fopen(lpszFileName, "wb")) == NULL) return false; + if(m_nChannels == 0 || lpszFileName == nullptr) return false; + if((f = fopen(lpszFileName, "wb")) == nullptr) return false; // Write song title { @@ -747,7 +748,7 @@ vector<SmpLength> sampleLength(32, 0); vector<SAMPLEINDEX> sampleSource(32, 0); - if(m_nInstruments) + if(GetNumInstruments()) { for(INSTRUMENTINDEX ins = 1; ins < 32; ins++) if (Instruments[ins]) { @@ -919,6 +920,7 @@ fwrite(&padding, 1, 1, f); } } + fclose(f); return true; } Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -2,10 +2,8 @@ * Load_s3m.cpp * ------------ * Purpose: S3M (ScreamTracker 3) module loader / saver - * Notes : This code is OLD and HORRIBLE! - * Authors: Olivier Lapicque - * Adam Goode (endian and char fixes for PPC) - * OpenMPT Devs + * Notes : (currently none) + * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ @@ -14,69 +12,14 @@ #include "Loaders.h" #include "../mptrack/version.h" #ifdef MODPLUG_TRACKER -#include "../mptrack/moddoc.h" +#include "../mptrack/moddoc.h" // Logging #endif // MODPLUG_TRACKER -#pragma warning(disable:4244) //"conversion from 'type1' to 'type2', possible loss of data" -typedef struct tagS3MSAMPLESTRUCT -{ - BYTE type; - CHAR dosname[12]; - BYTE hmem; - WORD memseg; - DWORD length; - DWORD loopbegin; - DWORD loopend; - BYTE vol; - BYTE bReserved; - BYTE pack; - BYTE flags; - DWORD finetune; - DWORD dwReserved; - WORD intgp; - WORD int512; - DWORD lastused; - CHAR name[28]; - CHAR scrs[4]; -} S3MSAMPLESTRUCT; - - -typedef struct tagS3MFILEHEADER -{ - CHAR name[28]; - BYTE b1A; - BYTE type; - WORD reserved1; - WORD ordnum; - WORD insnum; - WORD patnum; - WORD flags; - WORD cwtv; - WORD version; - DWORD scrm; // "SCRM" = 0x4D524353 - BYTE globalvol; - BYTE speed; - BYTE tempo; - BYTE mastervol; - BYTE ultraclicks; - BYTE panning_present; - BYTE reserved2[8]; - WORD special; - BYTE channels[32]; -} S3MFILEHEADER; - -enum -{ - S3I_TYPE_NONE = 0, - S3I_TYPE_PCM = 1, - S3I_TYPE_ADMEL = 2, -}; - void CSoundFile::S3MConvert(ModCommand &m, bool fromIT) const //-------------------------------------------------------- { - switch (m.command | 0x40) + switch(m.command | 0x40) { case 'A': m.command = CMD_SPEED; break; case 'B': m.command = CMD_POSITIONJUMP; break; @@ -108,7 +51,7 @@ // Chars under 0x40 don't save properly, so map : to ] and # to [. case ']': m.command = CMD_DELAYCUT; break; case '[': m.command = CMD_XPARAM; break; - default: m.command = 0; + default: m.command = CMD_NONE; } } @@ -120,10 +63,10 @@ { case CMD_SPEED: command = 'A'; break; case CMD_POSITIONJUMP: command = 'B'; break; - case CMD_PATTERNBREAK: command = 'C'; if (!toIT) param = ((param / 10) << 4) + (param % 10); break; + case CMD_PATTERNBREAK: command = 'C'; if(!toIT) param = ((param / 10) << 4) + (param % 10); break; case CMD_VOLUMESLIDE: command = 'D'; break; - case CMD_PORTAMENTODOWN: command = 'E'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break; - case CMD_PORTAMENTOUP: command = 'F'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break; + case CMD_PORTAMENTODOWN: command = 'E'; if (param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; + case CMD_PORTAMENTOUP: command = 'F'; if (param >= 0xE0 && (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) param = 0xDF; break; case CMD_TONEPORTAMENTO: command = 'G'; break; case CMD_VIBRATO: command = 'H'; break; case CMD_TREMOR: command = 'I'; break; @@ -143,13 +86,12 @@ case CMD_GLOBALVOLSLIDE: command = 'W'; break; case CMD_PANNING8: command = 'X'; - if (toIT && !(m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM))) + if(toIT && !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { if (param == 0xA4) { command = 'S'; param = 0x91; } else if (param <= 0x80) { param <<= 1; if (param > 255) param = 255; } else - command = param = 0; - } else - if (!toIT && (m_nType & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM))) + command = 0; + } else if (!toIT && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM | MOD_TYPE_MOD))) { param >>= 1; } @@ -163,19 +105,19 @@ command = '\\'; break; case CMD_XFINEPORTAUPDOWN: - if (param & 0x0F) switch(param & 0xF0) + if(param & 0x0F) switch(param & 0xF0) { case 0x10: command = 'F'; param = (param & 0x0F) | 0xE0; break; case 0x20: command = 'E'; param = (param & 0x0F) | 0xE0; break; case 0x90: command = 'S'; break; - default: command = param = 0; - } else command = param = 0; + default: command = 0; + } else command = 0; break; case CMD_MODCMDEX: command = 'S'; switch(param & 0xF0) { - case 0x00: command = param = 0; break; + case 0x00: command = 0; break; case 0x10: command = 'F'; param |= 0xF0; break; case 0x20: command = 'E'; param |= 0xF0; break; case 0x30: param = (param & 0x0F) | 0x10; break; @@ -184,32 +126,280 @@ case 0x60: param = (param & 0x0F) | 0xB0; break; case 0x70: param = (param & 0x0F) | 0x40; break; case 0x90: command = 'Q'; param &= 0x0F; break; - case 0xA0: if (param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command=param=0; break; - case 0xB0: if (param & 0x0F) { command = 'D'; param |= 0xF0; } else command=param=0; break; + case 0xA0: if(param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command = 0; break; + case 0xB0: if(param & 0x0F) { command = 'D'; param |= 0xF0; } else command = 0; break; } break; - // Chars under 0x40 don't save properly, so map : to ] and # to [. + // Chars under 0x40 don't save properly, so map : to ] and # to [. case CMD_DELAYCUT: if(compatibilityExport || !toIT) - command = param = 0; + command = 0; else command = ']'; break; case CMD_XPARAM: if(compatibilityExport || !toIT) - command = param = 0; + command = 0; else command = '['; break; default: - command = param = 0; + command = 0; } + if(command == 0) + { + param = 0; + } command &= ~0x40; } -// Functor for fixing VBlank MODs and MODs with 7-bit panning +#pragma pack(push, 1) + +// S3M File Header +struct S3MFileHeader +{ + // Magic Bytes + enum S3MMagic + { + idSCRM = 0x4D524353, + idEOF = 0x1A, + idS3MType = 0x10, + idPanning = 0xFC, + }; + + // Tracker Versions in the cwtv field + enum S3MTrackerVersions + { + trackerMask = 0xF000, + versionMask = 0x0FFF, + + trkScreamTracker = 0x1000, + trkImagoOrpheus = 0x2000, + trkImpulseTracker = 0x3000, + trkSchismTracker = 0x4000, + trkOpenMPT = 0x5000, + + trkST3_20 = 0x1320, + trkIT2_14 = 0x3214, + }; + + // Flags + enum S3MHeaderFlags + { + zeroVolOptim = 0x08, // Volume 0 optimisations + amigaLimits = 0x10, // Enforce Amiga limits + fastVolumeSlides = 0x40, // Fast volume slides (like in ST3.00) + }; + + // S3M Format Versions + enum S3MFormatVersion + { + oldVersion = 0x01, // Old Version, signed samples + newVersion = 0x02, // New Version, unsigned samples + }; + + char name[28]; // Song Title + uint8 dosEof; // Supposed to be 0x1A, but even ST3 seems to ignore this sometimes (see STRSHINE.S3M by Purple Motion) + uint8 fileType; // File Type, 0x10 = ST3 module + char reserved1[2]; // Reserved + uint16 ordNum; // Number of order items + uint16 smpNum; // Number of sample parapointers + uint16 patNum; // Number of pattern parapointers + uint16 flags; // Flags, see S3MHeaderFlags + uint16 cwtv; // "Made With" Tracker ID, see S3MTrackerVersions + uint16 formatVersion; // Format Version, see S3MFormatVersion + uint32 magic; // "SCRM" magic bytes + uint8 globalVol; // Default Global Volume (0...64) + uint8 speed; // Default Speed (1...254) + uint8 tempo; // Default Tempo (33...255) + uint8 masterVolume; // Sample Volume (0...127, stereo if high bit is set) + uint8 ultraClicks; // Number of channels used for ultra click removal + uint8 usePanningTable; // 0xFC => read extended panning table + char reserved2[8]; // More reserved bytes + uint16 special; // Pointer to special custom data (unused) + uint8 channels[32]; // Channel setup + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(ordNum); + SwapBytesLE(smpNum); + SwapBytesLE(patNum); + SwapBytesLE(flags); + SwapBytesLE(cwtv); + SwapBytesLE(formatVersion); + SwapBytesLE(magic); + } +}; + +STATIC_ASSERT(sizeof(S3MFileHeader) == 96); + + +// S3M Sample Header +struct S3MSampleHeader +{ + enum SampleMagic + { + idSCRS = 0x53524353, + }; + + enum SampleType + { + typeNone = 0, + typePCM = 1, + typeAdMel = 2, + }; + + enum SampleFlags + { + smpLoop = 0x01, + smpStereo = 0x02, + smp16Bit = 0x04, + }; + + enum SamplePacking + { + pUnpacked = 0x00, // PCM + pDP30ADPCM = 0x01, // Unused packing type + pADPCM = 0x04, // MODPlugin ADPCM :( + }; + + uint8 sampleType; // Sample type, see SampleType + char filename[12]; // Sample filename + uint8 dataPointer[3]; // Pointer to sample data (divided by 16) + uint32 length; // Sample length, in samples + uint32 loopStart; // Loop start, in samples + uint32 loopEnd; // Loop end, in samples + uint8 defaultVolume; // Default volume (0...64) + char reserved1; // Reserved + uint8 pack; // Packing algorithm, SamplePacking + uint8 flags; // Sample flags + uint32 c5speed; // Middle-C frequency + char reserved2[12]; // Reserved + Internal ST3 stuff + char name[28]; // Sample name + uint32 magic; // "SCRS" magic bytes + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c5speed); + SwapBytesLE(magic); + } + + // Convert an S3M sample header to OpenMPT's internal sample header. + void ConvertToMPT(ModSample &mptSmp) const + { + StringFixer::ReadString<StringFixer::maybeNullTerminated>(mptSmp.filename, filename); + + if((sampleType == typePCM || sampleType == typeNone) && magic == idSCRS) + { + // Sample Length and Loops + if(sampleType == typePCM) + { + mptSmp.nLength = min(length, MAX_SAMPLE_LENGTH); + mptSmp.nLoopStart = min(loopStart, mptSmp.nLength - 1); + mptSmp.nLoopEnd = min(loopEnd, mptSmp.nLength); + mptSmp.uFlags = (flags & smpLoop) ? CHN_LOOP : 0; + } else + { + mptSmp.nLength = 0; + mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; + mptSmp.uFlags = 0; + } + + if(mptSmp.nLoopEnd < 2 || mptSmp.nLoopStart >= mptSmp.nLoopEnd || mptSmp.nLoopEnd - mptSmp.nLoopStart < 1) + { + mptSmp.nLoopStart = mptSmp.nLoopEnd = 0; + mptSmp.uFlags = 0; + } + + // Volume / Panning + mptSmp.nVolume = min(defaultVolume, 64) * 4; + mptSmp.nGlobalVol = 64; + mptSmp.nPan = 128; + + // C-5 frequency + mptSmp.nC5Speed = c5speed; + if(mptSmp.nC5Speed == 0) + { + mptSmp.nC5Speed = 8363; + } else if(mptSmp.nC5Speed < 1024) + { + mptSmp.nC5Speed = 1024; + } + } + } + + // Convert OpenMPT's internal sample header to an S3M sample header. + SmpLength ConvertToS3M(const ModSample &mptSmp) + { + SmpLength smpLength = 0; + StringFixer::WriteString<StringFixer::maybeNullTerminated>(filename, mptSmp.filename); + + if(mptSmp.pSample != nullptr) + { + sampleType = typePCM; + length = static_cast<uint32>(min(mptSmp.nLength, uint32_max)); + loopStart = static_cast<uint32>(min(mptSmp.nLoopStart, uint32_max)); + loopEnd = static_cast<uint32>(min(mptSmp.nLoopEnd, uint32_max)); + + smpLength = length; + + flags = (mptSmp.uFlags & CHN_LOOP) ? smpLoop : 0; + if(mptSmp.uFlags & CHN_16BIT) + { + flags |= smp16Bit; + } + if(mptSmp.uFlags & CHN_STEREO) + { + flags |= smpStereo; + } + } else + { + sampleType = typeNone; + } + + defaultVolume = static_cast<uint8>(min(mptSmp.nVolume / 4, 64)); + if(mptSmp.nC5Speed != 0) + { + c5speed = mptSmp.nC5Speed; + } else + { + c5speed = CSoundFile::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune); + } + magic = idSCRS; + + return smpLength; + } + +}; + + +// Pattern decoding flags +enum S3MPattern +{ + s3mEndOfRow = 0x00, + s3mChannelMask = 0x1F, + s3mNotePresent = 0x20, + s3mVolumePresent = 0x40, + s3mEffectPresent = 0x80, + s3mAnyPresent = 0xE0, + + s3mNoteOff = 0xFE, + s3mNoteNone = 0xFF, +}; + +STATIC_ASSERT(sizeof(S3MSampleHeader) == 80); + +#pragma pack(pop) + + +// Functor for fixing PixPlay 4-Bit Zxx panning commands struct FixPixPlayPanning //====================== { @@ -224,587 +414,688 @@ }; -bool CSoundFile::ReadS3M(const BYTE *lpStream, const DWORD dwMemLength) -//--------------------------------------------------------------------- +bool CSoundFile::ReadS3M(FileReader &file) +//---------------------------------------- { - if ((!lpStream) || (dwMemLength <= sizeof(S3MFILEHEADER) + 64)) return false; + file.Rewind(); - UINT insnum, patnum, nins, npat; - BYTE s[1024]; - DWORD dwMemPos; - S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream; - bool keepMidiMacros = false, hasAdlibPatches = false; + S3MFileHeader fileHeader; + if(!file.ReadConvertEndianness(fileHeader) || !file.CanRead(fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2)) + { + return false; + } - psfh.reserved1 = LittleEndianW(psfh.reserved1); - psfh.ordnum = LittleEndianW(psfh.ordnum); - psfh.insnum = LittleEndianW(psfh.insnum); - psfh.patnum = LittleEndianW(psfh.patnum); - psfh.flags = LittleEndianW(psfh.flags); - psfh.cwtv = LittleEndianW(psfh.cwtv); - psfh.version = LittleEndianW(psfh.version); - psfh.scrm = LittleEndian(psfh.scrm); - psfh.special = LittleEndianW(psfh.special); - - if (psfh.scrm != 0x4D524353) return false; - - if((psfh.cwtv & 0xF000) == 0x5000) // OpenMPT Version number (Major.Minor) + // Is it a valid S3M file? + if(fileHeader.magic != S3MFileHeader::idSCRM + || fileHeader.fileType != S3MFileHeader::idS3MType + || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion)) { - m_dwLastSavedWithVersion = (psfh.cwtv & 0x0FFF) << 16; - keepMidiMacros = true; // simply load Zxx commands + return false; } - if(psfh.cwtv == 0x1320 && psfh.special == 0 && (psfh.ordnum & 0x0F) == 0 && psfh.ultraclicks == 0 && (psfh.flags & ~0x50) == 0) + + // ST3 ignored Zxx commands, so if we find that a file was made with ST3, we should erase all MIDI macros. + bool keepMidiMacros = false; + + if((fileHeader.cwtv & S3MFileHeader::trackerMask) == S3MFileHeader::trkOpenMPT) { - // MPT 1.16 and older versions of OpenMPT + // OpenMPT Version number (Major.Minor) + m_dwLastSavedWithVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16; + } else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && (fileHeader.ordNum & 0x0F) == 0 && fileHeader.ultraClicks == 0 && (fileHeader.flags & ~0x50) == 0) + { + // MPT 1.16 and older versions of OpenMPT - Simply keep default (filter) MIDI macros m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00); - // Simply keep default (filter) MIDI macros keepMidiMacros = true; } - if((psfh.cwtv & 0xF000) >= 0x2000) + if((fileHeader.cwtv & S3MFileHeader::trackerMask) > S3MFileHeader::trkScreamTracker) { - // 2xyy - Orpheus, 3xyy - IT, 4xyy - Schism, 5xyy - OpenMPT - if((psfh.cwtv & 0xF000) != 0x3000 || psfh.cwtv >= 0x3214) + // 2xyy - Imago Orpheus, 3xyy - IT, 4xyy - Schism, 5xyy - OpenMPT + if((fileHeader.cwtv & S3MFileHeader::trackerMask) != S3MFileHeader::trkImpulseTracker || fileHeader.cwtv >= S3MFileHeader::trkIT2_14) { // Keep MIDI macros if this is not an old IT version (BABYLON.S3M by Necros has Zxx commands and was saved with IT 2.05) keepMidiMacros = true; } } - if(!keepMidiMacros) // Remove macros so they don't interfere with tunes made in trackers that don't support Zxx + m_MidiCfg.Reset(); + if(!keepMidiMacros) { + // Remove macros so they don't interfere with tunes made in trackers that don't support Zxx MemsetZero(m_MidiCfg.szMidiSFXExt); MemsetZero(m_MidiCfg.szMidiZXXExt); } - dwMemPos = sizeof(S3MFILEHEADER); m_nType = MOD_TYPE_S3M; - MemsetZero(m_szNames); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], psfh.name); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], fileHeader.name); + m_nMinPeriod = 64; + m_nMaxPeriod = 32767; + m_dwSongFlags = (fileHeader.flags & S3MFileHeader::amigaLimits) ? SONG_AMIGALIMITS : 0; + + if(fileHeader.cwtv < S3MFileHeader::trkST3_20 || (fileHeader.flags & S3MFileHeader::fastVolumeSlides) != 0) + { + m_dwSongFlags |= SONG_FASTVOLSLIDES; + } + // Speed - m_nDefaultSpeed = psfh.speed; - if (!m_nDefaultSpeed || m_nDefaultSpeed == 255) m_nDefaultSpeed = 6; + m_nDefaultSpeed = fileHeader.speed; + if(m_nDefaultSpeed == 0 || m_nDefaultSpeed == 255) + { + // Even though ST3 accepts the command AFF as expected, it mysteriously fails to load a default speed of 255... + m_nDefaultSpeed = 6; + } // Tempo - m_nDefaultTempo = psfh.tempo; - //m_nDefaultTempo = CLAMP(m_nDefaultTempo, 32, 255); - if(m_nDefaultTempo < 33) m_nDefaultTempo = 125; + m_nDefaultTempo = fileHeader.tempo; + if(m_nDefaultTempo < 33) + { + // ST3 also fails to load an otherwise valid default tempo of 32... + m_nDefaultTempo = 125; + } // Global Volume - m_nDefaultGlobalVolume = psfh.globalvol << 2; + m_nDefaultGlobalVolume = min(fileHeader.globalVol, 64) * 4; // The following check is probably not very reliable, but it fixes a few tunes, f.e. // DARKNESS.S3M by Purple Motion (ST 3.00) and "Image of Variance" by C.C.Catch (ST 3.01): - if(!m_nDefaultGlobalVolume && psfh.cwtv < 0x1320) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; - if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + if(m_nDefaultGlobalVolume == 0 && fileHeader.cwtv < S3MFileHeader::trkST3_20) + { + m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + } - m_nSamplePreAmp = CLAMP(psfh.mastervol & 0x7F, 0x10, 0x7F); // Bit 8 = Stereo (we always use stereo) + // Bit 8 = Stereo (we always use stereo) + m_nSamplePreAmp = Clamp(fileHeader.masterVolume & 0x7F, 0x10, 0x7F); - // Channels + // Channel setup m_nChannels = 4; - for (UINT ich=0; ich<32; ich++) + for(CHANNELINDEX i = 0; i < 32; i++) { - ChnSettings[ich].nVolume = 64; + ChnSettings[i].nVolume = 64; - if(psfh.channels[ich] == 0xFF) + if(fileHeader.channels[i] == 0xFF) { - ChnSettings[ich].nPan = 128; - ChnSettings[ich].dwFlags = CHN_MUTE; + ChnSettings[i].nPan = 128; + ChnSettings[i].dwFlags = CHN_MUTE; } else { - m_nChannels = ich + 1; - ChnSettings[ich].nPan = (psfh.channels[ich] & 8) ? 0xC0 : 0x40; - if (psfh.channels[ich] & 0x80) + m_nChannels = i + 1; + ChnSettings[i].nPan = (fileHeader.channels[i] & 8) ? 192 : 64; + if(fileHeader.channels[i] & 0x80) { - ChnSettings[ich].dwFlags = CHN_MUTE; - /* Detect Adlib channels: - c = channels[ich] ^ 0x80; - if(c >= 16 && c < 32) adlibChannel = true; - */ + ChnSettings[i].dwFlags = CHN_MUTE; + // Detect Adlib channels here: + // c = channels[i] ^ 0x80; + // if(c >= 16 && c < 32) adlibChannel = true; } } } - if (m_nChannels < 1) m_nChannels = 1; - if ((psfh.cwtv < 0x1320) || (psfh.flags & 0x40)) m_dwSongFlags |= SONG_FASTVOLSLIDES; - - // Reading pattern order - UINT iord = psfh.ordnum; - iord = CLAMP(iord, 1, MAX_ORDERS); - if (iord) + if(m_nChannels < 1) { - Order.ReadAsByte(lpStream+dwMemPos, iord, dwMemLength-dwMemPos); - dwMemPos += iord; + m_nChannels = 1; } - if ((iord & 1) && (lpStream[dwMemPos] == 0xFF)) dwMemPos++; - // Reading file pointers - insnum = nins = psfh.insnum; - if (insnum >= MAX_SAMPLES) insnum = MAX_SAMPLES-1; - m_nSamples = insnum; - patnum = npat = psfh.patnum; - if (patnum > MAX_PATTERNS) patnum = MAX_PATTERNS; + Order.ReadAsByte(file, fileHeader.ordNum); // Read sample header offsets - vector<WORD> smppos(nins, 0); - for(UINT i = 0; i < nins; i++, dwMemPos += 2) + vector<uint16> sampleOffsets(fileHeader.smpNum); + for(size_t i = 0; i < fileHeader.smpNum; i++) { - WORD ptr = *((WORD *)(lpStream + dwMemPos)); - smppos[i] = LittleEndianW(ptr); + sampleOffsets[i] = file.ReadUint16LE(); } // Read pattern offsets - vector<WORD> patpos(npat, 0); - for(UINT i = 0; i < npat; i++, dwMemPos += 2) + vector<uint16> patternOffsets(fileHeader.patNum); + for(size_t i = 0; i < fileHeader.patNum; i++) { - WORD ptr = *((WORD *)(lpStream + dwMemPos)); - patpos[i] = LittleEndianW(ptr); + patternOffsets[i] = file.ReadUint16LE(); } - // Read channel panning - if (psfh.panning_present == 0xFC) + // Read extended channel panning + if(fileHeader.usePanningTable == S3MFileHeader::idPanning) { - const BYTE *chnpan = lpStream+dwMemPos; - for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20) + uint8 pan[32]; + file.ReadArray(pan); + for(CHANNELINDEX i = 0; i < 32; i++) { - ChnSettings[i].nPan = (UINT(chnpan[i] & 0x0F) * 256 + 8) / 15; + if((pan[i] & 0x20) != 0) + { + ChnSettings[i].nPan = (static_cast<uint16>(pan[i] & 0x0F) * 256 + 8) / 15; + } } } - // Reading instrument headers - vector<DWORD> smpdatapos(insnum, 0); - vector<BYTE> insflags(insnum, 0); - vector<BYTE> inspack(insnum, 0); + bool hasAdlibPatches = false; - for (UINT iSmp=1; iSmp<=insnum; iSmp++) + // Reading sample headers + m_nSamples = min(fileHeader.smpNum, MAX_SAMPLES - 1); + for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++) { - UINT nInd = ((DWORD)smppos[iSmp - 1]) * 16; - if(nInd > dwMemLength || 0x50 > dwMemLength - nInd) continue; + S3MSampleHeader sampleHeader; - memcpy(s, lpStream + nInd, 0x50); - StringFixer::ReadString<StringFixer::maybeNullTerminated>(Samples[iSmp].filename, reinterpret_cast<const char *>(s + 1), 12); + if(!file.Seek(sampleOffsets[smp] * 16) || !file.ReadConvertEndianness(sampleHeader)) + { + continue; + } - insflags[iSmp - 1] = s[0x1F]; - inspack[iSmp - 1] = s[0x1E]; - s[0x4C] = 0; - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[iSmp], reinterpret_cast<const char*>(s + 0x30), 28); + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[smp + 1], sampleHeader.name); + sampleHeader.ConvertToMPT(Samples[smp + 1]); - if ((s[0] == S3I_TYPE_PCM) && (s[0x4E] == 'R') && (s[0x4F] == 'S')) + if(sampleHeader.sampleType >= S3MSampleHeader::typeAdMel) { - Samples[iSmp].nLength = CLAMP(LittleEndian(*((DWORD *)(s + 0x10))), 4, MAX_SAMPLE_LENGTH); - Samples[iSmp].nLoopStart = CLAMP(LittleEndian(*((DWORD *)(s + 0x14))), 0, Samples[iSmp].nLength - 1); - Samples[iSmp].nLoopEnd = CLAMP(LittleEndian(*((DWORD *)(s + 0x18))), 0, Samples[iSmp].nLength); - Samples[iSmp].nVolume = CLAMP(s[0x1C], 0, 64) << 2; - Samples[iSmp].nGlobalVol = 64; - if (s[0x1F] & 1) Samples[iSmp].uFlags |= CHN_LOOP; + hasAdlibPatches = true; + } - UINT c5Speed; - c5Speed = LittleEndian(*((DWORD *)(s + 0x20))); - if (!c5Speed) c5Speed = 8363; - if (c5Speed < 1024) c5Speed = 1024; - Samples[iSmp].nC5Speed = c5Speed; + const uint32 sampleOffset = (sampleHeader.dataPointer[1] << 4) | (sampleHeader.dataPointer[2] << 12) | (sampleHeader.dataPointer[0] << 20); - smpdatapos[iSmp - 1] = (s[0x0E] << 4) | (s[0x0F] << 12) | (s[0x0D] << 20); + if(sampleHeader.length != 0 && file.Seek(sampleOffset)) + { + UINT flags = (fileHeader.formatVersion == S3MFileHeader::oldVersion) ? RS_PCM8S : RS_PCM8U; + if(sampleHeader.flags & S3MSampleHeader::smp16Bit) + { + flags += 5; + } + if(sampleHeader.flags & S3MSampleHeader::smpStereo) + { + flags |= RSF_STEREO; + } + if(sampleHeader.pack == S3MSampleHeader::pADPCM) + { + flags = RS_ADPCM4; // MODPlugin :( + } - if(Samples[iSmp].nLoopEnd < 2) - Samples[iSmp].nLoopStart = Samples[iSmp].nLoopEnd = 0; - - if ((Samples[iSmp].nLoopStart >= Samples[iSmp].nLoopEnd) || (Samples[iSmp].nLoopEnd - Samples[iSmp].nLoopStart < 1)) - Samples[iSmp].nLoopStart = Samples[iSmp].nLoopEnd = 0; - Samples[iSmp].nPan = 0x80; - - } else if(s[0] >= S3I_TYPE_ADMEL) - { - hasAdlibPatches = true; + ReadSample(&Samples[smp + 1], flags, file); } } - /* Try to find out if Zxx commands are supposed to be panning commands (PixPlay). - Actually I am only aware of one module that uses this panning style, namely "Crawling Despair" by $volkraq - and I have no idea what PixPlay is, so this code is solely based on the sample text of that module. - We won't convert if there are not enough Zxx commands, too "high" Zxx commands - or there are only "left" or "right" pannings (we assume that stereo should be somewhat balanced), - and modules not made with an old version of ST3 were probably made in a tracker that supports panning anyway. */ - bool pixPlayPanning = (psfh.cwtv < 0x1320); +#ifdef MODPLUG_TRACKER + if(hasAdlibPatches && GetpModDoc() != nullptr) + { + GetpModDoc()->AddToLog("This track uses Adlib instruments, which are not supported by OpenMPT."); + } +#endif // MODPLUG_TRACKER + + + // Try to find out if Zxx commands are supposed to be panning commands (PixPlay). + // Actually I am only aware of one module that uses this panning style, namely "Crawling Despair" by $volkraq + // and I have no idea what PixPlay is, so this code is solely based on the sample text of that module. + // We won't convert if there are not enough Zxx commands, too "high" Zxx commands + // or there are only "left" or "right" pannings (we assume that stereo should be somewhat balanced), + // and modules not made with an old version of ST3 were probably made in a tracker that supports panning anyway. + bool pixPlayPanning = (fileHeader.cwtv < S3MFileHeader::trkST3_20); int zxxCountRight = 0, zxxCountLeft = 0; // Reading patterns - for (UINT iPat = 0; iPat < patnum; iPat++) + const PATTERNINDEX readPatterns = min(fileHeader.patNum, MAX_PATTERNS); + for(PATTERNINDEX pat = 0; pat < readPatterns; pat++) { - bool fail = Patterns.Insert(iPat, 64); - UINT nInd = ((DWORD)patpos[iPat]) * 16; - if (nInd == 0 || nInd > dwMemLength || 0x40 > dwMemLength - nInd) continue; - WORD len = LittleEndianW(*((WORD *)(lpStream + nInd))); - nInd += 2; - if ((!len) || (nInd + len > dwMemLength - 6) - || (fail) ) continue; - LPBYTE src = (LPBYTE)(lpStream + nInd); + if(!file.Seek(patternOffsets[pat] * 16) || Patterns.Insert(pat, 64)) + { + continue; + } - // Unpacking pattern + // Skip pattern length indication. + // Some modules, for example http://aminet.net/mods/8voic/s3m_hunt.lha seem to have a wrong pattern length - + // If you strictly adhere the pattern length, you won't read the patterns correctly in that module. + file.Skip(2); - UINT row = 0; - UINT j = 0; - while (row < 64) // this fixes ftp://us.aminet.net/pub/aminet/mods/8voic/s3m_hunt.lha (was: while (j < len)) + // Read pattern data + ROWINDEX row = 0; + PatternRow rowBase = Patterns[pat].GetRow(0); + + while(row < 64) { - if(j + nInd + 1 >= dwMemLength) break; - BYTE b = src[j++]; - if (!b) + uint8 info = file.ReadUint8(); + + if(info == s3mEndOfRow) { - if (++row >= 64) break; - } else + // End of row + if(++row < 64) + { + rowBase = Patterns[pat].GetRow(row); + } + continue; + } + + CHANNELINDEX channel = (info & s3mChannelMask); + static ModCommand dummy; + ModCommand &m = (channel < GetNumChannels()) ? rowBase[channel] : dummy; + + if(info & s3mNotePresent) { - UINT chn = b & 0x1F; - if (chn < m_nChannels) + uint8 note = file.ReadUint8(), instr = file.ReadUint8(); + + if(note < 0xF0) { - ModCommand *m = Patterns[iPat].GetpModCommand(row, chn); - if (b & 0x20) + // Note + note = (note & 0x0F) + 12 * (note >> 4) + 12 + NOTE_MIN; + } else if(note == s3mNoteOff) + { + // ^^ + note = NOTE_NOTECUT; + } else if(note == s3mNoteNone) + { + // .. + note = NOTE_NONE; + } + + m.note = note; + m.instr = instr; + } + + if(info & s3mVolumePresent) + { + uint8 volume = file.ReadUint8(); + if(volume >= 128 && volume <= 192) + { + m.volcmd = VOLCMD_PANNING; + m.vol = volume - 128; + } else + { + m.volcmd = VOLCMD_VOLUME; + m.vol = min(volume, 64); + } + } + + if(info & s3mEffectPresent) + { + uint8 command = file.ReadUint8(), param = file.ReadUint8(); + + if(command != 0) + { + m.command = command; + m.param = param; + S3MConvert(m, false); + } + + if(m.command == CMD_MIDI) + { + // PixPlay panning test + if(m.param > 0x0F) { - if(j + nInd + 2 >= dwMemLength) break; - m->note = src[j++]; - if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12 * (m->note >> 4) + 13; - else if (m->note == 0xFF) m->note = NOTE_NONE; - m->instr = src[j++]; - } - if (b & 0x40) + // PixPlay has Z00 to Z0F panning, so we ignore this. + pixPlayPanning = false; + } else { - if(j + nInd + 1 >= dwMemLength) break; - UINT vol = src[j++]; - if ((vol >= 128) && (vol <= 192)) + if(m.param < 0x08) { - vol -= 128; - m->volcmd = VOLCMD_PANNING; - } else + zxxCountLeft++; + } else if(m.param > 0x08) { - if (vol > 64) vol = 64; - m->volcmd = VOLCMD_VOLUME; + zxxCountRight++; } - m->vol = vol; } - if (b & 0x80) - { - if(j + nInd + 2 >= dwMemLength) break; - m->command = src[j++]; - m->param = src[j++]; - if (m->command) S3MConvert(*m, false); - if(m->command == CMD_MIDI) - { - if(m->param > 0x0F) - { - // PixPlay has Z00 to Z0F panning, so we ignore this. - pixPlayPanning = false; - } - else - { - if(m->param < 0x08) zxxCountLeft++; - if(m->param > 0x08) zxxCountRight++; - } - } - } - } else - { - if (b & 0x20) j += 2; - if (b & 0x40) j++; - if (b & 0x80) j += 2; } } } } - if((zxxCountLeft + zxxCountRight) >= m_nChannels && pixPlayPanning && (-zxxCountLeft + zxxCountRight < (int)m_nChannels)) + if(pixPlayPanning && zxxCountLeft + zxxCountRight >= m_nChannels && (-zxxCountLeft + zxxCountRight) < static_cast<int>(m_nChannels)) { // There are enough Zxx commands, so let's assume this was made to be played with PixPlay Patterns.ForEachModCommand(FixPixPlayPanning()); } - // Reading samples - for (UINT iRaw = 1; iRaw <= insnum; iRaw++) if (Samples[iRaw].nLength) - { - UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U; - if (insflags[iRaw-1] & 4) flags += 5; - if (insflags[iRaw-1] & 2) flags |= RSF_STEREO; - if (inspack[iRaw-1] == 4) flags = RS_ADPCM4; // MODPlugin :( - if(smpdatapos[iRaw - 1] < dwMemLength) - { - dwMemPos = smpdatapos[iRaw - 1]; - } - if(dwMemPos < dwMemLength) - { - dwMemPos += ReadSample(&Samples[iRaw], flags, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos); - } - } - m_nMinPeriod = 64; - m_nMaxPeriod = 32767; - if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS; - -#ifdef MODPLUG_TRACKER - if(hasAdlibPatches && GetpModDoc() != nullptr) - { - GetpModDoc()->AddToLog("This track uses Adlib instruments, which are not supported by OpenMPT."); - } -#endif // MODPLUG_TRACKER - return true; } #ifndef MODPLUG_NO_FILESAVE -#pragma warning(disable:4100) //unreferenced formal parameter -static const BYTE S3MFiller[16] = +bool CSoundFile::SaveS3M(LPCSTR lpszFileName) const +//------------------------------------------------- { - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 -}; + static const uint8 filler[16] = + { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + }; - -bool CSoundFile::SaveS3M(LPCSTR lpszFileName) -//------------------------------------------- -{ FILE *f; - BYTE header[0x60]; - UINT nbo,nbi,nbp,i; - WORD patptr[128]; - WORD insptr[128]; - S3MSAMPLESTRUCT insex[128]; + if(m_nChannels == 0 || lpszFileName == nullptr) return false; + if((f = fopen(lpszFileName, "wb")) == nullptr) return false; - if ((!m_nChannels) || (!lpszFileName)) return false; - if ((f = fopen(lpszFileName, "wb")) == NULL) return false; - // Writing S3M header - memset(header, 0, sizeof(header)); - memset(insex, 0, sizeof(insex)); - memcpy(header, m_szNames[0], 0x1C); - header[0x1B] = 0; - header[0x1C] = 0x1A; - header[0x1D] = 0x10; + S3MFileHeader fileHeader; + MemsetZero(fileHeader); - nbo = Order.GetLengthTailTrimmed(); - if (nbo < 2) - nbo = 2; - else if (nbo & 1) // number of orders must be even - nbo++; - if(nbo > 0xF0) nbo = 0xF0; // sequence too long - header[0x20] = nbo & 0xFF; - header[0x21] = nbo >> 8; - nbi = m_nInstruments; - if (!nbi) nbi = m_nSamples; - if (nbi > 99) nbi = 99; - header[0x22] = nbi & 0xFF; - header[0x23] = nbi >> 8; - nbp = 0; - for (i = 0; Patterns[i]; i++) { nbp = i+1; if (nbp >= MAX_PATTERNS) break; } - for (ORDERINDEX nOrd = 0; nOrd < Order.GetLengthTailTrimmed(); nOrd++) if ((Order[nOrd] < MAX_PATTERNS) && (Order[nOrd] >= nbp)) nbp = Order[nOrd] + 1; - header[0x24] = nbp & 0xFF; - header[0x25] = nbp >> 8; - if (m_dwSongFlags & SONG_FASTVOLSLIDES) header[0x26] |= 0x40; - if ((m_nMaxPeriod < 20000) || (m_dwSongFlags & SONG_AMIGALIMITS)) header[0x26] |= 0x10; + StringFixer::WriteString<StringFixer::nullTerminated>(fileHeader.name, m_szNames[0]); + fileHeader.dosEof = S3MFileHeader::idEOF; + fileHeader.fileType = S3MFileHeader::idS3MType; + // Orders + ORDERINDEX writeOrders = Order.GetLengthTailTrimmed(); + if(writeOrders < 2) + { + writeOrders = 2; + } else if((writeOrders % 2) != 0) + { + // Number of orders should be even + writeOrders++; + } + LimitMax(writeOrders, static_cast<ORDERINDEX>(256)); + fileHeader.ordNum = static_cast<uint16>(writeOrders); + + // Samples + SAMPLEINDEX writeSamples = static_cast<SAMPLEINDEX>(GetNumInstruments()); + if(fileHeader.smpNum == 0) + { + writeSamples = GetNumSamples(); + } + writeSamples = Clamp(writeSamples, static_cast<SAMPLEINDEX>(1), static_cast<SAMPLEINDEX>(99)); + fileHeader.smpNum = static_cast<uint16>(writeSamples); + + // Patterns + PATTERNINDEX writePatterns = min(Patterns.GetNumPatterns(), 100u); + fileHeader.patNum = static_cast<uint16>(writePatterns); + + // Flags + if(m_dwSongFlags & SONG_FASTVOLSLIDES) + { + fileHeader.flags |= S3MFileHeader::fastVolumeSlides; + } + if(m_nMaxPeriod < 20000 || (m_dwSongFlags & SONG_AMIGALIMITS)) + { + fileHeader.flags |= S3MFileHeader::amigaLimits; + } + // Version info following: ST3.20 = 0x1320 - // Most significant nibble: 1 = ST3, 2 = Orpheus, 3 = IT, 4 = Schism, 5 = MPT + // Most significant nibble = Tracker ID, see S3MFileHeader::S3MTrackerVersions // Following: One nibble = Major version, one byte = Minor version (hex) - MptVersion::VersionNum vVersion = MptVersion::num; - header[0x28] = (BYTE)((vVersion >> 16) & 0xFF); // the "17" in OpenMPT 1.17 - header[0x29] = 0x50 | (BYTE)((vVersion >> 24) & 0x0F); // the "1." in OpenMPT 1.17 + OpenMPT Identifier 5 (works only for versions up to 9.99 :)) - header[0x2A] = 0x02; // Version = 1 => Signed samples - header[0x2B] = 0x00; - header[0x2C] = 'S'; - header[0x2D] = 'C'; - header[0x2E] = 'R'; - header[0x2F] = 'M'; - header[0x30] = m_nDefaultGlobalVolume >> 2; - header[0x31] = CLAMP(m_nDefaultSpeed, 1, 254); - header[0x32] = CLAMP(m_nDefaultTempo, 33, 255); - header[0x33] = CLAMP(m_nSamplePreAmp, 0x10, 0x7F) | 0x80; // Bit 8 = Stereo - header[0x34] = 0x08; // 8 Channels for UltraClick removal (default) - header[0x35] = 0xFC; // Write pan positions - for (i=0; i<32; i++) + fileHeader.cwtv = S3MFileHeader::trackerMask | static_cast<uint16>((MptVersion::num >> 16) & S3MFileHeader::versionMask); + fileHeader.formatVersion = S3MFileHeader::newVersion; + fileHeader.magic = S3MFileHeader::idSCRM; + + // Song Variables + fileHeader.globalVol = static_cast<uint8>(min(m_nDefaultGlobalVolume / 4, 64)); + fileHeader.speed = static_cast<uint8>(Clamp(m_nDefaultSpeed, 1u, 254u)); + fileHeader.tempo = static_cast<uint8>(Clamp(m_nDefaultTempo, 33u, 255u)); + fileHeader.masterVolume = static_cast<uint8>(Clamp(m_nSamplePreAmp, 16u, 127u) | 0x80); + fileHeader.ultraClicks = 8; + fileHeader.usePanningTable = S3MFileHeader::idPanning; + + // Channel Table + for(CHANNELINDEX chn = 0; chn < 32; chn++) { - if (i < m_nChannels) + if(chn < GetNumChannels()) { - UINT tmp = (i & 0x0F) >> 1; - tmp = (i & 0x10) | ((i & 1) ? 8 + tmp : tmp); - if((ChnSettings[i].dwFlags & CHN_MUTE) != 0) tmp |= 0x80; - header[0x40+i] = tmp; - } else header[0x40+i] = 0xFF; + uint8 ch = (chn & 0x0F) >> 1; + ch = (chn & 0x10) | ((chn & 1) ? 8 + ch : ch); + if((ChnSettings[chn].dwFlags & CHN_MUTE) != 0) + { + ch |= 0x80; + } + fileHeader.channels[chn] = ch; + } else + { + fileHeader.channels[chn] = 0xFF; + } } - fwrite(header, 0x60, 1, f); - nbo = Order.WriteAsByte(f, nbo); - memset(patptr, 0, sizeof(patptr)); - memset(insptr, 0, sizeof(insptr)); - UINT ofs0 = 0x60 + nbo; - UINT ofs1 = ((0x60 + nbo + nbi * 2 + nbp * 2 + 15) & 0xFFF0) + ((header[0x35] == 0xFC) ? 0x20 : 0); - UINT ofs = ofs1; - for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16); - for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16); - fwrite(insptr, nbi, 2, f); - fwrite(patptr, nbp, 2, f); - if (header[0x35] == 0xFC) + + fileHeader.ConvertEndianness(); + fwrite(&fileHeader, sizeof(fileHeader), 1, f); + Order.WriteAsByte(f, writeOrders); + + // Comment about parapointers stolen from Schism Tracker: + // The sample data parapointers are 24+4 bits, whereas pattern data and sample headers are only 16+4 + // bits -- so while the sample data can be written up to 268 MB within the file (starting at 0xffffff0), + // the pattern data and sample headers are restricted to the first 1 MB (starting at 0xffff0). In effect, + // this practically requires the sample data to be written last in the file, as it is entirely possible + // (and quite easy, even) to write more than 1 MB of sample data in a file. + // The "practical standard order" listed in TECH.DOC is sample headers, patterns, then sample data. + + // Calculate offset of first sample header... + size_t sampleHeaderOffset = ftell(f) + (writeSamples + writePatterns) * 2 + 32; + // ...which must be a multiple of 16, because parapointers omit the lowest 4 bits. + sampleHeaderOffset = (sampleHeaderOffset + 15) & ~15; + + vector<uint16> sampleOffsets(writeSamples); + for(SAMPLEINDEX smp = 0; smp < writeSamples; smp++) { - BYTE chnpan[32]; - for (i=0; i<32; i++) + STATIC_ASSERT((sizeof(S3MSampleHeader) % 16) == 0); + sampleOffsets[smp] = static_cast<uint16>((sampleHeaderOffset + smp * sizeof(S3MSampleHeader)) / 16); + SwapBytesLE(sampleOffsets[smp]); + } + + if(writeSamples != 0) + { + fwrite(&sampleOffsets[0], 2, writeSamples, f); + } + + size_t patternPointerOffset = ftell(f); + size_t firstPatternOffset = sampleHeaderOffset + writeSamples * sizeof(S3MSampleHeader); + vector<uint16> patternOffsets(writePatterns); + + // Need to calculate the real offsets later. + if(writePatterns != 0) + { + fwrite(&patternOffsets[0], 2, writePatterns, f); + } + + // Write channel panning + uint8 chnPan[32]; + for(CHANNELINDEX pat = 0; pat < 32; pat++) + { + if(pat < GetNumChannels()) { - const UINT nPan = ((ChnSettings[i].nPan * 15 + 128) / 256); - chnpan[i] = (i < m_nChannels) ? (0x20 | nPan) : 0x08; + chnPan[pat] = static_cast<uint8>(((ChnSettings[pat].nPan * 15 + 128) / 256)) | 0x20; + } else + { + chnPan[pat] = 0x08; } - fwrite(chnpan, 0x20, 1, f); } - if ((nbi*2+nbp*2) & 0x0F) + fwrite(chnPan, 32, 1, f); + + // Do we need to fill up the file with some padding bytes for 16-Byte alignment? + size_t curPos = ftell(f); + if(curPos < sampleHeaderOffset) { - fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f); + ASSERT(sampleHeaderOffset - curPos < 16); + fwrite(filler, sampleHeaderOffset - curPos, 1, f); } - fseek(f, ofs1, SEEK_SET); - ofs1 = ftell(f); - fwrite(insex, nbi, 0x50, f); - // Packing patterns - ofs += nbi * 0x50; - for (i = 0; i < nbp; i++) + + // Don't write sample headers for now, we are lacking the sample offset data. + fseek(f, firstPatternOffset, SEEK_SET); + + // Write patterns + for(PATTERNINDEX pat = 0; pat < writePatterns; pat++) { - WORD len = 64; - vector<BYTE> buffer(5 * 1024, 0); - patptr[i] = ofs / 16; - if (Patterns[i]) + ASSERT((ftell(f) % 16) == 0); + patternOffsets[pat] = static_cast<uint16>(ftell(f) / 16); + SwapBytesLE(patternOffsets[pat]); + + vector<uint8> buffer; + buffer.reserve(5 * 1024); + // Reserve space for length bytes + buffer.resize(2, 0); + + if(Patterns.IsValidPat(pat)) { - len = 2; - ModCommand *p = Patterns[i]; - for (UINT row=0; row<64; row++) if (row < Patterns[i].GetNumRows()) + for(ROWINDEX row = 0; row < 64; row++) { - for (UINT j=0; j<m_nChannels; j++) + if(row >= Patterns[pat].GetNumRows()) { - UINT b = j; - ModCommand *m = &p[row*m_nChannels+j]; - uint8 note = m->note; - ModCommand::VOLCMD volcmd = m->volcmd; - uint8 vol = m->vol; - uint8 command = m->command; - uint8 param = m->param; + // Invent empty row + buffer.push_back(s3mEndOfRow); + continue; + } - if ((note) || (m->instr)) b |= 0x20; + const PatternRow rowBase = Patterns[pat].GetRow(row); - if (!note) note = 0xFF; // no note - else if (note >= NOTE_MIN_SPECIAL) note = 0xFE; // special notes (notecut, noteoff etc) - else if (note < 13) note = NOTE_NONE; // too low - else note -= 13; + CHANNELINDEX writeChannels = min(32, GetNumChannels()); + for(CHANNELINDEX chn = 0; chn < writeChannels; chn++) + { + ModCommand &m = rowBase[chn]; - if (note < 0xFE) note = (note % 12) + ((note / 12) << 4); - if (command == CMD_VOLUME) + uint8 info = static_cast<uint8>(chn); + uint8 note = m.note; + ModCommand::VOLCMD volcmd = m.volcmd; + uint8 vol = m.vol; + uint8 command = m.command; + uint8 param = m.param; + + if(note != NOTE_NONE || m.instr != 0) { - command = 0; + info |= s3mNotePresent; + + if(note == NOTE_NONE) + { + // No Note, or note is too low + note = s3mNoteNone; + } else if(note >= NOTE_MIN_SPECIAL) + { + // Note Cut + note = s3mNoteOff; + } else if(note < 12 + NOTE_MIN) + { + // Too low + note = 0; + } else if(note <= NOTE_MAX) + { + note -= (12 + NOTE_MIN); + note = (note % 12) + ((note / 12) << 4); + } + } + + if(command == CMD_VOLUME) + { + command = CMD_NONE; volcmd = VOLCMD_VOLUME; vol = min(param, 64); } - if (volcmd == VOLCMD_VOLUME) b |= 0x40; else - if (volcmd == VOLCMD_PANNING) { vol |= 0x80; b |= 0x40; } - if (command) + + if(volcmd == VOLCMD_VOLUME) { + info |= s3mVolumePresent; + } else if(volcmd == VOLCMD_PANNING) + { + info |= s3mVolumePresent; + vol |= 0x80; + } + + if(command != CMD_NONE) + { S3MSaveConvert(command, param, false, true); - if (command) b |= 0x80; + if(command) + { + info |= s3mEffectPresent; + } } - if (b & 0xE0) + + if(info & s3mAnyPresent) { - buffer[len++] = b; - if (b & 0x20) + buffer.push_back(info); + if(info & s3mNotePresent) { - buffer[len++] = note; - buffer[len++] = m->instr; + buffer.push_back(note); + buffer.push_back(m.instr); } - if (b & 0x40) + if(info & s3mVolumePresent) { - buffer[len++] = vol; + buffer.push_back(vol); } - if (b & 0x80) + if(info & s3mEffectPresent) { - buffer[len++] = command; - buffer[len++] = param; + buffer.push_back(command); + buffer.push_back(param); } - if (len > buffer.size() - 20) - { //Buffer running out? Make it larger. - buffer.resize(buffer.size() + 1024, 0); - } } } - buffer[len++] = 0; - if (len > buffer.size() - 20) - { //Buffer running out? Make it larger. - buffer.resize(buffer.size() + 1024, 0); - } + + buffer.push_back(s3mEndOfRow); } + } else + { + // Invent empty pattern + buffer.insert(buffer.end(), 64, s3mEndOfRow); } - buffer[0] = (len) & 0xFF; - buffer[1] = (len) >> 8; - len = (len + 15) & (~0x0F); - fwrite(&buffer[0], len, 1, f); - ofs += len; + + size_t length = min(buffer.size(), uint16_max); + buffer[0] = static_cast<uint8>(length & 0xFF); + buffer[1] = static_cast<uint8>((length >> 8) & 0xFF); + + if((buffer.size() % 16) != 0) + { + // Add padding bytes + buffer.insert(buffer.end(), 16 - (buffer.size() % 16), 0); + } + + fwrite(&buffer[0], buffer.size(), 1, f); } - // Writing samples - for (i=1; i<=nbi; i++) + + size_t sampleDataOffset = ftell(f); + + // Write samples + vector<S3MSampleHeader> sampleHeader(writeSamples); + + for(SAMPLEINDEX smp = 0; smp < writeSamples; smp++) { - ModSample *pSmp = &Samples[i]; - if (m_nInstruments) + SAMPLEINDEX realSmp = smp + 1; + if(GetNumInstruments() != 0 && Instruments[smp] != nullptr) { - pSmp = Samples; - if (Instruments[i]) + // Find some valid sample associated with this instrument. + for(size_t i = 0; i < CountOf(Instruments[smp]->Keyboard); i++) { - for (UINT j=0; j<128; j++) + if(Instruments[smp]->Keyboard[i] > 0 && Instruments[smp]->Keyboard[i] <= GetNumSamples()) { - UINT n = Instruments[i]->Keyboard[j]; - if ((n) && (n < MAX_INSTRUMENTS)) - { - pSmp = &Samples[n]; - break; - } + realSmp = Instruments[smp]->Keyboard[i]; + break; } } } - StringFixer::WriteString<StringFixer::maybeNullTerminated>(insex[i - 1].dosname, pSmp->filename); - StringFixer::WriteString<StringFixer::nullTerminated>(insex[i-1].name, m_szNames[i]); + if(realSmp > GetNumSamples()) + { + continue; + } - memcpy(insex[i-1].scrs, "SCRS", 4); + SmpLength smpLength = sampleHeader[smp].ConvertToS3M(Samples[realSmp]); - insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20); - insex[i-1].memseg = (WORD)((DWORD)ofs >> 4); - if (pSmp->pSample) + StringFixer::WriteString<StringFixer::nullTerminated>(sampleHeader[smp].name, m_szNames[realSmp]); + + if(Samples[realSmp].pSample) { - insex[i-1].type = 1; - insex[i-1].length = pSmp->nLength; - insex[i-1].loopbegin = pSmp->nLoopStart; - insex[i-1].loopend = pSmp->nLoopEnd; - insex[i-1].vol = pSmp->nVolume / 4; - insex[i-1].flags = (pSmp->uFlags & CHN_LOOP) ? 1 : 0; - if (pSmp->nC5Speed) - insex[i-1].finetune = min(pSmp->nC5Speed, 0xFFFF); - else - insex[i-1].finetune = TransposeToFrequency(pSmp->RelativeTone, pSmp->nFineTune); + // Write sample data + sampleHeader[smp].dataPointer[1] = static_cast<uint8>((sampleDataOffset >> 4) & 0xFF); + sampleHeader[smp].dataPointer[2] = static_cast<uint8>((sampleDataOffset >> 12) & 0xFF); + sampleHeader[smp].dataPointer[0] = static_cast<uint8>((sampleDataOffset >> 20) & 0xFF); UINT flags = RS_PCM8U; - if (pSmp->uFlags & CHN_16BIT) + if(Samples[realSmp].uFlags & CHN_16BIT) { - insex[i-1].flags |= 4; flags = RS_PCM16U; } - if (pSmp->uFlags & CHN_STEREO) + if(Samples[realSmp].uFlags & CHN_STEREO) { - insex[i-1].flags |= 2; - flags = (pSmp->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U; + flags |= RSF_STEREO; } - DWORD len = WriteSample(f, pSmp, flags); - if (len & 0x0F) + UINT writtenLength = WriteSample(f, &Samples[realSmp], flags, smpLength); + sampleDataOffset += writtenLength; + if((writtenLength % 16) != 0) { - fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f); + size_t fillSize = 16 - (writtenLength % 16); + fwrite(filler, fillSize, 1, f); + sampleDataOffset += fillSize; } - ofs += (len + 15) & (~0x0F); - } else - { - insex[i-1].length = 0; } + + sampleHeader[smp].ConvertEndianness(); } - // Updating parapointers - fseek(f, ofs0, SEEK_SET); - fwrite(insptr, nbi, 2, f); - fwrite(patptr, nbp, 2, f); - fseek(f, ofs1, SEEK_SET); - fwrite(insex, 0x50, nbi, f); + + // Now we know where the patterns are. + if(writePatterns != 0) + { + fseek(f, patternPointerOffset, SEEK_SET); + fwrite(&patternOffsets[0], 2, writePatterns, f); + } + + // And we can finally write the sample headers. + if(writeSamples != 0) + { + fseek(f, sampleHeaderOffset, SEEK_SET); + fwrite(&sampleHeader[0], sizeof(sampleHeader[0]), writeSamples, f); + } + fclose(f); return true; } -#pragma warning(default:4100) #endif // MODPLUG_NO_FILESAVE Modified: trunk/OpenMPT/soundlib/Load_umx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_umx.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Load_umx.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -273,7 +273,7 @@ // Read as module if(ReadIT(data, fileChunk.GetLength()) || ReadXM(data, fileChunk.GetLength()) - || ReadS3M(data, fileChunk.GetLength()) + || ReadS3M(fileChunk) || ReadWav(data, fileChunk.GetLength()) || ReadMod(fileChunk)) { Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2012-04-23 15:28:34 UTC (rev 1254) @@ -621,7 +621,7 @@ // -! NEW_FEATURE#0023 && !ReadIT(lpStream, dwMemLength) /*&& !ReadMPT(lpStream, dwMemLength)*/ - && !ReadS3M(lpStream, dwMemLength) + && !ReadS3M(file) && !ReadWav(lpStream, dwMemLength) #ifndef MODPLUG_BASIC_SUPPORT && !ReadSTM(lpStream, dwMemLength) @@ -2852,7 +2852,7 @@ ModCommand *fixCmd = (&m) - chn; for(CHANNELINDEX i = 0; i < chn; i++, fixCmd++) { - if(fixCmd->command == CMD_S3MCMDEX && (fixCmd->param & 0xF0) == 0x60) + if((fixCmd->command == CMD_S3MCMDEX || fixCmd->command == CMD_XFINEPORTAUPDOWN) && (fixCmd->param & 0xF0) == 0x60) { fixCmd->command = CMD_NONE; } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2012-04-21 23:08:23 UTC (rev 1253) +++ trunk/OpenMPT/soundlib/Sndfile.h 2012-04-23 15:28:34 UTC (rev 1254) @@ -370,7 +370,7 @@ // Module Loaders bool ReadXM(const LPCBYTE lpStream, const DWORD dwMemLength); - bool ReadS3M(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadS3M(FileReader &file); bool ReadMod(FileReader &file); bool ReadMed(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadMTM(const LPCBYTE lpStream, const DWORD dwMemLength); @@ -409,... [truncated message content] |